Inline vs Remote MCP Apps
MCP Apps can be delivered as inline HTML (bundled string) or remote URL (hosted content). Both have identical capabilitiesβthe only difference is how the HTML is delivered.
Important: Both inline and remote MCP Apps have identical capabilities including: sendMessage(), callTool(), openLink(), reportSize(), fetch() for external APIs, loading external images, streaming updates, and state persistence.
Two Ways to Deliver Your MCP App
Inline HTML
Your React component is compiled to an HTML string and provided through the MCP resources array. The HTML is served through a proxy and runs in a sandboxed iframe. Note: Inline HTML is delivered via the proxy on each load and won't be browser-cached like traditional static files.
Remote URL (HTTPS Required)
Your MCP App is hosted at an HTTPS URL (CDN, server, etc.). The host fetches and serves it through a proxy to the sandboxed iframe. Remote URLs benefit from browser caching and can be deployed independently.
Inline HTML
How Bundling Works
In the SDK Playground, we use Next.js to bundle React components into standalone HTML:
- Create a React component in
pages/examples/mcp-apps/widgets/my-app.tsx - Next.js compiles it to a standalone HTML page with all dependencies
- Use
fetchMcpAppHtml('my-app')to read the compiled HTML - Return the HTML string in your resource's
getContent()
Remote URL (HTTPS Required)
Host your MCP App on any HTTPS server (CDN, Vercel, Netlify, your own server, etc.). Remote URLs must use HTTPS because MCP Apps are served through a secure proxy.
Local Development with ngrok
For local development in this playground, you can use ngrok to create an HTTPS tunnel:
Define Your Tool with _meta
The _meta field is defined in the MCP specification (SEP-1865) and allows you to attach UI resources to tools:
CORS & External Resources
Both inline and remote MCP Apps can access external resources, but you must configure CSP (Content Security Policy) in your tool metadata.
For External Images, Fonts, Stylesheets
Use csp.resourceDomains to allow loading resources from specific origins. The Bonsai Shop example demonstrates this:
For External API Calls (fetch)
Use csp.connectDomains to allow fetch/XHR requests to specific APIs: