|
| 1 | +# MCP Apps: Interactive Tools for AI Agents |
| 2 | + |
| 3 | +*February 2026* |
| 4 | + |
| 5 | +AI tool calling has a limitation: it's one-way. The LLM calls a tool, gets a result, and moves on. But what if the tool needs user input that's hard to describe in words—like picking a location on a map? We've implemented MCP Apps in Agentic Forge to bridge this gap, starting with an interactive location picker for our weather server. |
| 6 | + |
| 7 | +## The Problem: Some Inputs Need a UI |
| 8 | + |
| 9 | +Consider asking an agent: "What's the weather at my favorite hiking spot?" |
| 10 | + |
| 11 | +The agent can call a weather API, but it doesn't know *where* your hiking spot is. It could ask you to describe it, but coordinates from memory are imprecise. What if you could just... point to it on a map? |
| 12 | + |
| 13 | +This is the kind of interaction that text-based tools can't handle well. You need a visual interface. |
| 14 | + |
| 15 | +## What are MCP Apps? |
| 16 | + |
| 17 | +MCP Apps are an extension to the Model Context Protocol that allows tools to include interactive UI components. When a tool returns a response with UI metadata, the host application renders the interface in a sandboxed iframe, letting users interact directly before the conversation continues. |
| 18 | + |
| 19 | +The specification was [introduced by Anthropic in November 2025](https://blog.modelcontextprotocol.io/posts/2025-11-21-mcp-apps/) and reached stable 1.0 in [January 2026](https://blog.modelcontextprotocol.io/posts/2026-01-26-mcp-apps/). It's since been adopted by major platforms including [OpenAI's ChatGPT](https://developers.openai.com/apps-sdk/mcp-apps-in-chatgpt/). |
| 20 | + |
| 21 | +## Our First MCP App: Location Picker |
| 22 | + |
| 23 | +We built a location picker app for the weather MCP server. Here it is in action: |
| 24 | + |
| 25 | +<video controls width="100%" style="border-radius: 8px; margin: 1rem 0;"> |
| 26 | + <source src="/videos/mcp-app-location-selection.mp4" type="video/mp4"> |
| 27 | + Your browser does not support the video tag. |
| 28 | +</video> |
| 29 | + |
| 30 | +The flow works like this: |
| 31 | + |
| 32 | +1. **User asks** about weather at an unspecified location |
| 33 | +2. **Agent calls** the `pick_location` tool |
| 34 | +3. **Map UI appears** with search and click-to-select |
| 35 | +4. **User picks** their location visually |
| 36 | +5. **Agent continues** with the selected coordinates |
| 37 | + |
| 38 | +No need to describe latitude/longitude or spell out addresses—just point and click. |
| 39 | + |
| 40 | +## Architecture |
| 41 | + |
| 42 | +MCP Apps add a UI layer on top of standard tool calling: |
| 43 | + |
| 44 | + |
| 45 | + |
| 46 | +The diagram shows the complete flow: |
| 47 | + |
| 48 | +1. The agent calls `pick_location`, which returns a `_meta.ui` field pointing to a UI resource |
| 49 | +2. forge-ui fetches the HTML from the MCP server (via Armory) and renders it in a sandboxed iframe |
| 50 | +3. The user interacts with the map—clicking to select a location or searching by name |
| 51 | +4. When the user clicks "Continue", the app calls `updateModelContext` to pass the selected coordinates back to the conversation |
| 52 | + |
| 53 | +The app runs completely sandboxed—no access to the parent page's DOM or storage. Communication happens through JSON-RPC messages over `postMessage`. |
| 54 | + |
| 55 | +## How It Works |
| 56 | + |
| 57 | +### Server Side |
| 58 | + |
| 59 | +The MCP server defines both the tool and the UI resource. The tool returns a `_meta.ui` field containing the resource URI, required permissions (like geolocation), and whether user interaction is required before continuing. |
| 60 | + |
| 61 | +### App Side |
| 62 | + |
| 63 | +The location picker is a Vue 3 app bundled to a single HTML file using `vite-plugin-singlefile`. It uses the official `@modelcontextprotocol/ext-apps` SDK for communication with the host. |
| 64 | + |
| 65 | +The app can call tools on its parent MCP server—the geocoding search reuses the weather server's existing `geocode` tool rather than implementing its own. When the user selects a location, the app calls `updateModelContext` to send the coordinates back. |
| 66 | + |
| 67 | +### Host Side |
| 68 | + |
| 69 | +forge-ui's `McpAppRenderer` component handles rendering and message routing. It fetches the HTML resource, creates the sandboxed iframe, and sets up the JSON-RPC bridge. When the app calls `updateModelContext`, the host captures the data and makes it available for the LLM's next turn. |
| 70 | + |
| 71 | +## Security Model |
| 72 | + |
| 73 | +MCP Apps run in sandboxed iframes with minimal permissions: |
| 74 | + |
| 75 | +- **Sandboxed execution** — `allow-scripts allow-forms` only, no access to parent DOM |
| 76 | +- **Origin validation** — Communication only via `postMessage` with source verification |
| 77 | +- **Permission requests** — Apps can request additional permissions (like `geolocation`) which the host may grant |
| 78 | +- **Proxied tool calls** — All tool calls go through the host, maintaining an audit trail |
| 79 | + |
| 80 | +This means a malicious MCP App can't steal cookies, access local storage, or manipulate the chat interface. |
| 81 | + |
| 82 | +## Building Your Own MCP Apps |
| 83 | + |
| 84 | +The location picker serves as a reference implementation. The key components are: |
| 85 | + |
| 86 | +| File | Purpose | |
| 87 | +|------|---------| |
| 88 | +| `src/App.vue` | Main component, state management | |
| 89 | +| `src/composables/useAppBridge.ts` | JSON-RPC bridge to host | |
| 90 | +| `src/components/MapView.vue` | Leaflet.js map rendering | |
| 91 | +| `vite.config.ts` | Bundle to single HTML file | |
| 92 | + |
| 93 | +The build produces a self-contained HTML file with inlined JS and CSS. Deployment is simple—just serve the file as a text resource from your MCP server. |
| 94 | + |
| 95 | +## What's Next |
| 96 | + |
| 97 | +The location picker is our first MCP App, but the pattern opens up many possibilities: |
| 98 | + |
| 99 | +- **Weather Explorer** — Interactive dashboard with charts and forecasts |
| 100 | +- **Search Refinement** — Visual filters for web search results |
| 101 | +- **Data Visualization** — Charts and graphs for analytical tools |
| 102 | +- **Form Builders** — Complex input collection that would be tedious in text |
| 103 | + |
| 104 | +We're also working on dark/light theme synchronization so apps match the host's appearance automatically. |
| 105 | + |
| 106 | +## Try It |
| 107 | + |
| 108 | +The location picker is available in the [demo](https://agentic-forge.compulife.com.pk). Ask the agent about weather at a location and see the map appear. |
| 109 | + |
| 110 | +## Source Code |
| 111 | + |
| 112 | +- [mcp-weather](https://github.com/agentic-forge/mcp-weather) — Weather server with location picker app |
| 113 | +- [forge-ui](https://github.com/agentic-forge/forge-ui) — Host implementation with McpAppRenderer |
| 114 | +- [forge-armory](https://github.com/agentic-forge/forge-armory) — Gateway with ui:// resource routing |
| 115 | + |
| 116 | +## References |
| 117 | + |
| 118 | +- [MCP Apps Announcement](https://blog.modelcontextprotocol.io/posts/2025-11-21-mcp-apps/) — Original introduction |
| 119 | +- [MCP Apps 1.0 Specification](https://blog.modelcontextprotocol.io/posts/2026-01-26-mcp-apps/) — Stable release |
| 120 | +- [@modelcontextprotocol/ext-apps](https://www.npmjs.com/package/@modelcontextprotocol/ext-apps) — Official SDK |
| 121 | +- [OpenAI MCP Apps Integration](https://developers.openai.com/apps-sdk/mcp-apps-in-chatgpt/) — ChatGPT adoption |
| 122 | + |
| 123 | +--- |
| 124 | + |
| 125 | +*This is part of a series on building [Agentic Forge](https://agentic-forge.github.io).* |
0 commit comments