MCP MCP Cheatsheet
A detailed, searchable MCP reference covering architecture, JSON-RPC, lifecycle, transports, tools, resources, prompts, sampling, roots, elicitation, authorization, security, SDK development, testing, registry publishing, extensions, and production patterns.
151 reference blocks
MCP Fundamentals
What MCP Is
MCP standardizes how AI applications connect to external context, capabilities, and workflows.
Model Context Protocol (MCP) is an open, JSON-RPC-based protocol for connecting an AI host to external systems through interoperable clients and servers.
| Primitive | Primary purpose | Typical example |
|---|---|---|
| Tools | Perform actions or computations | Search, create issue, run query |
| Resources | Read context identified by URI | File, database schema, document |
| Prompts | Retrieve reusable message templates | Code review workflow |
| Sampling | Ask the host to run an LLM | Server-managed agent step |
| Roots | Advertise relevant URI boundaries | Workspace directories |
| Elicitation | Ask the user for additional input | Confirmation or form fields |
MCP separates how a capability is exposed from which model or host uses it, reducing one-off integration code.
Why Use MCP
Use one protocol to expose integrations across multiple AI hosts and models.
MCP is useful when you need:
- Standard discovery: clients can list tools, prompts, resources, and templates.
- Typed invocation: JSON Schema describes tool inputs and optional outputs.
- Bidirectional workflows: servers can request sampling, roots, or elicitation when negotiated.
- Transport choice: local subprocesses use stdio; remote services use Streamable HTTP.
- Capability negotiation: optional features are used only when both sides advertise support.
- Security boundaries: hosts remain responsible for consent, permissions, isolation, and user-visible approvals.
MCP does not replace the external system's own API. The MCP server usually adapts that API into model-oriented primitives.
MCP vs Direct API Integration
MCP adds discovery, schemas, lifecycle, and host-mediated interaction on top of ordinary service APIs.
| Dimension | Direct REST/API integration | MCP integration |
|---|---|---|
| Discovery | Custom or OpenAPI-specific | Standard list methods |
| Model interface | Application-specific | Tools, resources, prompts |
| Lifecycle | Usually stateless requests | Initialization and capability negotiation |
| Server-to-client needs | Custom callbacks/UI | Sampling, elicitation, roots |
| Local process support | Custom IPC | Standard stdio transport |
| User approval | Application-specific | Host responsibility, protocol hints |
Choose direct APIs for service-to-service logic that does not need model-aware discovery. Choose MCP when multiple AI hosts should consume the same integration safely and consistently.
Stable and Draft Status
Pin implementations to a protocol date and label draft-only features clearly.
Baseline used in this cheatsheet: stable protocol version 2025-11-25.
Implementation rules:
- Send the newest protocol version your client actually supports in
initialize. - Accept the server-selected version only if your client supports it.
- Gate every optional method behind negotiated capabilities.
- Treat pages under
/specification/draft/as provisional. - Pin SDK major versions because SDK APIs may change independently of the wire-protocol date.
Draft work can introduce breaking changes to requests, sessions, tasks, logging, or extensions. Avoid silently implementing draft behavior under a stable version string.
Architecture and Trust Boundaries
Host, Client, and Server
A host manages one client connection per server and integrates results with the model and UI.
| Component | Responsibility |
|---|---|
| Host | Runs the AI application, coordinates models, permissions, UI, and multiple servers |
| Client | Maintains one protocol connection to one server and translates host actions into MCP messages |
| Server | Exposes focused tools, resources, prompts, and optional server behavior |
A host can manage many clients. Each client-server connection has its own lifecycle, negotiated capabilities, and optional session state.
Relationship Model
The host owns policy; the client owns protocol connection state; the server owns integration logic.
User
│
▼
MCP Host ── model, UI, approvals, context aggregation
├── MCP Client A ⇄ Filesystem Server
├── MCP Client B ⇄ Issue Tracker Server
└── MCP Client C ⇄ Remote Database Server
Keep the boundaries explicit:
- A server should not assume it can access another server's data.
- A client should not merge identities or sessions across unrelated servers.
- The host decides which server output reaches the model.
- User credentials should be scoped to the intended remote server and resource.
Local vs Remote Servers
Local servers are spawned processes; remote servers are network services with stronger authentication and transport concerns.
| Server type | Common transport | Main risks |
|---|---|---|
| Local | stdio | Malicious executable, environment leakage, filesystem overreach |
| Remote | Streamable HTTP | Token theft, origin attacks, session hijacking, impersonation |
Local does not mean trusted. Require explicit installation, validate commands and package sources, minimize inherited environment variables, and sandbox filesystem/network access.
Remote does not mean stateless. A server may issue an MCP session ID and maintain scoped session state.
Context Aggregation
The host decides how to combine resources, prompt messages, tool results, and model history.
Recommended host pipeline:
- Discover each server's capabilities.
- Build a per-server catalog of tools, prompts, and resources.
- Apply policy filters and user permissions.
- Provide only relevant items to the model.
- Validate proposed tool calls before execution.
- Normalize and label returned content by server origin.
- Preserve provenance in logs and UI.
Never treat server-provided descriptions, titles, annotations, or resource text as trusted policy instructions.
JSON-RPC Base Protocol
Request Shape
Requests include a protocol marker, correlation ID, method, and optional parameters.
{
"jsonrpc": "2.0",
"id": 17,
"method": "tools/list",
"params": {"cursor": "next-page-token"}
}
jsonrpcmust be exactly"2.0".idcorrelates one response to one request; string and integer IDs are common.methodis a namespaced method string.paramsis usually an object and should match the method schema.
Do not reuse an in-flight ID on the same connection.
Success and Error Responses
A response contains either result or error, never both.
{
"jsonrpc": "2.0",
"id": 17,
"result": {"tools": []}
}
{
"jsonrpc": "2.0",
"id": 17,
"error": {
"code": -32602,
"message": "Invalid parameters",
"data": {"field": "cursor"}
}
}
The response id must match the request. Use error.data for machine-readable diagnostics without exposing secrets or stack traces.
Notifications
Notifications are messages without an ID and therefore receive no response.
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
Common notification classes:
- Lifecycle:
notifications/initialized - Catalog changes:
notifications/tools/list_changed - Resource changes:
notifications/resources/updated - Utilities: progress, cancellation, logging
Because notifications have no request ID, delivery confirmation must come from transport behavior or application-specific state—not a JSON-RPC response.
Message Direction
Both client and server can send requests when the relevant capability is negotiated.
Client → server examples
tools/list,tools/callresources/list,resources/readprompts/list,prompts/get
Server → client examples in stable MCP
sampling/createMessageroots/listelicitation/create
Responses travel in the reverse direction and retain the original request ID. Notifications can originate from either side where defined.
Ordering and Concurrency
Correlate by ID rather than assuming responses arrive in request order.
Implementations may process multiple requests concurrently. Therefore:
- Store a map of
id → pending request. - Apply per-request timeouts.
- Make handlers cancellation-aware.
- Serialize state mutations or use locks where needed.
- Preserve logical ordering for dependent notifications.
- Avoid relying on transport packet boundaries; rely on transport framing rules.
For stdio, each complete JSON-RPC message is newline-delimited. For HTTP, each POST body carries one message.
Lifecycle, Versioning, and Capabilities
Lifecycle Phases
Every connection moves through initialization, operation, and transport-level shutdown.
| Phase | Allowed behavior |
|---|---|
| Initialization | Negotiate version, capabilities, and implementation metadata |
| Operation | Use only successfully negotiated features |
| Shutdown | Close the underlying transport cleanly |
Initialization must be the first substantive interaction. Before it completes, only narrowly allowed health/logging behavior should occur.
Initialize Handshake
The client proposes a version and capabilities; the server returns its selected version and capabilities.
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {"roots": {"listChanged": true}, "sampling": {}},
"clientInfo": {"name": "example-client", "version": "1.0.0"}
}
}
After the successful response, the client sends:
{"jsonrpc":"2.0","method":"notifications/initialized"}
Only then should normal operations begin.
Version Negotiation
The server may select another supported date-based version; disconnect if the client cannot support it.
Negotiation algorithm:
- Client sends its newest supported version.
- Server returns the same version when supported.
- Otherwise, server returns another version it supports.
- Client verifies the returned version.
- If unsupported, client ends the connection.
For Streamable HTTP, include the negotiated version on subsequent requests:
MCP-Protocol-Version: 2025-11-25
Capability Negotiation
Capabilities are feature gates, not descriptive metadata only.
Typical server capabilities
toolswith optionallistChangedresourceswith optionalsubscribeandlistChangedpromptswith optionallistChangedlogging,completions, experimental/task fields when supported
Typical client capabilities
rootswith optionallistChangedsamplingelicitationmodes- experimental/task fields when supported
Calling a capability-dependent method without negotiation is a protocol bug.
Capability-Safe Client Logic
Branch behavior by negotiated capability and provide a graceful fallback.
if server_capabilities.tools:
tools = await session.list_tools()
else:
tools = []
if client_capabilities.elicitation:
# Server may request structured user input.
...
else:
# Return an actionable tool error or use defaults.
...
Fallbacks should explain what is unavailable without pretending the feature succeeded. Cache capabilities per connection, not globally across all servers.
Transports and Sessions
Transport Responsibilities
A transport frames UTF-8 JSON-RPC messages, manages connection state, and preserves protocol semantics.
Standard MCP transports:
| Transport | Best for | Framing |
|---|---|---|
| stdio | Local subprocess servers | One JSON-RPC message per line |
| Streamable HTTP | Remote or independently hosted servers | One message per POST; optional SSE response/GET streams |
Custom transports are allowed only if they preserve message format, lifecycle, and bidirectional behavior.
stdio Rules
Use stdin/stdout exclusively for MCP messages and stderr for logs.
Host process
└─ spawns server
stdin ← JSON-RPC from client
stdout → JSON-RPC from server
stderr → logs and diagnostics
Rules:
- Every message is a single line with no embedded newline.
stdoutmust contain only valid MCP messages.- Human logs belong on
stderr. - The client closes stdin for graceful shutdown, then escalates process termination if necessary.
- Validate the executable, arguments, working directory, and inherited environment before spawning.
Streamable HTTP Basics
POST sends messages; GET may open an SSE channel for server-originated traffic.
A Streamable HTTP server exposes one MCP endpoint such as /mcp.
Client POST requirements
POST /mcp
Accept: application/json, text/event-stream
Content-Type: application/json
MCP-Protocol-Version: 2025-11-25
The server returns either one JSON object or an SSE stream. A client may issue GET with Accept: text/event-stream to listen for server messages; unsupported GET should return 405 Method Not Allowed.
HTTP Session Management
Servers may issue a cryptographically secure session ID during initialization.
MCP-Session-Id: opaque-secure-session-id
When issued:
- The client includes the header on all later requests.
- Missing required IDs should produce HTTP 400.
- Expired or terminated IDs should produce HTTP 404.
- A client receiving 404 creates a fresh session with a new
initializerequest. - A client may send HTTP DELETE to request session termination.
- Never place credentials or sensitive user data inside the session ID.
SSE Resumption in Stable 2025-11-25
Stable Streamable HTTP allows resumable SSE streams with event IDs and Last-Event-ID.
A server may attach unique SSE event IDs. After disconnect, the client can reconnect with:
Last-Event-ID: previous-event-id
The server may replay later messages from that same stream. Avoid duplicate side effects by designing operations to be idempotent and tracking request IDs.
Version note: draft protocol work may change or remove resumability semantics. Implement this only for versions that define it.
HTTP Transport Security
Validate origins, bind local HTTP servers narrowly, authenticate remote requests, and constrain request sizes.
Minimum controls:
- Validate
Origin; reject invalid origins with HTTP 403. - For local HTTP, bind to
127.0.0.1, not0.0.0.0, unless explicitly intended. - Use HTTPS for remote endpoints.
- Authenticate and authorize each protected request.
- Rate-limit by identity and operation class.
- Enforce header, body, and streaming limits.
- Protect session IDs from logging, URLs, and cross-origin leakage.
- Validate host/origin to mitigate DNS rebinding and virtual-host confusion.
Host, Client, and Server Responsibilities
MCP Host Responsibilities
The host combines protocol clients with models, user experience, policy, and consent.
A production host should:
- Manage multiple isolated client connections.
- Decide which servers and capabilities are enabled.
- Present permission and confirmation UI.
- Select models for sampling requests.
- Filter context before adding it to the model.
- Label server-originated content and preserve provenance.
- Store credentials securely and scope them per server.
- Enforce organization and user policies.
- Provide cancellation, timeout, and audit controls.
MCP Client Responsibilities
The client owns the protocol session and mediates between host policy and server requests.
A client should:
- Connect over a supported transport.
- Perform initialization and version negotiation.
- Cache server capabilities and catalogs.
- Validate request and response shapes.
- Correlate responses, progress, and cancellation.
- Handle server requests only when client capabilities permit them.
- Refresh catalogs after list-change notifications.
- Recover or reconnect without replaying unsafe actions.
- Expose actionable errors to the host.
MCP Server Responsibilities
The server exposes focused capabilities and applies authorization and validation before touching external systems.
A server should:
- Declare only capabilities it implements.
- Give tools precise schemas and descriptions.
- Expose stable resource URIs and MIME types.
- Return prompts as reusable, user-controlled workflows.
- Validate all arguments, URIs, identities, and permissions.
- Keep logs off stdout under stdio.
- Bound work by time, size, concurrency, and rate.
- Sanitize errors and untrusted downstream data.
- Shut down cleanly and release resources.
Server Instructions
Initialization may include natural-language instructions, but hosts must treat them as untrusted guidance.
serverInfo describes software identity; optional instructions can explain intended usage.
Good instructions:
- Describe domain constraints and intended workflows.
- Explain naming conventions and safe sequencing.
- Avoid asking the host to override user or system policy.
- Avoid hidden directives or credential requests.
Hosts should display or selectively use instructions only after applying trust and policy checks.
Tool Definition
A tool is a model-invocable operation with a stable name, description, and input schema.
Core fields commonly include:
{
"name": "issues.create",
"title": "Create issue",
"description": "Create one issue in the selected repository.",
"inputSchema": {
"type": "object",
"properties": {
"repository": {"type": "string"},
"title": {"type": "string", "minLength": 1},
"body": {"type": "string"}
},
"required": ["repository", "title"],
"additionalProperties": false
}
}
Descriptions should state side effects, boundaries, and required preconditions.
List Tools
`tools/list` returns the available catalog and supports cursor-based pagination.
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
Representative result:
{
"jsonrpc":"2.0",
"id":2,
"result": {
"tools": [{"name":"weather.current","inputSchema":{"type":"object"}}],
"nextCursor":"opaque-cursor"
}
}
Refresh the cached catalog after notifications/tools/list_changed when the server advertised listChanged.
Call Tools
`tools/call` names one tool and supplies a structured arguments object.
{
"jsonrpc":"2.0",
"id":3,
"method":"tools/call",
"params": {
"name":"weather.current",
"arguments":{"city":"Pune","units":"metric"}
}
}
Execution flow:
- Validate the tool exists in the active catalog.
- Validate arguments against
inputSchema. - Apply authorization and confirmation policy.
- Execute with timeout and cancellation support.
- Validate or normalize output.
- Return content and/or structured content.
Tool Input Schemas
Use JSON Schema to reject ambiguity before business logic runs.
Schema checklist:
- Root type is usually
object. - Mark truly required properties in
required. - Use
additionalProperties: falsefor closed schemas when compatibility allows. - Apply
minLength,maxLength, numeric ranges, and array limits. - Use
enumfor bounded choices. - Use descriptions for domain meaning, not policy overrides.
- Keep nested objects shallow when possible.
- Avoid accepting raw shell commands, SQL, paths, or URLs without strict validation.
Defaults are hints; servers should still normalize omitted values explicitly.
Tool Output Schemas and Structured Content
Declare outputSchema when clients benefit from machine-readable results.
A tool result can include:
content: text, image, audio, resource link, or embedded resource items.structuredContent: machine-readable JSON.isError: an execution-level failure flag.
When outputSchema is declared, validate structuredContent against it. Provide concise text fallback for clients that do not render structured output.
Do not place secrets, internal traces, or unbounded binary data in results.
Tool Result Content Types
Results may combine multiple content items for human and machine consumers.
| Content type | Use |
|---|---|
text |
Explanation, summary, plain output |
image |
Base64 image with MIME type |
audio |
Base64 audio with MIME type |
embedded resource |
Inline resource content |
resource_link |
Link to separately retrievable context |
Prefer a resource link over embedding large content. Include MIME types and enforce size limits. Treat rendered images, HTML-like text, and documents as untrusted content.
Tool Errors
Separate protocol failures from expected tool execution failures.
Protocol-level error: malformed JSON-RPC, unknown method, or invalid envelope; return JSON-RPC error.
Tool execution error: the call is structurally valid but the operation fails; return a normal tool result with isError: true and useful content.
Examples:
- Missing required argument discovered by schema validation → execution error where supported by the targeted spec/SDK behavior.
- Downstream API returns 429 → tool error with retry guidance.
- Unknown JSON-RPC method →
-32601 Method not found.
Never return raw stack traces or access tokens.
Tool Annotations and Confirmation
Annotations are hints, not trusted security guarantees.
Common annotations communicate expectations such as:
- Read-only behavior
- Destructive behavior
- Idempotency
- Open-world interaction
Hosts may use them to select confirmation UX, but must not rely on self-declared annotations as authorization proof. A destructive or externally visible action should normally require clear user intent and a preview of important arguments.
Tool Naming
Use stable, unique, namespaced identifiers and separate human-readable titles.
Recommended patterns:
github.issues.create
calendar.events.list
warehouse.query.read_only
Guidelines:
- Keep machine names stable across releases.
- Put display-friendly wording in
title. - Prefix by domain to avoid collisions across servers.
- Make verbs explicit:
list,get,create,update,delete. - Separate read and write operations.
- Avoid vague names such as
run,process, ordo_action.
Resources
Resource Definition
A resource is contextual data addressed by a URI and read under application control.
Resources are appropriate for data that can be identified and retrieved, such as:
file:///workspace/README.mddb://analytics/schema/ordersdocs://handbook/security-policygit://repo/main/src/app.py
A resource descriptor commonly includes URI, name/title, description, MIME type, and optional size metadata. The host decides whether and when to place resource content into model context.
List and Read Resources
`resources/list` discovers concrete resources; `resources/read` retrieves content by URI.
{"jsonrpc":"2.0","id":4,"method":"resources/list","params":{}}
{
"jsonrpc":"2.0",
"id":5,
"method":"resources/read",
"params":{"uri":"docs://handbook/security-policy"}
}
The read result may contain multiple resource contents. Validate URI syntax, authorization, MIME type, and size before returning content.
Text and Binary Resource Content
Return text directly and binary data as base64 with explicit MIME metadata.
Representative content:
{
"uri":"docs://handbook/security-policy",
"mimeType":"text/markdown",
"text":"# Security Policy
..."
}
{
"uri":"assets://logo.png",
"mimeType":"image/png",
"blob":"iVBORw0KGgo..."
}
Apply byte limits before base64 encoding. Reject mismatched or unsafe MIME types and avoid automatic execution or rendering of active content.
Resource Templates
`resources/templates/list` advertises URI templates for dynamic or parameterized resources.
Example template:
{
"uriTemplate":"repo://{owner}/{name}/files/{path}",
"name":"Repository file",
"description":"Read a UTF-8 file from an allowed repository",
"mimeType":"text/plain"
}
Clients can combine template metadata with completion support to help users choose valid variables. Servers must validate expanded URIs and enforce access boundaries after expansion.
Subscriptions
Subscriptions allow clients to receive updates for resources that change over time.
When the server advertises resources.subscribe:
resources/subscribestarts updates for one URI.notifications/resources/updatedsignals changed content.resources/unsubscribestops updates.notifications/resources/list_changedsignals catalog additions/removals when supported.
Subscriptions are not a substitute for authorization checks. Re-check permissions on update delivery and clean up subscriptions when sessions end.
Resource Security
Treat every resource URI and payload as untrusted, even when it originated locally.
Controls:
- Parse and normalize URIs before authorization.
- Prevent
.., symlink, and encoding-based path traversal. - Enforce an allowlist of schemes and roots.
- Separate user identity from resource identifiers.
- Limit content size and read duration.
- Filter secrets and private fields.
- Avoid following redirects to untrusted destinations.
- Label content provenance for the model and user.
Prompts
Prompt Definition
Prompts are reusable, user-controlled templates that generate one or more model messages.
Use prompts for discoverable workflows such as:
- Review a pull request
- Summarize a resource
- Prepare an incident report
- Explain a database schema
A prompt descriptor includes a stable name, optional title/description, and arguments. Prompts should remain transparent and should not execute side effects merely because they are retrieved.
List Prompts
`prompts/list` returns prompt descriptors and supports pagination.
{"jsonrpc":"2.0","id":6,"method":"prompts/list","params":{}}
A descriptor may define required and optional arguments. Refresh the catalog after notifications/prompts/list_changed when the capability is advertised.
Get a Prompt
`prompts/get` renders a selected template using supplied arguments.
{
"jsonrpc":"2.0",
"id":7,
"method":"prompts/get",
"params": {
"name":"review_pull_request",
"arguments":{"repository":"acme/api","number":"42"}
}
}
The result can include a description and multiple messages. Validate required arguments and return a clear invalid-argument error for unsupported values.
Prompt Messages
Prompt results can mix roles and supported content types across multiple messages.
Prompt messages may use user or assistant roles and content such as text, images, audio, or embedded resources.
Design guidelines:
- Keep system-level policy in the host, not in server prompts.
- Use multiple messages when examples or context benefit from role separation.
- Label embedded resources and avoid oversized payloads.
- Make user-supplied arguments visible in the final prompt.
- Do not conceal tool calls or destructive actions inside prompt text.
Prompt Design Patterns
Prompts should describe a repeatable workflow while leaving execution under user and host control.
A strong prompt definition has:
- A clear task-oriented name.
- A description of the intended output.
- Minimal explicit arguments.
- Guardrails for missing context.
- Resource references instead of copying large documents.
- No hidden instructions to bypass host policy.
- Stable output expectations without over-constraining the model.
Prompts are best for how to ask; tools are best for what to execute.
Sampling
Sampling Purpose
Sampling lets a server request an LLM generation through the host without owning model credentials.
sampling/createMessage supports nested model calls for server-managed workflows. The host remains in control of:
- Whether the request is allowed
- Which model is selected
- What context is included
- What the user sees or approves
- Whether tool-enabled sampling is available
- What result is returned to the server
A server should request only the minimum context and tokens needed.
Sampling Request Shape
A request supplies messages, generation limits, preferences, and optional context instructions.
Representative request:
{
"jsonrpc":"2.0",
"id":8,
"method":"sampling/createMessage",
"params": {
"messages":[{"role":"user","content":{"type":"text","text":"Summarize the incident."}}],
"maxTokens":500,
"temperature":0.2,
"systemPrompt":"Return a concise factual summary.",
"includeContext":"thisServer"
}
}
The exact supported fields must match the negotiated protocol version and SDK types.
Model Preferences
Preferences guide host model selection but do not force a specific model.
Model preference dimensions can include:
- Hints such as a model family or name
- Cost priority
- Speed priority
- Intelligence priority
The host may ignore or reinterpret hints based on availability, policy, privacy, and user settings. Servers should not infer identity, capabilities, or pricing solely from the returned model name.
Sampling Results
The client returns assistant content, the selected model name, and a stop reason where defined.
A sampling result usually contains:
role: "assistant"- Generated content
- Model identifier/name
- Stop reason
Treat the result as untrusted model output. Validate structured expectations, check for prompt injection, and require user review before externally visible or destructive follow-up actions.
Sampling With Tools
Tool-enabled sampling can support multi-step server workflows but requires strict loop and permission controls.
When supported, a sampling request may include tool declarations and tool-choice behavior. The host can return tool-call content; the server executes or resolves those calls and may continue the sampling loop with tool-result messages.
Safety controls:
- Cap sampling rounds and tool calls.
- Restrict tools to the specific request.
- Revalidate each call and user authorization.
- Detect repeated or cyclic calls.
- Apply independent time and token budgets.
- Preserve a complete audit trail.
Roots
Root Definition
Roots tell servers which URI or filesystem boundaries the client considers relevant.
Roots are informational guidance, not an enforcement mechanism. A root typically includes:
{"uri":"file:///home/user/project","name":"Current workspace"}
A server can use roots to focus file discovery, reduce accidental overreach, and improve defaults. Actual authorization and sandboxing must be enforced separately.
List Roots
A supporting server requests the current roots from the client with `roots/list`.
{"jsonrpc":"2.0","id":9,"method":"roots/list"}
Representative result:
{
"jsonrpc":"2.0",
"id":9,
"result":{"roots":[{"uri":"file:///workspace","name":"Workspace"}]}
}
An empty root list is valid and means the client is not advertising a relevant boundary.
Root Change Notifications
Clients may notify servers when the advertised workspace boundaries change.
When roots.listChanged is negotiated, the client can send:
{"jsonrpc":"2.0","method":"notifications/roots/list_changed"}
The server should re-read roots and invalidate derived caches. It must not assume previously permitted paths remain allowed after a change.
Root Security
Normalize paths and enforce real access controls independently of advertised roots.
Server-side controls:
- Resolve symlinks before boundary checks.
- Normalize percent encoding and path separators.
- Reject traversal outside the allowlist.
- Limit globbing and recursive scans.
- Avoid following device files, sockets, or special files.
- Re-check permissions at operation time.
- Keep file write tools distinct from read tools.
Treat roots as a usability hint, not a sandbox.
Elicitation
Elicitation Purpose
Elicitation lets a server request additional user input during an active workflow.
Use elicitation/create when a server cannot safely or correctly continue without user input—for example:
- Choosing among bounded options
- Confirming a proposed action
- Supplying a non-sensitive project parameter
- Completing a structured form
- Finishing a secure out-of-band flow in URL mode
The host controls the UI and may accept, decline, or cancel.
Form Mode
Form elicitation requests structured input using a restricted schema.
Representative request:
{
"jsonrpc":"2.0",
"id":10,
"method":"elicitation/create",
"params": {
"mode":"form",
"message":"Choose the deployment environment.",
"requestedSchema": {
"type":"object",
"properties":{"environment":{"type":"string","enum":["staging","production"]}},
"required":["environment"]
}
}
}
Keep requested fields minimal, bounded, and understandable.
Elicitation Result Actions
The client reports whether the user accepted, declined, or cancelled and returns content only on acceptance.
| Action | Meaning |
|---|---|
accept |
User submitted content |
decline |
User explicitly refused the request |
cancel |
Interaction ended without a decision |
Servers should handle all actions without coercion. A decline is not an error to retry repeatedly. Validate accepted content again on the server.
Sensitive Information Restrictions
Do not request passwords, private keys, access tokens, or other secrets through ordinary form elicitation.
For sensitive or regulated workflows:
- Use a secure, trusted, out-of-band authorization page.
- Explain the destination and purpose before navigation.
- Bind completion to the correct user and session.
- Never ask users to paste tokens into model-visible text fields.
- Minimize collected data and define retention.
- Allow users to cancel without losing unrelated work.
The host may block fields or modes that violate policy.
Elicitation Design
Ask one clear question at a time and return actionable alternatives when elicitation is unavailable.
Good elicitation requests:
- State why the information is needed.
- Use plain labels and constrained choices.
- Provide safe defaults only where appropriate.
- Avoid collecting data already available to the server.
- Do not chain endless follow-up questions.
- Respect client capability and user cancellation.
When unsupported, return a tool error that names the missing input and lets the host collect it through another UI.
Utilities
Pagination
List methods use opaque cursor-based pagination.
Request:
{"params":{"cursor":"opaque-cursor"}}
Response:
{"result":{"items":[],"nextCursor":"next-opaque-cursor"}}
Rules:
- Treat cursors as opaque strings.
- Omit
nextCursorat end of results. - Reject malformed or expired cursors cleanly.
- Keep page ordering deterministic when possible.
- Do not encode sensitive query state in readable cursors.
Argument Completion
`completion/complete` supports autocompletion for prompt arguments and resource-template variables.
Completion can improve discovery for bounded or searchable fields such as repository names, branches, environments, and resource identifiers.
Implementation guidance:
- Return a small, relevant set of values.
- Filter by the partial input and completion context.
- Preserve authorization boundaries.
- Avoid exposing hidden resource names through suggestions.
- Handle truncation or additional-result indicators where defined.
- Treat completion as advisory; validate the final submitted value.
Progress Tracking
Long-running requests can emit progress notifications correlated by a progress token.
A sender can attach a progress token in request metadata. The receiver may send progress updates containing current progress, optional total, and a human-readable message.
Guidelines:
- Progress should be monotonic when numeric.
- Avoid excessive notification frequency.
- Use progress to improve UX, not to extend work indefinitely.
- Keep a hard maximum timeout even when progress arrives.
- Do not include secrets in progress messages.
Cancellation
Either side can notify that an in-flight request should be cancelled.
Cancellation is cooperative:
- Sender issues a cancellation notification referencing the request ID.
- Receiver stops work when practical.
- Receiver releases locks, subprocesses, network calls, and temporary files.
- Race conditions are possible: a result may arrive just before cancellation.
- Cancellation must not roll back already committed external side effects unless the tool explicitly supports transactions.
Make handlers idempotent and cancellation-aware.
Ping and Liveness
`ping` checks protocol liveness and returns an empty result.
Use ping to distinguish an idle but healthy connection from a dead transport.
{"jsonrpc":"2.0","id":11,"method":"ping"}
{"jsonrpc":"2.0","id":11,"result":{}}
Set a reasonable timeout. Do not flood connections with pings, and do not use ping as a substitute for application-level health checks of downstream services.
Logging
Servers may emit structured logs at negotiated levels, while stdio process logs still belong on stderr.
Logging concepts include:
- Standard log levels
- Optional logger names
- Structured data payloads
- Client-selected logging level where supported
notifications/messagefor server log messages
Filter credentials, personal data, request bodies, and model prompts. Include request correlation IDs and server identity. Be aware that draft versions may revise logging controls.
Tasks and Extensions
Task Status
Tasks represent long-running operations whose status and result can be retrieved later.
Typical task concepts:
- Unique task identifier
- Status such as working, input required, completed, failed, or cancelled
- Creation and last-update timestamps
- Optional expiration
- Status message and progress
- Final result or error
Version warning: task methods and their location in core versus an official extension are evolving. Use the exact specification and SDK version you target.
Task Operations
Clients create or receive task handles, poll status, provide input where supported, and cancel when allowed.
A robust task client should:
- Persist the task ID with server/session identity.
- Poll with exponential backoff or use supported notifications.
- Handle
input_requiredwithout losing previous state. - Retrieve the final result only after completion.
- Allow user cancellation and surface non-cancellable states.
- Stop polling after expiration or terminal status.
- Avoid treating unknown status as success.
Task State Handling
Treat task state as a state machine with terminal and non-terminal statuses.
| State | Client behavior |
|---|---|
| Working | Continue polling; show progress |
| Input required | Collect allowed input; resume/update task |
| Completed | Retrieve and validate result |
| Failed | Show safe error and retry options |
| Cancelled | Stop work and confirm cleanup |
| Unknown | Re-read status or surface incompatibility |
Never replay the original write operation merely because task status is temporarily unavailable.
Extensions
Extensions add optional features without pretending they are part of every MCP implementation.
Extension principles:
- Use a globally unique extension identifier.
- Negotiate support explicitly.
- Keep core behavior interoperable without the extension.
- Version extension schemas and semantics.
- Document dependencies on protocol versions.
- Provide a fallback path.
- Do not use an experimental field as a hidden capability bypass.
Consult client support matrices before depending on an extension in end-user workflows.
Authorization
Authorization Scope
MCP authorization protects HTTP-based servers using OAuth-based resource-server patterns.
Roles:
| Role | Responsibility |
|---|---|
| MCP server | Protected resource server |
| Authorization server | Authenticates user/client and issues tokens |
| MCP client | Obtains and presents access token |
| Resource owner | Grants consent for requested access |
Authorization is transport-level protection. Tool-level authorization must still verify the caller may perform the specific operation on the specific resource.
OAuth Authorization Code Flow
Interactive clients commonly use authorization code with PKCE and metadata discovery.
High-level flow:
- Discover protected-resource metadata.
- Discover authorization-server metadata.
- Register or identify the client.
- Build an authorization request with PKCE and state.
- User authenticates and consents.
- Validate redirect, state, issuer, and authorization code.
- Exchange code for tokens.
- Call the MCP endpoint with a bearer access token.
- Refresh or re-authorize when needed.
Never send client secrets from a public client.
Access Tokens
Validate issuer, audience, expiration, scopes, and signature before accepting a bearer token.
Authorization: Bearer <access-token>
Server checks:
- Signature or introspection result
- Issuer and authorization-server binding
- Intended audience/resource
- Expiration and not-before time
- Required scopes
- Revocation or token status where applicable
Reject token passthrough: an MCP server should not blindly forward a token to unrelated downstream services.
Authorization Metadata
Metadata tells clients which authorization servers and scopes apply to the protected resource.
Metadata may communicate:
- Protected resource identifier
- Authorization server locations
- Supported scopes
- Issuer identity
- Registration and token endpoints
- Resource indicators
Fetch metadata over HTTPS, validate issuer relationships, and cache with expiration. Do not follow arbitrary metadata URLs supplied by untrusted tool arguments.
Dynamic Client Registration
Registration lets a client obtain an identifier while binding redirect URIs and metadata.
Security checklist:
- Register exact redirect URIs.
- Distinguish public and confidential clients.
- Persist credentials by authorization-server issuer.
- Do not reuse credentials with a different issuer.
- Validate software metadata and registration responses.
- Rotate or revoke client credentials where supported.
- Prefer metadata documents or pre-registration in managed environments when dynamic registration is restricted.
Machine-to-Machine Authorization
Use client credentials only for non-interactive confidential clients with narrowly scoped access.
Suitable for service accounts or backend automation where no user delegation is required.
Controls:
- Authenticate the confidential client strongly.
- Issue audience-restricted, short-lived tokens.
- Grant only machine-appropriate scopes.
- Separate service identity from employee identity.
- Rotate credentials and audit each use.
- Do not use client credentials to impersonate an end user.
Enterprise-Managed Authorization
Organizations can centralize identity, client registration, and policy enforcement.
Enterprise patterns include:
- Identity-provider-mediated login
- Organization-managed MCP clients
- Central allowlists for remote servers
- Employee and device posture checks
- Scope and data-loss-prevention policies
- Central token revocation
- Administrative audit logs
Hosts should clearly distinguish organization policy from server-provided instructions.
Security Principles and Threats
Core Security Principles
Consent, control, privacy, least privilege, and secure defaults are host and server responsibilities.
Apply these principles:
- Explicit consent: users understand what data and actions are involved.
- User control: users can inspect, deny, cancel, and revoke.
- Least privilege: narrow servers, tools, scopes, roots, and tokens.
- Data minimization: share only necessary context.
- Secure defaults: read-only before write, local-only before network-exposed.
- Defense in depth: schemas, policy checks, sandboxing, rate limits, and audit logs.
- Human-in-the-loop: confirm high-impact or irreversible operations.
Prompt Injection and Tool Poisoning
Server metadata and returned content can manipulate the model unless the host treats them as untrusted.
Mitigations:
- Separate data from trusted policy instructions.
- Label content by source and trust level.
- Do not automatically follow instructions inside resources or tool output.
- Restrict which tools are visible in each model step.
- Require user confirmation for consequential actions.
- Scan tool descriptions and updates for unexpected behavior changes.
- Pin or approve server versions.
- Keep policy enforcement outside the model.
Confused Deputy and Data Exfiltration
A server or model may try to use host authority for a purpose the user did not approve.
Prevent confused-deputy behavior by binding every action to:
- The initiating user
- The selected server
- The intended resource
- The approved tool and arguments
- The correct OAuth audience and scopes
- A short-lived request or task context
Block cross-server token sharing, hidden URL callbacks, unrestricted network egress, and automatic upload of resource data.
Token Theft and Session Hijacking
Protect credentials and session identifiers as bearer secrets.
Controls:
- Use HTTPS and secure credential storage.
- Never put tokens in URLs, prompts, tool descriptions, or logs.
- Bind tokens to the correct audience and issuer.
- Use short expirations and refresh rotation where available.
- Generate unpredictable MCP session IDs.
- Validate origin and host headers.
- Invalidate sessions on logout or policy change.
- Monitor unusual source, rate, and scope patterns.
Malicious Local Servers
A local subprocess can read inherited secrets or execute arbitrary code with the user’s privileges.
Before installing or launching a local server:
- Show the exact command, package, version, arguments, and working directory.
- Verify publisher and package integrity.
- Avoid shell interpolation.
- Pass a minimal environment allowlist.
- Restrict filesystem and network access.
- Require approval before installation or first run.
- Surface updates that change executable or permissions.
- Provide an easy disable/uninstall path.
Remote Server Hardening
Treat public MCP endpoints as sensitive APIs with streaming and session-specific attack surfaces.
Use:
- HTTPS, authentication, and authorization
- Origin and host validation
- DNS rebinding mitigations
- Request/body/header size limits
- Connection and stream limits
- Rate limiting and abuse detection
- Session rotation and expiration
- SSRF-safe outbound networking
- Input and output validation
- Audit logging with secret redaction
Validation and Error Handling
Input Validation
Validate protocol envelopes, method parameters, and business rules before side effects.
Validation layers:
- UTF-8 and JSON parsing
- JSON-RPC envelope
- MCP method schema
- Tool JSON Schema
- Authorization and resource ownership
- Domain constraints
- Downstream API validation
Enforce type, length, range, enumeration, array count, nesting depth, and unknown-field rules. Normalize only after preserving the original value for audit where appropriate.
Output Validation
Validate server output before sending and validate remote output before exposing it to the model.
Check:
- Declared tool
outputSchema - MIME type and encoding
- Maximum item and byte counts
- Resource URI consistency
- Structured-content JSON validity
- Dangerous active content
- Secrets and personal data
- Downstream error leakage
A client should not assume a schema declaration guarantees the result actually conforms.
Common JSON-RPC Error Codes
Use standard codes for protocol failures and documented custom codes only where necessary.
| Code | Meaning |
|---|---|
-32700 |
Parse error |
-32600 |
Invalid request |
-32601 |
Method not found |
-32602 |
Invalid params |
-32603 |
Internal error |
-32000 to -32099 |
Reserved server error range |
Prefer execution-level tool errors for expected operational failures so the model can reason about recovery.
Error Taxonomy
Classify failures so clients know whether to retry, fix input, reauthorize, reconnect, or stop.
| Error class | Typical response |
|---|---|
| Protocol/schema | Fix implementation or input; usually no blind retry |
| Authorization | Refresh token, request consent, or deny |
| Resource not found | Correct URI or refresh catalog |
| Rate limit | Retry after delay with jitter |
| Timeout | Cancel, inspect progress, retry only if idempotent |
| Transport/session | Reconnect or reinitialize |
| Tool execution | Show user/model-safe diagnostic |
| Internal server | Log correlation ID; avoid leaking internals |
Retry Rules
Retry only operations known to be safe, idempotent, and authorized.
Retry checklist:
- Was the request read-only or explicitly idempotent?
- Could the server have committed a side effect before disconnect?
- Is there an idempotency key or task ID?
- Did the server provide retry timing?
- Is the token/session still valid?
- Has the user cancelled?
- Will retry amplify load or duplicate notifications?
Use exponential backoff with jitter and a finite attempt limit.
Python SDK Development
Python Version Status
Pin the Python SDK major version and distinguish the stable v1 line from prerelease v2 documentation.
As of this cheatsheet's build date:
- Stable production line:
mcpv1.x - v2: prerelease and subject to breaking changes
Recommended production constraint:
mcp = ">=1.27,<2"
Always check the official SDK release notes before upgrading. Protocol support and Python API shape are separate compatibility dimensions.
Install the Python SDK
Install the CLI extra with uv or pip and use an isolated environment.
uv init mcp-server-demo
cd mcp-server-demo
uv add "mcp[cli]>=1.27,<2"
python -m venv .venv
. .venv/bin/activate
pip install "mcp[cli]>=1.27,<2"
Pin dependencies for deployments and avoid installing unreviewed MCP servers globally.
FastMCP Server
Decorators turn typed Python functions into tools, resources, and prompts.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo", json_response=True)
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two integers."""
return a + b
@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
return f"Hello, {name}!"
@mcp.prompt()
def explain(topic: str) -> str:
return f"Explain {topic} with one example."
if __name__ == "__main__":
mcp.run(transport="streamable-http")
Type hints and docstrings help generate schemas and descriptions.
Async Tool Handler
Use async handlers for network or database I/O and propagate cancellation.
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Weather")
@mcp.tool()
async def current_weather(city: str) -> dict[str, object]:
"""Return current weather for one city."""
timeout = httpx.Timeout(10.0)
async with httpx.AsyncClient(timeout=timeout) as client:
response = await client.get(
"https://api.example.test/weather",
params={"city": city},
)
response.raise_for_status()
return response.json()
Add input constraints, output normalization, safe error handling, and egress controls in production.
Python Client Pattern
Use an async context manager, initialize the session, then list and call negotiated features.
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main() -> None:
params = StdioServerParameters(
command="python",
args=["server.py"],
env=None,
)
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
result = await session.call_tool("add", {"a": 2, "b": 3})
print(tools)
print(result)
asyncio.run(main())
Match imports and APIs to your pinned SDK version.
Python Testing
Prefer in-memory or controlled transport tests and validate schemas plus error paths.
Test categories:
- Unit-test pure tool/resource functions.
- Validate generated input schemas.
- Run client-server integration tests in memory or over stdio.
- Test cancellation and timeouts.
- Test malformed arguments and downstream failures.
- Test authentication with fake issuers/tokens.
- Confirm stdout remains protocol-clean.
- Snapshot tool/resource/prompt catalogs to detect accidental breaking changes.
Use deterministic fixtures; never call production systems from unit tests.
TypeScript SDK Development
TypeScript Version Status
Use the production-supported SDK line and pin versions during the v1-to-v2 transition.
The TypeScript SDK may expose different package names and APIs across major versions. Before copying examples:
- Check whether the documentation targets v1 or v2.
- Pin package versions in
package.jsonand lockfile. - Match the SDK generation to the intended protocol version.
- Review migration notes before changing transports or schema libraries.
Do not combine v2 package imports with v1 tutorials.
Minimal TypeScript Server
Register typed tools and connect a stdio transport.
import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import * as z from "zod/v4";
const server = new McpServer({
name: "greeting-server",
version: "1.0.0",
});
server.registerTool(
"greet",
{
description: "Greet one person by name",
inputSchema: z.object({ name: z.string().min(1).max(120) }),
},
async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name}!` }],
}),
);
await server.connect(new StdioServerTransport());
Use imports matching the installed major version.
TypeScript Client Flow
Connect, initialize, discover features, and call tools with runtime validation.
Conceptual flow:
const client = new Client({ name: "demo-client", version: "1.0.0" });
await client.connect(transport);
const { tools } = await client.listTools();
const result = await client.callTool({
name: "greet",
arguments: { name: "Ada" },
});
Wrap calls with timeouts, cancellation, result-size checks, and capability checks. The exact imports and constructors depend on the pinned SDK line.
Schema Validation
Use a supported runtime schema library and keep generated JSON Schema compatible with clients.
Guidelines:
- Use Zod or another SDK-supported Standard Schema implementation for the targeted version.
- Express bounds and enums in the runtime schema.
- Avoid transforms that cannot be represented clearly in JSON Schema.
- Validate returned structured content separately.
- Version tool schemas when changing required fields or semantics.
- Keep error messages concise and user-safe.
Transport Setup
Select stdio for local subprocesses and Streamable HTTP for remote services.
For stdio:
- Never log to stdout.
- Handle process signals and graceful closure.
- Avoid shell command strings; pass executable and args separately.
For HTTP:
- Use framework adapters supported by your SDK line.
- Validate host and origin.
- Configure body and stream limits.
- Implement OAuth and secure session handling.
- Test both JSON and SSE response modes.
Building an MCP Server
Server Build Checklist
Start with a narrow integration boundary and declare only implemented capabilities.
- Define the external system and trust boundary.
- Choose local stdio or remote HTTP.
- Define read-only resources first.
- Add small, specific tools with schemas.
- Add prompts only for reusable user workflows.
- Decide whether sampling, roots, or elicitation are truly needed.
- Implement lifecycle and capability declaration.
- Add auth, validation, timeouts, and limits.
- Test with Inspector and automated clients.
- Document installation, permissions, and failure modes.
Register Focused Tools
Prefer several explicit tools over one universal command executor.
Good:
orders.list
orders.get
orders.create_draft
orders.submit
Risky:
run_api_request
execute_sql
shell
Focused tools reduce prompt ambiguity, improve validation, enable per-operation authorization, and make user confirmation clearer.
Resource-First Context
Expose stable read-only context as resources instead of forcing every read through a tool.
Use resources for:
- Documentation and policies
- Schemas and metadata
- Repository files
- Read-only records with stable URIs
- Large context retrieved lazily
Use tools when the operation has computation, filtering too complex for URI selection, or side effects. Resource-first design improves caching, provenance, and context-size control.
Graceful Shutdown
Stop accepting work, cancel or finish handlers, and release external resources.
Shutdown sequence:
- Mark server draining.
- Reject new long-running operations.
- Cancel or finish in-flight tasks according to policy.
- Flush protocol responses and logs.
- Close database pools and HTTP clients.
- Delete temporary files and subscriptions.
- Close transport or exit the subprocess.
Do not write shutdown diagnostics to stdout in stdio mode.
Building an MCP Client
Client Build Checklist
A client must combine protocol correctness with host policy and usable approval flows.
- Parse server configuration safely.
- Establish the transport.
- Initialize and negotiate version/capabilities.
- Discover catalogs lazily.
- Build a server-scoped cache.
- Validate model-selected calls.
- Request user approval where required.
- Execute with timeout/cancellation.
- Normalize and label results.
- Recover sessions and connections safely.
- Disconnect and clean up.
Tool Invocation Pipeline
Never pass a model-generated tool call directly to the transport without checks.
Model proposal
→ tool exists?
→ schema valid?
→ server enabled?
→ user/organization policy?
→ confirmation needed?
→ execute with timeout
→ validate result
→ label provenance
→ return to model/user
Preserve the exact approved arguments and warn when they change before execution.
Handle Server Requests
Sampling, roots, and elicitation must route through host policy and UI.
For each server-initiated request:
- Confirm the client advertised the capability.
- Verify it relates to an allowed active workflow.
- Apply server-specific permissions and rate limits.
- Show user-facing context where necessary.
- Return decline/cancel outcomes accurately.
- Avoid exposing data from other servers or unrelated conversations.
- Bound nested calls to prevent recursion loops.
Catalog Caching
Cache list results per server while respecting list-change notifications and session changes.
Cache key should include:
- Server identity and endpoint
- Authenticated user/tenant
- Negotiated protocol version
- Session where catalog is session-dependent
- Capability set
Invalidate on list-change notifications, reconnect with changed server version, authorization changes, or explicit refresh. Keep deterministic ordering for stable model prompts.
Server Configuration
Local Server Configuration
Specify executable, arguments, environment, working directory, and permissions explicitly.
Generic configuration shape:
{
"command": "uv",
"args": ["run", "server.py"],
"cwd": "/absolute/project/path",
"env": {"LOG_LEVEL": "INFO"},
"timeout_ms": 30000
}
Security rules:
- Avoid shell command concatenation.
- Use absolute or verified executable paths.
- Pass only required environment variables.
- Review filesystem/network access before first run.
- Pin package and runtime versions.
Package Runner Configuration
Package runners are convenient but can execute newly downloaded code, so pin and approve them.
Examples include uvx, npx, or language-specific runners.
Safer practice:
- Pin exact package versions or immutable hashes.
- Use trusted registries.
- Disable install scripts where possible.
- Review transitive dependencies.
- Cache and scan artifacts.
- Require approval when the resolved package changes.
- Do not expose broad secrets to the spawned process.
Remote Server Configuration
Store endpoint, authorization, headers, timeout, and reconnection policy separately from tool data.
{
"url": "https://mcp.example.com/mcp",
"headers": {"X-Tenant": "tenant-id"},
"auth": {"type": "oauth"},
"connect_timeout_ms": 10000,
"request_timeout_ms": 60000,
"reconnect": {"max_attempts": 3}
}
Never put static bearer tokens in shared configuration files. Validate custom headers and prevent model-controlled header injection.
Timeout Configuration
Use separate connection, request, stream-idle, and maximum-operation timeouts.
Suggested timeout classes:
- DNS/TCP/TLS connect timeout
- Initialization timeout
- Default request timeout
- Per-tool override
- SSE idle timeout
- Maximum operation/task lifetime
- Graceful shutdown timeout
Progress may reset an idle timer, but should not bypass the maximum lifetime. Expose timeout errors with enough context to retry safely.
Inspector, Debugging, and Testing
MCP Inspector
Use Inspector to connect, inspect capabilities, list primitives, invoke tools, and view protocol traffic.
Typical launch:
npx -y @modelcontextprotocol/inspector
Use it to:
- Verify initialization and capability declarations.
- Inspect tool input schemas.
- Call tools manually with controlled arguments.
- Read resources and expand templates.
- Retrieve prompts.
- Observe logs and protocol errors.
- Compare behavior across transports.
Do not connect Inspector to production with privileged credentials unless explicitly authorized.
Debug stdio
Most stdio failures come from polluted stdout, incorrect commands, environment differences, or process exits.
Checklist:
- Run the configured command manually.
- Confirm one JSON-RPC message per stdout line.
- Send all logs to stderr.
- Check working directory and file permissions.
- Print inherited environment names, not secret values.
- Verify runtime/package version.
- Capture exit code and stderr.
- Test shutdown after stdin closes.
Debug Streamable HTTP
Inspect status codes, headers, content types, session IDs, and SSE event framing.
Check:
- Correct MCP endpoint path
- POST
Acceptheader includes JSON and SSE Content-Typematches response bodyMCP-Protocol-Versionafter initializationMCP-Session-Idpropagation- Origin validation behavior
- GET support or expected 405
- SSE
data:framing and event IDs where applicable - Proxy buffering and timeout settings
Protocol Message Inspection
Log correlation metadata and sanitized envelopes, not full secrets or model context.
Useful fields:
- Timestamp
- Connection/server identity
- Direction
- Request ID
- Method
- Duration
- Result/error class
- Payload byte size
- Retry/cancellation state
- Trace context
Redact authorization headers, cookies, tokens, personal data, resource bodies, and elicited content.
Test Matrix
Cover handlers, protocol boundaries, transports, authorization, and end-to-end user flows.
| Layer | Examples |
|---|---|
| Unit | Tool logic, URI parser, policy rules |
| Schema | Valid/invalid input and output examples |
| Protocol | Initialization, capabilities, error codes |
| Transport | stdio framing, HTTP JSON/SSE, sessions |
| Security | Traversal, injection, auth, rate limits |
| Integration | Mock client/server and downstream API |
| End-to-end | Real host + test server + user approval |
| Compatibility | Supported protocol/SDK versions |
Registry and Publishing
Registry Purpose
A registry helps clients and users discover published MCP server metadata and distribution options.
Registry entries can describe:
- Server identity and display metadata
- Package or distribution type
- Version information
- Remote endpoint information
- Documentation and website links
- Installation metadata
- Publisher identity
Discovery does not equal trust. Hosts should still verify publisher, package integrity, permissions, and organization policy.
Prepare a Server for Publishing
Publish a focused, versioned, documented package with reproducible installation.
Checklist:
- Stable machine name and display title
- Semantic package version
- Supported protocol versions
- Clear description and use cases
- Exact installation command
- Required permissions and environment variables
- Security and privacy notes
- License and source repository
- Icons/website metadata where supported
- Changelog and migration guidance
- Automated tests and release provenance
Registry Authentication
Authenticate the publisher using the registry-supported workflow and protect release credentials.
- Use organization-controlled publisher identities for production servers.
- Prefer short-lived CI credentials or workload identity.
- Protect signing keys and release tokens.
- Require branch protection and review for release metadata.
- Audit publish and update events.
- Revoke compromised credentials immediately.
- Do not let the MCP server runtime possess registry publishing credentials.
Version Management
Treat tool schemas, resource URIs, and authorization behavior as public compatibility surfaces.
Breaking changes include:
- Removing or renaming tools
- Adding new required input fields
- Changing output meaning or type
- Reassigning resource URIs
- Expanding side effects or permissions
- Dropping supported transports/protocol versions
Use release notes, migration windows, and parallel versions for breaking changes. Avoid silently replacing a trusted package with materially different behavior.
MCP Apps and Interactive UI
MCP Apps Concept
MCP Apps let tools provide interactive, host-rendered user interfaces alongside protocol data.
An app-oriented integration may combine:
- A tool invocation
- An app resource describing UI content
- Host-rendered sandboxed presentation
- User interactions sent back through controlled channels
- Tool results synchronized with the UI
Apps are an optional extension, so always provide a non-UI fallback for clients that do not support them.
Tool-to-UI Communication
Keep UI events structured and scoped to the originating tool/app instance.
Design principles:
- Use explicit event names and schemas.
- Bind events to the correct server, user, and app instance.
- Reject unexpected event types and oversized payloads.
- Do not allow arbitrary script-to-host method calls.
- Preserve the final authoritative state on the server.
- Make destructive actions confirmable outside untrusted rendered content.
UI Sandboxing
Render server-provided UI as untrusted content with strong isolation.
Controls:
- Sandboxed iframe or equivalent isolation
- Restrictive Content Security Policy
- No ambient access to host DOM, cookies, credentials, or clipboard
- Explicit allowlist for network destinations
- Sanitized resource URLs
- Bounded storage and message sizes
- User-visible server identity
- Safe teardown when the tool/session ends
App Compatibility
Check extension support and degrade to text or structured tool results.
Fallback strategy:
- Return
structuredContentfor machine use. - Return concise text for universal rendering.
- Include the app resource only for supporting hosts.
- Avoid making essential results accessible only through the UI.
- Test keyboard, accessibility, mobile, and no-script fallback behavior.
- Version app resources independently when needed.
Design Patterns
One Server per Integration Boundary
Keep servers cohesive and independently permissionable.
Good boundaries follow a product, data domain, or trust zone:
- Source control server
- Calendar server
- Internal knowledge server
- Finance reporting server
Avoid one mega-server with every credential and tool. Smaller servers simplify consent, isolation, updates, auditing, and failure containment.
Read and Write Separation
Separate safe retrieval from side-effecting operations in names, schemas, and authorization.
Pattern:
contacts.search # read
contacts.get # read
contacts.create_draft # reversible preparation
contacts.send_message # external side effect; confirmation
contacts.delete # destructive; strong confirmation
This supports different scopes, confirmation policies, rate limits, and model visibility.
Human-in-the-Loop Actions
Preview consequential actions and require explicit confirmation close to execution.
Confirmation should show:
- Exact operation
- Target system and account
- Important arguments
- Expected external effect
- Whether it is reversible
- Costs or audience where relevant
After approval, execute the same argument set. If anything material changes, ask again.
Idempotent Operations
Design writes so safe retries do not duplicate effects.
Techniques:
- Client-generated idempotency keys
- Upsert semantics where appropriate
- Create-draft then submit workflow
- Compare-and-set version fields
- Task IDs for long-running work
- Deduplication records with expiration
- Return existing result when the same key is replayed
Document idempotency scope and retention.
Context-Size Management
Discover broadly but retrieve and inject context lazily.
- List metadata first.
- Read resources only when relevant.
- Paginate large catalogs.
- Summarize large tool results.
- Prefer resource links over embedded blobs.
- Cache stable content with provenance.
- Cap prompt and result sizes.
- Let users choose scope before expensive retrieval.
Do not expose thousands of tools to the model when only a small domain subset is relevant.
Performance, Reliability, and Observability
Performance Optimization
Reuse connections and minimize discovery, payload, and model-context overhead.
- Reuse initialized connections when safe.
- Discover tools/resources/prompts lazily.
- Cache catalogs and stable resources.
- Use pagination and bounded page sizes.
- Stream long responses where supported.
- Compress HTTP at the transport layer when appropriate.
- Avoid repeated schema serialization in prompts.
- Return structured summaries instead of huge raw payloads.
- Use connection pools for downstream services.
Reliability
Use bounded retries, health checks, graceful degradation, and persistent task state.
- Set per-request and maximum timeouts.
- Retry only safe operations.
- Use jittered backoff.
- Keep read paths available when write systems are degraded.
- Persist long-running task state.
- Return partial results with explicit completeness metadata.
- Detect stale sessions and reinitialize.
- Test dependency failure and recovery.
- Use circuit breakers for unstable downstream APIs.
Structured Logging
Emit queryable events with correlation while redacting sensitive content.
Recommended fields:
timestamp, level, server.name, server.version,
connection.id, session.id_hash, request.id, method,
tool.name, duration_ms, status, error.class,
input_bytes, output_bytes, user/tenant pseudonymous ID
Hash or omit session IDs. Do not log full prompts, tokens, resource bodies, or elicitation responses by default.
Metrics and Tracing
Measure protocol health, downstream health, model usage, and user-visible outcomes.
Useful metrics:
- Active connections and sessions
- Initialization failures by version
- Requests by method and status
- Tool latency and error rate
- Cancellation and timeout rate
- Payload sizes
- Catalog cache hit rate
- Task duration and terminal state
- Authorization failures
- User confirmation accept/decline rate
Propagate OpenTelemetry trace context through allowed metadata fields without trusting arbitrary inbound trace data.
Audit Logs
Record security-relevant decisions separately from debug logs.
Audit events should capture:
- Server installation, enablement, update, and removal
- Authorization grants and revocations
- Tool approval and execution
- Destructive operations
- Resource access to sensitive domains
- Elicitation of user data
- Policy blocks
- Administrative configuration changes
Protect audit integrity and define retention/access controls.
Common Pitfalls
Protocol Pitfalls
Most interoperability failures come from lifecycle, framing, or capability mistakes.
- Sending normal requests before initialization completes
- Returning a protocol version the client does not support
- Calling methods without negotiated capabilities
- Reusing request IDs while requests are in flight
- Writing non-JSON logs to stdout under stdio
- Sending embedded newlines in stdio messages
- Returning both
resultanderror - Assuming responses arrive in request order
- Forgetting HTTP protocol/session headers
Schema Pitfalls
Loose or mismatched schemas make model behavior unpredictable and validation ineffective.
- Tool description disagrees with actual side effects
- Required fields omitted from
required - Unbounded strings, arrays, paths, or URLs
- Accepting unknown fields unintentionally
- Declaring
outputSchemabut returning incompatible data - Using ambiguous unions without descriptions
- Changing schema semantics without versioning
- Trusting client-side validation only
Security Pitfalls
Convenience defaults often expand authority beyond user intent.
- Giving every server every tool and credential
- Treating local servers as trusted
- Passing tokens through to downstream APIs
- Assuming roots enforce filesystem access
- Rendering server UI without sandboxing
- Following instructions inside resource text
- Auto-confirming destructive tools
- Logging secrets or elicited data
- Binding HTTP to all interfaces by default
- Missing origin validation
Compatibility Pitfalls
Not every client implements every optional or draft feature.
- Assuming list-change notifications exist
- Requiring sampling or elicitation without fallback
- Depending on one content type only
- Mixing stable protocol behavior with draft behavior
- Copying SDK examples from another major version
- Treating annotations as universally enforced
- Using custom extensions without negotiation
- Ignoring cursor pagination
- Hard-coding server catalog order
MCP Compared with Related Technologies
MCP vs REST APIs
REST exposes application resources over HTTP; MCP exposes model-oriented primitives over a negotiated protocol.
MCP servers often wrap REST APIs. REST remains the underlying service contract, while MCP adds discovery, model-readable schemas, prompts/resources, bidirectional requests, local stdio, and host-mediated consent.
Use REST directly for ordinary application integration; add MCP when AI hosts need a reusable, model-oriented interface.
MCP vs Function Calling
Function calling is usually a model API feature; MCP standardizes discovery and invocation across hosts and servers.
Function calling describes how one model requests a function. MCP defines how a host discovers external tools, calls them over a transport, retrieves resources/prompts, negotiates capabilities, and supports server-to-client workflows.
A host may translate MCP tools into the model provider's function-calling format.
MCP vs Plugins
Plugin systems are product-specific packaging models; MCP is an interoperable protocol.
A plugin may include UI, lifecycle hooks, permissions, and proprietary APIs. MCP focuses on a standard wire protocol and primitives. A product can package an MCP server as a plugin, but the concepts are not identical.
MCP vs Agent Frameworks
Agent frameworks orchestrate reasoning and workflows; MCP standardizes access to external capabilities.
Frameworks may manage planning, memory, retries, and multi-agent coordination. MCP supplies reusable servers and clients that those frameworks can consume. Avoid embedding orchestration assumptions into a general-purpose server unless the server's domain requires them.
MCP vs Language Server Protocol
MCP borrows the client-server and JSON-RPC style, but targets AI context and actions rather than editor language features.
Both use capability-aware JSON-RPC interactions and support notifications. LSP standardizes language tooling such as diagnostics and completion; MCP standardizes tools, resources, prompts, and AI-oriented client features.
MCP vs RAG
RAG retrieves information for generation; MCP can expose retrieval plus actions, prompts, and interactive workflows.
A vector-search RAG system can be exposed through an MCP tool or resources. MCP does not prescribe embeddings, ranking, chunking, or generation strategy. It standardizes the boundary between the host and the retrieval/action service.
MCP vs OpenAPI
OpenAPI describes HTTP APIs; MCP describes an AI integration protocol and can wrap OpenAPI-described services.
OpenAPI is excellent for documenting endpoints, parameters, and HTTP responses. MCP adds initialization, capability negotiation, prompts/resources, server-initiated client requests, stdio, sessions, and model-oriented tool results. Automated OpenAPI-to-MCP conversion still requires careful tool design and security review.
Quick Reference
Core Method Map
Common MCP methods grouped by direction and feature.
| Feature | Method / notification |
|---|---|
| Lifecycle | initialize, notifications/initialized |
| Health | ping |
| Tools | tools/list, tools/call, notifications/tools/list_changed |
| Resources | resources/list, resources/read, resources/templates/list |
| Resource updates | resources/subscribe, resources/unsubscribe, update/list notifications |
| Prompts | prompts/list, prompts/get, prompt list-change notification |
| Sampling | sampling/createMessage |
| Roots | roots/list, roots list-change notification |
| Elicitation | elicitation/create |
| Completion | completion/complete |
| Utilities | progress, cancellation, logging notifications/methods |
Always verify names against the negotiated protocol version.
Production Readiness Checklist
Ship only after protocol, security, operations, and user experience checks pass.
- [ ] Protocol version pinned and tested
- [ ] Capabilities accurate
- [ ] Input/output schemas validated
- [ ] Auth scopes minimized
- [ ] Destructive tools confirmed
- [ ] Local command/package verified
- [ ] HTTP origin/host/security controls enabled
- [ ] Timeouts, cancellation, and retries bounded
- [ ] Payload and rate limits configured
- [ ] Logs and audits redact secrets
- [ ] Inspector and automated tests pass
- [ ] Fallbacks exist for optional features
- [ ] Upgrade and rollback plan documented
Choosing the Right Primitive
Use the primitive that matches user intent and data behavior.
| Need | Choose |
|---|---|
| Retrieve identifiable context | Resource |
| Execute computation or action | Tool |
| Offer reusable user workflow | Prompt |
| Ask host model to generate | Sampling |
| Learn relevant client boundaries | Roots |
| Ask user for missing input | Elicitation |
| Track long-running work | Task/extension for targeted version |
| Render interactive host UI | MCP Apps extension |
Avoid using a broad tool when a read-only resource or prompt is sufficient.
Minimal Safe Flow
The safest default path is discover, validate, authorize, confirm, execute, validate, and label.
Initialize
→ negotiate version/capabilities
→ discover relevant primitive
→ validate request
→ authorize identity/resource
→ confirm consequential action
→ execute with timeout/cancellation
→ validate and limit output
→ label provenance
→ log audit event
This flow applies whether the integration is local, remote, Python, TypeScript, or another official SDK.
