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