Bir neçə ay öncə, OpenAI ChatGPT üçün Apps təqdim etdi. aşağıda görəcəyiniz kimi, bu, şirkətlərin istifadəçilərin istefa verməyə kömək etmək üçün ürəklərini çata endirməyə imkan verir. Bir app açıq bir xatırlatma ilə və ya modelin app faydalı olacağına karar verdiyi zaman aktivləşdirilə bilər. So, what is a ChatGPT App? Müştərilər üçün bu, textual interfeisin kəşf etməsindən başqa, daha zengin istifadəçi deneyimini və funksiyasını əldə etmək üçün bir yoldur. Bir biznes üçün, doğru vaxtda 800 milyondan çox ChatGPT istifadəçisini tapmaq üçün bir yoldur. Bir proqramçı üçün, bu bir MCP serveri və bir iframe <= işləyən bir web appdır. Demo ilə Bu postda, aşağıda göstərilən bir basit test app yaratmaq üçün bunu bir nümunə olaraq istifadə edəcəyəm. Ötən ilin yanvar ayının 28-də “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin” “Qəbələ”nin “Qəbələ”nin” “Qəbələ”nin “Qəbələ”nin” If you want to follow along, Bir standart 20 $ / ay müştərinin abonement kifayət edər. Important Note: you will need a paid ChatGPT subscription to enable Developer Mode Yüksək flux Belə ki, belə bir proses baş verə bilər (çox az fərqlənir): İlk olaraq, proqramın yaradıcısı onu ChatGPT-də Bu, app ilə işləyir İŞİD Ətraflı “MCP” serverimiz “ChatGPT” kimi modelləri araşdırmağa və digər xidmətlərlə mübahisə etməyə imkan verir. “İ” “Qazaxıstan”ın “Qazaxıstan”ı bu mövsümdə providing a link to the MCP server (1) MCP Model Context Protocol tools resources ChatGPT learns and remembers what our app does and when it can be useful. Əvvəllər aparıldıqda və istifadəçi “Make a quiz about Sam Altman” kimi, ChatGPT istifadəçi üçün daha yaxşı deneyim vermək üçün texta cavabı qoyub istifadə edə biləcək bir App varlığına baxar. . (2) (3) Əgər bir App tapılırsa, ChatGPT Appın ehtiyacı olan data şemasına baxır. Applikaatımız verileri aşağıdaki JSON formatında qəbul etməlidir: (4) { questions: [ { question: "Where was Sam Altman born", options: ["San Francisco", ...], correctIndex: 2, ... }, ... ] } Bu adlandırılır Onu da app-a göndərəcəyik. . ChatGPT will generate quiz data exactly in this format toolInput (5) “App” bu işləyə bilər Ümumiyyətlə, ürəklər ChatGPT, proqramın istifadə etdiyi HTML "resurssuzunu" chat pencerəsində göstərəcək və onu Datça Son olaraq, istifadəçi app-u görəcək və onunla mübahisə edə bilər. . toolInput toolOutput toolOutput (6) (7) MCP serverin yaradılması Bizim ChatGPT app üçün kod repo: . https://github.com/renal128/quizaurus-tutorial 2 projekt var: və Birincisi, biz özümüzü Əsas səhifə » Əsas səhifə » Əsas səhifə quizaurus-plain quizaurus-react quizaurus-plain Bütün serverin kodu bu faildədir - yalnız 140-dən çox kodu! https://github.com/renal128/quizaurus-tutorial/blob/main/quizaurus-plain/src/server.ts Serverin yaradılması MCP serveri burada listələnən SDK-lərdən birini istifadə etmək üçün bir çox seçki vardır: https://modelcontextprotocol.io/docs/sdk Burada biz də istifadə edəcək . Sürücülər MCP SDK Aşağıdaki kod onu necə qurmaq üçün göstərir: // Create an MCP server const mcpServer = new McpServer({ name: 'quizaurus-server', version: '0.0.1' }); // Add the tool that receives and validates questions, and starts a quiz mcpServer.registerTool( ... ); // Add a resource that contains the frontend code for rendering the widget mcpServer.registerResource( ... ); // Create an Express app const expressApp = express(); expressApp.use(express.json()); // Set up /mcp endpoint that will be handled by the MCP server expressApp.post('/mcp', async (req, res) => { const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true }); res.on('close', () => { transport.close(); }); await mcpServer.connect(transport); await transport.handleRequest(req, res, req.body); }); const port = parseInt(process.env.PORT || '8000'); // Start the Express app expressApp.listen(port, () => { console.log(`MCP Server running on http://localhost:${port}/mcp`); }).on('error', error => { console.error('Server error:', error); process.exit(1); }); Key Point xəritədə: Express app (Express app) - ChatGPT-dən (HTTP istehlakları kimi) açıq-aşkar əlaqələr qəbul edən bir serverdir. Express istifadə edərək, ChatGPT-ə bizim MCP serverimizin adresi olaraq verəcəyimiz /mcp terminali daxil edərik (HTTPS://mysite.com/mcp kimi). The handling of the endpoint is delegated to the MCP server, that runs within the Express app /mcp all of the MCP protocol that we need is handled within that endpoint by the MCP server mcpServer.registerTool(...) və mcpServer.registerResource(...) bizim Quiz app qurmaq üçün istifadə edəcəyimizdir MCP alətləri İndi boşluğu doldurmalıyıq Üstəlik, “İnter”in “İnter”in “İnter”in “İnter”in “İnter”in “İnter”in “İnter”in “İnter”in “İnter”in “İnter”in “İnter”in “İnter”in “İnter”. mcpServer.registerTool(…) ChatGPT, istifadəçi üçün lazım olduğunda, ChatGPT-nin istifadə etdiyi alət definisiya kitabını oxuyar: // Add the tool that receives and validates questions, and starts a quiz mcpServer.registerTool( 'render-quiz', { title: 'Render Quiz', description: ` Use this when the user requests an interactive quiz. The tool expects to receive high-quality single-answer questions that match the schema in input/structuredContent: each item needs { question, options[], correctIndex, explanation }. Use 5–10 questions unless the user requests a specific number of questions. The questions will be shown to the user by the tool as an interactive quiz. Do not print the questions or answers in chat when you use this tool. Do not provide any sensitive or personal user information to this tool.`, _meta: { "openai/outputTemplate": "ui://widget/interactive-quiz.html", // <- hook to the resource }, inputSchema: { topic: z.string().describe("Quiz topic (e.g., 'US history')."), difficulty: z.enum(["easy", "medium", "hard"]).default("medium"), questions: z.array( z.object({ question: z.string(), options: z.array(z.string()).min(4).max(4), correctIndex: z.number().int(), explanation: z.string().optional(), }) ).min(1).max(40), }, }, async (toolInput) => { const { topic, difficulty, questions } = toolInput; // Here you can run any server-side logic to process the input from ChatGPT and // prepare toolOutput that would be fed into the frontend widget code. // E.g. you can receive search filters and return matching items. return { // Optional narration beneath the component content: [{ type: "text", text: `Starting a ${difficulty} quiz on ${topic}.` }], // `structuredContent` will be available as `toolOutput` in the frontend widget code structuredContent: { topic, difficulty, questions, }, // Private to the component; not visible to the model _meta: { "openai/locale": "en" }, }; } ); Kodun üst yarısı alətin bir tanımını verir - ChatGPT onu nə zaman və necə istifadə etmək üçün anlayacaq: ChatGPT onu istifadə edər ki, alətin istifadəçilərə uyğun olup olmadığını seçsin. Onu da qeyd etmək lazımdır ki, “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda” “Qazaxıstanda”. Burada “Shared” şeması istisnadır, lakin ChatGPT-ə strukturedContent-in hansı şeması olacağını söyləmək üçün bu şemayı verə bilərsiniz. Belə ki, bir anlamda, alət burada ChatGPT App-i tanımlayan şeydir. Başqa iki bölgəyə baxmalıyıq: _meta[“openai/outputTemplate”] ChatGPT App-in widgetini göstərmək üçün istifadə etdiyi MCP resursunun tanımlayıcısıdır. Xatırladaq ki, bu problemin başlanğıcına səbəb ola bilər, lakin bu problemin başlanğıcına səbəb ola bilər və bu problemin başlanğıcına səbəb ola bilər. MCP resursları Aşağıda MCP resursunu necə tanımlayırıq: // Add an MCP resource that contains frontend code for rendering the widget mcpServer.registerResource( 'interactive-quiz', "ui://widget/interactive-quiz.html", // must match `openai/outputTemplate` in the tool definition above {}, async (uri) => { // copy frontend script and css const quizaurusJs = await fs.readFile("./src/dist/QuizaurusWidget.js", "utf8"); const quizaurusCss = await fs.readFile("./src/dist/QuizaurusWidget.css", "utf8"); return { contents: [ { uri: uri.href, mimeType: "text/html+skybridge", // Below is the HTML code for the widget. // It defines a root div and injects our custom script from src/dist/QuizaurusWidget.js, // which finds the root div by its ID and renders the widget components in it. text: ` <div id="quizaurus-root" class="quizaurus-root"></div> <script type="module"> ${quizaurusJs} </script> <style> ${quizaurusCss} </style>` } ] } } ); Burda “Resource” App-in frontend (widget) hissəsini təmin edir. Ui://widget/interactive-quiz.html resurs ID-dir və yukarıdaki əvvəlki bölmədəki tool definisiya _meta[“openai/outputTemplate”] ilə eşidilməlidir. provides HTML code of the widget contents the HTML here is very simple - we just define the root div and add that will find that root div by ID, create necessary elements (buttons, etc) and define the quiz app logic. We will look at the script in the next section below. quiz-app-root the custom script Widget qurmaq Widget xəritədə İndi isə sürətli baxmalıyıq Bu barədə “The Daily Mail” xəbər verir: QuizaurusWidget.js Script xəritədə // Find the root div defined by the MCP resource const root = document.querySelector('#quiz-app-root'); // create HTML elements inside the root div ... // try to initialize for widgetState to restore the quiz state in case the chat page gets reloaded const selectedAnswers = window.openai.widgetState?.selectedAnswers ?? {}; let currentQuestionIndex = window.openai.widgetState?.currentQuestionIndex ?? 0; function refreshUI() { // Read questions from window.openai.toolOutput - this is the output of the tool defined in server.ts const questions = window.openai.toolOutput?.questions; // Initially the widget will be rendered with empty toolOutput. // It will be populated when ChatGPT receives toolOutput from our tool. if (!questions) { console.log("Questions have not yet been provided. Try again in a few sec.") return; } // Update UI according to the current state ... }; // when an answer button is clicked, we update the state and call refreshUI() optionButtons.forEach((b) => { b.onclick = (event) => { const selectedOption = event.target.textContent selectedAnswers[currentQuestionIndex] = selectedOption; // save and expose selected answers to ChatGPT window.openai.setWidgetState({ selectedAnswers, currentQuestionIndex }); refreshUI(); }; }); ... // at the end of the quiz, the user can click this button to review the answers with ChatGPT reviewResultsButton.onclick = () => { // send a prompt to ChatGPT, it will respond in the chat window.openai.sendFollowUpMessage({ prompt: "Review my answers and explain mistakes" }); reviewResultsButton.disabled = true; }; startQuizButton.onclick = refreshUI; refreshUI(); Əvvəlki xəbər: Bu kodu MCP resursunda definisiyalarımız olan HTML ( HTML və script ChatGPT chat sayfasında bir iframe içində olacaq. <script type="module">… ChatGPT bəzi məlumatları və hackləri Global objekt: Burada istifadə etdiyimiz şey budur: window.openai MCP tool tərəfindən qaytarılan sorğu verilərini window.openai.toolOutput içerir. İlk olaraq, html toolOutput qaytarmadan əvvəl render ediləcək, bu yüzden window.openai.toolOutput boş olacaq. Xatırladaq ki, bu barədə “The Guardian” xəbər verir ki, bu barədə “The Guardian” xəbər verir ki, bu barədə “The Guardian” məlumat yayıb. “FollowUpMessage” ({prompt: “...”}) ChatGPT-yə yazdığı kimi bir öndə göndərmək və ChatGPT-nin cavabını çata yazmaq üçün bir yoldur. OpenAI dokumentasiyasında daha çox imkanları burada bulabilirsiniz: https://developers.openai.com/apps-sdk/build/custom-ux Bütün bunları birləşdirmək Bunu test etmək zamanı! Bir sürətli xatırlatma olaraq, Developer modunu aktiv etmək üçün paytaxt ChatGPT abonementinə ehtiyacınız olacaq. Clone this repo [Download the code] https://github.com/renal128/quizaurus-tutorial There are 2 projects in this repo, a minimalistic one, described above, and a slicker-looking React one. We’ll focus on the first one for now. Open a terminal, navigate to the repo directory and run the following commands: [Starting the server] cd quizaurus-plain install NodeJS if you don’t have it https://nodejs.org/en/download/ to install dependencies defined in package.json npm install to start the Express app with MCP server - npm start keep it running [ ] Expose your local server to the web Create a free ngrok account: https://ngrok.com/ Open a (the other one with the Express app should keep running separately) new terminal Install ngrok: https://ngrok.com/docs/getting-started#1-install-the-ngrok-agent-cli on MacOS brew install ngrok Connect ngrok on your laptop to your ngrok account by configuring it with your auth token: https://ngrok.com/docs/getting-started#2-connect-your-account Start ngrok: ngrok http 8000 You should see something like this in the bottom of the output: Forwarding: https://xxxxx-xxxxxxx-xxxxxxxxx.ngrok-free ngrok created a tunnel from your laptop to a public server, so that your local server is available to everyone on the internet, including ChatGPT. Again, , don’t close the terminal keep it running - this is the part that r , $20/month, otherwise you may not see developer mode available. [Enable Developer Mode on ChatGPT] equires a paid customer subscription Go to ChatGPT website => Settings => Apps & Connectors => Advanced settings Enable the “Developer mode” toggle [Add the app] Go back to “Apps & Connectors” and click “Create” in the top-right corner Fill in the details as on the screenshot. For “MCP Server URL” use the URL that ngrok gave you in the terminal output and . add /mcp to it at the end Click on your newly added app You should see the MCP tool under Actions - now ChatGPT knows when and how to use the app. When you make changes to the code, sometimes , otherwise it can remain cached (sometimes I even delete and re-add the app due to avoid caching). you need to click Refresh to make ChatGPT pick up the changes [ ] Finally, we’re ready to test it! Test the app In the chat window you can nudge ChatGPT to use your app by selecting it under the “ ” button. In my experience, it’s not always necessary, but let’s do it anyway. Then try a prompt like “Make an interactive 3-question quiz about Sam Altman”. + You should see ChatGPT asking your approval to call the MCP tool with the displayed . I assume that it’s a feature for unapproved apps, and it won’t happen once the app is properly reviewed by OpenAI (although, as of Nov 2025 there’s no defined process to publish an app yet). So, just click “Confirm” and wait a few seconds. toolInput As I mentioned above, the widget gets rendered before is returned by our MCP server. This means that if you click “Start Quiz” too soon, it won’t do anything - try again a couple seconds later. (we will fix that with React in the next section below). When the data is ready, clicking “Start Quiz” should show the quiz! toolOutput Reaksiya ilə bağlı Üstəlik, bu problemdən biri də bu problemin həllində olan problemlərdir. , React istifadə edərək bir ChatGPT app necə qurulacağını göstərir. Qazaxıstanda reaksiya Burada OpenAI-dən bir neçə faydalı dokumentasiya əldə edə bilərsiniz: . https://developers.openai.com/apps-sdk/build/custom-ux/ useOpenAiGlobal helper hooks Bunları burada görürsünüz, kod dokumentundan kopyalıb: https://github.com/renal128/quizaurus-tutorial/blob/main/quizaurus-react/web/src/openAiHooks.ts Ən faydalı olanı Bu barədə “React” app-a yeni update-lər təqdim edirik. Əvvəla, bu barədə “Qəbələ”yə istinadən xəbər verir ki, “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”nin “Qəbələ”in “Qəbələ”in “Qəbələ”in “Qəbələ”in “Qəbələ”in “Qəbələ”in useToolOutput window.openai.toolOutput function App() { const toolOutput = useToolOutput() as QuizData | null; if (!toolOutput) { return ( <div className="quiz-container"> <p className="quiz-loading__text">Generating your quiz...</p> </div> ); } // otherwise render the quiz ... } ToolOutput yerləşdirildiyi zaman, React automatik olaraq app-u yenidən göstərəcək və yüklənmənin statusu yerine quşunu göstərəcək. Reaksiya Router Uygulamanın göstərildiyi iframe-in navigasiya tarixçəsi sayının navigasiya tarixçəsinə bağlıdır, belə ki, React Router kimi yönəltmək API-lərini istifadə edə bilərsiniz. Diqqət və digər xüsusiyyətlər Note: ChatGPT proqramının geliştirilməsi şu anda çox stabil deyil, çünkü funksiya tamamilə yaradılmamışdır, bu yüzden API-nin və ya kiçik bugların açıqlanmamış dəyişikliklərini gözləmək düzgündür. https://developers.openai.com/apps-sdk ChatGPT istifadəçilərə appunuzu necə və nə zaman göstərməyə qərar verir The most important part is that your app’s metadata, such as the tool description, must feel relevant to the conversation. ChatGPT’s goal here is to provide the best UX to the user, so obviously if the app’s description is irrelevant to the prompt, the app won’t be shown. I’ve also seen ChatGPT asking the user to rate if the app was helpful or not, I suppose this feedback is also taken into account. App Metadata. Official recommendations: https://developers.openai.com/apps-sdk/guides/optimize-metadata The in order to be used. How would the user know to link an app? There are 2 ways: App Discovery. app needs to be linked/connected to the user’s account Manual - go to and find the app there. Settings => Apps & Connectors Contextual Suggestion - if the app is not connected, but is highly relevant in the conversation, ChatGPT may offer to connect it. I wasn’t able to make it work with my app, but I saw it working with pre-integrated apps like Zillow or Spotify: VVD - Hollandiyada futbolçu bu adla tanımır, orada VVD daha çox mərkəz-sağı təmsilən edən siyasi partiyanın adının qısaltması kimi bilinir - artıq sorğu-suala ehtiyacı olmayan ulduzdu. Destek platformaları - since it’s implemented via iframe, web is the easiest platform to support and I had almost no issues there. Web Mobil app - webdə app bağlayırsanız, onu mobilda görmək mümkün olmalıdır. mobilda app başlamaq mümkün olmadı - alətə çağırmaq imkansızdı, lakin webdə app başlattığım zaman mobilda onunla mübahisə edə bilirdim. Autentifikasiya ChatGPT Apps OAuth 2.1 dəstəkləyir: https://developers.openai.com/apps-sdk/build/auth Bu böyük bir temadır, bu barədə ayrı bir yazı yazmaq faydalı olarmı? İnternet istəkləri Bu barədə məlumat yayıb ( • “ OpenAI ortaqınızla işləyin, əgər tamamilə izin verməyə ehtiyacınız varsa. Kaynak Standard fetch requests are allowed only when they comply with the CSP Başqa bir yerdə ( Buna görə də konfigurasiya Domeynlərinizin imkanlandırılması üçün resurs definisiyasında objekt: Burada _meta _meta: { ... /* Assigns a subdomain for the HTML. When set, the HTML is rendered within `chatgpt-com.web-sandbox.oaiusercontent.com` It's also used to configure the base url for external links. */ "openai/widgetDomain": 'https://chatgpt.com', /* Required to make external network requests from the HTML code. Also used to validate `openai.openExternal()` requests. */ 'openai/widgetCSP': { // Maps to `connect-src` rule in the iframe CSP connect_domains: ['https://chatgpt.com'], // Maps to style-src, style-src-elem, img-src, font-src, media-src etc. in the iframe CSP resource_domains: ['https://*.oaistatic.com'], } } Başqa bir şey var ki, istifadə edə bilərsiniz. MCP serverinizdə bir alət çağırmaq üçün app widgetiniz (frontend) istifadə edə bilər - MCP alət adınızı və alət verinInput data və geri toolOutput alırsınız: window.openai.callTool await window.openai?.callTool("my_tool_name", { "param_name": "param_value" }); Öncəki SonrakıSonrakı Sonrakı Bu dokumentasiya üçün Frontend kodunun nə olduğunu görmək Şirkət : window.openai https://developers.openai.com/apps-sdk/build/custom-ux Sonraki İçerikİnter (İnter) proqramı təqdim olunacaq Xatırlayırsınız ki, Xatırladaq ki, Xatırladaq ki, Xatırladaq ki, Xatırladaq: window.openai.theme theme: Theme; userAgent: UserAgent; locale: string; // layout maxHeight: number; displayMode: DisplayMode; safeArea: SafeArea; // state toolInput: ToolInput; toolOutput: ToolOutput | null; toolResponseMetadata: ToolResponseMetadata | null; widgetState: WidgetState | null; Sonraki İçerikİnteraksiya: Sonraki İçerikİnteraksiya: Sonraki İçerikİnteraksiya: Sonraki App-unuzu tam ekranlaşdırmaq üçün: await window.openai?.requestDisplayMode({ mode: "fullscreen" }); /** Calls a tool on your MCP. Returns the full response. */ callTool: ( name: string, args: Record<string, unknown> ) => Promise<CallToolResponse>; /** Triggers a followup turn in the ChatGPT conversation */ sendFollowUpMessage: (args: { prompt: string }) => Promise<void>; /** Opens an external link, redirects web page or mobile app */ openExternal(payload: { href: string }): void; /** For transitioning an app from inline to fullscreen or pip */ requestDisplayMode: (args: { mode: DisplayMode }) => Promise<{ /** * The granted display mode. The host may reject the request. * For mobile, PiP is always coerced to fullscreen. */ mode: DisplayMode; }>; /** Update widget state */ setWidgetState: (state: WidgetState) => Promise<void>; təşəkkür edirəm! Bütün bu, oxuduğunuz üçün təşəkkür və inşa etdiyiniz hər şey üçün şans!