What Are MCP Apps? Hybrid Chat Interfaces with Rich UIs Explained
I’ve been building AI-powered applications for a while now, and I kept running into the same problem: chat interfaces are great for natural language, but terrible for tasks that need visual precision. Like selecting a location on a map, or adjusting a slider to set a value. Typing coordinates or numbers works, but it’s clunky and error-prone.
Then I discovered MCP Apps. They solve this exact problem by letting you embed rich HTML/JavaScript UIs directly into chat interfaces. Let me show you what they are and how they work.
What’s the Problem with Chat-Only Interfaces?
Traditional AI chat interfaces are limited to text-based interactions. This works fine for asking questions or getting explanations. But when you need to:
- Pick a location on a map
- Select multiple items from a list
- Adjust values with sliders
- Fill out forms with validation
Text-based input becomes frustrating. I’ve typed coordinates like “latitude 37.7749, longitude -122.4194” and hoped I didn’t make a typo. It’s inefficient compared to just clicking a point on a map.
MCP Apps: The Solution
MCP Apps are a feature of the Model Context Protocol (MCP) that bridges this gap. They let MCP servers serve HTML/JavaScript/CSS UIs within the chat context. The result is a hybrid experience where chat and application blend together.
You can have a conversation with an AI, and when needed, an interactive UI appears right in the chat. You interact with it, and the results flow back to the AI model.
How MCP Apps Work
An MCP App has two core elements:
- A tool with metadata referencing HTML resources - This tells the MCP client that there’s a UI available
- An HTML resource served by the MCP server - The actual UI code (HTML, JS, CSS)
The UI runs in a special MCP client (like Claude Desktop or MCP Jam) that communicates via JSON-RPC with both the MCP server and the host assistant.
┌─────────────────────────────────────────────────────────┐│ MCP Client ││ ┌─────────────────┐ ┌─────────────────────────┐ ││ │ Chat Area │ │ App UI (iframe) │ ││ │ │ │ │ ││ │ User: Show me │ │ ┌───────────────────┐ │ ││ │ nearby cafes │ │ │ Interactive Map │ │ ││ │ │ │ │ [buttons, etc] │ │ ││ │ AI: Here's a │ │ └───────────────────┘ │ ││ │ map... │ │ │ ││ └─────────────────┘ └─────────────────────────┘ ││ │ │ ││ ▼ ▼ ││ JSON-RPC to AI JSON-RPC to MCP Server │└─────────────────────────────────────────────────────────┘Building a Simple MCP App
Let me show you how to create a basic MCP App UI. The UI connects to the AI assistant and can update the model context based on user interactions.
// Import the MCP App library
// Create and connect the appconst app = new App({ name: "my-mcp-app", version: "1.0.0" });
app.connect().then(() => { console.log("Connected to AI assistant!");
// Set up your UI interactions document.getElementById("myButton").addEventListener("click", () => { // Send data back to the AI model app.updateModelContext({ content: [{ type: "text", text: "User clicked the button!" }], }); });});The key here is the updateModelContext method. When users interact with your UI, you send that information back to the AI model. The AI then knows what happened and can continue the conversation naturally.
A More Practical Example
Here’s a simple location picker UI:
<!DOCTYPE html><html><head> <script type="module">
const app = new App({ name: "location-picker", version: "1.0.0" });
app.connect().then(() => { // Initialize your map library here (e.g., Leaflet) const map = L.map('map').setView([51.505, -0.09], 13); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
map.on('click', (e) => { const { lat, lng } = e.latlng;
// Tell the AI what location the user selected app.updateModelContext({ content: [{ type: "text", text: `User selected location: ${lat.toFixed(4)}, ${lng.toFixed(4)}` }], }); }); }); </script></head><body> <div id="map" style="height: 300px;"></div></body></html>Now instead of typing coordinates, the user just clicks on the map. The AI receives the coordinates and can continue helping with whatever task is at hand.
Spring AI Support for MCP Apps
If you’re building with Java, Spring AI 2.0.0-M3 introduced support for MCP Apps through tool and resource annotations. This makes it easier to serve MCP Apps from a Spring backend.
@RestControllerpublic class McpAppController {
@McpTool(name = "location-picker", description = "Opens a map for location selection") @McpResource(uri = "app://location-picker") public String locationPicker() { return """ <!DOCTYPE html> <html> <body> <div id="map" style="height: 300px;"></div> <script type="module"> import { App } from "https://unpkg.com/@modelcontextprotocol/[email protected]/app-with-deps"; const app = new App({ name: "location-picker", version: "1.0.0" }); // ... your app logic </script> </body> </html> """; }}The annotations handle the MCP protocol details, letting you focus on building the UI.
Common Misconceptions
When I first learned about MCP Apps, I made a few mistakes:
Mistake 1: Thinking they’re just iframes or webviews
MCP Apps aren’t simply embedded web pages. They’re integrated with the AI model context. The UI can send data back to the AI, and the AI can trigger UI updates. It’s bidirectional communication.
Mistake 2: Assuming they replace all chat interactions
MCP Apps are for cases where visual interaction is better than text. Not every conversation needs a UI. Use them when they add value, not just because you can.
Mistake 3: Forgetting about the connection lifecycle
The UI needs to connect to the AI assistant before it can communicate. Make sure you handle the connection promise properly, like I showed in the examples above.
When to Use MCP Apps
I’ve found MCP Apps useful for:
- Location-based interactions - Maps, geofencing, route selection
- Multi-select scenarios - Choosing items from lists, tagging
- Value adjustments - Sliders, color pickers, date selectors
- Form inputs - Structured data entry with validation
- Visual feedback - Charts, graphs, live previews
They work best when you need both the flexibility of natural language and the precision of traditional UI elements.
Supported Clients
MCP Apps work in MCP-compatible clients that support the app feature:
- Claude Desktop - Anthropic’s official desktop client
- MCP Jam - A web-based MCP client
- Any custom client built with MCP SDKs that implement the app specification
Wrapping Up
MCP Apps solve a real problem: the tension between conversational AI and visual precision. Instead of forcing users to type everything, you can show them interactive UIs right in the chat. It’s not about replacing chat—it’s about enhancing it.
The combination of natural language for high-level intent and visual UIs for precise input gives users the best of both worlds. And with Spring AI support, integrating MCP Apps into Java applications is getting easier.
If you’re building AI-powered tools and find yourself frustrated with text-only inputs, give MCP Apps a try. They might be exactly what you need.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments