Adrienne Vermorel
MCP Apps: Interactive Visualizations in Claude
The typical data engineering workflow involves six context switches: write SQL in your IDE, execute in the warehouse, export to CSV, import to your BI tool, build the visualization, share the dashboard link. Each step breaks your train of thought. By the time you’ve built the chart, you’ve forgotten the question that prompted it.
MCP Apps collapses this into a single conversation. Announced January 2026, this extension to the Model Context Protocol lets servers return interactive HTML interfaces that render directly inside Claude. You ask a question, get a chart, drill down with follow-ups, and the AI maintains context throughout.
Connecting Your Existing Stack
The practical value depends on connecting to tools you already use.
BigQuery has production-ready MCP support through Google’s official MCP Toolbox for Databases. It provides bigquery-execute-sql, bigquery-forecast, and bigquery-conversational-analytics tools, configured via OAuth in a tools.yaml file.
dbt integration comes from dbt Labs’ official server. Beyond CLI operations (build, run, test, compile), it exposes the semantic layer through list_metrics and query_metrics. The Fusion tier adds column-level lineage via get_column_lineage.
GA4 works through google-analytics-mcp, which exposes run_report with 200+ dimensions and metrics, plus real-time reporting. A query like “revenue by country and device category for the last 30 days” returns structured data ready for visualization.
Once data flows in, you need something to render it. AntV mcp-server-chart offers 26+ chart types including geographic maps, network graphs, and sankey diagrams:
npx -y @antv/mcp-server-chartThe Vega-Lite server takes a declarative approach where you specify visualization structure rather than rendering logic. For fully private analysis, mcp-visualization-duckdb combines Plotly with local LLM processing so data never leaves your machine.
When This Makes Sense (and When It Doesn’t)
MCP Apps excels at cross-source analysis. Combining Looker metrics with Jira tickets and CRM data in a single conversation isn’t something traditional BI tools handle well. Claude’s reasoning also handles ambiguous multi-part questions that would require multiple dashboard views.
Traditional BI retains real advantages though. Looker’s LookML semantic layer enforces consistent metric definitions across the organization, providing governance that MCP Apps lacks. Tableau produces the polish expected in board presentations. Metabase offers simple self-hosted deployment.
| Capability | MCP Apps | Traditional BI |
|---|---|---|
| Query interface | Natural language | LookML/SQL/Drag-and-drop |
| Setup complexity | Medium | High (Looker) to Low (Metabase) |
| Governance | Via MCP permissions | Strong semantic layers |
| Multi-tool orchestration | Native | Tool-centric |
| Best for | Ad-hoc exploration | Production dashboards |
The sensible architecture isn’t either/or: use dbt for transformation, Looker for the semantic layer and production dashboards, MCP Apps as a conversational layer for ad-hoc exploration. Google’s Looker MCP Server (launched August 2025) enables exactly this hybrid approach.
How It Works Under the Hood
MCP Apps extends the protocol through two primitives: tools that declare UI metadata, and resources that serve HTML content.
When you call a tool with MCP Apps support, the tool description includes a _meta.ui.resourceUri field pointing to a ui:// resource. This lets hosts preload the interface before execution. The host fetches the HTML/JavaScript bundle, renders it in a sandboxed iframe, and establishes bidirectional JSON-RPC communication over postMessage. The app can call server tools while the host pushes fresh data.
// Tool with UI metadataregisterAppTool(server, "visualize-data", { title: "Visualize Data", description: "Returns an interactive chart visualization", inputSchema: { type: "object", properties: { data: { type: "array" } } }, _meta: { ui: { resourceUri: "ui://charts/interactive" } }}, async (args) => { return { content: [{ type: "text", text: JSON.stringify(args.data) }] };});Apps receive tool results via app.ontoolresult, call server tools via app.callServerTool(), and can update model context with app.updateModelContext() to inform the AI what actions the user took in the interface.
Security Considerations
All UI content runs in sandboxed iframes with restricted permissions. Apps cannot access the parent window’s DOM, read host cookies, navigate the parent page, or execute scripts in the parent context. Pre-declared templates enable security review before execution, and hosts can require explicit user approval for UI-initiated tool calls.
The broader MCP ecosystem faces real challenges though. Research from Equixly found command injection flaws in 43% of analyzed MCP servers. Docker’s security guidance recommends containerizing every MCP server with CPU/memory caps and read-only filesystems. Maintaining allowlists of approved servers and auditing message logs should be standard practice.
Building a Custom Visualization Server
If the existing servers don’t cover your needs, the implementation requires Node.js 18+ and the @modelcontextprotocol/ext-apps SDK. You register a tool with UI metadata and a corresponding HTML resource:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";import * as fs from "fs/promises";
const server = new McpServer({ name: "Analytics Dashboard", version: "1.0.0" });const resourceUri = "ui://dashboard/main.html";
// Register the toolregisterAppTool(server, "show-dashboard", { title: "Analytics Dashboard", description: "Display interactive metrics dashboard", inputSchema: { type: "object", properties: { metrics: { type: "array" } } }, _meta: { ui: { resourceUri } }}, async (args) => ({ content: [{ type: "text", text: JSON.stringify(args.metrics) }]}));
// Register the HTML resourceregisterAppResource(server, resourceUri, resourceUri, { mimeType: RESOURCE_MIME_TYPE }, async () => { const html = await fs.readFile("./dist/dashboard.html", "utf-8"); return { contents: [{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }] }; });The client-side App SDK handles communication with the host:
import { App } from "@modelcontextprotocol/ext-apps";
const app = new App({ name: "Dashboard App", version: "1.0.0" });
app.ontoolresult = (result) => { const data = JSON.parse(result.content?.find(c => c.type === "text")?.text); renderChart(data); // Your visualization logic};
// Call additional server tools from UI interactionsasync function drillDown(segment) { const result = await app.callServerTool({ name: "get-segment-details", arguments: { segment } }); // Update visualization with segment data}
app.connect();Vite with vite-plugin-singlefile bundles the UI into the single HTML file that MCP Apps requires. Starter templates exist for React, Vue, Svelte, Preact, Solid, and vanilla JavaScript.
Common Setup Issues
macOS PATH problems: Apps launched from Finder don’t inherit shell PATH. Use absolute paths like /opt/homebrew/bin/npx in your configuration.
Silent JSON failures: Syntax errors in MCP configuration files fail silently. Validate with a JSON linter before restarting Claude. Debug logs live at ~/Library/Logs/Claude/mcp-server-*.log.
Tool proliferation: Research shows 50 tools achieve only 31% success rates while 8 focused tools reach 89%. If you can’t explain what each tool does in a sentence, consolidate.
Current limitations: Support is limited to text/html content. External URLs, remote DOM, and native widgets are deferred to future iterations. Each tool call involves round-trip latency.
Getting Started
The quickest path to seeing what’s possible is installing the AntV chart server and asking Claude to visualize some data. Once you understand the interaction model, connect your data sources and build from there.
Production dashboards still belong in Looker and Tableau. But exploratory analysis works differently when the visualization lives in the same place as the conversation. You see a chart, ask a follow-up question, and drill down without losing the thread that got you there.
Resources:
- Official MCP Apps documentation
@modelcontextprotocol/ext-appsSDK on npm- AntV mcp-server-chart for production-ready visualization
- ext-apps example servers on GitHub