The Model Context Protocol,
explained the way agents actually use it.
A practical, practitioner-grade reference: what MCP is, how it works, how to build one well, and how to keep it secure - with animated diagrams of every flow.
What is MCP?
An open JSON-RPC 2.0 standard that gives any LLM a single, uniform way to call tools, read data, and use reusable prompts from any compliant external system. The "USB-C for AI" - one connector, every device.
A short history
- Nov 2024 - Anthropic publishes the spec and open-sources the SDKs.
- 2025 - OpenAI, Google DeepMind, Microsoft, AWS and most major IDEs adopt MCP.
- Dec 2025 - Anthropic donates MCP to the Agentic AI Foundation under the Linux Foundation, reinforcing vendor-neutral governance.
- 2026 - Anthropic reports 97M+ monthly SDK downloads and 10,000+ active public MCP servers across the ecosystem.
The building blocks
MCP organizes capabilities into a small set of named primitives. Three live on the server, three live on the client, and a handful are protocol-level. Know them cold.
Server-side primitives what your server exposes
Tools
Functions the model can invoke - query a DB, send an email, create a GitHub issue. Each has a name, description and JSON Schema.
model-controlledResources
Read-only data identified by URI - file contents, DB rows, API responses. Pulled into context by the host or user.
application-controlledPrompts
Reusable, parameterized templates the server exposes - slash commands, workflows. The user picks them from a menu.
user-controlledClient-side primitives what the server can ask the host to do
Sampling
Server asks the host's LLM to run a completion - so an agentic server can reason without shipping its own API key. User must approve.
sampling/createMessageRoots
Client tells the server "you may operate within these URIs" - filesystem paths, repo URLs, namespaces. Dynamic, updatable.
scope boundaryElicitation
Server asks the user a structured follow-up question mid-flow - "Which environment do you want to deploy to?"
elicitation/createProtocol-level primitives
- Notifications - server-pushed events (tools changed, resource updated, log line) so hosts don't poll.
- Capability negotiation - at
initialize, each side declares what features it supports. - Logging - standardized channel for structured log records with levels: debug / info / warning / error.
How MCP works, end-to-end
Built on JSON-RPC 2.0. Every message is a request, response, or notification. Two standardized transports: stdio for local, Streamable HTTP for remote.
The two transports, side by side
stdio
Host spawns the server as a subprocess. Talks over stdin/stdout. Best for local, single-user integrations - IDE plugins, desktop apps. Trust the host process.
Streamable HTTP
Server runs as a remote service. Client POSTs JSON-RPC; server streams responses and notifications over SSE on the same connection. This is how multi-tenant production servers run.
What to consider when building a server
A "hello world" MCP server is 50 lines. A production-grade one is a product. Here's the checklist that separates toys from tools agents love.
- Define the agent story first. Write the user-and-agent workflows you want to support, then design the minimum tools to satisfy them in one or two calls - not seven.
- Pick the right transport. stdio for local; Streamable HTTP for remote multi-tenant.
- Choose stateful vs stateless deliberately. Default to stateless; externalize session state to Redis/DynamoDB.
- Budget your tool surface. 5-8 tools per server is the sweet spot. Past ~12, agent performance degrades.
- Write tool descriptions for the LLM. Action-first, disambiguating, under ~200 tokens. They go straight into the context window.
- Design payloads for context economy. Return only what the agent needs for the next decision. Offer a
verboseflag if power users need more. - Errors are guidance, not just failures. "Permission denied" is bad. "Reauthenticate with repo:write scope" is useful.
- Version gracefully. Tool names and schemas are a public API. Add fields as optional; never repurpose existing ones.
- Observability from day one. Structured logs, per-tool latency, audit trail of who called what.
Why MCP and not just APIs?
MCP and REST solve different problems for different consumers. The fastest way to misuse MCP is to think of it as "an API with extra steps." It isn't.
tools/list at runtimeWhen to reach for each
Use MCP when...
An agent dynamically chooses what to do · three+ tools combine in one chat · you want the same integration to work across Claude, ChatGPT, Cursor, your in-house agent · destructive actions need user-consent flow.
Keep REST when...
A scheduled job calls a known endpoint with known params · mobile app needs deterministic CRUD with strict latency · the caller is human-written code, not a model.
How agents interact with MCP
From the agent's point of view, MCP tools look identical to natively defined functions - but richer, with semantic descriptions and live discovery.
The five phases of agent ↔ MCP
- Connection - host spawns/connects each configured server, runs the initialize handshake.
- Discovery - client calls
tools/list; descriptions land in the agent's system prompt. - Decision - LLM, given the catalog, decides whether to answer or call a tool. MCP's richer descriptions improve tool-selection accuracy materially.
- Invocation - chosen call goes out as
tools/call; server executes; result feeds back as a tool message. - Streaming & callbacks - long tools stream progress; servers can push
list_changed, run sampling, elicit user input.
Security designs for your MCP server
Public MCP deployments have already shown familiar security failures: leaked credentials, broad tokens, weak audit trails, and prompt-injection exposure. Treat the bar as high from day one.
The five recurring attack classes
Prompt injection
Malicious instructions hidden in data the agent reads - an issue title, an email body - that hijack the agent into calling tools it shouldn't.
indirect injectionTool poisoning / rug pulls
Hosted server ships benign tools, then mutates them with hidden directives later. Defend with pinning and signature verification.
MCPTox vectorOver-privileged tokens
User grants a broad scope once; every agent action runs with the union. Least-privilege per tool is essential.
scope sprawlCredential sprawl
Every dev spins up their own server with their own keys, stored insecurely in source or env files. Leaked keys turn a small server into a large incident.
secret hygieneAudit blind spots
No record of which agent called which tool, on whose behalf, with what arguments. Compliance fails when you can't answer.
governance gapCross-server token replay
Token issued for server A reused at server B. Mitigated by RFC 8707 Resource Indicators binding tokens to a server URI.
RFC 8707The compact security rule
Security baseline for HTTP deployments
- OAuth 2.1 with PKCE - use the standard authorization flow for protected HTTP MCP servers.
- Resource Indicators (RFC 8707) - every access token must bind to the specific MCP server URI. Server rejects mismatched audience claims.
- Short-lived access tokens - 15-60 minutes - paired with refresh tokens.
- TLS for HTTP deployments - including internal systems unless local development is explicitly isolated.
- Human-in-the-loop for destructive actions - refunds, deletes, money movement need explicit user confirmation.
- Allow-list outbound calls - block egress to user-supplied URLs unless that is literally the tool's job.
Designing MCP when you already have rich APIs
The most common starting point - and the most commonly bungled. The trap: one MCP tool per REST endpoint. It works. It's frustrating. Simple goals take five calls.
Patterns that work
Workflow tools, not CRUD tools
Instead of list_issues + get_issue + update_issue + list_comments + add_comment, expose triage_issue that does the obvious orchestrated thing.
Service-prefixed names
Pattern: {service}_{verb}_{noun} - slack_send_message, linear_create_issue, stripe_refund_charge. Avoids collisions across loaded servers.
Domain-sharded servers
A 400-endpoint API != one MCP server with 400 tools. It's 10-20 small servers, each scoped to a coherent domain. Hosts load only what they need.
Generated scaffold, hand-tuned surface
Stainless, FastMCP, Azure APIM auto-generate stubs from OpenAPI. Treat as starting point. Hand-curate names, collapse endpoints, prune fields.
Server-side ranking + pagination
500 results is fine for REST. For MCP it's broken. Default to 5-20, rank by relevance server-side, let the model ask for more.
Anti-patterns to avoid
Every endpoint "for completeness" · raw API JSON unchanged · HTTP status codes as errors · agent forced to know internal IDs.
A migration path
- Stand up a thin generated server from your OpenAPI spec to validate plumbing.
- Instrument it. Log which tools the agent actually uses for real workflows.
- Identify the top 3-5 workflows by frequency.
- Replace each cluster of fine-grained tools with one workflow tool.
- Retire unused fine-grained tools, or move behind a "power user" flag.
- Re-evaluate quarterly - usage shifts as agents and users learn what's possible.
Session management - shared vs per-agent
One of the most consequential decisions in MCP architecture. The 2026 roadmap highlights transport scalability, stateless operation, and explicit session handling.
Stateful vs stateless tradeoffs
Stateful - the upside
Handshake paid once. Subsequent calls are compact and fast. Multi-step workflows hold server-side state (cursors, transactions). Bidirectional flow stays open for notifications, sampling, elicitation.
Stateful - the cost
Sticky routing fights load balancers and rolling deploys. Restart drops sessions unless externalized. Horizontal scaling has to plan for concurrent open sessions, not just request rate.
Shared session vs one-per-agent
One per agent recommended
Each agent session gets its own MCP session. State is isolated. A misbehaving agent can't pollute another. Auth scopes bound to the calling user. What virtually all production hosts do.
Shared across agents dangerous
Cross-tenant leakage risk · auth confusion (whose scopes?) · concurrent-modification bugs. If you need shared expensive resources, share the resource, not the session.
Architectural best practices
Consolidated from the official spec, the 2026 roadmap, and what production teams have learned the hard way.
Scope & structure
Schema & contracts
Transport & deployment
Security
Reliability
Observability
Developer experience
- README opens with three concrete agent prompts that should "just work."
- Read your
tools/listout loud - if it doesn't make sense, the agent won't either. - Local dev mode - stdio + fake auth, runs against the real server logic.
- Contract tests verifying JSON Schema of every tool's response, on every commit.
- Quarterly review of which tools agents actually call. Remove what isn't used.