Protocols and Frameworks
Model Context Protocol (MCP)
The USB-C of tools
You already know how an agent calls a tool. But every tool you wire up by hand is a one-off. MCP is the standard that turns that bespoke wiring into a plug: write a tool once as a server, and every MCP-capable agent can use it. This lesson is the protocol layer of the modern agent stack.
The problem: M times N bespoke integrations
Before MCP, connecting an AI app to an external system - Google Drive, Slack, GitHub, a Postgres database - meant writing a custom integration for that pair. With M AI applications and N tools or data sources, the ecosystem trends toward M times N one-off connectors: a combinatorial explosion nobody can maintain, that re-fragments every time a model or a tool changes.[1]
The collapses that surface to M plus N. A tool author writes one MCP server; a model-app author writes one MCP client. Then any client speaks to any server, with no bespoke glue.[1] This is the exact move the Language Server Protocol made for editors and compilers.
Tap a node to see what it does.
The one-line analogy
Architecture: host, client, server
MCP defines three roles. Getting these straight is the whole mental model.[2]
- Host. The user-facing AI app that runs the LLM, enforces consent, and manages connections. Claude Desktop, Claude Code, Cursor, VS Code, ChatGPT.
- Client. A connector object inside the host. The host spins up one client per server, each holding a dedicated 1:1 connection.
- Server. A program that exposes capabilities. Local servers run as a subprocess; remote servers run on a platform. "Server" is a role, not a location.
The one-client-per-server rule is a security decision, not an accident: each connection is a clean trust boundary, so a misbehaving server is scoped to its own client and cannot silently reach into another.[2]
Tap a node to see what it does.
Two layers, cleanly split
The primitives: what a server exposes
An MCP server offers three kinds of capability. The difference between them is who is in control: the model, the app, or the user.[2]
- Tools (model-controlled). Executable functions the model calls to take action or cause side effects: query a DB, open a PR, send a message. Each has a name, a description, and a JSON-Schema
inputSchema. Methods:tools/list,tools/call. - Resources (app-controlled). Read-only, URI-addressed context: file contents, a DB schema, logs, an API response. Data to load into context, not an action to run. Methods:
resources/list,resources/read. - Prompts (user-controlled). Reusable, parameterized templates the server author encodes: system prompts, few-shot flows, slash-command-style workflows the host surfaces to the user. Methods:
prompts/list,prompts/get.
Why three, not one
What makes MCP bidirectional, and richer than a plain tool API, is that the server can also call back into the client. The two to know:
Sampling (reverse)
sampling/createMessage.Elicitation (reverse)
elicitation/create.Mental model: Tools are model-controlled (the LLM decides to call them), Resources are app-controlled (the host decides what to load), Prompts are user-controlled (the user picks a template). Sampling and Elicitation invert that direction, letting the server reach back toward the client's model and user.
Transports: how the bytes move
The data layer is transport-agnostic; MCP ships two transports.[3]
stdio - local
stdin/stdout with newline-delimited JSON-RPC. stderr is free for logs. Zero network overhead; ideal for local tools. Clients SHOULD support it whenever possible.Streamable HTTP - remote
MCP-Session-Id header and supports Last-Event-ID resumability. MCP recommends OAuth 2.1 for auth.The original 2024-11-05 spec used a two-endpoint HTTP+SSE transport. The 2025-03-26 revision replaced it with single-endpoint Streamable HTTP - fixing the pain of long-lived connections, load-balancing, and resumability - leaving HTTP+SSE as legacy back-compat only.[3]
What a small MCP server actually looks like
Concretely: a tiny weather server exposes one tool, one resource, and one prompt, then runs over stdio. Below is the server, followed by the JSON-RPC the host and server exchange on the wire.[2]
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
# TOOL - model-callable action, described for the LLM
@mcp.tool()
def get_current(location: str, units: str = "metric") -> str:
"""Get current weather for any location worldwide."""
return fetch_weather(location, units)
# RESOURCE - read-only, URI-addressed context
@mcp.resource("weather://cities")
def known_cities() -> str:
"""The cities this server can report on."""
return "\n".join(CITY_INDEX)
# PROMPT - reusable, user-picked template
@mcp.prompt()
def trip_brief(city: str) -> str:
return f"Summarize today's weather in {city} for a traveler."
if __name__ == "__main__":
mcp.run(transport="stdio") # local subprocess// client → server
{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18",
"capabilities":{"elicitation":{}},
"clientInfo":{"name":"example-client","version":"1.0.0"}}}
// server → client - declares what it supports
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18",
"capabilities":{"tools":{"listChanged":true},"resources":{}},
"serverInfo":{"name":"weather","version":"1.0.0"}}}
// client → server - no id: it's a notification
{"jsonrpc":"2.0","method":"notifications/initialized"}// client → server - what can you do?
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
// server → client - schema handed to the LLM as a function (abridged)
{"jsonrpc":"2.0","id":2,"result":{"tools":[
{"name":"get_current",
"description":"Get current weather for any location worldwide",
"inputSchema":{"type":"object",
"properties":{"location":{"type":"string"}},
"required":["location"]}}]}}
// client → server - the LLM chose to call it
{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"get_current","arguments":{"location":"San Francisco"}}}
// server → client - content injected back into the conversation
{"jsonrpc":"2.0","id":3,"result":{"content":[
{"type":"text","text":"68°F, partly cloudy..."}]}}The host merges tools from all connected servers into one registry and hands their schemas to the LLM as available functions.[2] If the server declared "listChanged": true at init, it can later emit notifications/tools/list_changed to keep a live agent's toolset current without polling - that is paying off.
Ecosystem and adoption (2025 to 2026)
MCP went from an Anthropic proposal to the industry's de-facto tool-connection standard in about a year.
- OpenAI adopted MCP in March 2025 across the Agents SDK, the Responses API, and the ChatGPT desktop app. A direct competitor endorsing Anthropic's protocol signaled real consolidation.[5] First-class client support now spans Claude, ChatGPT, Gemini, Cursor, Microsoft Copilot and VS Code, and Amazon Bedrock.[4]
- The registry hit about 2,000 entries by the one-year mark (Nov 2025, a roughly 407% jump since its September launch), with thousands of active servers and a fast-growing contributor base.[4]
- Governance went vendor-neutral. On 9 December 2025 Anthropic donated MCP to the Linux Foundation's Agentic AI Foundation - co-founded with Block and OpenAI, backed by Google, Microsoft, AWS, Cloudflare, and Bloomberg - so no single vendor owns the standard.[6]
The context bill comes due
Security: MCP's power is also its danger
MCP mixes tools and data from many sources into one model context - the same property that makes it useful makes it dangerous. The security literature converges on a handful of named failure modes.[8]
Tool poisoning
Rug pulls and shadowing
The framing that ties it together is Simon Willison's : an agent is exploitable for data exfiltration the moment it has all three of access to private data, exposure to untrusted content, and the ability to communicate externally.[10] MCP's mix-and-match tools make it easy to assemble all three by accident.
Real exploits, not theory
Origin header and bind local servers to 127.0.0.1, and never assemble all three trifecta legs in one context.MCP is not A2A
Two protocols anchor the agent stack, and they solve different problems. MCP is vertical - an agent reaching down to tools and data. Google's A2A (April 2025) is horizontal - an agent talking sideways to another agent.[13]
| MCP | A2A | |
|---|---|---|
| Axis | Vertical: agent to tools/data | Horizontal: agent to agent |
| Core job | Give one model access to tools, resources, prompts | Let agents discover, delegate to, and coordinate with each other |
| Key abstractions | Host/client/server; Tools, Resources, Prompts, Sampling | Agent Cards, Tasks, Artifacts, status updates |
| Relationship | Complementary, not competing - they compose | Complementary, not competing - they compose |
The canonical composition: an orchestrator uses A2A to delegate a subtask to a specialist agent, and that specialist uses MCP to reach the database or API it needs. MCP for data access, A2A for coordination. The next lesson builds out the horizontal side.[13]
Check yourself
Name the three MCP roles and the one-client-per-server rule. Why does that rule matter?
What security property does it buy? Try to state it, then check.
Match each MCP concept to what it is.
model-controlled action with side effects
app-controlled readable data by URI
user-controlled reusable template
transport for a local child process
the underlying message format
In MCP, what is the difference between a Tool and a Resource?
Why does MCP build on JSON-RPC with a runtime discovery step instead of a fixed, compiled-in tool list?
Lock it in
- MCP collapses M times N into M plus N. Write a tool once as a server, a model app once as a client - USB-C for AI applications.
- Host, client, server. The host runs the LLM and spins up one client per server; each connection is a clean trust boundary.
- Primitives split by control. Tools (model-controlled actions), Resources (app-controlled context), Prompts (user-controlled templates), plus Sampling and Elicitation calling back into the client.
- Two transports. stdio for local subprocesses; single-endpoint Streamable HTTP (OAuth 2.1) for remote servers.
- Security is the headline risk. Tool poisoning, rug pulls, and the lethal trifecta make untrusted servers dangerous - pin what you trust and gate consequential tools.
- MCP is not A2A. MCP is vertical (agent to tools), A2A is horizontal (agent to agent); they compose.
Primary source
MCP Architecture - modelcontextprotocol.io docsThe authoritative walkthrough of participants, the data vs transport layers, the primitives, lifecycle and capability negotiation, and a full JSON-RPC trace. Read this one end-to-end.
Sources
- 1.Anthropic, Introducing the Model Context Protocol
- 2.MCP Architecture, modelcontextprotocol.io docs
- 3.MCP Specification, Transports (2025-11-25)
- 4.Model Context Protocol, First anniversary (Nov 2025)
- 5.OpenAI Agents SDK, Model Context Protocol
- 6.Anthropic, Donating MCP and establishing the Agentic AI Foundation
- 7.Anthropic, Code execution with MCP
- 8.Simon Willison, MCP has prompt injection security problems
- 9.OWASP MCP Top 10, Tool Poisoning (MCP03:2025)
- 10.Simon Willison, The lethal trifecta for AI agents
- 11.Simon Willison, GitHub MCP exploited via prompt injection
- 12.Simon Willison, Supabase MCP lethal trifecta
- 13.Descope, MCP vs A2A