Model Context Protocol
Understand Model Context Protocol: clients, servers, tools, resources, prompts, transport, and production integration trade-offs.
What is Model Context Protocol?
The Model Context Protocol (MCP) is an open protocol for connecting an AI application to programs that provide context or actions. Instead of inventing a connector for every integration, a host can use MCP to discover and exchange typed resources, prompts, and tools over JSON-RPC.
In plain language, MCP gives AI applications and capability providers a shared conversation format. It does not decide whether a server is trustworthy or whether an action is allowed.
The core invariant is capability is not authority. A successful handshake says which protocol features both sides understand. Authorization, user consent, tenant isolation, and operation policy remain separate decisions.
Keep the host, client, and server separate
An MCP deployment has three protocol participants. The distinction matters because each participant owns a different part of security and failure recovery.
One MCP connection
A host may manage many clients, but each client maintains one isolated connection to one server.
Application boundary
Host
Owns the user experience, model integration, consent, policy, and any movement of context between servers.
Session boundary
MCP client
Negotiates one stateful session, routes JSON-RPC messages, and tracks the capabilities of one server.
Capability boundary
MCP server
Publishes focused primitives and validates every request before touching its dependencies.
Data or side effect
External system
Provides the records, files, APIs, or business actions behind the server's MCP contract.
The host should give each server only the context needed for its task. A server should not receive the whole conversation or inspect another server's session.
Choose the primitive by who initiates it
MCP server primitives differ in how they enter the user experience. That ownership should shape discovery, review, and approval.
Application-controlled
Resources
Addressable context such as files, schemas, or records. The client lists or reads a URI, then decides whether the result belongs in model context.
User-controlled
Prompts
Reusable message templates. A user explicitly selects a prompt and supplies its arguments before the client retrieves the generated messages.
Model-controlled
Tools
Schema-described operations the model may request. The application should expose the request, validate its inputs, apply policy, and let a human deny sensitive calls.
Clients can also advertise features to servers, including roots, sampling, elicitation, and task support. Negotiating a feature only makes its messages legal for the session; it does not make every use safe.
Finish initialization before normal work
MCP is a stateful protocol. Initialization must be the first interaction, and both sides may use only the version and capabilities established for that session.
1 Initialize
Propose a version
The client sends
initializewith its latest supported protocol revision, implementation information, and client capabilities.2 Negotiate
Return the contract
The server returns a supported revision, server information, and server capabilities. The client disconnects if it cannot support the returned revision.
3 Acknowledge
Mark the session ready
The client sends
notifications/initialized. Normal tools, resources, and prompts operations begin only after this lifecycle boundary.4 Use
Operate within bounds
Both sides respect negotiated sub-capabilities, apply finite timeouts, validate messages, and terminate through the underlying transport.
For example, advertising resources does not imply subscription support, and advertising tools does not imply listChanged notifications or task-augmented calls. Check the specific capability object before sending related messages.
Compose the transport and capability contract
Transport selection changes process ownership, authentication, streaming, and failure behavior. Capability selection changes which protocol operations the session can legally perform. Build a connection and inspect both consequences together.
Loading connection composer...
The healthy design is not the bundle with the most features. It is the smallest negotiated surface that satisfies the workload across the correct process boundary.
Select transport by deployment boundary
The protocol defines two standard transports. Both carry UTF-8 JSON-RPC messages, but they have different operating models.
Local subprocess
stdio
The client launches the server and exchanges newline-delimited messages through standard input and output. Logs belong on standard error. Pin the executable and constrain its environment, filesystem, and network access.
Remote or shared service
Streamable HTTP
The server exposes one MCP endpoint for POST and GET, with optional server-sent events. Validate Origin, authenticate protected requests, and bind local-only endpoints to localhost.
Streamable HTTP replaced the older HTTP+SSE transport from the 2024-11-05 revision. A compatibility migration may temporarily serve both, but new clients should target the current transport contract.
Treat schemas and annotations as inputs, not proof
MCP uses JSON Schema throughout the protocol. A tool can define an input schema and optional output schema, but schema validity proves only that a value has the expected shape.
Validate every boundary
- Reject unknown fields when a tool contract should be closed.
- Validate tool arguments before business logic and validate structured results before returning them.
- Apply user, tenant, resource-ownership, rate-limit, and approval checks after schema validation.
- Treat tool annotations as untrusted unless the server itself is trusted.
- Sanitize returned text, links, and embedded resources before they enter model context.
Separate protocol errors from tool errors
- Use JSON-RPC errors for invalid methods, malformed parameters, and protocol failures.
- Return a tool result with
isError: truefor an expected operation failure the model can safely reason about. - Preserve correlation identifiers without logging tokens, authorization codes, secrets, or sensitive result bodies.
Put authorization around the session
For HTTP, MCP defines an OAuth-based authorization flow. Authentication protects access to the MCP endpoint, while host and server policy still decide whether a particular primitive or tool call is allowed.
A protected remote tool call
The token accepted by the MCP server is audience-bound to that server. A downstream API requires a separate credential.
Intent
User and host
Review the server, requested scopes, tool inputs, target resource, and side effect.
Grant
Authorization server
Issues a token for the canonical MCP server URI after the client requests the correct resource and scopes.
Enforce
MCP server
Validates issuer, audience, expiry, signature, scope, tenant, ownership, and current approval.
Separate audience
Downstream API
Receives its own credential. The server never forwards the client's MCP access token unchanged.
Token passthrough is forbidden by the MCP authorization specification. A token issued for the MCP server is not a reusable credential for a downstream API.
For stdio, the HTTP authorization flow does not apply. The local process normally receives narrowly scoped credentials through its environment, and the host must treat launching that process as a privileged action.
Recover the boundary that actually failed
An expired MCP session, an insufficient OAuth scope, a wrong token audience, and an ambiguous tool completion require different responses. Choose an incident and apply a recovery action to see whether it restores the correct boundary or creates a second failure.
Loading recovery runbook...
A lost HTTP connection does not prove that a write was canceled. Reconcile by operation identifier or server-side state before retrying, and make write tools idempotent when the dependency supports it.
Design timeouts, cancellation, and session state together
Bound request lifetime
- Configure a finite timeout for every request.
- Send a cancellation notification when the timeout expires and stop waiting for the response.
- Allow progress to extend a working deadline only under an absolute maximum.
- Remember that cancellation is a request, not proof that remote work stopped.
Keep session identity separate from user identity
- Treat
MCP-Session-Idas untrusted input and never as authentication. - Send
MCP-Protocol-Versionon subsequent HTTP requests. - If a server returns HTTP
404for a known session, discard that session ID and initialize a new session. - Recheck authorization on every protected request and rotate session state when identity or grants change.
Make replay behavior explicit
- Use caller-scoped idempotency keys for retryable writes.
- Record an operation state that can distinguish accepted, running, completed, failed, and unknown outcomes.
- Reconcile ambiguous outcomes before issuing another side effect.
- Keep recovery evidence in audit logs without retaining secrets.
Review an MCP integration as three contracts
Interoperability
Protocol contract
Pin supported revisions, test initialization order, validate schemas, and use only negotiated capabilities and sub-capabilities.
Trust
Authority contract
Verify server provenance, minimize context, audience-bind tokens, separate downstream credentials, and require meaningful approval.
Operations
Recovery contract
Define timeout, cancellation, session expiry, reconciliation, idempotency, audit, revocation, and kill-switch behavior.
A production review should answer:
- Which host owns user intent and each client connection?
- Which protocol revision and exact capabilities were negotiated?
- Which server supplied each primitive and returned content item?
- Which host policy exposed it to the model, and which approval authorized the call?
- Which identity, tenant, scope, and token audience reached each protected system?
- Which evidence distinguishes a completed write from an ambiguous or retryable failure?
Sources and version notes
This lesson targets the latest stable MCP revision available while authoring, 2025-11-25. MCP uses dated revisions, so implementations should negotiate versions and consult the matching specification instead of treating a sample message as timeless.