The operating model
Stateless protocol. Explicit application state.
A tool call carries the protocol version, client capabilities, and usually client identity with the request. Any compatible server instance can process it. Authentication, databases, jobs, drafts, and business workflows may remain stateful; the request refers to that state directly when it needs it.
What travels with a request
There is no required connection-opening handshake or protocol session. A client can call a method immediately. If it wants to inspect the server first, it may call server/discover to learn supported protocol versions, capabilities, identity, and extensions.
Version
Which MCP rules this request follows
Capabilities
What the client supports for this call
Method + name
What operation or tool is requested
Arguments
The inputs and explicit state references
Self-contained request → independently authorized work → typed result
Why this fits ordinary web infrastructure
Scale
Route to any healthy instance
Remote servers can sit behind a normal round-robin load balancer. The protocol layer does not need sticky sessions or a shared session store.
Policy
Inspect without parsing the body
Mcp-Method and Mcp-Name HTTP headers let gateways route, meter, rate-limit, and apply policy. The request body remains the source of truth.
Caching
Reuse stable catalogs
Tool, prompt, and resource-list results include freshness and cache-scope hints. Deterministic ordering keeps client and model prompt caches more stable.
Recovery
Retry deliberately
A broken in-flight HTTP response is reissued as a new request with a new request ID. Consequential tools still need application-level idempotency.
Four ways to carry work forward
| Need | MCP pattern | Example |
|---|---|---|
| Continue ordinary application state | Return an opaque server-minted handle and pass it as a later tool argument. | proposal_id, draft_id, or pagination cursor |
| Ask for missing input or approval | Return resultType: "input_required"; the client collects responses and retries the original request. | Confirm a refund amount or choose between two matching accounts |
| Run durable long work | Use the optional Tasks extension. Return a task handle, poll with tasks/get, and provide mid-flight input with tasks/update. | Deployment, batch import, report generation, or human review |
| Receive change notifications | Opt into selected event types through subscriptions/listen. | Tool-list changes, resource subscriptions, or task status |
Multi-round-trip input without a server-initiated call
A server sometimes needs something it cannot safely infer: a confirmation, missing field, choice, or information available only to the client. It returns an input-required result describing what it needs. The client obtains the answer and retries the original method with inputResponses.
tools/callprepare action
input_requiredshow exact consequence
tools/call + responsecontinue explicitly
This turn-based pattern supports elicitation and other client-provided input without requiring the server to initiate a JSON-RPC request over a permanently open bidirectional stream.
Tasks are stateful by design
Tasks are the durable pattern for operations that outlive one response. A task can survive a client disconnect, report progress, wait for input, complete, fail, or be cancelled. The task ID is explicit application state: clients should persist it, servers should set a lifetime, and every later lookup or update must be authorized.
Use a task when
- The operation may exceed normal request or intermediary timeouts.
- The client should recover after a disconnect or restart.
- Progress, partial status, or human review matters.
- An upstream system already works through durable job IDs.
Stateless does not mean
Unauthenticated
Every request still needs the appropriate authentication and resource-level authorization.
No database
The server may store business records, tasks, drafts, caches, and audit evidence.
No streaming
A request may stream its own progress, and clients may explicitly subscribe to selected changes.
Automatically idempotent
Retries are simpler to route, but tool authors must still prevent duplicate consequential writes.
No conversation state
The AI host owns the conversation. The MCP server receives only the focused context and arguments it needs.
Progressive tool exposure
Cacheable tool lists reduce repeated discovery; the host still decides which definitions enter model context.
Compatibility in real deployments
The specification calls versions from 2026-07-28 onward modern and earlier handshake-based versions legacy. A dual-era implementation can support both at one endpoint: self-contained requests use modern semantics, while an initialize request selects legacy behavior.
For a production server, declare the versions you support, implement server/discover, use an SDK with the required compatibility mode, and test every target host. Supporting the modern protocol does not guarantee that every host supports every optional extension.
Use the current replacements
Several older protocol features remain available only for compatibility and should not be the foundation of a new implementation.
| Avoid for new implementations | Use instead |
|---|---|
| Roots | Pass directories or files through tool parameters, resource URIs, or server configuration. |
| Sampling | Integrate directly with the appropriate model-provider API. |
| MCP Logging | Write to stderr for stdio or use OpenTelemetry for remote observability. |
| HTTP+SSE transport | Use Streamable HTTP. |
| Dynamic Client Registration | Prefer Client ID Metadata Documents or pre-registration. |
Implementation baseline
- Keep protocol processing independent of a connection or server instance.
- Authenticate and authorize every request; derive tenant scope from verified identity.
- Return opaque, expiring state handles instead of hiding workflow state in transport sessions.
- Use idempotency keys and explicit outcome fields for consequential writes.
- Return deterministic tool lists with accurate
ttlMsandcacheScope. - Use MRTR for bounded additional input, Tasks for durable work, and subscriptions only for consumers that need changes pushed.
- Propagate trace context and retain correlation IDs without logging secrets or unnecessary payloads.
The useful mental model
Pay for state only when the work requires it.
Most calls stay simple, portable, and independently routable. Workflows that need continuity name it explicitly, making recovery, authorization, observability, and model orchestration easier to reason about.
Primary references: the MCP 2026-07-28 specification, versioning and compatibility, transport model, Tasks extension, and key protocol details.