AI Development

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

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:

  1. Send the newest protocol version your client actually supports in initialize.
  2. Accept the server-selected version only if your client supports it.
  3. Gate every optional method behind negotiated capabilities.
  4. Treat pages under /specification/draft/ as provisional.
  5. 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:

  1. Discover each server's capabilities.
  2. Build a per-server catalog of tools, prompts, and resources.
  3. Apply policy filters and user permissions.
  4. Provide only relevant items to the model.
  5. Validate proposed tool calls before execution.
  6. Normalize and label returned content by server origin.
  7. Preserve provenance in logs and UI.

Never treat server-provided descriptions, titles, annotations, or resource text as trusted policy instructions.

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"}
}
  • jsonrpc must be exactly "2.0".
  • id correlates one response to one request; string and integer IDs are common.
  • method is a namespaced method string.
  • params is 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/call
  • resources/list, resources/read
  • prompts/list, prompts/get

Server → client examples in stable MCP

  • sampling/createMessage
  • roots/list
  • elicitation/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:

  1. Client sends its newest supported version.
  2. Server returns the same version when supported.
  3. Otherwise, server returns another version it supports.
  4. Client verifies the returned version.
  5. 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

  • tools with optional listChanged
  • resources with optional subscribe and listChanged
  • prompts with optional listChanged
  • logging, completions, experimental/task fields when supported

Typical client capabilities

  • roots with optional listChanged
  • sampling
  • elicitation modes
  • 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.
  • stdout must 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 initialize request.
  • 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, not 0.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:

  1. Validate the tool exists in the active catalog.
  2. Validate arguments against inputSchema.
  3. Apply authorization and confirmation policy.
  4. Execute with timeout and cancellation support.
  5. Validate or normalize output.
  6. 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: false for closed schemas when compatibility allows.
  • Apply minLength, maxLength, numeric ranges, and array limits.
  • Use enum for 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, or do_action.

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.md
  • db://analytics/schema/orders
  • docs://handbook/security-policy
  • git://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/subscribe starts updates for one URI.
  • notifications/resources/updated signals changed content.
  • resources/unsubscribe stops updates.
  • notifications/resources/list_changed signals 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.

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:

  1. A clear task-oriented name.
  2. A description of the intended output.
  3. Minimal explicit arguments.
  4. Guardrails for missing context.
  5. Resource references instead of copying large documents.
  6. No hidden instructions to bypass host policy.
  7. Stable output expectations without over-constraining the model.

Prompts are best for how to ask; tools are best for what to execute.

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.

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 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.

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 nextCursor at 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:

  1. Sender issues a cancellation notification referencing the request ID.
  2. Receiver stops work when practical.
  3. Receiver releases locks, subprocesses, network calls, and temporary files.
  4. Race conditions are possible: a result may arrive just before cancellation.
  5. 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/message for 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.

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:

  1. Persist the task ID with server/session identity.
  2. Poll with exponential backoff or use supported notifications.
  3. Handle input_required without losing previous state.
  4. Retrieve the final result only after completion.
  5. Allow user cancellation and surface non-cancellable states.
  6. Stop polling after expiration or terminal status.
  7. 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 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:

  1. Discover protected-resource metadata.
  2. Discover authorization-server metadata.
  3. Register or identify the client.
  4. Build an authorization request with PKCE and state.
  5. User authenticates and consents.
  6. Validate redirect, state, issuer, and authorization code.
  7. Exchange code for tokens.
  8. Call the MCP endpoint with a bearer access token.
  9. 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.

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:

  1. UTF-8 and JSON parsing
  2. JSON-RPC envelope
  3. MCP method schema
  4. Tool JSON Schema
  5. Authorization and resource ownership
  6. Domain constraints
  7. 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 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: mcp v1.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 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.json and 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.

  1. Define the external system and trust boundary.
  2. Choose local stdio or remote HTTP.
  3. Define read-only resources first.
  4. Add small, specific tools with schemas.
  5. Add prompts only for reusable user workflows.
  6. Decide whether sampling, roots, or elicitation are truly needed.
  7. Implement lifecycle and capability declaration.
  8. Add auth, validation, timeouts, and limits.
  9. Test with Inspector and automated clients.
  10. 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:

  1. Mark server draining.
  2. Reject new long-running operations.
  3. Cancel or finish in-flight tasks according to policy.
  4. Flush protocol responses and logs.
  5. Close database pools and HTTP clients.
  6. Delete temporary files and subscriptions.
  7. Close transport or exit the subprocess.

Do not write shutdown diagnostics to stdout in stdio mode.

Client Build Checklist

A client must combine protocol correctness with host policy and usable approval flows.

  1. Parse server configuration safely.
  2. Establish the transport.
  3. Initialize and negotiate version/capabilities.
  4. Discover catalogs lazily.
  5. Build a server-scoped cache.
  6. Validate model-selected calls.
  7. Request user approval where required.
  8. Execute with timeout/cancellation.
  9. Normalize and label results.
  10. Recover sessions and connections safely.
  11. 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.

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 Accept header includes JSON and SSE
  • Content-Type matches response body
  • MCP-Protocol-Version after initialization
  • MCP-Session-Id propagation
  • 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 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:

  1. Return structuredContent for machine use.
  2. Return concise text for universal rendering.
  3. Include the app resource only for supporting hosts.
  4. Avoid making essential results accessible only through the UI.
  5. Test keyboard, accessibility, mobile, and no-script fallback behavior.
  6. Version app resources independently when needed.

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.

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 result and error
  • 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 outputSchema but 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.

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.