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