I Built an Interactive MCP Demo to Show How the Model Context Protocol Actually Works
How I built an interactive visualization of the full MCP pipeline — tool discovery, selection, JSON-RPC execution, and response generation — in an afternoon with Claude Code.
This post was written with AI assistance.
After building my RAG demo, I wanted to apply the same “show the pipeline, not just the output” approach to another concept that keeps coming up in AI engineering: the Model Context Protocol (MCP).
MCP is the open protocol that lets AI models talk to external tools through a standardized interface. It’s how Claude Desktop connects to file systems, databases, and APIs. But most explanations either hand-wave over the protocol details or dump you into SDK documentation. I wanted to build something that makes the protocol visible — so I built How does MCP work?.
What it does
Like the RAG demo, it’s a chat interface with a pipeline visualization sidebar. You ask a question, and the left panel shows the MCP protocol flow in four steps:
-
Tool Discovery — the MCP client sends a
tools/listJSON-RPC request and the server responds with all registered tools, their descriptions, and input schemas. You see the actual request/response JSON. -
Tool Selection — the system analyzes your query and picks the right tool(s). In local mode this is keyword matching; with an API key, Claude makes the decision. The sidebar shows which tool was chosen and why.
-
Tool Execution — the client sends a
tools/callrequest with the tool name and arguments. The server executes it and returns the result. Both the request and response are shown as expandable JSON-RPC viewers. -
Response Generation — the tool results are passed to the LLM, which generates a natural-language answer incorporating the data.
The demo includes three tools: get_weather (returns mock weather for any city), calculate (math operations), and search_knowledge_base (TF-IDF search over docs about MCP itself — a self-referential touch I carried over from the RAG demo).
Multi-tool support
The feature I’m most pleased with: compound queries work. Ask “What’s 100 / 7, and what’s the weather in Paris?” and the system detects both intents, selects both tools, executes them separately, and shows both execution flows in the sidebar with their own JSON-RPC request/response pairs.
This demonstrates one of MCP’s key strengths — the protocol is stateless and composable, so multiple tool calls in a single interaction are natural.
How I built it
Same stack and approach as the RAG demo, built in an afternoon with Claude Code:
- Next.js 16 with App Router and Tailwind CSS v4
- Vercel AI SDK for streaming chat with custom data stream parts
- Anthropic Claude (via Vercel AI Gateway) for response generation
- Simulated MCP — an in-process server/client using real JSON-RPC 2.0 message formats
The simulated MCP layer
Rather than pulling in the @modelcontextprotocol/sdk (which is designed for real stdio/SSE transport between separate processes), I built a lightweight simulation: lib/mcp-server.ts handles tools/list and tools/call requests, and lib/mcp-client.ts sends requests and records every JSON-RPC message exchanged.
The key design decision: every message uses the exact JSON-RPC 2.0 spec — jsonrpc: "2.0", proper id fields, method, params, result, error codes. The simulation is fake, but the protocol is real. If you expand any message in the sidebar, you’re looking at what actual MCP traffic looks like.
Custom data stream parts
Same pattern as the RAG demo — the Vercel AI SDK’s createUIMessageStream sends pipeline metadata alongside the LLM response:
data-tools— the registered tool list from discoverydata-selections— which tool(s) were selected and why (array for multi-tool)data-executions— the JSON-RPC request/response pairs with execution timing (array for multi-tool)data-messages— the full chronological list of all JSON-RPC messages
These arrive as typed parts in message.parts on the client, and the sidebar renders them with staggered animations as they come in.
Local fallback
Like the RAG demo, the full pipeline runs without an API key. Tool selection falls back to keyword matching (“weather” triggers get_weather, math expressions trigger calculate, everything else hits the knowledge base). The response shows the raw tool result instead of a Claude-generated answer, but all the protocol visualization works identically.
What I’d add next
- Real MCP server connection — connect to an actual MCP server over stdio and visualize the real transport
- Tool result streaming — show partial results as they arrive for long-running tools
- Drag-and-drop tool registration — let users define custom tools and see them appear in the discovery step
- Side-by-side protocol comparison — show MCP vs. traditional function calling to highlight what the protocol standardizes
But as a portfolio piece that demonstrates MCP knowledge, the current version covers the core concepts: discovery, selection, execution, and the JSON-RPC protocol that ties it all together.
The source code is on GitHub and the live demo is at how-does-mcp-work.vercel.app.