[{"data":1,"prerenderedAt":1497},["ShallowReactive",2],{"navigation_docs":3,"-apps-testing-publishing":287,"-apps-testing-publishing-surround":1492},[4,40,70,99,122,156,189,258],{"title":5,"path":6,"stem":7,"children":8,"page":39},"Getting Started","\u002Fgetting-started","1.getting-started",[9,14,19,24,29,34],{"title":10,"path":11,"stem":12,"icon":13},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-book-open",{"title":15,"path":16,"stem":17,"icon":18},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":20,"path":21,"stem":22,"icon":23},"Configuration","\u002Fgetting-started\u002Fconfiguration","1.getting-started\u002F3.configuration","i-lucide-settings",{"title":25,"path":26,"stem":27,"icon":28},"Inspector","\u002Fgetting-started\u002Finspector","1.getting-started\u002F4.inspector","i-lucide-circuit-board",{"title":30,"path":31,"stem":32,"icon":33},"Connection","\u002Fgetting-started\u002Fconnection","1.getting-started\u002F5.connection","i-lucide-plug",{"title":35,"path":36,"stem":37,"icon":38},"Agent Skills","\u002Fgetting-started\u002Fagent-skills","1.getting-started\u002F6.agent-skills","i-lucide-sparkles",false,{"title":41,"path":42,"stem":43,"children":44,"page":39},"Tools","\u002Ftools","2.tools",[45,50,55,60,65],{"title":46,"path":47,"stem":48,"icon":49},"Overview","\u002Ftools\u002Foverview","2.tools\u002F0.overview","i-lucide-wrench",{"title":51,"path":52,"stem":53,"icon":54},"Schema, handler & returns","\u002Ftools\u002Fschema-handler","2.tools\u002F1.schema-handler","i-lucide-braces",{"title":56,"path":57,"stem":58,"icon":59},"Annotations & input examples","\u002Ftools\u002Fannotations","2.tools\u002F2.annotations","i-lucide-badge-info",{"title":61,"path":62,"stem":63,"icon":64},"Errors & caching","\u002Ftools\u002Ferrors-caching","2.tools\u002F3.errors-caching","i-lucide-shield",{"title":66,"path":67,"stem":68,"icon":69},"Groups, files & dynamic registration","\u002Ftools\u002Fgroups-organization","2.tools\u002F4.groups-organization","i-lucide-tags",{"title":71,"path":72,"stem":73,"children":74,"page":39},"Resources","\u002Fresources","3.resources",[75,79,84,89,94],{"title":46,"path":76,"stem":77,"icon":78},"\u002Fresources\u002Foverview","3.resources\u002F0.overview","i-lucide-package",{"title":80,"path":81,"stem":82,"icon":83},"Static resources & structure","\u002Fresources\u002Fstatic-and-structure","3.resources\u002F1.static-and-structure","i-lucide-file-stack",{"title":85,"path":86,"stem":87,"icon":88},"Templates & handlers","\u002Fresources\u002Ftemplates-and-handlers","3.resources\u002F2.templates-and-handlers","i-lucide-git-branch",{"title":90,"path":91,"stem":92,"icon":93},"Metadata, content & errors","\u002Fresources\u002Fcontent-metadata-errors","3.resources\u002F3.content-metadata-errors","i-lucide-layers",{"title":95,"path":96,"stem":97,"icon":98},"Groups & organization","\u002Fresources\u002Forganization","3.resources\u002F4.organization","i-lucide-folder-tree",{"title":100,"path":101,"stem":102,"children":103,"page":39},"Prompts","\u002Fprompts","4.prompts",[104,108,113,117],{"title":46,"path":105,"stem":106,"icon":107},"\u002Fprompts\u002Foverview","4.prompts\u002F0.overview","i-lucide-message-square",{"title":109,"path":110,"stem":111,"icon":112},"Authoring & structure","\u002Fprompts\u002Fauthoring","4.prompts\u002F1.authoring","i-lucide-pen-line",{"title":114,"path":115,"stem":116,"icon":93},"Input, handler & messages","\u002Fprompts\u002Finput-handler-messages","4.prompts\u002F2.input-handler-messages",{"title":118,"path":119,"stem":120,"icon":121},"Patterns & advanced","\u002Fprompts\u002Fpatterns-advanced","4.prompts\u002F3.patterns-advanced","i-lucide-line-chart",{"title":123,"path":124,"stem":125,"children":126,"page":39},"Handlers","\u002Fhandlers","5.handlers",[127,131,136,141,146,151],{"title":46,"path":128,"stem":129,"icon":130},"\u002Fhandlers\u002Foverview","5.handlers\u002F0.overview","i-lucide-server",{"title":132,"path":133,"stem":134,"icon":135},"Default & custom handlers","\u002Fhandlers\u002Fdefault-and-custom","5.handlers\u002F1.default-and-custom","i-lucide-toggle-left",{"title":137,"path":138,"stem":139,"icon":140},"Structure & options","\u002Fhandlers\u002Fstructure-and-options","5.handlers\u002F2.structure-and-options","i-lucide-sliders-horizontal",{"title":142,"path":143,"stem":144,"icon":145},"Examples & routing","\u002Fhandlers\u002Fexamples-routing","5.handlers\u002F3.examples-routing","i-lucide-route",{"title":147,"path":148,"stem":149,"icon":150},"Sharing & practices","\u002Fhandlers\u002Fsharing-practices","5.handlers\u002F4.sharing-practices","i-lucide-share-2",{"title":152,"path":153,"stem":154,"icon":155},"Multi-handler organization","\u002Fhandlers\u002Forganization","5.handlers\u002F5.organization","i-lucide-network",{"title":157,"path":158,"stem":159,"children":160,"page":39},"Apps","\u002Fapps","6.apps",[161,165,170,175,179,184],{"title":46,"path":162,"stem":163,"icon":164},"\u002Fapps\u002Foverview","6.apps\u002F0.overview","i-lucide-app-window",{"title":166,"path":167,"stem":168,"icon":169},"Authoring & defineMcpApp","\u002Fapps\u002Fauthoring","6.apps\u002F1.authoring","i-lucide-code-2",{"title":171,"path":172,"stem":173,"icon":174},"useMcpApp() bridge","\u002Fapps\u002Fuse-mcp-app","6.apps\u002F2.use-mcp-app","i-lucide-message-circle",{"title":176,"path":177,"stem":178,"icon":64},"CSP & build pipeline","\u002Fapps\u002Fcsp-and-wiring","6.apps\u002F3.csp-and-wiring",{"title":180,"path":181,"stem":182,"icon":183},"Testing & publishing","\u002Fapps\u002Ftesting-publishing","6.apps\u002F4.testing-publishing","i-lucide-rocket",{"title":185,"path":186,"stem":187,"icon":188},"Patterns & limits","\u002Fapps\u002Fpatterns-reference","6.apps\u002F5.patterns-reference","i-lucide-book-marked",{"title":190,"path":191,"stem":192,"children":193,"page":39},"Advanced Topics","\u002Fadvanced","7.advanced",[194,199,204,209,214,219,223,228,233,238,243,248,253],{"title":195,"path":196,"stem":197,"icon":198},"Custom Paths","\u002Fadvanced\u002Fcustom-paths","7.advanced\u002F1.custom-paths","i-lucide-folder",{"title":200,"path":201,"stem":202,"icon":203},"Logging","\u002Fadvanced\u002Flogging","7.advanced\u002F10.logging","i-lucide-scroll-text",{"title":205,"path":206,"stem":207,"icon":208},"MCP Apps Internals","\u002Fadvanced\u002Fmcp-apps-internals","7.advanced\u002F11.mcp-apps-internals","i-lucide-cog",{"title":210,"path":211,"stem":212,"icon":213},"Listing Definitions","\u002Fadvanced\u002Flisting-definitions","7.advanced\u002F12.listing-definitions","i-lucide-list",{"title":215,"path":216,"stem":217,"icon":218},"llms.txt discovery","\u002Fadvanced\u002Fllms-txt","7.advanced\u002F13.llms-txt","i-lucide-file-text",{"title":220,"path":221,"stem":222,"icon":64},"Middleware","\u002Fadvanced\u002Fmiddleware","7.advanced\u002F2.middleware",{"title":224,"path":225,"stem":226,"icon":227},"TypeScript","\u002Fadvanced\u002Ftypescript","7.advanced\u002F3.typescript","i-lucide-type",{"title":229,"path":230,"stem":231,"icon":232},"Hooks","\u002Fadvanced\u002Fhooks","7.advanced\u002F4.hooks","i-lucide-webhook",{"title":234,"path":235,"stem":236,"icon":237},"MCP Evals","\u002Fadvanced\u002Fevals","7.advanced\u002F5.evals","i-lucide-flask-conical",{"title":239,"path":240,"stem":241,"icon":242},"Sessions","\u002Fadvanced\u002Fsessions","7.advanced\u002F6.sessions","i-lucide-database",{"title":244,"path":245,"stem":246,"icon":247},"Dynamic Definitions","\u002Fadvanced\u002Fdynamic-definitions","7.advanced\u002F7.dynamic-definitions","i-lucide-toggle-right",{"title":249,"path":250,"stem":251,"icon":252},"Code Mode","\u002Fadvanced\u002Fcode-mode","7.advanced\u002F8.code-mode","i-lucide-code",{"title":254,"path":255,"stem":256,"icon":257},"Elicitation","\u002Fadvanced\u002Felicitation","7.advanced\u002F9.elicitation","i-lucide-message-square-quote",{"title":259,"path":260,"stem":261,"children":262,"page":39},"Examples","\u002Fexamples","8.examples",[263,268,273,278,283],{"title":264,"path":265,"stem":266,"icon":267},"Authentication","\u002Fexamples\u002Fauthentication","8.examples\u002F1.authentication","i-lucide-shield-check",{"title":269,"path":270,"stem":271,"icon":272},"API Integration","\u002Fexamples\u002Fapi-integration","8.examples\u002F2.api-integration","i-lucide-globe",{"title":274,"path":275,"stem":276,"icon":277},"Common Patterns","\u002Fexamples\u002Fcommon-patterns","8.examples\u002F3.common-patterns","i-lucide-lightbulb",{"title":279,"path":280,"stem":281,"icon":282},"File Operations","\u002Fexamples\u002Ffile-operations","8.examples\u002F4.file-operations","i-lucide-file",{"title":284,"path":285,"stem":286,"icon":107},"Prompt Examples","\u002Fexamples\u002Fprompt-examples","8.examples\u002F5.prompt-examples",{"id":288,"title":180,"body":289,"description":1483,"extension":1484,"links":1485,"meta":1486,"navigation":1487,"path":181,"seo":1488,"stem":182,"__hash__":1491},"docs\u002F6.apps\u002F4.testing-publishing.md",{"type":290,"value":291,"toc":1462},"minimark",[292,297,402,413,417,431,434,498,501,512,532,566,569,573,576,593,596,605,610,619,622,664,671,680,683,709,712,821,824,889,896,900,907,916,923,963,966,1070,1077,1081,1084,1135,1164,1168,1178,1181,1203,1207,1210,1225,1233,1236,1247,1251,1254,1326,1334,1338,1345,1355,1358,1362,1365,1369,1388,1391,1394,1398,1458],[293,294,296],"h2",{"id":295},"host-compatibility","Host compatibility",[298,299,300,332],"table",{},[301,302,303],"thead",{},[304,305,306,310,313,319,324,329],"tr",{},[307,308,309],"th",{},"Host",[307,311,312],{},"Render",[307,314,315],{},[316,317,318],"code",{},"sendPrompt",[307,320,321],{},[316,322,323],{},"callTool",[307,325,326],{},[316,327,328],{},"openLink",[307,330,331],{},"Notes",[333,334,335,356,379],"tbody",{},[304,336,337,344,347,349,351,353],{},[338,339,340],"td",{},[341,342,343],"strong",{},"Cursor",[338,345,346],{},"✅",[338,348,346],{},[338,350,346],{},[338,352,346],{},[338,354,355],{},"Tested with the JSON-RPC bridge and legacy ready\u002Fresize messages.",[304,357,358,363,365,368,370,372],{},[338,359,360],{},[341,361,362],{},"ChatGPT (Apps SDK)",[338,364,346],{},[338,366,367],{},"⚠️",[338,369,346],{},[338,371,346],{},[338,373,374,375,378],{},"Uses ",[316,376,377],{},"window.openai"," when available. Follow-ups are sent, but the next tool is not always rendered inline.",[304,380,381,386,388,391,393,395],{},[338,382,383],{},[341,384,385],{},"MCP UI \u002F Inspector-style hosts",[338,387,346],{},[338,389,390],{},"varies",[338,392,390],{},[338,394,390],{},[338,396,397,398,401],{},"The bridge emits spec JSON-RPC messages plus legacy ",[316,399,400],{},"mcp-ui"," envelopes where useful. Verify each host before documenting support.",[403,404,405,406,408,409,412],"p",{},"The bridge auto-detects the host on handshake and adapts to its protocol — modern JSON-RPC for MCP UI hosts, the legacy ",[316,407,400],{}," envelope for older clients, the ChatGPT Apps SDK globals when present. Your code just calls ",[316,410,411],{},"useMcpApp()",".",[293,414,416],{"id":415},"local-test-loop","Local test loop",[403,418,419,420,423,424,427,428,412],{},"MCP Apps use the same streamable HTTP endpoint as your tools, resources, and prompts. The default route is ",[316,421,422],{},"\u002Fmcp"," unless you set ",[316,425,426],{},"mcp.route"," in ",[316,429,430],{},"nuxt.config",[403,432,433],{},"Start your Nuxt app:",[435,436,437,459,474,486],"code-group",{},[438,439,445],"pre",{"className":440,"code":441,"filename":442,"language":443,"meta":444,"style":444},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm dev\n","pnpm","bash","",[316,446,447],{"__ignoreMap":444},[448,449,452,455],"span",{"class":450,"line":451},"line",1,[448,453,442],{"class":454},"sBMFI",[448,456,458],{"class":457},"sfazB"," dev\n",[438,460,463],{"className":440,"code":461,"filename":462,"language":443,"meta":444,"style":444},"npm run dev\n","npm",[316,464,465],{"__ignoreMap":444},[448,466,467,469,472],{"class":450,"line":451},[448,468,462],{"class":454},[448,470,471],{"class":457}," run",[448,473,458],{"class":457},[438,475,478],{"className":440,"code":476,"filename":477,"language":443,"meta":444,"style":444},"yarn dev\n","yarn",[316,479,480],{"__ignoreMap":444},[448,481,482,484],{"class":450,"line":451},[448,483,477],{"class":454},[448,485,458],{"class":457},[438,487,490],{"className":440,"code":488,"filename":489,"language":443,"meta":444,"style":444},"bun dev\n","bun",[316,491,492],{"__ignoreMap":444},[448,493,494,496],{"class":450,"line":451},[448,495,489],{"class":454},[448,497,458],{"class":457},[403,499,500],{},"Your local MCP URL is:",[438,502,506],{"className":503,"code":504,"language":505,"meta":444,"style":444},"language-txt shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","http:\u002F\u002Flocalhost:3000\u002Fmcp\n","txt",[316,507,508],{"__ignoreMap":444},[448,509,510],{"class":450,"line":451},[448,511,504],{},[403,513,514,515,519,520,523,524,527,528,531],{},"Use the ",[516,517,518],"a",{"href":26},"MCP Inspector",", ",[316,521,522],{},"npx @modelcontextprotocol\u002Finspector@latest",", or the ",[341,525,526],{},"MCP"," panel in ",[341,529,530],{},"Nuxt DevTools"," first. Confirm that:",[533,534,535,547,553,560],"ul",{},[536,537,538,539,542,543,546],"li",{},"the app SFC appears as a tool, for example ",[316,540,541],{},"color-picker"," or ",[316,544,545],{},"release-control",";",[536,548,549,550,546],{},"calling the tool returns ",[316,551,552],{},"structuredContent",[536,554,555,556,559],{},"the tool result includes a ",[316,557,558],{},"text\u002Fhtml;profile=mcp-app"," resource;",[536,561,562,563,412],{},"the resource URI looks like ",[316,564,565],{},"ui:\u002F\u002Fmcp-app\u002F\u003Cname>",[403,567,568],{},"Some clients can call the tool but cannot render the iframe. Use a host with MCP Apps support when validating the UI itself.",[293,570,572],{"id":571},"test-in-chatgpt-with-ngrok","Test in ChatGPT with ngrok",[403,574,575],{},"ChatGPT requires a public HTTPS endpoint, even for local development. Tunnel your local Nuxt server:",[438,577,579],{"className":440,"code":578,"language":443,"meta":444,"style":444},"ngrok http 3000\n",[316,580,581],{"__ignoreMap":444},[448,582,583,586,589],{"class":450,"line":451},[448,584,585],{"class":454},"ngrok",[448,587,588],{"class":457}," http",[448,590,592],{"class":591},"sbssI"," 3000\n",[403,594,595],{},"ngrok prints a forwarding URL:",[438,597,599],{"className":503,"code":598,"language":505,"meta":444,"style":444},"Forwarding https:\u002F\u002Fyour-subdomain.ngrok-free.dev -> http:\u002F\u002Flocalhost:3000\n",[316,600,601],{"__ignoreMap":444},[448,602,603],{"class":450,"line":451},[448,604,598],{},[403,606,514,607,609],{},[316,608,422],{}," route on that origin:",[438,611,613],{"className":503,"code":612,"language":505,"meta":444,"style":444},"https:\u002F\u002Fyour-subdomain.ngrok-free.dev\u002Fmcp\n",[316,614,615],{"__ignoreMap":444},[448,616,617],{"class":450,"line":451},[448,618,612],{},[403,620,621],{},"In ChatGPT:",[623,624,625,640,647,653,658,661],"ol",{},[536,626,627,628,427,631,634,635,634,637,412],{},"Enable ",[341,629,630],{},"Developer Mode",[341,632,633],{},"Settings"," → ",[341,636,157],{},[341,638,639],{},"Advanced settings",[536,641,642,643,634,645,412],{},"Open ",[341,644,633],{},[341,646,157],{},[536,648,649,650,412],{},"Click ",[341,651,652],{},"Create app",[536,654,655,656,412],{},"Enter your public MCP URL, including ",[316,657,422],{},[536,659,660],{},"Enable the app and start a new chat.",[536,662,663],{},"Select your app from the composer before prompting the model.",[403,665,666,667,670],{},"Mention the app with ",[316,668,669],{},"@"," so ChatGPT routes the prompt through your connector:",[438,672,674],{"className":503,"code":673,"language":505,"meta":444,"style":444},"@Weather App What is the weather in London?\n",[316,675,676],{"__ignoreMap":444},[448,677,678],{"class":450,"line":451},[448,679,673],{},[403,681,682],{},"Then test the iframe behaviour:",[533,684,685,692,698,704],{},[536,686,687,688,691],{},"click a button that calls ",[316,689,690],{},"callTool()"," and confirm the widget updates without a new chat turn;",[536,693,687,694,697],{},[316,695,696],{},"sendPrompt()"," and confirm a follow-up message appears in the conversation;",[536,699,687,700,703],{},[316,701,702],{},"openLink()"," and confirm ChatGPT opens or prompts for the external URL;",[536,705,706,707,412],{},"watch your Nuxt terminal and ngrok dashboard for POST requests to ",[316,708,422],{},[403,710,711],{},"If you expose local dev through ngrok, allow the tunnel host in Vite:",[438,713,718],{"className":714,"code":715,"filename":716,"language":717,"meta":444,"style":444},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtConfig({\n  vite: {\n    server: {\n      allowedHosts: ['.ngrok-free.dev', '.ngrok.app'],\n    },\n  },\n})\n","nuxt.config.ts","ts",[316,719,720,741,754,764,800,806,812],{"__ignoreMap":444},[448,721,722,726,729,733,737],{"class":450,"line":451},[448,723,725],{"class":724},"s7zQu","export",[448,727,728],{"class":724}," default",[448,730,732],{"class":731},"s2Zo4"," defineNuxtConfig",[448,734,736],{"class":735},"sTEyZ","(",[448,738,740],{"class":739},"sMK4o","{\n",[448,742,744,748,751],{"class":450,"line":743},2,[448,745,747],{"class":746},"swJcz","  vite",[448,749,750],{"class":739},":",[448,752,753],{"class":739}," {\n",[448,755,757,760,762],{"class":450,"line":756},3,[448,758,759],{"class":746},"    server",[448,761,750],{"class":739},[448,763,753],{"class":739},[448,765,767,770,772,775,778,781,783,786,789,792,794,797],{"class":450,"line":766},4,[448,768,769],{"class":746},"      allowedHosts",[448,771,750],{"class":739},[448,773,774],{"class":735}," [",[448,776,777],{"class":739},"'",[448,779,780],{"class":457},".ngrok-free.dev",[448,782,777],{"class":739},[448,784,785],{"class":739},",",[448,787,788],{"class":739}," '",[448,790,791],{"class":457},".ngrok.app",[448,793,777],{"class":739},[448,795,796],{"class":735},"]",[448,798,799],{"class":739},",\n",[448,801,803],{"class":450,"line":802},5,[448,804,805],{"class":739},"    },\n",[448,807,809],{"class":450,"line":808},6,[448,810,811],{"class":739},"  },\n",[448,813,815,818],{"class":450,"line":814},7,[448,816,817],{"class":739},"}",[448,819,820],{"class":735},")\n",[403,822,823],{},"For cross-origin hosts such as ChatGPT, configure MCP origin checks intentionally:",[438,825,827],{"className":714,"code":826,"filename":716,"language":717,"meta":444,"style":444},"export default defineNuxtConfig({\n  mcp: {\n    security: {\n      allowedOrigins: '*',\n    },\n  },\n})\n",[316,828,829,841,850,859,875,879,883],{"__ignoreMap":444},[448,830,831,833,835,837,839],{"class":450,"line":451},[448,832,725],{"class":724},[448,834,728],{"class":724},[448,836,732],{"class":731},[448,838,736],{"class":735},[448,840,740],{"class":739},[448,842,843,846,848],{"class":450,"line":743},[448,844,845],{"class":746},"  mcp",[448,847,750],{"class":739},[448,849,753],{"class":739},[448,851,852,855,857],{"class":450,"line":756},[448,853,854],{"class":746},"    security",[448,856,750],{"class":739},[448,858,753],{"class":739},[448,860,861,864,866,868,871,873],{"class":450,"line":766},[448,862,863],{"class":746},"      allowedOrigins",[448,865,750],{"class":739},[448,867,788],{"class":739},[448,869,870],{"class":457},"*",[448,872,777],{"class":739},[448,874,799],{"class":739},[448,876,877],{"class":450,"line":802},[448,878,805],{"class":739},[448,880,881],{"class":450,"line":808},[448,882,811],{"class":739},[448,884,885,887],{"class":450,"line":814},[448,886,817],{"class":739},[448,888,820],{"class":735},[403,890,891,892,895],{},"Use ",[316,893,894],{},"'*'"," only for demos or public read-only surfaces. For production apps with private data or real side effects, use a list of trusted origins.",[293,897,899],{"id":898},"deploy-to-vercel-or-another-cloud","Deploy to Vercel or another cloud",[403,901,902,903,906],{},"MCP Apps do ",[341,904,905],{},"not"," use a second URL. Deploy the Nuxt app and connect ChatGPT to the same MCP route:",[438,908,910],{"className":503,"code":909,"language":505,"meta":444,"style":444},"https:\u002F\u002Fyour-project.vercel.app\u002Fmcp\n",[316,911,912],{"__ignoreMap":444},[448,913,914],{"class":450,"line":451},[448,915,909],{},[403,917,918,919,922],{},"The toolkit auto-detects ",[316,920,921],{},"_meta.ui.domain"," from common hosting variables:",[533,924,925,930,939,945,951,957],{},[536,926,927,546],{},[316,928,929],{},"NUXT_PUBLIC_APP_URL",[536,931,932,933,519,936,546],{},"Vercel: ",[316,934,935],{},"VERCEL_PROJECT_PRODUCTION_URL",[316,937,938],{},"VERCEL_URL",[536,940,941,942,546],{},"Netlify: ",[316,943,944],{},"URL",[536,946,947,948,546],{},"Render: ",[316,949,950],{},"RENDER_EXTERNAL_URL",[536,952,953,954,546],{},"Railway: ",[316,955,956],{},"RAILWAY_PUBLIC_DOMAIN",[536,958,959,960,412],{},"Fly: ",[316,961,962],{},"FLY_APP_NAME",[403,964,965],{},"If you need to override the detected value, set it explicitly:",[438,967,972],{"className":968,"code":969,"filename":970,"language":971,"meta":444,"style":444},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup lang=\"ts\">\ndefineMcpApp({\n  _meta: {\n    ui: {\n      domain: 'https:\u002F\u002Fmy-app.example.com',\n    },\n  },\n})\n\u003C\u002Fscript>\n","app\u002Fmcp\u002Fmy-app.vue","vue",[316,973,974,1002,1011,1020,1029,1045,1049,1053,1060],{"__ignoreMap":444},[448,975,976,979,982,986,989,992,995,997,999],{"class":450,"line":451},[448,977,978],{"class":739},"\u003C",[448,980,981],{"class":746},"script",[448,983,985],{"class":984},"spNyl"," setup",[448,987,988],{"class":984}," lang",[448,990,991],{"class":739},"=",[448,993,994],{"class":739},"\"",[448,996,717],{"class":457},[448,998,994],{"class":739},[448,1000,1001],{"class":739},">\n",[448,1003,1004,1007,1009],{"class":450,"line":743},[448,1005,1006],{"class":731},"defineMcpApp",[448,1008,736],{"class":735},[448,1010,740],{"class":739},[448,1012,1013,1016,1018],{"class":450,"line":756},[448,1014,1015],{"class":746},"  _meta",[448,1017,750],{"class":739},[448,1019,753],{"class":739},[448,1021,1022,1025,1027],{"class":450,"line":766},[448,1023,1024],{"class":746},"    ui",[448,1026,750],{"class":739},[448,1028,753],{"class":739},[448,1030,1031,1034,1036,1038,1041,1043],{"class":450,"line":802},[448,1032,1033],{"class":746},"      domain",[448,1035,750],{"class":739},[448,1037,788],{"class":739},[448,1039,1040],{"class":457},"https:\u002F\u002Fmy-app.example.com",[448,1042,777],{"class":739},[448,1044,799],{"class":739},[448,1046,1047],{"class":450,"line":808},[448,1048,805],{"class":739},[448,1050,1051],{"class":450,"line":814},[448,1052,811],{"class":739},[448,1054,1056,1058],{"class":450,"line":1055},8,[448,1057,817],{"class":739},[448,1059,820],{"class":735},[448,1061,1063,1066,1068],{"class":450,"line":1062},9,[448,1064,1065],{"class":739},"\u003C\u002F",[448,1067,981],{"class":746},[448,1069,1001],{"class":739},[403,1071,1072,1073,1076],{},"For Vercel, make sure your build includes the MCP Apps bundling dependencies from the toolkit version you deploy. If you test an unreleased package, use a fresh ",[316,1074,1075],{},"pkg.pr.new"," build or install the required build dependencies in the app until the package is published.",[293,1078,1080],{"id":1079},"prepare-for-chatgpt-submission","Prepare for ChatGPT submission",[403,1082,1083],{},"OpenAI reviews apps before broad distribution. Before submitting, check:",[533,1085,1086,1089,1094,1104,1110,1115,1118,1123,1132],{},[536,1087,1088],{},"your MCP server is publicly reachable over HTTPS;",[536,1090,1091,1092,546],{},"each app resource returns ",[316,1093,558],{},[536,1095,1096,1097,519,1100,1103],{},"each app tool has clear ",[316,1098,1099],{},"description",[316,1101,1102],{},"inputSchema",", and behavior annotations;",[536,1105,1106,1109],{},[316,1107,1108],{},"_meta.ui.resourceUri"," is present (the toolkit generates it);",[536,1111,1112,1114],{},[316,1113,921],{}," is set or auto-detected;",[536,1116,1117],{},"CSP is explicit for external images, scripts, fonts, APIs, or iframes;",[536,1119,1120,1122],{},[316,1121,552],{}," is concise and safe for the model to read;",[536,1124,1125,1126,1129,1130,546],{},"large or widget-only data goes in ",[316,1127,1128],{},"_meta",", not in ",[316,1131,552],{},[536,1133,1134],{},"OAuth, privacy policy, app name, screenshots, and test prompts are ready if your app needs public distribution.",[403,1136,1137,1138,1141,1142,1144,1145,1148,1149,1154,1155,1160,1161,1163],{},"When the host exposes the ",[341,1139,1140],{},"Apps SDK"," (",[316,1143,377],{},") or enforces widget CSP, the toolkit mirrors your ",[316,1146,1147],{},"csp"," to ",[341,1150,1151],{},[316,1152,1153],{},"_meta.ui.csp"," and ",[341,1156,1157],{},[316,1158,1159],{},"openai\u002FwidgetCSP",". Behaviour, especially ",[316,1162,318],{}," and follow-up re-renders, can change between ChatGPT releases. Re-test your app before submitting or announcing support.",[293,1165,1167],{"id":1166},"troubleshooting","Troubleshooting",[1169,1170,1172,1175,1176],"h3",{"id":1171},"_403-forbidden-from-mcp",[316,1173,1174],{},"403 Forbidden"," from ",[316,1177,422],{},[403,1179,1180],{},"The request reached your server but failed an origin or host check.",[533,1182,1183,1192,1198],{},[536,1184,1185,1186,1148,1189,1191],{},"For ChatGPT\u002Fngrok demos, set ",[316,1187,1188],{},"mcp.security.allowedOrigins",[316,1190,894],{}," or to a trusted origin list.",[536,1193,1194,1195,412],{},"For Vite dev server tunnels, add the tunnel domain to ",[316,1196,1197],{},"vite.server.allowedHosts",[536,1199,1200,1201,412],{},"Restart the Nuxt dev server after changing ",[316,1202,716],{},[1169,1204,1206],{"id":1205},"widget-does-not-render","Widget does not render",[403,1208,1209],{},"Check the tool result:",[533,1211,1212,1217,1222],{},[536,1213,1214,1215,412],{},"The resource MIME type must be ",[316,1216,558],{},[536,1218,1219,1220,412],{},"The resource URI should match ",[316,1221,1108],{},[536,1223,1224],{},"The host must support MCP Apps. Some MCP clients can call the tool but only display text.",[1169,1226,1228,1229,1232],{"id":1227},"no-ui-messages-arrive","No ",[316,1230,1231],{},"ui\u002F*"," messages arrive",[403,1234,1235],{},"The iframe loaded, but the host did not enable the MCP Apps bridge.",[533,1237,1238,1241,1244],{},[536,1239,1240],{},"Confirm the host renders the HTML as an MCP App resource, not as a plain file.",[536,1242,1243],{},"Check the browser console inside the host devtools for CSP or sandbox errors.",[536,1245,1246],{},"Test in Cursor or ChatGPT to compare host behaviour.",[1169,1248,1250],{"id":1249},"csp-blocks-images-or-fetch-calls","CSP blocks images or fetch calls",[403,1252,1253],{},"Add explicit allow-lists:",[438,1255,1257],{"className":714,"code":1256,"language":717,"meta":444,"style":444},"defineMcpApp({\n  csp: {\n    resourceDomains: ['https:\u002F\u002Fimages.example.com'],\n    connectDomains: ['https:\u002F\u002Fapi.example.com'],\n  },\n})\n",[316,1258,1259,1267,1276,1296,1316,1320],{"__ignoreMap":444},[448,1260,1261,1263,1265],{"class":450,"line":451},[448,1262,1006],{"class":731},[448,1264,736],{"class":735},[448,1266,740],{"class":739},[448,1268,1269,1272,1274],{"class":450,"line":743},[448,1270,1271],{"class":746},"  csp",[448,1273,750],{"class":739},[448,1275,753],{"class":739},[448,1277,1278,1281,1283,1285,1287,1290,1292,1294],{"class":450,"line":756},[448,1279,1280],{"class":746},"    resourceDomains",[448,1282,750],{"class":739},[448,1284,774],{"class":735},[448,1286,777],{"class":739},[448,1288,1289],{"class":457},"https:\u002F\u002Fimages.example.com",[448,1291,777],{"class":739},[448,1293,796],{"class":735},[448,1295,799],{"class":739},[448,1297,1298,1301,1303,1305,1307,1310,1312,1314],{"class":450,"line":766},[448,1299,1300],{"class":746},"    connectDomains",[448,1302,750],{"class":739},[448,1304,774],{"class":735},[448,1306,777],{"class":739},[448,1308,1309],{"class":457},"https:\u002F\u002Fapi.example.com",[448,1311,777],{"class":739},[448,1313,796],{"class":735},[448,1315,799],{"class":739},[448,1317,1318],{"class":450,"line":802},[448,1319,811],{"class":739},[448,1321,1322,1324],{"class":450,"line":808},[448,1323,817],{"class":739},[448,1325,820],{"class":735},[403,1327,1328,1329,1154,1331,1333],{},"The toolkit mirrors these to ",[316,1330,1153],{},[316,1332,1159],{}," for hosts that enforce widget CSP.",[1169,1335,1337],{"id":1336},"vercel-cannot-find-generated-mcp-app-files","Vercel cannot find generated MCP App files",[403,1339,1340,1341,1344],{},"Use a toolkit version that includes the MCP Apps build fixes. Older unreleased builds may import ",[316,1342,1343],{},".nuxt\u002Fmcp-apps\u002Fgen\u002F*.ts"," at runtime, which does not exist inside the deployed Vercel function.",[1169,1346,1348,542,1351,1354],{"id":1347},"vite-plugin-singlefile-or-vitejsplugin-vue-is-missing",[316,1349,1350],{},"vite-plugin-singlefile",[316,1352,1353],{},"@vitejs\u002Fplugin-vue"," is missing",[403,1356,1357],{},"Use a toolkit version that ships the MCP Apps bundling dependencies, or install them in the app while testing an unreleased build.",[1169,1359,1361],{"id":1360},"chatgpt-keeps-showing-an-old-widget","ChatGPT keeps showing an old widget",[403,1363,1364],{},"ChatGPT can cache widget templates by URI. If you make a breaking UI change, change the resource URI or file name so hosts load a fresh template.",[293,1366,1368],{"id":1367},"other-clients","Other clients",[403,1370,1371,519,1374,1377,1378,519,1380,1383,1384,1387],{},[341,1372,1373],{},"Claude Code",[341,1375,1376],{},"Claude Desktop"," (where remote MCP is enabled), ",[341,1379,343],{},[341,1381,1382],{},"VS Code",", and ",[341,1385,1386],{},"Codex","-style clients connect to your server with the same MCP URL you use for tools. There is no separate “apps-only” endpoint.",[403,1389,1390],{},"Web and mobile ChatGPT\u002FClaude apps may not render MCP UI widgets on every release channel. Always verify inline iframes on the product version you support.",[403,1392,1393],{},"Prefer Cursor as the main development vehicle when debugging the JSON-RPC UI bridge; it is the most exercised environment in this module’s test suite.",[293,1395,1397],{"id":1396},"related","Related",[533,1399,1400,1408,1413,1422,1430,1437,1444,1451],{},[536,1401,1402,1404,1405,1407],{},[516,1403,176],{"href":177}," — how HTML and ",[316,1406,1128],{}," are produced.",[536,1409,1410,1412],{},[516,1411,185],{"href":186}," — iframe constraints and API cheat sheet.",[536,1414,1415,1417,1418,1421],{},[516,1416,123],{"href":128}," — optional ",[316,1419,1420],{},"https:\u002F\u002F…\u002Fmcp\u002Fapps"," surface if you split apps from other tools.",[536,1423,1424],{},[516,1425,1429],{"href":1426,"rel":1427},"https:\u002F\u002Fdevelopers.openai.com\u002Fapps-sdk\u002Fbuild\u002Fmcp-server",[1428],"nofollow","OpenAI: Build your MCP server",[536,1431,1432],{},[516,1433,1436],{"href":1434,"rel":1435},"https:\u002F\u002Fdevelopers.openai.com\u002Fapps-sdk\u002Fdeploy\u002Fconnect-chatgpt",[1428],"OpenAI: Connect from ChatGPT",[536,1438,1439],{},[516,1440,1443],{"href":1441,"rel":1442},"https:\u002F\u002Fdevelopers.openai.com\u002Fapps-sdk\u002Fdeploy\u002Ftesting",[1428],"OpenAI: Test your integration",[536,1445,1446],{},[516,1447,1450],{"href":1448,"rel":1449},"https:\u002F\u002Fdevelopers.openai.com\u002Fapps-sdk\u002Fdeploy\u002Fsubmission",[1428],"OpenAI: Submit and maintain your app",[536,1452,1453],{},[516,1454,1457],{"href":1455,"rel":1456},"https:\u002F\u002Fdevelopers.openai.com\u002Fapps-sdk\u002Fapp-submission-guidelines",[1428],"OpenAI: App submission guidelines",[1459,1460,1461],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":444,"searchDepth":743,"depth":743,"links":1463},[1464,1465,1466,1467,1468,1469,1481,1482],{"id":295,"depth":743,"text":296},{"id":415,"depth":743,"text":416},{"id":571,"depth":743,"text":572},{"id":898,"depth":743,"text":899},{"id":1079,"depth":743,"text":1080},{"id":1166,"depth":743,"text":1167,"children":1470},[1471,1473,1474,1476,1477,1478,1480],{"id":1171,"depth":756,"text":1472},"403 Forbidden from \u002Fmcp",{"id":1205,"depth":756,"text":1206},{"id":1227,"depth":756,"text":1475},"No ui\u002F* messages arrive",{"id":1249,"depth":756,"text":1250},{"id":1336,"depth":756,"text":1337},{"id":1347,"depth":756,"text":1479},"vite-plugin-singlefile or @vitejs\u002Fplugin-vue is missing",{"id":1360,"depth":756,"text":1361},{"id":1367,"depth":743,"text":1368},{"id":1396,"depth":743,"text":1397},"Test MCP Apps locally, pick a compatible host, and ship HTTPS endpoints for ChatGPT, Claude, and IDE clients.","md",null,{},{"icon":183},{"title":1489,"description":1490},"MCP Apps — Testing & publishing","How to test MCP UI locally and publish a streamable HTTP MCP server for ChatGPT, Claude, Cursor, and VS Code.","hPDiidVihWNFqg6F5JJCkKCgWwWnNAVJQzk0J33NKtM",[1493,1495],{"title":176,"path":177,"stem":178,"description":1494,"icon":64,"children":-1},"Content Security Policy, allow-listed domains, and how HTML bundles are produced.",{"title":185,"path":186,"stem":187,"description":1496,"icon":188,"children":-1},"UI patterns, unsupported Nuxt features in the iframe, and API reference.",1787670842300]