# Model Context Protocol (MCP) — full corpus # LLM Wiki An open-source template for building LLM-powered knowledge bases, following [Andrej Karpathy's "LLM Wiki" pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f). You provide raw sources. The LLM reads them, writes structured wiki pages, cross-links everything, and maintains it over time. You never edit the wiki directly — you curate sources and ask questions. ## How It Works The system has three layers: ``` raw/ Sources you collect (articles, transcripts, notes, PDFs) wiki/ LLM-written & maintained pages (summaries, concepts, entities, syntheses) CLAUDE.md Schema that tells the LLM how to structure everything ``` Three operations drive the workflow: | Operation | Trigger | What happens | |-----------|---------|--------------| | **Ingest** | "ingest raw/my-source.txt" | LLM reads the source, creates a summary page, creates/updates concept and entity pages, adds cross-links, updates the index and log | | **Query** | Ask any question | LLM searches the wiki, synthesizes an answer with citations, optionally creates a synthesis page for novel insights | | **Lint** | "lint" or "health check" | LLM audits all pages for orphans, contradictions, missing links, incomplete sections, and low-confidence claims — fixes what it can, reports the rest | ## Quick Start 1. **Clone this repo** ```bash git clone https://github.com/YOUR_USERNAME/llm-wiki.git my-knowledge-base cd my-knowledge-base ``` 2. **Customize CLAUDE.md** for your domain - Update the Purpose section with your topic - Replace the placeholder tagging taxonomy with your own categories - Adjust confidence level descriptions if needed - Everything else (workflows, page formats, linking rules) works as-is 3. **Drop sources into `raw/`** - Text files, transcripts, articles, notes — any plain text - These are immutable once added; the LLM never modifies them 4. **Tell the LLM to ingest** ``` ingest raw/my-first-source.txt ``` The LLM will create summary pages, concept pages, entity pages, cross-links, and update the index. 5. **Ask questions** ``` What are the key differences between X and Y? ``` The LLM answers from the wiki, citing specific pages. 6. **Run health checks** ``` lint ``` The LLM audits the wiki and fixes issues. ## Directory Structure ``` . ├── CLAUDE.md # Schema — the LLM's instructions ├── raw/ # Your source documents (immutable) └── wiki/ ├── index.md # Master catalog of all pages ├── log.md # Append-only activity log ├── dashboard.md # Dataview dashboard (Obsidian) ├── analytics.md # Charts View analytics (Obsidian) ├── flashcards.md # Spaced repetition cards ├── summaries/ # One page per source document ├── concepts/ # Concept and framework pages ├── entities/ # People, tools, organizations, etc. ├── syntheses/ # Cross-cutting analyses and comparisons ├── journal/ # Research/session journal entries │ └── template.md # Journal entry template └── presentations/ # Marp slide decks ``` ## Enhancements This template includes several extras beyond the core wiki pattern: ### Dataview Dashboard (`wiki/dashboard.md`) Live queries that surface low-confidence pages, recent updates, concepts by tag, and pages with the most sources. Requires the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) Obsidian plugin. ### Charts View Analytics (`wiki/analytics.md`) Visual analytics with pie charts, bar charts, and word clouds. Requires the [Charts View](https://github.com/caronchen/obsidian-chartsview-plugin) Obsidian plugin. ### Mermaid Diagrams Use Mermaid code blocks in any wiki page to create flowcharts, sequence diagrams, or concept maps. Native support in Obsidian and GitHub. ### Marp Slides (`wiki/presentations/`) Create slide decks from markdown using [Marp](https://marp.app/). Drop presentation files in this directory. ### Research Journal (`wiki/journal/`) Track your research sessions, experiments, or applied work with the included template. The LLM can reference journal entries when answering queries. ### Spaced Repetition (`wiki/flashcards.md`) Flashcards in the format used by the [Spaced Repetition](https://github.com/st3v3nmw/obsidian-spaced-repetition) Obsidian plugin. Ask the LLM to generate flashcards from any wiki page. ### MCP Server This repo works with Claude Code's MCP server capabilities. Point an MCP-compatible client at this repo and the LLM can read/write the wiki programmatically. ## Customizing for Your Domain The schema in `CLAUDE.md` is domain-agnostic. To adapt it: 1. **Purpose** — Describe your knowledge domain in one paragraph 2. **Tagging taxonomy** — Replace placeholder categories with your own (e.g., for a cooking KB: `cuisine`, `technique`, `ingredient`, `equipment`) 3. **Confidence levels** — Adjust the descriptions to match your domain's evidence standards 4. **Entity types** — Update the entity page description to match what entities mean in your domain (people, tools, companies, etc.) 5. **Journal template** — Customize `wiki/journal/template.md` for your workflow Everything else — page format, linking conventions, workflows, rules — is universal and works across domains. ## Example Domains This template works for any knowledge-intensive topic: - **Research notes** — papers, experiments, methodologies - **Book analysis** — themes, characters, author techniques - **Competitive analysis** — companies, products, market trends - **Course notes** — lectures, readings, key concepts - **Personal development** — frameworks, habits, book summaries - **Technical documentation** — APIs, architectures, design patterns - **Hobby deep-dives** — any subject you want to master ## License MIT --- title: "MCP Knowledge Base — Index" type: index updated: 2026-07-07 mcp_version: "2025-11-25" --- # Model Context Protocol (MCP) — Knowledge Base The open protocol that connects AI applications (hosts/clients) to external tools, data, and prompts (servers). This wiki covers the protocol as of spec revision **2025-11-25**: architecture, transports, server and client capabilities, authorization, and how to build, connect, debug, and publish servers and clients — plus the official SDKs and registry. Master catalog — every page appears here. ## Concepts ### Protocol core - [[concepts/what-is-mcp]] — what MCP is and the host/client/server model - [[concepts/architecture]] — participants, layers, capability negotiation - [[concepts/transports]] — stdio and Streamable HTTP transports - [[concepts/lifecycle]] — initialize handshake, capability exchange, shutdown - [[concepts/versioning]] — date-based protocol versioning and key changes - [[concepts/protocol-utilities]] — ping, cancellation, progress, pagination, completion, logging ### Server & client capabilities - [[concepts/resources]] — application-driven context (URIs, read, subscribe) - [[concepts/tools]] — model-controlled actions (tools/list, tools/call) - [[concepts/prompts]] — user-controlled prompt templates - [[concepts/sampling]] — server-initiated LLM calls via the client - [[concepts/roots]] — client-exposed filesystem boundaries - [[concepts/elicitation]] — server requesting structured user input ### Authorization & building - [[concepts/authorization]] — OAuth 2.1 flow, discovery, tokens, scopes - [[concepts/security-best-practices]] — threats, consent, token handling - [[concepts/building-a-server]] — scaffold and run an MCP server - [[concepts/building-a-client]] — connect, initialize, call capabilities - [[concepts/connecting-to-servers]] — local (stdio) vs remote (HTTP) connection config - [[concepts/debugging]] — debugging workflow, inspector, logs ## Entities - [[entities/python-sdk]] — the official Python SDK (`mcp`) - [[entities/typescript-sdk]] — the official TypeScript SDK - [[entities/mcp-inspector]] — the interactive debugging tool - [[entities/mcp-registry]] — the official server registry - [[entities/mcp-apps]] — MCP Apps (interactive UI extension) - [[entities/publishing-to-registry]] — publish and version a server ## Syntheses - [[syntheses/server-feature-picker]] — resources vs tools vs prompts: which to use - [[syntheses/transport-decision]] — stdio vs Streamable HTTP: when to use which - [[syntheses/local-vs-remote-servers]] — local vs remote servers: trade-offs ## Statistics - **Total pages**: 27 - **Concepts**: 18 - **Entities**: 6 - **Summaries**: 0 - **Syntheses**: 3 --- title: "MCP Architecture" type: concept tags: [protocol, architecture, foundational, json-rpc, capabilities, well-established] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-architecture.md", "raw/llms_txt_doc-architecture-overview.md"] confidence: high --- # MCP Architecture ## Definition MCP follows a **client-host-server architecture** where each host can run multiple client instances. Built on **JSON-RPC 2.0**, MCP is a **stateful session protocol** focused on context exchange and sampling coordination between clients and servers. The architecture lets users integrate AI capabilities across applications while maintaining clear security boundaries and isolating concerns. Conceptually, MCP is split into two layers — a **data layer** (the JSON-RPC protocol itself) wrapped by a **transport layer** (the communication channel). ## How It Works **Three participants** collaborate (see also [[concepts/what-is-mcp]]): - **Host** — the application process that acts as container and coordinator. It creates and manages multiple client instances; controls client connection permissions and lifecycle; enforces security policies and consent requirements; handles user authorization decisions; coordinates AI/LLM integration and sampling; and manages context aggregation across clients. - **Client** — created by the host, each client maintains one isolated server connection. It establishes one stateful session per server, handles protocol negotiation and capability exchange, routes protocol messages bidirectionally, manages subscriptions and notifications, and maintains security boundaries between servers. A client has a **1:1 relationship** with a particular server. - **Server** — provides specialized context and capabilities. It exposes resources, tools, and prompts via MCP primitives; operates independently with focused responsibilities; can request sampling through client interfaces; must respect security constraints; and can be a local process or a remote service. **Two layers:** - **Data layer** (the inner layer) — the JSON-RPC 2.0 based exchange protocol defining message structure and semantics. It covers lifecycle management, server features (tools, resources, prompts), client features (sampling, elicitation, logging), and utility features (notifications, progress). See [[concepts/lifecycle]]. - **Transport layer** (the outer layer) — manages communication channels and authentication, handling connection establishment, message framing, and secure communication. It abstracts communication details so the same JSON-RPC 2.0 message format works across every transport. See [[concepts/transports]]. **JSON-RPC message types** (the base protocol): - **Requests** — initiate an operation. Shape: `{ jsonrpc: "2.0", id: string | number, method: string, params?: {...} }`. The `id` **MUST** be a string or integer, **MUST NOT** be `null`, and **MUST NOT** have been previously used by the requestor within the same session. - **Result responses** — `{ jsonrpc: "2.0", id, result: {...} }`. **MUST** include the same `id` as the request and a `result` field. - **Error responses** — `{ jsonrpc: "2.0", id?, error: { code: number, message: string, data?: unknown } }`. Error `code` **MUST** be an integer. - **Notifications** — one-way messages, `{ jsonrpc: "2.0", method, params? }`. They **MUST NOT** include an `id`, and the receiver **MUST NOT** send a response. **Primitives.** Servers expose three: **Tools** (executable functions, e.g. API calls, DB queries), **Resources** (data sources providing context), and **Prompts** (reusable templates). Clients expose: **Sampling** (`sampling/createMessage` — request an LLM completion from the host), **Elicitation** (`elicitation/create` — request info from the user), and **Logging**. Each primitive type has methods for discovery (`*/list`), retrieval (`*/get`), and, in some cases, execution (`tools/call`). Clients use `*/list` to discover primitives, which lets listings be dynamic. There is also an experimental cross-cutting primitive, **Tasks**, for durable execution with deferred result retrieval. ## Key Parameters - **Design principles:** (1) servers should be extremely easy to build — hosts handle complex orchestration; (2) servers should be highly composable; (3) servers should **not** be able to read the whole conversation, nor "see into" other servers — full history stays with the host, each connection stays isolated; (4) features can be added to servers and clients progressively, preserving backwards compatibility. - **Local vs remote:** local servers using the **stdio** transport typically serve a single client; remote servers using the **Streamable HTTP** transport typically serve many clients. See [[syntheses/local-vs-remote-servers]]. - **Scope of the project:** the MCP Specification, the language SDKs (see [[entities/python-sdk]], [[entities/typescript-sdk]]), MCP development tools (e.g. [[entities/mcp-inspector]]), and reference server implementations. ## Capability Negotiation MCP uses a **capability-based negotiation system**: clients and servers explicitly declare supported features during initialization, and capabilities determine which protocol features and primitives are available during a session. - Servers declare capabilities like resource subscriptions, tool support, and prompt templates. - Clients declare capabilities like sampling support and notification handling. - Both parties **must** respect declared capabilities throughout the session. - Additional capabilities can be negotiated through protocol extensions. Concretely: implemented server features must be advertised in the server's capabilities; emitting resource subscription notifications requires the server to declare `subscribe` support; tool invocation requires the server to declare `tools`; sampling requires the client to declare `sampling`. See [[concepts/lifecycle]] for the full capability table and the `listChanged` / `subscribe` sub-capabilities. ## When To Use Understand this architecture when building any MCP participant — it defines who is responsible for what. Server authors lean on the "servers are easy to build" principle and focus on one capability. Client/host authors own orchestration, security enforcement, and context aggregation. Anyone debugging a connection needs to know that requests, responses, and notifications flow bidirectionally and that capabilities gate what is even legal to send. ## Risks & Pitfalls - **Reusing request IDs** within a session violates the spec — IDs must be unique per requestor per session and never `null`. - **Sending un-negotiated features.** Using a capability the other side never declared breaks the session contract; always check negotiated capabilities first. - **Assuming servers see everything.** By design, servers receive only necessary contextual information; do not architect a server that expects full conversation history. - **Confusing "server" with "remote."** A server is the program serving context regardless of location — a local stdio subprocess is still an MCP server. ## Related Concepts - [[concepts/what-is-mcp]] - [[concepts/lifecycle]] - [[concepts/transports]] - [[concepts/protocol-utilities]] - [[concepts/resources]], [[concepts/tools]], [[concepts/prompts]] - [[concepts/sampling]], [[concepts/elicitation]], [[concepts/roots]] - [[concepts/security-best-practices]] - [[syntheses/local-vs-remote-servers]], [[syntheses/server-feature-picker]] ## Sources - `raw/llms_txt_doc-architecture.md` - `raw/llms_txt_doc-architecture-overview.md` --- title: "Authorization" type: concept tags: [authorization, oauth, security, transports, foundational] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-authorization.md", "raw/llms_txt_doc-understanding-authorization-in-mcp.md", "raw/llms_txt_doc-oauth-client-credentials.md", "raw/llms_txt_doc-authorization-extensions.md"] confidence: high --- # Authorization ## Definition Authorization in MCP secures access to protected servers, letting an MCP client make requests on behalf of a resource owner. It is provided **at the transport level** and is **OPTIONAL** — implementations may skip it entirely. When used, it is based on a selected subset of **OAuth 2.1** (IETF draft `draft-ietf-oauth-v2-1-13`). HTTP-based transports **SHOULD** conform to this spec; **STDIO transports SHOULD NOT** — local servers instead retrieve credentials from the environment. In OAuth roles, a protected MCP server is the **resource server**, the MCP client is the **OAuth client**, and a separate **authorization server** interacts with the user and issues access tokens. ## How It Works The interactive (authorization-code + PKCE) flow proceeds: 1. **Initial handshake / 401.** The client makes an unauthenticated request; the server returns `401 Unauthorized` with a `WWW-Authenticate` header pointing to its Protected Resource Metadata (PRM): ```http HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="mcp", resource_metadata="https://your-server.com/.well-known/oauth-protected-resource" ``` 2. **PRM discovery.** Servers **MUST** implement RFC 9728 Protected Resource Metadata; the document **MUST** include an `authorization_servers` field: ```json { "resource": "https://your-server.com/mcp", "authorization_servers": ["https://auth.your-server.com"], "scopes_supported": ["mcp:tools", "mcp:resources"] } ``` Clients use the `resource_metadata` URL from the header when present, otherwise fall back to well-known URIs (`/.well-known/oauth-protected-resource/` then root). 3. **Authorization server discovery.** The client fetches AS metadata via **RFC 8414** (OAuth 2.0 Authorization Server Metadata) or **OpenID Connect Discovery 1.0**. Clients **MUST** try multiple well-known endpoints in priority order; servers **MUST** support at least one mechanism, clients both. Result yields `authorization_endpoint`, `token_endpoint`, `registration_endpoint`. 4. **Client registration** (see Key Parameters). 5. **User authorization.** Client generates PKCE parameters, opens a browser to `/authorize` with `code_challenge` and the `resource` parameter; user consents; the AS redirects back with an authorization code that the client exchanges (with `code_verifier` + `resource`) for an access token (+ refresh token). 6. **Authenticated requests.** Every HTTP request carries `Authorization: Bearer `. Tokens **MUST NOT** appear in the URI query string, and **MUST** be sent on every request even within one session. **Machine-to-machine (client credentials).** The `io.modelcontextprotocol/oauth-client-credentials` extension adds the OAuth 2.0 client credentials flow for background services, CI/CD, and daemons with no user present. Two credential formats: **JWT Bearer Assertions** (RFC 7523, recommended — the client signs a JWT with its private key; `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer`) and **client secrets** (`grant_type=client_credentials`, `client_id` + `client_secret`). Declare it in the `initialize` capabilities: ```json { "capabilities": { "extensions": { "io.modelcontextprotocol/oauth-client-credentials": {} } } } ``` ## Key Parameters - **`resource` (RFC 8707 Resource Indicators)** — clients **MUST** include it in both authorization and token requests, identifying the MCP server via its canonical URI (e.g. `https://mcp.example.com/mcp`; no fragment, includes scheme, no trailing slash). Sent regardless of AS support. - **PKCE** — clients **MUST** implement it with the `S256` method and **MUST** verify support via `code_challenge_methods_supported` in AS metadata (refuse to proceed if absent). - **Client registration approaches** (priority order): (1) pre-registered static credentials; (2) **Client ID Metadata Documents** — an HTTPS URL as `client_id` pointing to a JSON doc with `client_id`, `client_name`, `redirect_uris` (advertised via `client_id_metadata_document_supported: true`); (3) **Dynamic Client Registration** (RFC 7591, `POST /register`, for backwards compat); (4) prompt the user. - **Scopes** — request via `WWW-Authenticate` `scope` in the 401; else use all of `scopes_supported`. Follow least privilege. - **Token validation** — servers **MUST** validate the token was issued for them (audience/`aud` claim per RFC 8707/9068), reject others with 401. - **Error codes** — `401` (unauthorized/invalid token), `403` (insufficient scope, with `error="insufficient_scope"` + required `scope` in `WWW-Authenticate`), `400` (malformed request). ## When To Use Authorization is optional but strongly recommended when the server accesses user-specific data (emails, documents, databases), needs auditing of who did what, grants access to APIs requiring consent, targets enterprise environments with strict access controls, or needs per-user rate limiting. For **local STDIO servers**, use environment/embedded credentials instead of OAuth. Use the **client-credentials extension** for background services, CI/CD pipelines, and server-to-server integrations with no human. Use **Enterprise-Managed Authorization** for org-wide IdP-enforced policy. ## Risks & Pitfalls - **Do not hand-roll token validation** — use well-tested libraries. Always validate; a received token is not necessarily valid or intended for you. - **Confused-deputy** — proxy servers with static client IDs **MUST** obtain per-client user consent before forwarding to third-party ASes (see [[concepts/security-best-practices]]). - **Token passthrough is forbidden** — never forward a client's token to an upstream API; the MCP server acts as a separate OAuth client there. - **Use short-lived tokens**, rotate refresh tokens for public clients, store tokens in secure encrypted storage, enforce HTTPS in production (localhost-only exception), never log `Authorization` headers or secrets. - **Client ID Metadata Documents** expose SSRF risk (the AS fetches an attacker URL) and cannot prevent `localhost` redirect impersonation on their own. - **Least-privilege scopes** — avoid catch-all/omnibus scopes (`*`, `full-access`); use step-up authorization for elevation. ## Related Concepts - [[concepts/security-best-practices]] — attack vectors and mitigations - [[concepts/transports]] — why OAuth is HTTP-only, STDIO uses env credentials - [[concepts/lifecycle]] — the `initialize` handshake and capability negotiation - [[concepts/building-a-server]] — implementing a protected resource server - [[entities/python-sdk]] · [[entities/typescript-sdk]] — SDK auth helpers ## Sources - `raw/llms_txt_doc-authorization.md` — normative OAuth 2.1 authorization spec - `raw/llms_txt_doc-understanding-authorization-in-mcp.md` — tutorial + Keycloak/SDK example - `raw/llms_txt_doc-oauth-client-credentials.md` — machine-to-machine extension - `raw/llms_txt_doc-authorization-extensions.md` — extension overview --- title: "Building a Client" type: concept tags: [client, how-to, sdk, tools, foundational] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-build-an-mcp-client.md", "raw/llms_txt_doc-understanding-mcp-clients.md", "raw/github_doc-docs-clients-connect-md.md", "raw/github_doc-docs-clients-calling-md.md"] confidence: high --- # Building a Client ## Definition An MCP client is the protocol-level component a **host** application (Claude.ai, an IDE, an agent) instantiates to talk to one MCP server — one client per server. The host manages the overall UX and coordinates multiple clients. Beyond consuming server context, clients may offer server-facing features: **Elicitation** (servers request structured info from users), **Roots** (clients declare filesystem boundaries via `file://` URIs), and **Sampling** (servers request LLM completions through the client, keeping the client in control of permissions). This page is an operational how-to: connect, initialize, discover, and call capabilities. ## How It Works ### Connect (TypeScript SDK) A client holds one connection: construct a `Client`, pick a transport, `connect()`. ```ts import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client'; const client = new Client({ name: 'my-client', version: '1.0.0' }); const transport = new StreamableHTTPClientTransport(new URL('http://localhost:3000/mcp')); await client.connect(transport); ``` `connect()` runs the `initialize` handshake and resolves once complete. For a local child process, swap only the transport (`StdioClientTransport`, from `@modelcontextprotocol/client/stdio`): ```ts const transport = new StdioClientTransport({ command: 'node', args: ['server.js'] }); await client.connect(transport); ``` `InMemoryTransport.createLinkedPair()` links a client and server in one process (used for tests). For SSE-only servers that predate Streamable HTTP, try `StreamableHTTPClientTransport` first and fall back to `SSEClientTransport`. After connecting, three accessors return what the server declared (all `undefined` until `connect()` resolves): ```ts console.log(client.getServerVersion()); // { name: 'travel', version: '2.1.0' } console.log(client.getServerCapabilities()); // { tools: { listChanged: true } } console.log(client.getInstructions()); // put this in the system prompt ``` The capability object gates every verb — only ask for what the server advertised. Disconnect cleanly: `await transport.terminateSession(); await client.close();`. `close()` rejects in-flight requests with `CONNECTION_CLOSED`. ### Discover and call capabilities ```ts const { tools } = await client.listTools(); const result = await client.callTool({ name: 'lookup-order', arguments: { id: 'A-1041' } }); console.log(result.content); // [ { type: 'text', text: 'A-1041: 3 items, shipped' } ] ``` `listTools`, `listResources`, `listResourceTemplates`, and `listPrompts` auto-aggregate every page (following `nextCursor`); passing `{ cursor }` returns one raw page. `ClientOptions.listMaxPages` (default 64) caps the walk. A **failed tool call is still a result** — check `isError` before trusting `content`; only protocol failures (unknown tool, timeout) throw. Read structured output via `result.structuredContent` (validated against the tool's `outputSchema` when known). Read resources with `readResource({ uri })`, get prompts with `getPrompt({ name, arguments })` (returns model-ready `messages`), autocomplete with `complete(...)`, and track long calls with `onprogress` request options (plus `resetTimeoutOnProgress`, `maxTotalTimeout`). ### The full LLM loop (Python quickstart) ```python from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client server_params = StdioServerParameters(command=command, args=[server_script_path], env=None) stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params)) self.stdio, self.write = stdio_transport self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write)) await self.session.initialize() response = await self.session.list_tools() # discover result = await self.session.call_tool(tool_name, tool_args) # execute ``` The processing loop: get tools from the server → send query + tool descriptions to the model → the model decides which tools to call → the client executes calls through the server → results go back to the model → the model returns a natural-language response. SDKs exist for Python, TypeScript, Java (Spring AI `spring-ai-starter-mcp-client`), Kotlin, C# (`McpClient.CreateAsync`), and Ruby. ## Key Parameters - **Server script dispatch** — clients pick the launch command by extension: `.py` → `python`/`python3`, `.js` → `node`, `.jar` → `java -jar`, `.csproj`/dir → `dotnet run --project`. - **Client-side features** — declare Elicitation / Roots / Sampling capabilities to let servers use them; each has a human-in-the-loop model. Sampling requests carry `modelPreferences` (hints, `costPriority`, `speedPriority`, `intelligencePriority`), `systemPrompt`, `maxTokens`. - **Roots** — `{ "uri": "file:///Users/agent/travel-planning", "name": "..." }`; advisory, not a security boundary; updates fire `roots/list_changed`. - **Progress** — `onprogress` streams `notifications/progress` without changing the return type. ## When To Use Build a client when your application needs to consume MCP servers directly (a custom agent, chatbot, or IDE integration) rather than relying on an existing host. Use the high-level SDK `Client`/`ClientSession` for standard verbs; the SDK only exposes verbs for methods MCP defines. Offer Sampling/Elicitation/Roots when you want servers to build richer, interactive workflows. ## Risks & Pitfalls - **Response timing** — the first response can take up to 30 seconds (server init + model + tools); don't interrupt. - **Path issues** — use absolute paths; on Windows use forward slashes or escaped backslashes; verify the file extension matches the runtime. - **Error handling** — wrap tool calls in try/catch, validate server responses, be cautious with tool permissions, store API keys in `.env` (gitignored). Common errors: `Connection refused` (server/path), `Tool execution failed` (missing env vars), `Timeout` (raise the client timeout). - **Privacy** — Elicitation never requests passwords/API keys; Sampling should run human-in-the-loop review. ## Related Concepts - [[concepts/building-a-server]] — the other half of the connection - [[concepts/connecting-to-servers]] · [[concepts/transports]] · [[concepts/lifecycle]] - [[concepts/elicitation]] · [[concepts/roots]] · [[concepts/sampling]] — client-provided features - [[concepts/tools]] · [[entities/python-sdk]] · [[entities/typescript-sdk]] ## Sources - `raw/llms_txt_doc-build-an-mcp-client.md` — multi-language client quickstart (LLM loop) - `raw/llms_txt_doc-understanding-mcp-clients.md` — host vs client, elicitation/roots/sampling - `raw/github_doc-docs-clients-connect-md.md` — TS `Client` connect/introspect/disconnect - `raw/github_doc-docs-clients-calling-md.md` — list/call/read/getPrompt/complete/progress --- title: "Building a Server" type: concept tags: [server, how-to, tools, sdk, foundational] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-build-an-mcp-server.md", "raw/llms_txt_doc-understanding-mcp-servers.md", "raw/github_doc-docs-advanced-low-level-server-md.md"] confidence: high --- # Building a Server ## Definition An MCP server is a program that exposes capabilities to AI applications through the standardized protocol. Servers provide three building blocks: **Tools** (model-controlled functions the LLM can call, with user approval), **Resources** (application-controlled read-only data sources with unique URIs), and **Prompts** (user-controlled instruction templates). This page is an operational how-to for scaffolding a server, registering tools, and running it — walking the official "weather server" quickstart (two tools: `get_alerts`, `get_forecast`). ## How It Works ### Python (FastMCP) — the fast path Install `uv`, then scaffold: ```bash # Create a new directory for our project uv init weather cd weather # Create virtual environment and activate it uv venv source .venv/bin/activate # Install dependencies uv add "mcp[cli]" httpx # Create our server file touch weather.py ``` Requires **Python 3.10+** and **MCP SDK 1.2.0+**. Create the instance and register tools — FastMCP reads type hints and docstrings to generate tool definitions automatically: ```python from mcp.server.fastmcp import FastMCP # Initialize FastMCP server mcp = FastMCP("weather") @mcp.tool() async def get_alerts(state: str) -> str: """Get weather alerts for a US state. Args: state: Two-letter US state code (e.g. CA, NY) """ ... ``` Run it over stdio: ```python def main(): # Initialize and run the server mcp.run(transport="stdio") if __name__ == "__main__": main() ``` Start with `uv run weather.py`. ### TypeScript ```bash npm install @modelcontextprotocol/sdk zod@3 npm install -D @types/node typescript ``` Set `"type": "module"` in `package.json`. Create the server and register tools with a Zod input schema: ```typescript import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; const server = new McpServer({ name: "weather", version: "1.0.0" }); server.registerTool( "get_alerts", { description: "Get weather alerts for a state", inputSchema: { state: z.string().length(2).describe("Two-letter state code (e.g. CA, NY)"), }, }, async ({ state }) => ({ content: [{ type: "text", text: "..." }] }), ); ``` Run over stdio, then `npm run build` (a required step): ```typescript async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Weather MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); }); ``` Other supported SDKs: **C#** (`dotnet add package ModelContextProtocol --prerelease`, `builder.Services.AddMcpServer().WithStdioServerTransport().WithToolsFromAssembly()`), **Java/Spring AI** (`spring-ai-starter-mcp-server`, `@Tool` annotations), **Kotlin** (`io.modelcontextprotocol:kotlin-sdk`), and **Ruby**. ### The low-level `Server` (Python) `@mcp.tool()` sits on top of a lower `Server` class that speaks raw MCP. Drop down when you need an exact JSON Schema (not one derived from a signature), full control of the result (`_meta`, `is_error`, `structured_content`), or a method MCP doesn't define. Key differences: - **Handlers are constructor parameters** (`on_list_tools=`, `on_call_tool=`), each `async (ctx, params) -> result`. - **You write `Tool.input_schema`** as a plain JSON Schema dict — it is *advertised* but never *applied*; nothing validates `params.arguments` for you. - **You build `CallToolResult(content=[TextContent(...)])`** by hand; nothing is wrapped or inferred. - An exception from a handler is **always** a `-32603` protocol error, never `is_error=True`. To let the model recover, validate yourself and return `CallToolResult(..., is_error=True)`. - `add_request_handler(method, params_type, handler)` serves any custom method; `initialize` is reserved to the runner. - Advertised capabilities follow which handlers you registered. ## Key Parameters - **Capabilities** — a server advertises only the method families it backs. Protocol operations: `tools/list`, `tools/call`, `resources/list`, `resources/templates/list`, `resources/read`, `resources/subscribe`, `prompts/list`, `prompts/get`. - **Resource URIs** — direct (`calendar://events/2024`) or templated (`travel://activities/{city}/{category}`), each declaring a `mimeType`; templates support parameter completion. - **`outputSchema`** — declare it and return `structuredContent` for typed output the client validates. - **`_meta`** — a third channel addressed to the client application, not the model; namespace keys (`bookshop/record_ids`); `io.modelcontextprotocol/*` is reserved. Never put secrets in any tool result. - **Transport** — `stdio` for local; Streamable HTTP for remote (see [[concepts/transports]], [[concepts/connecting-to-servers]]). ## When To Use Build a server to expose your data, APIs, or actions to any MCP host (Claude Desktop, IDEs, agents). Use FastMCP / high-level SDK classes for nearly everything. Drop to the low-level `Server` only for exact-schema control, custom methods, or full result construction. ## Risks & Pitfalls - **STDIO logging** — never write to stdout: `print()`, `console.log()`, `System.out.println()`, `println()`, `puts`, `Console.WriteLine()` all corrupt the JSON-RPC stream and break the server. Log to **stderr** (`print(..., file=sys.stderr)`, `console.error()`) or a file. HTTP servers may log to stdout freely. - For TypeScript, forgetting `npm run build` prevents the server from connecting. - Low-level `Server` validates nothing — a missing arg raises `KeyError`, surfacing to the client as a generic `-32603` the model can't learn from. - In C#, use `CreateEmptyApplicationBuilder` (not `CreateDefaultBuilder`) for STDIO to avoid extra console output. ## Related Concepts - [[concepts/tools]] · [[concepts/resources]] · [[concepts/prompts]] — the three server primitives - [[concepts/building-a-client]] — the other half of the connection - [[concepts/connecting-to-servers]] — wiring a host to your server - [[concepts/transports]] · [[concepts/debugging]] · [[entities/python-sdk]] · [[entities/typescript-sdk]] - [[syntheses/server-feature-picker]] — choosing tools vs resources vs prompts ## Sources - `raw/llms_txt_doc-build-an-mcp-server.md` — multi-language quickstart with verbatim scaffolding - `raw/llms_txt_doc-understanding-mcp-servers.md` — the three capability types and protocol operations - `raw/github_doc-docs-advanced-low-level-server-md.md` — the low-level `Server` class --- title: "Connecting to Servers" type: concept tags: [client, host, transports, how-to, config, foundational] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-connect-to-local-mcp-servers.md", "raw/llms_txt_doc-connect-to-remote-mcp-servers.md"] confidence: high --- # Connecting to Servers ## Definition Connecting a host to an MCP server means telling the host application how to reach a server and, if needed, authenticate to it. There are two shapes: **local servers** run as a child process on your machine and communicate over the **stdio** transport (configured via a JSON config file with a launch command); **remote servers** are internet-hosted, reached over **HTTP** by URL, and usually require authentication. This page gives the verbatim configuration for both, using Claude Desktop as the example host (the concepts apply to any MCP client). ## How It Works ### Local (stdio) — Claude Desktop config file Claude Desktop starts configured local servers automatically at launch. Open **Settings → Developer → Edit Config**, which opens/creates the config file: - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` Servers go under the `mcpServers` key. Example installing the Filesystem Server with access to two directories: ```json { "mcpServers": { "filesystem": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-filesystem", "/Users/username/Desktop", "/Users/username/Downloads" ] } } } ``` On Windows use double-backslash paths (`C:\\Users\\username\\Desktop`). The config fields: `"command"` is the executable (`npx` runs a Node package), `"-y"` auto-confirms package install, the package name is the server, and the remaining args are the directories the server may access. After saving, **fully quit and restart** Claude Desktop; the UI only shows MCP elements once at least one server is configured. Verify via the "Add files, connectors, and more" indicator → **Connectors** → **Manage connectors**. Servers that need secrets or extra environment take an `env` key: ```json { "brave-search": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-brave-search"], "env": { "APPDATA": "C:\\Users\\user\\AppData\\Roaming\\", "BRAVE_API_KEY": "..." } } } ``` To validate a server independently, run its command directly in a terminal, e.g.: ```bash npx -y @modelcontextprotocol/server-filesystem /Users/username/Desktop /Users/username/Downloads ``` ### Remote (HTTP) — Custom Connectors Remote servers expose the same tools/prompts/resources but are reached by URL. In Claude, **Custom Connectors** are the bridge. Steps: 1. **Settings → Connectors** (Desktop: `Ctrl+Comma`; Browser: profile → Settings). 2. Click **Add → Add custom connector**, enter the remote server URL (must include `https://` and any path), e.g.: ```text https://example-server.modelcontextprotocol.io/mcp ``` Click **Add**. 3. **Complete authentication** — most remote servers require it (commonly OAuth, sometimes API keys or username/password). Follow the prompts; you may be redirected to a third-party provider. See [[concepts/authorization]] for the OAuth flow. 4. **Access resources and prompts** via the "Add files, connectors, and more" indicator → Connectors. 5. **Configure tool permissions** — in the connector's settings, enable/disable specific tools and set usage limits so Claude only performs authorized actions. ## Key Parameters - **`command` / `args` / `env`** — the three fields of a local `mcpServers` entry. `command` should be an absolute path if the executable isn't reliably on PATH. - **Transport selection** — stdio for local child processes, Streamable HTTP for remote (see [[concepts/transports]]). - **Directory allowlist** — for filesystem-style servers, the accessible directories are passed as trailing args; the server runs with your user's permissions. - **Remote URL** — the full MCP endpoint, provided by the server developer/administrator. ## When To Use Use **local (stdio)** servers for direct system access (file operations, local tools) and when you control the machine — no hosting or network exposure needed, but each device must be configured separately. Use **remote (HTTP)** servers for cloud-based tools, server-side processing, shared team services, and web-based hosts — available from any client with internet access, no per-device install. See [[syntheses/local-vs-remote-servers]] for the full trade-off. ## Risks & Pitfalls - **Local security** — only grant access to directories you're comfortable exposing; the server runs with your account's full permissions. - **Config gotchas** — invalid JSON syntax, relative paths (use absolute), and missing global npm install (`%APPDATA%\npm` must exist; `npm install -g npm`) all cause a server to fail to load. An `ENOENT` / `${APPDATA}` error on Windows means adding `APPDATA` to the server's `env`. - **Restart required** — configuration changes only take effect after a full restart of the host; closing the window is not enough. - **Remote trust** — verify a remote server's authenticity before connecting; only connect to trusted sources, review requested permissions, and remove unused connectors. - If a server doesn't appear: restart the host, check config syntax and absolute paths, and inspect the logs (see [[concepts/debugging]]). ## Related Concepts - [[concepts/transports]] — stdio vs Streamable HTTP mechanics - [[concepts/building-a-server]] · [[concepts/building-a-client]] - [[concepts/authorization]] — authenticating to remote servers - [[concepts/debugging]] — diagnosing connection failures - [[syntheses/local-vs-remote-servers]] · [[syntheses/transport-decision]] ## Sources - `raw/llms_txt_doc-connect-to-local-mcp-servers.md` — Claude Desktop config, filesystem server, troubleshooting - `raw/llms_txt_doc-connect-to-remote-mcp-servers.md` — Custom Connectors flow for remote servers --- title: "Debugging" type: concept tags: [debugging, tooling, inspector, logging, how-to] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-debugging.md", "raw/llms_txt_doc-mcp-inspector.md"] confidence: high --- # Debugging ## Definition Debugging MCP integrations means diagnosing failures across three layers: the **MCP Inspector** (an interactive, transport-agnostic testing UI — the recommended first stop), **server logging** (structured logs to stderr for stdio, or `notifications/message` for all transports), and **client developer tools** (host logs and connection state). This page is an operational how-to for the tools, common errors, and the debugging workflow. ## How It Works ### MCP Inspector The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) runs directly through `npx` with no install: ```bash npx @modelcontextprotocol/inspector ``` Inspect a published server package: ```bash # npm package npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem /Users/username/Desktop # PyPI package npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/mcp/servers.git ``` Inspect a locally developed server: ```bash # TypeScript npx @modelcontextprotocol/inspector node path/to/server/index.js args... # Python npx @modelcontextprotocol/inspector \ uv \ --directory path/to/server \ run \ package-name \ args... ``` The UI offers: a **Server connection pane** (select transport, customize args/env), **Resources tab** (list, metadata, content, subscription testing), **Prompts tab** (arguments, test with custom args, preview messages), **Tools tab** (schemas, test with custom inputs, results), and a **Notifications pane** (server logs and notifications). ### Server-side logging For the **stdio transport**, everything written to **stderr** is captured automatically by the host — never write to **stdout**, which corrupts protocol operation. For **Streamable HTTP**, stderr is *not* captured; use log-message notifications, your own aggregation, or HTTP tooling (curl, DevTools Network panel) to inspect requests, `Mcp-Session-Id` headers, and SSE streams. For all transports, send a log notification to the client: ```python @server.tool() async def my_tool(ctx: Context) -> str: await ctx.session.send_log_message(level="info", data="Server started successfully") return "done" ``` ```typescript await server.sendLoggingMessage({ level: "info", data: "Server started successfully" }); ``` MCP defines eight RFC 5424 severity levels (`debug` through `emergency`); clients set the minimum via `logging/setLevel`. Log initialization steps, resource access, tool execution, error conditions, and performance metrics. ### Debugging in Claude Desktop Check server status via the "Add files, connectors, and more" plus icon → **Connectors**. Log files: - **macOS**: `~/Library/Logs/Claude` - **Windows**: `%APPDATA%\Claude\logs` `mcp.log` holds general connection logging; `mcp-server-SERVERNAME.log` holds a server's stderr. Tail them: ```bash # macOS tail -n 20 -F ~/Library/Logs/Claude/mcp*.log ``` ```powershell # Windows type "$env:AppData\Claude\logs\mcp*.log" ``` Enable **Chrome DevTools** inside Claude Desktop by creating `developer_settings.json` with `{"allowDevTools": true}`, then `Command-Option-I` (macOS) / `Ctrl+Alt+I` (Windows); use the Console panel for client-side errors and the Network panel for message payloads and timing. ## Key Parameters - **Working directory** — a stdio server's working directory may be undefined (e.g. `/` on macOS) because the host can launch from anywhere. Always use **absolute paths** in config and `.env`, not relative (`./data`). - **Environment variables** — stdio servers inherit only a limited, platform-dependent subset. Provide your own via the `env` key in `claude_desktop_config.json`: ```json { "mcpServers": { "myserver": { "command": "mcp-server-myapp", "env": { "MYAPP_API_KEY": "some_key" } } } } ``` - **Error `-32602`** — the JSON-RPC "Invalid params" code; a common cause is a server sending sampling/elicitation requests to a client that never declared that capability. Inspect the `initialize` exchange to verify both sides declared what you expect. ## When To Use Reach for the **Inspector first** during initial development and quick iteration — verify connectivity, capability negotiation, and individual tools/prompts/resources before wiring into a real host. Move to **integration testing** (host logs, error handling) once basics work. Use host DevTools/logs when a server connects to the Inspector but misbehaves inside the client. ## Risks & Pitfalls - **stdout logging** on a stdio server corrupts JSON-RPC and breaks the server — the single most common failure. Log to stderr or files. - **Restart to apply changes** — config changes need a client restart; server code changes need a full quit-and-reopen of Claude Desktop (closing the window is not enough). - **Connection failures** — check client logs, verify the server process is running, test standalone with the Inspector, verify protocol/version compatibility and capability negotiation. - **Security while debugging** — sanitize logs, protect credentials, mask personal information; never log tokens or `Authorization` headers (see [[concepts/security-best-practices]]). ## Related Concepts - [[entities/mcp-inspector]] — the Inspector tool entity - [[concepts/connecting-to-servers]] — config-file reference and connection troubleshooting - [[concepts/building-a-server]] · [[concepts/building-a-client]] - [[concepts/transports]] · [[concepts/lifecycle]] · [[concepts/protocol-utilities]] — logging, capability negotiation - [[concepts/security-best-practices]] — safe logging ## Sources - `raw/llms_txt_doc-debugging.md` — debugging tools, logging, common issues, workflow - `raw/llms_txt_doc-mcp-inspector.md` — Inspector install, invocation, and feature reference --- title: "Elicitation" type: concept tags: [client-feature, elicitation, forms, url-mode, user-input, oauth] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-elicitation.md"] confidence: high --- ## Definition Elicitation is the MCP flow by which a **server** requests additional information from the user, through the client, *mid-operation*. It lets user-input requests occur *nested* inside other server features while the client stays in control of the interaction and data sharing. Elicitation is a **client-provided** capability (like [[concepts/sampling]] and [[concepts/roots]]) and supports **two modes**: **form mode** (structured, in-band data collection with an optional JSON schema) and **URL mode** (out-of-band navigation to an external URL for sensitive interactions that must *not* pass through the MCP client). URL mode is a new feature in the `2025-11-25` spec version. ## How It Works A client that supports elicitation **MUST** declare the `elicitation` capability during [[concepts/lifecycle|initialization]], listing the modes it supports: ```json { "capabilities": { "elicitation": { "form": {}, "url": {} } } } ``` An empty `"elicitation": {}` is equivalent to `{ "form": {} }` (form mode only). Clients declaring the capability **MUST** support at least one mode, and servers **MUST NOT** send requests using an unsupported mode. Servers send an **`elicitation/create`** request. Every request includes `mode` (`"form"` or `"url"`; optional for form, defaulting to `"form"`) and a human-readable `message`. **Form mode** adds `requestedSchema` — a JSON Schema (restricted to *flat objects with primitive properties only*: string, number/integer, boolean, and single/multi-select enums via `enum`/`oneOf`/`anyOf`). Example: ```json { "jsonrpc": "2.0", "id": 1, "method": "elicitation/create", "params": { "mode": "form", "message": "Please provide your GitHub username", "requestedSchema": { "type": "object", "properties": { "name": { "type": "string" } }, "required": ["name"] } } } ``` ```json { "jsonrpc": "2.0", "id": 1, "result": { "action": "accept", "content": { "name": "octocat" } } } ``` **URL mode** adds `url` (the URL to navigate to) and `elicitationId` (a unique identifier). It directs the user out-of-band for auth flows, payment, or providing secrets. Data other than the URL is **not** exposed to the client; a URL-mode `accept` response omits `content` and means only that the user consented, not that the interaction completed. Servers **MAY** later send `notifications/elicitation/complete` (echoing the `elicitationId`) to signal completion. ## Key Parameters - **Method:** `elicitation/create`. **Notification:** `notifications/elicitation/complete`. - **Common params:** `mode` (`"form"` | `"url"`), `message`. - **Form params:** `requestedSchema` (flat object; primitive types; string formats `email`, `uri`, `date`, `date-time`; all types support `default`). - **URL params:** `url`, `elicitationId`. - **Response actions** (three-action model, both modes): - `accept` — user approved/submitted. Form: `content` holds data matching the schema. URL: `content` omitted. - `decline` — user explicitly declined (`content` omitted). - `cancel` — user dismissed without choosing (closed dialog, Escape, load failure). - **`URLElicitationRequiredError`** (code `-32042`) — a server **MAY** return this when a request (e.g. `tools/call`) can't proceed until a URL-mode elicitation completes; `data.elicitations` lists required URL-mode elicitations (each with an `elicitationId`). Servers **MUST NOT** return it except when URL mode is required. - **Client error:** a request with a mode not declared in client capabilities → `-32602` (Invalid params). ## When To Use Use elicitation when a server discovers **mid-operation that it needs input from the human** — a missing username, a configuration choice, a confirmation. Use **form mode** for ordinary structured data (contact info, options, preferences). Use **URL mode** for anything sensitive or third-party: collecting an API key, running a payment flow, or performing a **third-party OAuth** flow where the server acts as an OAuth client to another service. Note URL mode is *not* for authorizing the MCP client to the MCP server — that is [[concepts/authorization|MCP authorization]]. For LLM calls instead of user input, use [[concepts/sampling]]. ## Risks & Pitfalls - **Never request secrets via form mode:** servers **MUST NOT** use form mode for passwords, API keys, access tokens, or payment credentials — those **MUST** use URL mode. (Ordinary contact/profile fields are permitted, subject to user review.) - **No token passthrough:** the MCP server **MUST NOT** transmit URL-mode-obtained third-party credentials to the client, and **MUST NOT** use the client's credentials for the third party (forbidden [[concepts/security-best-practices|token passthrough]]). - **Phishing / identity binding:** the server **MUST** verify that the user who *opened* the URL is the same user the elicitation was generated for (e.g. via a `sub`-claim session-cookie check on a `/connect` URL) to prevent account-takeover attacks. Servers **MUST** bind elicitation state to a verified user identity — never to a session ID alone, and never trust client-provided identity. - **Safe URL handling:** clients **MUST NOT** pre-fetch the URL or open it without explicit consent, **MUST** show the full URL, and **MUST** open it so neither client nor LLM can inspect its content (e.g. `SFSafariViewController`, not `WkWebView`). Servers **MUST NOT** put sensitive data or pre-authenticated access in the URL and **SHOULD** use HTTPS. - **Statefulness:** most real uses require the server to securely persist per-user state. ## Related Concepts - [[concepts/sampling]] — server-initiated LLM calls (vs. user input) - [[concepts/roots]] — another client-provided capability - [[concepts/authorization]] — MCP client↔server auth, distinct from URL-mode third-party auth - [[concepts/security-best-practices]] — token passthrough, phishing, safe URL handling - [[concepts/tools]] — a `tools/call` can trigger a `URLElicitationRequiredError` - [[concepts/lifecycle]] — capability negotiation at initialization ## Sources - `raw/llms_txt_doc-elicitation.md` — MCP specification 2025-11-25, Client / Elicitation --- title: "MCP Lifecycle" type: concept tags: [protocol, lifecycle, initialization, capabilities, versioning, well-established] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-lifecycle.md"] confidence: high --- # MCP Lifecycle ## Definition The **lifecycle** is the rigorous, ordered sequence MCP defines for every client-server connection to ensure proper capability negotiation and state management. It has three phases: **Initialization** (capability negotiation and protocol version agreement), **Operation** (normal protocol communication), and **Shutdown** (graceful termination). Because MCP is a stateful protocol, this lifecycle is mandatory — its purpose is to negotiate the capabilities that both client and server support before any real work happens. ## How It Works ### Initialization The initialization phase **MUST** be the first interaction between client and server. The client **MUST** initiate it by sending an `initialize` request containing the protocol version it supports, its capabilities, and its implementation info (`clientInfo`). Example request: ```json { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-11-25", "capabilities": { "roots": { "listChanged": true }, "sampling": {}, "elicitation": { "form": {}, "url": {} }, "tasks": { "requests": { "elicitation": { "create": {} }, "sampling": { "createMessage": {} } } } }, "clientInfo": { "name": "ExampleClient", "title": "Example Client Display Name", "version": "1.0.0", "description": "An example MCP client application" } } } ``` The server **MUST** respond with its own `protocolVersion`, `capabilities`, and `serverInfo`, and **MAY** include an optional top-level `instructions` string. Example server capabilities include `logging`, `prompts` (`listChanged`), `resources` (`subscribe`, `listChanged`), `tools` (`listChanged`), and `tasks`. After a successful `initialize`, the client **MUST** send an `initialized` notification to signal it is ready: ```json { "jsonrpc": "2.0", "method": "notifications/initialized" } ``` Before the server has responded to `initialize`, the client **SHOULD NOT** send requests other than [pings](/specification/2025-11-25/basic/utilities/ping). Before receiving the `initialized` notification, the server **SHOULD NOT** send requests other than pings and logging. ### Operation During operation the client and server exchange messages according to the negotiated capabilities. Both parties **MUST** respect the negotiated protocol version and **MUST** only use capabilities that were successfully negotiated. ### Shutdown In shutdown, one side (usually the client) cleanly terminates the connection. **No specific shutdown messages are defined** — the underlying transport signals termination: - **stdio:** the client **SHOULD** shut down by (1) closing the input stream to the child process (server), (2) waiting for the server to exit or sending `SIGTERM` if it does not exit in a reasonable time, then (3) sending `SIGKILL` if it still does not exit. The server **MAY** initiate shutdown by closing its output stream and exiting. - **HTTP:** shutdown is indicated by closing the associated HTTP connection(s). ## Key Parameters ### Version negotiation In the `initialize` request the client **MUST** send a protocol version it supports, which **SHOULD** be the *latest* it supports. If the server supports that version it **MUST** respond with the same version; otherwise it **MUST** respond with another version it supports (**SHOULD** be its latest). If the client does not support the version in the server's response, it **SHOULD** disconnect. If using HTTP, the client **MUST** thereafter send the `MCP-Protocol-Version` header on all requests (see [[concepts/transports]]). See [[concepts/versioning]] for the version scheme. ### Capability negotiation Client and server capabilities establish which optional features are available for the session. Key capabilities: | Category | Capability | Description | | --- | --- | --- | | Client | `roots` | Ability to provide filesystem [[concepts/roots]] | | Client | `sampling` | Support for LLM [[concepts/sampling]] requests | | Client | `elicitation` | Support for server [[concepts/elicitation]] requests | | Client | `tasks` | Support for task-augmented client requests | | Client | `experimental` | Non-standard experimental features | | Server | `prompts` | Offers [[concepts/prompts]] templates | | Server | `resources` | Provides readable [[concepts/resources]] | | Server | `tools` | Exposes callable [[concepts/tools]] | | Server | `logging` | Emits structured log messages | | Server | `completions` | Supports argument autocompletion | | Server | `tasks` | Support for task-augmented server requests | | Server | `experimental` | Non-standard experimental features | Capability objects can describe sub-capabilities: **`listChanged`** (support for list-change notifications, for prompts, resources, and tools) and **`subscribe`** (support for subscribing to individual items' changes — resources only). ### Timeouts Implementations **SHOULD** set timeouts for all sent requests to prevent hung connections. On timeout the sender **SHOULD** issue a [cancellation notification](/specification/2025-11-25/basic/utilities/cancellation) (see [[concepts/protocol-utilities]]) and stop waiting. SDKs **SHOULD** allow per-request timeout configuration. Implementations **MAY** reset the timeout clock when a matching [progress notification](/specification/2025-11-25/basic/utilities/progress) arrives, but **SHOULD** always enforce a maximum timeout regardless. ## When To Use Every MCP connection goes through this lifecycle — there is no "skip init." Implement the `initialize` → `initialized` handshake first when building a server (see [[concepts/building-a-server]]) or client (see [[concepts/building-a-client]]). Reference it whenever debugging why a capability is unavailable: if it was not declared during init, it cannot be used. ## Risks & Pitfalls - **Protocol version mismatch.** If a mutually compatible version is not negotiated, the connection should be terminated. Example error uses code `-32602` with message `"Unsupported protocol version"` and a `data` object listing `supported` versions and the `requested` value. - **Using un-negotiated capabilities.** Both parties must only use successfully negotiated capabilities; sending, say, a resource subscription when `subscribe` was not declared is a violation. - **Sending premature requests.** Do not send non-ping requests before `initialize` completes, or non-ping/non-logging server requests before the `initialized` notification. - **Ignoring timeouts.** Missing timeouts risk hung connections and resource exhaustion; progress notifications may extend but must not remove the maximum timeout. - **`initialize` cannot be cancelled** by clients (see [[concepts/protocol-utilities]]). ## Related Concepts - [[concepts/architecture]] - [[concepts/versioning]] - [[concepts/transports]] - [[concepts/protocol-utilities]] - [[concepts/roots]], [[concepts/sampling]], [[concepts/elicitation]] - [[concepts/resources]], [[concepts/tools]], [[concepts/prompts]] - [[concepts/building-a-server]], [[concepts/building-a-client]] ## Sources - `raw/llms_txt_doc-lifecycle.md` --- title: "Prompts" type: concept tags: [server-feature, prompts, templates, user-controlled, slash-commands] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-prompts.md"] confidence: high --- ## Definition Prompts are reusable, parameterized message templates an MCP **server** exposes to clients — structured messages and instructions for interacting with a language model. Clients can discover available prompts, retrieve their contents, and supply arguments to customize them. Prompts are **user-controlled**: they are surfaced so the user can explicitly select them, typically through user-initiated commands such as **slash commands** in the UI. Prompts are one of the three server features, alongside read-only [[concepts/resources]] and model-invoked [[concepts/tools]]. ## How It Works A server that supports prompts **MUST** declare the `prompts` capability during [[concepts/lifecycle|initialization]]; `listChanged` indicates whether it emits notifications when the prompt list changes: ```json { "capabilities": { "prompts": { "listChanged": true } } } ``` Two methods drive prompts: - **`prompts/list`** — client retrieves available prompts. Supports [[concepts/protocol-utilities|pagination]] (`cursor` / `nextCursor`). Each prompt returns `name`, optional `title`, `description`, `icons`, and an optional `arguments` list (each argument has `name`, `description`, `required`). - **`prompts/get`** — client retrieves a specific prompt by `name`, passing an `arguments` object. Arguments may be auto-completed through the completion API. Example `prompts/get` request/response: ```json { "jsonrpc": "2.0", "id": 2, "method": "prompts/get", "params": { "name": "code_review", "arguments": { "code": "def hello():\n print('world')" } } } ``` ```json { "jsonrpc": "2.0", "id": 2, "result": { "description": "Code review prompt", "messages": [ { "role": "user", "content": { "type": "text", "text": "Please review this Python code:\ndef hello():\n print('world')" } } ] } } ``` The result is a `description` plus a `messages` array. Each **PromptMessage** has a `role` (`"user"` or `"assistant"`) and a `content` object. When the prompt list changes, servers that declared `listChanged` **SHOULD** send `notifications/prompts/list_changed`. ## Key Parameters - **Methods:** `prompts/list`, `prompts/get`. **Notification:** `notifications/prompts/list_changed`. - **Prompt definition fields:** `name` (unique id), `title`, `description`, `icons`, `arguments`. - **Argument fields:** `name`, `description`, `required` (boolean). - **PromptMessage fields:** `role` (`"user"` | `"assistant"`), `content`. - **Content types** (each supports optional annotations for audience/priority/modification time): - **Text** — `{ "type": "text", "text": "..." }` (most common). - **Image** — `{ "type": "image", "data": "", "mimeType": "image/png" }`; data **MUST** be base64-encoded with a valid MIME type. - **Audio** — `{ "type": "audio", "data": "", "mimeType": "audio/wav" }`. - **Embedded resource** — `{ "type": "resource", "resource": { "uri": "...", "mimeType": "...", "text": "..." } }`; must include a valid URI, appropriate MIME type, and either `text` or base64 `blob` data. This lets prompts pull in server-managed [[concepts/resources]] like docs or code samples. ## When To Use Use prompts when you want to offer the **user** a curated, named way to start or shape an interaction — a "/review this code", "/summarize", or "/plan a migration" command. Because they are user-controlled, prompts are ideal for workflows a person deliberately triggers, as opposed to [[concepts/tools]] (which the model invokes) or [[concepts/resources]] (read-only context the app injects). Embed resources in a prompt's messages to bundle reference material with the instruction. See [[syntheses/server-feature-picker]] for choosing among the three. ## Risks & Pitfalls - **Validate arguments:** servers **SHOULD** validate prompt arguments before processing; missing required arguments or an invalid prompt name return `-32602` (Invalid params). Internal errors return `-32603`. - **Handle pagination:** clients **SHOULD** handle pagination for large prompt lists. - **Respect capability negotiation:** both parties **SHOULD** honor negotiated capabilities. - **Injection risk:** implementations **MUST** carefully validate all prompt inputs and outputs to prevent injection attacks or unauthorized access to resources embedded in messages. ## Related Concepts - [[concepts/tools]] — model-controlled actions - [[concepts/resources]] — read-only context; can be embedded in prompt messages - [[concepts/protocol-utilities]] — pagination and completion used by prompts - [[concepts/lifecycle]] — capability negotiation at initialization - [[syntheses/server-feature-picker]] — prompts vs. tools vs. resources ## Sources - `raw/llms_txt_doc-prompts.md` — MCP specification 2025-11-25, Server / Prompts --- title: "Protocol Utilities" type: concept tags: [protocol, utilities, ping, cancellation, progress, pagination, completion, logging, well-established] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-ping.md", "raw/llms_txt_doc-cancellation.md", "raw/llms_txt_doc-progress.md", "raw/llms_txt_doc-pagination.md", "raw/llms_txt_doc-completion.md", "raw/llms_txt_doc-logging.md"] confidence: high --- # Protocol Utilities ## Definition MCP defines a set of small, cross-cutting **utility features** that augment how requests are executed rather than exposing domain content. This page collects six of them — **ping**, **cancellation**, **progress**, **pagination**, **completion**, and **logging**. Each is optional and layered on top of the base JSON-RPC protocol (see [[concepts/architecture]]). They handle connection health, request lifecycle, large result sets, argument autocompletion, and structured diagnostics. ## How It Works ### Ping An optional mechanism letting either party verify the counterpart is responsive and the connection is alive. Either side sends a `ping` request (a standard JSON-RPC request with no parameters), and the receiver **MUST** respond promptly with an empty result: ```json { "jsonrpc": "2.0", "id": "123", "method": "ping" } ``` Response: `{ "jsonrpc": "2.0", "id": "123", "result": {} }`. If no response arrives within a reasonable timeout, the sender **MAY** consider the connection stale, terminate it, or attempt reconnection. ### Cancellation Optional termination of an in-progress request via a `notifications/cancelled` notification carrying the ID of the request to cancel and an optional `reason` string: ```json { "jsonrpc": "2.0", "method": "notifications/cancelled", "params": { "requestId": "123", "reason": "User requested cancellation" } } ``` A cancellation **MUST** only reference requests issued in the same direction and believed still in-progress. The `initialize` request **MUST NOT** be cancelled by clients. For task-augmented requests, `tasks/cancel` **MUST** be used instead (tasks have their own cancellation returning the final task state). Receivers **SHOULD** stop processing, free resources, and not send a response; they **MAY** ignore cancellations for unknown/completed/uncancellable requests. Because of network latency a cancellation may arrive after completion — both sides **MUST** handle this race gracefully, and the sender **SHOULD** ignore any late response. ### Progress Optional progress tracking for long-running operations. To *receive* updates, a party includes a `progressToken` in the request's `_meta`; the token **MUST** be a string or integer and **MUST** be unique across all active requests. ```json { "jsonrpc": "2.0", "id": 1, "method": "some_method", "params": { "_meta": { "progressToken": "abc123" } } } ``` The receiver **MAY** then send `notifications/progress` notifications carrying the `progressToken`, a `progress` value, an optional `total`, and an optional `message`: ```json { "jsonrpc": "2.0", "method": "notifications/progress", "params": { "progressToken": "abc123", "progress": 50, "total": 100, "message": "Reticulating splines..." } } ``` The `progress` value **MUST** increase with each notification even if `total` is unknown; `progress` and `total` **MAY** be floating point. Notifications **MUST** only reference active tokens and **MUST** stop after completion. For tasks, the original `progressToken` **MUST** keep being used until the task reaches a terminal status (`completed`, `failed`, or `cancelled`). ### Pagination Lets servers return large list results in smaller chunks using an **opaque cursor-based** approach (not numbered pages). The **cursor** is an opaque string token; **page size is determined by the server** and clients **MUST NOT** assume a fixed size. A response includes the current page plus an optional `nextCursor` if more results exist: ```json { "jsonrpc": "2.0", "id": "123", "result": { "resources": [], "nextCursor": "eyJwYWdlIjogM30=" } } ``` To continue, the client reissues the list request with `params.cursor` set to that value. Operations supporting pagination: **`resources/list`**, **`resources/templates/list`**, **`prompts/list`**, and **`tools/list`**. Clients **MUST** treat cursors as opaque — don't parse, modify, or persist them across sessions — and **SHOULD** treat a missing `nextCursor` as the end. Invalid cursors **SHOULD** result in error code `-32602` (Invalid params). ### Completion A standardized way for servers to offer autocompletion for the arguments of prompts and resource templates. Servers that support it **MUST** declare the `completions` capability (`{ "capabilities": { "completions": {} } }`). Clients send a `completion/complete` request specifying what is being completed through a reference type: ```json { "jsonrpc": "2.0", "id": 1, "method": "completion/complete", "params": { "ref": { "type": "ref/prompt", "name": "code_review" }, "argument": { "name": "language", "value": "py" } } } ``` The response returns `completion.values` (array of suggestions, **max 100 items**), an optional `total`, and a `hasMore` boolean. Two reference types exist: **`ref/prompt`** (references a prompt by name) and **`ref/resource`** (references a resource URI, e.g. `{"type": "ref/resource", "uri": "file:///{path}"}`). For multi-argument prompts/templates, clients include prior completions in the `context.arguments` object. Error cases use standard JSON-RPC codes: `-32601` (method/capability not supported), `-32602` (invalid params, e.g. bad prompt name or missing args), `-32603` (internal error). ### Logging A standardized way for servers to send structured log messages to clients. Servers that emit them **MUST** declare the `logging` capability (`{ "capabilities": { "logging": {} } }`). Log levels follow the **RFC 5424** syslog severities: `debug`, `info`, `notice`, `warning`, `error`, `critical`, `alert`, `emergency`. Clients **MAY** set the minimum level with a `logging/setLevel` request (`params.level`); servers then send `notifications/message` notifications carrying `level`, an optional `logger` name, and arbitrary JSON-serializable `data`: ```json { "jsonrpc": "2.0", "method": "notifications/message", "params": { "level": "error", "logger": "database", "data": { "error": "Connection failed", "details": { "host": "localhost", "port": 5432 } } } } ``` After a level change the server only sends messages at that level and above. Invalid log level errors use `-32602`; configuration errors use `-32603`. ## Key Parameters - **Methods:** `ping`, `completion/complete`, `logging/setLevel`. - **Notifications:** `notifications/cancelled`, `notifications/progress`, `notifications/message`. - **Capabilities to declare:** `completions`, `logging`. Ping, cancellation, progress, and pagination require no dedicated capability. - **Key fields:** `requestId` + `reason` (cancellation); `progressToken`, `progress`, `total`, `message` (progress); `cursor` / `nextCursor` (pagination); `ref` (`ref/prompt`/`ref/resource`), `argument`, `context.arguments`, `values`/`total`/`hasMore` (completion); `level`, `logger`, `data` (logging). - **Limits:** completion returns max 100 values; progress must be monotonically increasing. ## When To Use - **Ping** — periodically, to detect connection health; frequency **SHOULD** be configurable and excessive pinging avoided. - **Cancellation** — when a user or timeout aborts an in-flight request (see [[concepts/lifecycle]] timeouts). - **Progress** — for long-running operations so the UI can show status; both sides **SHOULD** rate-limit to prevent flooding. - **Pagination** — for any list operation that may return large result sets, especially over the internet. - **Completion** — to power IDE-style argument autocompletion for [[concepts/prompts]] and resource templates (see [[concepts/resources]]). - **Logging** — to surface structured server diagnostics to the client for debugging and monitoring (see [[concepts/debugging]]). ## Risks & Pitfalls - **Log leakage.** Log messages **MUST NOT** contain credentials/secrets, personal identifying information, or internal system details that could aid attacks; servers **SHOULD** rate-limit, validate `data` fields, and control log access (see [[concepts/security-best-practices]]). - **Cancellation races.** A cancellation may arrive after the response was already sent; ignore late responses and never rely on a response *not* arriving. - **Cancelling `initialize`.** Clients must not cancel the `initialize` request; use `tasks/cancel` for task-augmented requests. - **Treating cursors as structured.** Parsing, modifying, or persisting cursors across sessions is forbidden; page size is server-controlled, so never assume it. - **Non-increasing progress.** `progress` must always increase, and notifications must stop after completion, or clients may hang. - **Completion input abuse.** Implementations **MUST** validate all completion inputs, rate-limit, control access to sensitive suggestions, and prevent completion-based information disclosure. ## Related Concepts - [[concepts/architecture]] - [[concepts/lifecycle]] - [[concepts/transports]] - [[concepts/resources]], [[concepts/tools]], [[concepts/prompts]] - [[concepts/debugging]] - [[concepts/security-best-practices]] ## Sources - `raw/llms_txt_doc-ping.md` - `raw/llms_txt_doc-cancellation.md` - `raw/llms_txt_doc-progress.md` - `raw/llms_txt_doc-pagination.md` - `raw/llms_txt_doc-completion.md` - `raw/llms_txt_doc-logging.md` --- title: "Resources" type: concept tags: [server-feature, resources, context, uri, subscriptions] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-resources.md"] confidence: high --- ## Definition Resources are a standardized way for an MCP **server** to expose data that provides context to language models — files, database schemas, or application-specific information. Each resource is uniquely identified by a [URI](https://datatracker.ietf.org/doc/html/rfc3986). Resources are **application-driven**: the host application decides how to incorporate the context (an explicit picker, search/filter, or automatic inclusion). The protocol mandates no specific interaction model. Resources are one of the three server-provided features alongside [[concepts/tools]] and [[concepts/prompts]]. ## How It Works A server that supports resources **MUST** declare the `resources` capability during [[concepts/lifecycle|initialization]], optionally with two feature flags: ```json { "capabilities": { "resources": { "subscribe": true, "listChanged": true } } } ``` - `subscribe`: whether the client can subscribe to be notified of changes to individual resources. - `listChanged`: whether the server emits notifications when the list of available resources changes. Both are optional — a server can support neither (`"resources": {}`), either, or both. The core protocol messages are: - **`resources/list`** — client discovers available resources. Supports [[concepts/protocol-utilities|pagination]] via a `cursor` param and `nextCursor` in the result. Each returned resource carries `uri`, `name`, optional `title`, `description`, `mimeType`, `icons`, and `size`. - **`resources/read`** — client retrieves contents by `uri`. The response `result.contents` is an array where each entry has `uri`, `mimeType`, and either `text` (text content) or `blob` (base64-encoded binary). - **`resources/templates/list`** — client discovers *parameterized* resources (resource templates). - **`resources/subscribe`** — client subscribes to a specific `uri` for change notifications. Example `resources/read` request/response: ```json { "jsonrpc": "2.0", "id": 2, "method": "resources/read", "params": { "uri": "file:///project/src/main.rs" } } ``` ```json { "jsonrpc": "2.0", "id": 2, "result": { "contents": [ { "uri": "file:///project/src/main.rs", "mimeType": "text/x-rust", "text": "fn main() {\n println!(\"Hello world!\");\n}" } ] } } ``` **Resource templates** expose parameterized resources using [URI templates (RFC 6570)](https://datatracker.ietf.org/doc/html/rfc6570), e.g. `"uriTemplate": "file:///{path}"`. Arguments can be auto-completed through the completion API. **Subscriptions & notifications** — when a subscribed resource changes, the server sends `notifications/resources/updated` with the affected `uri`; the client then re-reads. When the resource list changes, servers that declared `listChanged` **SHOULD** send `notifications/resources/list_changed`. ## Key Parameters - **Capability flags:** `subscribe`, `listChanged`. - **Methods:** `resources/list`, `resources/read`, `resources/templates/list`, `resources/subscribe`. - **Notifications:** `notifications/resources/updated`, `notifications/resources/list_changed`. - **Resource fields:** `uri` (required), `name` (required), `title`, `description`, `icons`, `mimeType`, `size`. - **Contents fields:** `uri`, `mimeType`, `text` OR `blob` (base64). - **Annotations** (hints for clients): `audience` (array of `"user"` / `"assistant"`), `priority` (0.0–1.0, where 1 is effectively required), `lastModified` (ISO 8601 timestamp, e.g. `"2025-01-12T15:00:58Z"`). - **Standard URI schemes:** `https://` (client can fetch directly), `file://` (filesystem-like; may use XDG MIME types such as `inode/directory`), `git://`, plus custom schemes (must comply with RFC 3986). ## When To Use Use resources when the server needs to **provide read-only context** to the model or user rather than perform an action: - Exposing files, documents, or logs the model should be able to read. - Sharing database schemas or configuration the model needs to reason about. - Publishing frequently-changing data (with `subscribe`) so clients stay current. - Offering a browsable/parameterized namespace via resource templates. Resources are the read/context primitive; when the model needs to *act* or *compute*, use [[concepts/tools]] instead. See [[syntheses/server-feature-picker]] for choosing between them. ## Risks & Pitfalls - **URI validation:** servers **MUST** validate all resource URIs; access controls **SHOULD** be implemented for sensitive resources, and permissions **SHOULD** be checked before operations. - **Binary encoding:** binary data **MUST** be properly base64-encoded in the `blob` field. - **`https://` misuse:** servers **SHOULD** use the `https://` scheme only when the client can fetch the resource directly on its own; otherwise prefer another/custom scheme. - **Resource links from tools** (`resource_link` content) are *not* guaranteed to appear in `resources/list` results. - **Error codes:** resource-not-found is `-32002`; internal errors are `-32603`. The error `data` may include the offending `uri`. ## Related Concepts - [[concepts/tools]] — the action/compute server primitive - [[concepts/prompts]] — user-controlled prompt templates that can embed resources - [[concepts/protocol-utilities]] — pagination and completion used by resources - [[concepts/lifecycle]] — capability negotiation at initialization - [[concepts/security-best-practices]] — access control for sensitive resources - [[syntheses/server-feature-picker]] — resources vs. tools vs. prompts ## Sources - `raw/llms_txt_doc-resources.md` — MCP specification 2025-11-25, Server / Resources --- title: "Roots" type: concept tags: [client-feature, roots, filesystem, boundaries, workspace] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-roots.md"] confidence: high --- ## Definition Roots are a standardized way for an MCP **client** to expose filesystem "roots" to servers. A root defines the **boundaries of where a server can operate** within the filesystem — which directories and files it has access to. Servers can request the list of roots from supporting clients and receive notifications when that list changes. Roots are a **client-provided** capability (like [[concepts/sampling]] and [[concepts/elicitation]]) and are typically surfaced through workspace or project configuration — for example a workspace/project picker, optionally combined with automatic detection from version control or project files. ## How It Works A client that supports roots **MUST** declare the `roots` capability during [[concepts/lifecycle|initialization]]; `listChanged` indicates whether the client emits notifications when the root list changes: ```json { "capabilities": { "roots": { "listChanged": true } } } ``` The server retrieves roots with a **`roots/list`** request (note: unlike list operations elsewhere in MCP, this takes no params and the spec shows no pagination): ```json { "jsonrpc": "2.0", "id": 1, "method": "roots/list" } ``` ```json { "jsonrpc": "2.0", "id": 1, "result": { "roots": [ { "uri": "file:///home/user/projects/myproject", "name": "My Project" } ] } } ``` When roots change, clients that support `listChanged` **MUST** send `notifications/roots/list_changed`; the server then re-requests `roots/list` to get the updated set. A client may expose multiple roots at once (e.g. a frontend and a backend repository), each with its own `uri` and `name`. ## Key Parameters - **Method:** `roots/list` (server → client). - **Notification:** `notifications/roots/list_changed` (client → server). - **Capability flag:** `listChanged`. - **Root definition fields:** - `uri` — unique identifier for the root. This **MUST** be a `file://` URI in the current specification. - `name` — optional human-readable name for display. - **Example roots:** - Project directory: `{ "uri": "file:///home/user/projects/myproject", "name": "My Project" }` - Multiple repositories: an array of roots such as `file:///home/user/repos/frontend` ("Frontend Repository") and `file:///home/user/repos/backend` ("Backend Repository"). ## When To Use Use roots when a server needs to know **which filesystem locations it is allowed to work in** — a filesystem server, a code-analysis server, or any server whose operations should be scoped to the user's chosen project(s). The client declaring roots lets the server discover the workspace up front and adjust when the user switches projects. Roots complement the server-side [[concepts/resources]] feature: resources expose *content*, while roots communicate the *boundaries* within which a server should look. It is one of three client capabilities alongside [[concepts/sampling]] (LLM calls) and [[concepts/elicitation]] (user input). ## Risks & Pitfalls - **`file://` only:** in the current spec every root `uri` **MUST** be a `file://` URI — other schemes are not valid here. - **Not supported errors:** if the client does not support roots, the correct JSON-RPC error is `-32601` (Method not found); internal errors are `-32603`. Servers **SHOULD** check for the roots capability before use and handle its absence gracefully. - **Path traversal:** clients **MUST** validate all root URIs to prevent path traversal and only expose roots with appropriate permissions and access controls. - **Respect boundaries:** servers **SHOULD** validate all paths against the provided roots and respect those boundaries during operations — roots are a boundary *declaration*, not automatically enforced by the protocol. - **Availability:** servers **SHOULD** handle roots becoming unavailable, cache root information appropriately, and react to `list_changed` notifications. - **Consent:** clients **SHOULD** prompt users for consent before exposing roots to servers and validate accessibility before exposing. ## Related Concepts - [[concepts/resources]] — server-exposed content (boundaries vs. content) - [[concepts/sampling]] — another client-provided capability - [[concepts/elicitation]] — client capability for structured user input - [[concepts/lifecycle]] — capability negotiation at initialization - [[concepts/security-best-practices]] — path-traversal prevention, access controls ## Sources - `raw/llms_txt_doc-roots.md` — MCP specification 2025-11-25, Client / Roots --- title: "Sampling" type: concept tags: [client-feature, sampling, llm, model-preferences, human-in-the-loop] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-sampling.md"] confidence: high --- ## Definition Sampling is the MCP flow by which a **server** requests an LLM completion ("sampling", "completions", or "generations") *from the client*. The client owns model access, selection, and permissions, so servers can leverage AI capabilities **with no server API keys necessary**. It lets servers implement agentic behaviors where LLM calls occur *nested* inside other server features. Sampling is a **client-provided** capability (like [[concepts/roots]] and [[concepts/elicitation]]) — the inverse direction from [[concepts/tools]], which the server provides to the model. For trust & safety there **SHOULD** always be a human in the loop able to deny sampling requests, review/edit prompts, and review responses before delivery. ## How It Works A client that supports sampling **MUST** declare the `sampling` capability during [[concepts/lifecycle|initialization]]: ```json { "capabilities": { "sampling": {} } } ``` To add tool-use support the client declares `"sampling": { "tools": {} }`; to support (soft-deprecated) context inclusion it declares `"sampling": { "context": {} }`. The server sends a **`sampling/createMessage`** request; the client (after human review) forwards it to an LLM and returns the generation. Example: ```json { "jsonrpc": "2.0", "id": 1, "method": "sampling/createMessage", "params": { "messages": [ { "role": "user", "content": { "type": "text", "text": "What is the capital of France?" } } ], "modelPreferences": { "hints": [ { "name": "claude-3-sonnet" } ], "intelligencePriority": 0.8, "speedPriority": 0.5 }, "systemPrompt": "You are a helpful assistant.", "maxTokens": 100 } } ``` ```json { "jsonrpc": "2.0", "id": 1, "result": { "role": "assistant", "content": { "type": "text", "text": "The capital of France is Paris." }, "model": "claude-3-sonnet-20240307", "stopReason": "endTurn" } } ``` **Sampling with tools.** If the client declared `sampling.tools`, servers **MAY** include a `tools` array and optional `toolChoice` so the client's LLM can call tools mid-sampling. The LLM returns `tool_use` content with `stopReason: "toolUse"`; the server executes the tools, appends `tool_result` content, and calls `sampling/createMessage` again — a multi-turn loop repeated until a final `stopReason: "endTurn"`. Servers **MUST NOT** send tool-enabled requests to clients that did not declare `sampling.tools`. ## Key Parameters - **Method:** `sampling/createMessage`. - **Request params:** `messages`, `modelPreferences`, `systemPrompt`, `maxTokens`, and (with tools) `tools`, `toolChoice`. - **Result fields:** `role` (`"assistant"`), `content`, `model` (the concrete model used), `stopReason` (e.g. `"endTurn"`, `"toolUse"`). - **Message roles:** only `"user"` and `"assistant"`. Content types: `text`, `image` (base64 + `mimeType`), `audio`. - **`modelPreferences`:** - **Capability priorities** (normalized 0–1): `costPriority` (higher → cheaper), `speedPriority` (higher → faster), `intelligencePriority` (higher → more capable). - **`hints`:** ordered array of `{ "name": "..." }` treated as flexible substrings of model names; clients **MAY** map a hint to an equivalent model from another provider (e.g. a `sonnet` hint → `gemini-1.5-pro`). Hints are advisory — the client makes the final selection. - **`toolChoice` modes:** `{mode: "auto"}` (default — model decides), `{mode: "required"}` (must use ≥1 tool), `{mode: "none"}` (must not use tools; often forced on the loop's last iteration). ## When To Use Use sampling when a **server** needs LLM reasoning but should not hold its own model credentials — e.g. summarizing data it fetched, classifying input, or driving an agentic multi-step tool loop entirely through the client's model. Because the client mediates, this keeps model choice, cost, and permissions with the user. Pair with server [[concepts/tools]] to build nested agent loops. When a server instead needs *structured input from the human*, use [[concepts/elicitation]]; when it needs filesystem scope, use [[concepts/roots]]. ## Risks & Pitfalls - **Tool-use/result balance:** every assistant message with `ToolUseContent` (`id`) **MUST** be immediately followed by a user message consisting *entirely* of `ToolResultContent`, each `toolUseId` matching an `id`, before any other message. Missing or mismatched results are invalid. - **No mixed tool-result messages:** a message containing `type: "tool_result"` **MUST** contain only tool results (no text/image/audio) — this preserves compatibility with provider APIs using dedicated tool roles (OpenAI `"tool"`, Gemini `"function"`). - **`includeContext` deprecation:** the values `"thisServer"` and `"allServers"` are soft-deprecated; omit `includeContext` (defaults to `"none"`) unless the client declared `sampling.context`. - **Error codes:** user rejected sampling → `-1`; tool result missing or tool results mixed with other content → `-32602`. - **Security:** clients **SHOULD** implement user approval controls and rate limiting; both parties **SHOULD** validate content and **MUST** handle sensitive data appropriately; both **SHOULD** enforce iteration limits on tool loops. ## Related Concepts - [[concepts/tools]] — server tools the client's LLM can call during sampling - [[concepts/roots]] — another client-provided capability - [[concepts/elicitation]] — server requesting structured user input (vs. an LLM call) - [[concepts/lifecycle]] — capability negotiation at initialization - [[concepts/security-best-practices]] — human-in-the-loop, rate limiting - [[syntheses/server-feature-picker]] — where sampling fits among features ## Sources - `raw/llms_txt_doc-sampling.md` — MCP specification 2025-11-25, Client / Sampling --- title: "Security Best Practices" type: concept tags: [security, authorization, threats, transports, advanced] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-security-best-practices.md", "raw/llms_txt_doc-client-best-practices.md"] confidence: high --- # Security Best Practices ## Definition This page catalogs the attack vectors specific to MCP implementations and their mitigations, complementing the [[concepts/authorization]] specification. The primary audience is developers implementing authorization flows, server operators, and security reviewers. It should be read alongside the MCP Authorization spec and [OAuth 2.0 security best practices (RFC 9700)](https://datatracker.ietf.org/doc/html/rfc9700). ## How It Works The threat model addresses named attacks, each with mitigations expressed in RFC 2119 terms (**MUST**/**SHOULD**): **Confused Deputy.** An MCP proxy server fronting a third-party API using a **static client ID**, while allowing MCP clients to dynamically register, can be abused: the third-party AS sets a consent cookie after the first authorization, and an attacker later reuses that cookie (via a crafted `redirect_uri` on a new dynamically registered client) to steal an authorization code without a fresh consent screen. Mitigation: proxy servers **MUST** implement per-client consent *before* forwarding to the third-party AS — maintain a registry of approved `client_id`s per user, show an MCP-owned consent page naming the client and scopes, and validate `redirect_uri` with exact string matching. The OAuth `state` value **MUST** be cryptographically random, stored server-side only *after* consent approval, single-use, and short-lived (~10 min). **Token Passthrough.** An anti-pattern where a server accepts tokens not issued to it and forwards them downstream. Explicitly **forbidden** — it circumvents security controls (rate limiting, validation), breaks audit trails, and creates trust-boundary issues. Servers **MUST NOT** accept any token not explicitly issued for them. **Server-Side Request Forgery (SSRF).** During OAuth metadata discovery a malicious server can populate `resource_metadata`, `authorization_servers`, or `token_endpoint` with internal URLs (`http://169.254.169.254/` cloud metadata, `http://localhost:6379/`, private IPs) to exfiltrate cloud credentials or reach internal services. Mitigations: clients **SHOULD** require HTTPS for OAuth URLs (loopback exception), block private/reserved IP ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `127.0.0.0/8`, `169.254.0.0/16`, `fc00::/7`, `fe80::/10`), validate redirect targets, and use egress proxies (e.g. Stripe's Smokescreen). Do **not** hand-roll IP validation — encoding tricks (octal/hex/IPv4-mapped IPv6) defeat custom parsers; beware DNS-rebinding TOCTOU. **Session Hijacking.** With multiple stateful HTTP servers, an attacker who obtains a session ID can inject events or impersonate a user. Servers implementing authorization **MUST** verify all inbound requests and **MUST NOT** use sessions for authentication. Use secure non-deterministic session IDs (UUIDs from a secure RNG), and **SHOULD** bind them to user info using a key like `:`. **Local MCP Server Compromise.** Locally run servers execute with the client's privileges. Malicious startup commands can exfiltrate data (`curl -X POST -d @~/.ssh/id_rsa ...`) or destroy files (`sudo rm -rf ...`). Clients offering one-click config **MUST** show the exact command without truncation, flag dangerous patterns (`sudo`, `rm -rf`), warn about privileges, and require explicit approval; **SHOULD** sandbox spawned servers. Server authors should use `stdio` to limit access, or require an auth token / Unix domain sockets over HTTP. **OAuth Authorization URL Validation.** A malicious server supplying a `javascript:` URL as its authorization endpoint can achieve XSS/RCE. Clients **MUST** allow only `http://`/`https://` schemes (http only for loopback), **MUST** reject `javascript:`, `data:`, `file:`, `vbscript:`, **MUST NOT** use shell commands to open URLs, and **SHOULD** use allowlist validation + CSP. In proxy architectures this can escalate stdio spawning to full system compromise. **Scope Minimization.** Broad scopes (`files:*`, `admin:*`) granted up front expand the blast radius of a stolen token and cause consent abandonment. Use a progressive least-privilege model: minimal initial scope (e.g. `mcp:tools-basic`), incremental elevation via `WWW-Authenticate` `scope="..."` challenges, and down-scoping tolerance. Avoid publishing all scopes in `scopes_supported` or using wildcard/omnibus scopes. ## Key Parameters - **Consent cookies** — `__Host-` prefix; `Secure`, `HttpOnly`, `SameSite=Lax`; signed or server-side; bound to `client_id`. - **Consent UI** — CSRF protection; anti-clickjacking via `frame-ancestors` CSP or `X-Frame-Options: DENY`. - **`Mcp-Session-Id`** — treat as untrusted input; never tie authorization to it; regenerate on auth changes. - **Client-scaling patterns** (from client best practices): **progressive tool discovery** (defer `tools/list` definitions, expose a `search_tools` meta-tool once definitions exceed ~1–5% of the context window) and **programmatic tool calling / code mode** (model writes sandboxed code calling tools; only the final result returns). The sandbox **MUST** have no direct network access; credentials stay host-side; apply per-call authorization to sandbox-originated calls. ## When To Use Apply on **every** MCP deployment that crosses a trust boundary: any HTTP/remote server, any proxy to third-party APIs, any one-click local-server installer, and any host connecting to many untrusted servers. Confused-deputy and token-passthrough rules apply specifically to proxy servers; SSRF and URL-validation rules apply to any client fetching server-supplied URLs. ## Risks & Pitfalls - Treating a received token or session ID as trusted without validation. - Forwarding client tokens upstream (token passthrough). - Setting the `state` consent cookie *before* the user approves — renders the consent screen ineffective. - Manual IP/URL parsing that misses encoding tricks or DNS rebinding. - Publishing the full scope catalog and requesting all scopes up front. - Truncating startup commands or output — hides malicious payloads. ## Related Concepts - [[concepts/authorization]] — the OAuth flow these threats target - [[concepts/transports]] — stdio vs HTTP security surfaces - [[concepts/building-a-client]] — client-side validation duties - [[concepts/tools]] — human-in-the-loop tool consent - [[syntheses/local-vs-remote-servers]] — differing risk profiles ## Sources - `raw/llms_txt_doc-security-best-practices.md` — attack vectors and mitigations - `raw/llms_txt_doc-client-best-practices.md` — progressive discovery, code mode, sandbox security --- title: "Tools" type: concept tags: [server-feature, tools, json-schema, model-controlled, error-handling] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-tools.md"] confidence: high --- ## Definition Tools are functions an MCP **server** exposes for a language model to invoke, letting the model interact with external systems — querying databases, calling APIs, or performing computations. Each tool is uniquely identified by a `name` and includes metadata describing its schema. Tools are **model-controlled**: the model can discover and invoke them automatically based on context and the user's prompts. For trust & safety there **SHOULD** always be a human in the loop with the ability to deny tool invocations. Tools are the "action" server primitive, contrasted with read-only [[concepts/resources]] and user-invoked [[concepts/prompts]]. ## How It Works A server that supports tools **MUST** declare the `tools` capability, where `listChanged` indicates whether it will notify when the tool list changes: ```json { "capabilities": { "tools": { "listChanged": true } } } ``` Two core methods drive tools: - **`tools/list`** — client discovers tools. Supports [[concepts/protocol-utilities|pagination]] (`cursor` / `nextCursor`). Each tool returns `name`, optional `title`, `description`, `inputSchema`, optional `outputSchema`, `icons`, `annotations`, and `execution`. - **`tools/call`** — client invokes a tool by `name` with an `arguments` object. Example `tools/call`: ```json { "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "get_weather", "arguments": { "location": "New York" } } } ``` ```json { "jsonrpc": "2.0", "id": 2, "result": { "content": [ { "type": "text", "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy" } ], "isError": false } } ``` When the tool list changes, servers that declared `listChanged` **SHOULD** send `notifications/tools/list_changed`. **Results** may be **unstructured** or **structured**. Unstructured content goes in the `content` array and may hold multiple items: `text`, `image` (base64 + `mimeType`), `audio`, `resource_link` (a URI pointing at a [[concepts/resources|resource]]), or embedded `resource`. Structured content is returned as a JSON object in the `structuredContent` field; for backwards compatibility a tool returning structured content **SHOULD** also return the serialized JSON in a text content block. ## Key Parameters - **Methods:** `tools/list`, `tools/call`. **Notification:** `notifications/tools/list_changed`. - **Tool definition fields:** `name`, `title`, `description`, `icons`, `inputSchema`, `outputSchema`, `annotations`, `execution`. - **`inputSchema`:** a JSON Schema object defining parameters. Defaults to **2020-12** if no `$schema` field is present; **MUST** be a valid JSON Schema object (not `null`). For no-parameter tools, prefer `{ "type": "object", "additionalProperties": false }`. - **`outputSchema`:** optional JSON Schema for structured results. If provided, servers **MUST** return structured results conforming to it and clients **SHOULD** validate against it. Structured results go in `structuredContent`. - **`execution.taskSupport`:** whether the tool supports task-augmented execution — `"forbidden"` (default), `"optional"`, or `"required"`. - **Tool names:** SHOULD be 1–128 chars, case-sensitive, using only `A-Z a-z 0-9 _ - .`; no spaces/commas; unique within a server. Valid examples: `getUser`, `DATA_EXPORT_v2`, `admin.tools.list`. - **Result fields:** `content` (array), `structuredContent` (object), `isError` (boolean). - **Annotations** (`audience`, `priority`, `lastModified`) describe tool behavior but **MUST** be treated as untrusted unless from a trusted server. ## When To Use Use a tool when the model needs to **do something or compute something** with side effects or fresh data — call an API, run a query, transform input. Provide an `outputSchema` when downstream code or the model benefits from typed, validated results. Use `resource_link` or embedded resources in results to hand back larger data as [[concepts/resources]]. When the need is read-only context, use resources; when it's a user-triggered template, use [[concepts/prompts]]. See [[syntheses/server-feature-picker]]. ## Risks & Pitfalls - **Two error channels.** *Protocol errors* are standard JSON-RPC errors (e.g. unknown tool → `-32602`, malformed request failing the CallToolRequest schema, server errors). *Tool execution errors* are reported **in the result** with `isError: true` and a message the model can use to self-correct and retry. Clients **SHOULD** surface tool execution errors to the model; protocol errors are less recoverable. - **Human in the loop:** clients **SHOULD** show tool inputs to the user before calling the server (to avoid data exfiltration) and prompt for confirmation on sensitive operations. - **Untrusted annotations:** never trust tool annotations from untrusted servers. - **Server duties:** validate all tool inputs, implement access controls, rate-limit invocations, and sanitize outputs. Clients **SHOULD** validate results before passing to the LLM and implement timeouts. ## Related Concepts - [[concepts/resources]] — read-only context; tools can return `resource_link`s - [[concepts/prompts]] — user-controlled templates - [[concepts/sampling]] — servers can ask the client's LLM to use tools *during* sampling - [[concepts/protocol-utilities]] — pagination for `tools/list` - [[concepts/security-best-practices]] — input validation, confirmation, human-in-the-loop - [[syntheses/server-feature-picker]] — tools vs. resources vs. prompts ## Sources - `raw/llms_txt_doc-tools.md` — MCP specification 2025-11-25, Server / Tools --- title: "MCP Transports" type: concept tags: [protocol, transport, stdio, streamable-http, sse, security, well-established] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-transports.md"] confidence: high --- # MCP Transports ## Definition A **transport** is the communication mechanism that carries MCP's JSON-RPC messages between a client and a server. MCP uses JSON-RPC to encode messages, and those messages **MUST** be UTF-8 encoded. The protocol currently defines two standard transports: **stdio** (communication over standard input and standard output) and **Streamable HTTP**. Clients **SHOULD** support stdio whenever possible. Clients and servers **MAY** also implement custom transports, since the protocol is transport-agnostic over any bidirectional channel. ## How It Works ### stdio In the **stdio** transport the client runs the server as a local subprocess: - The client launches the MCP server as a subprocess. - The server reads JSON-RPC messages from its standard input (`stdin`) and writes messages to its standard output (`stdout`). - Messages are individual JSON-RPC requests, notifications, or responses, **delimited by newlines**, and **MUST NOT** contain embedded newlines. - The server **MAY** write UTF-8 strings to standard error (`stderr`) for any logging purpose (informational, debug, error). The client **MAY** capture, forward, or ignore `stderr` and **SHOULD NOT** assume `stderr` output indicates errors. - The server **MUST NOT** write anything to `stdout` that is not a valid MCP message; the client **MUST NOT** write anything to the server's `stdin` that is not a valid MCP message. ### Streamable HTTP Streamable HTTP **replaces** the older HTTP+SSE transport from protocol version `2024-11-05`. The server runs as an independent process handling multiple client connections, using HTTP POST and GET requests, and **MAY** use **Server-Sent Events (SSE)** to stream multiple server messages. - The server **MUST** provide a single HTTP endpoint path (the **MCP endpoint**) that supports both POST and GET — for example `https://example.com/mcp`. - **Sending to the server:** every JSON-RPC message from the client **MUST** be a new HTTP POST to the MCP endpoint. The client **MUST** include an `Accept` header listing both `application/json` and `text/event-stream`. The POST body **MUST** be a single JSON-RPC request, notification, or response. - If the POST body is a response or notification and the server accepts it, the server **MUST** return **HTTP 202 Accepted** with no body. - If the POST body is a request, the server **MUST** return either `Content-Type: text/event-stream` (to open an SSE stream) or `Content-Type: application/json` (to return one JSON object); the client **MUST** support both. - **Listening for server messages:** the client **MAY** issue an HTTP GET to the MCP endpoint to open an SSE stream (with `Accept: text/event-stream`), letting the server push requests/notifications without the client first POSTing. The server **MUST** return `text/event-stream` or else **HTTP 405 Method Not Allowed** if it offers no SSE at that endpoint. ### Custom transports Implementers **MAY** add custom transports but **MUST** preserve the JSON-RPC message format and lifecycle requirements, and **SHOULD** document their connection and message-exchange patterns for interoperability. ## Key Parameters - **`MCP-Session-Id` header** — a server using Streamable HTTP **MAY** assign a session ID at initialization by including it on the HTTP response carrying `InitializeResult`. It **SHOULD** be globally unique and cryptographically secure (e.g. a UUID, JWT, or hash) and **MUST** contain only visible ASCII characters (0x21 to 0x7E). If assigned, the client **MUST** include it on all subsequent requests. A server that requires a session ID **SHOULD** answer requests lacking it (other than init) with **HTTP 400 Bad Request**; after terminating a session the server **MUST** respond **HTTP 404 Not Found**, and on 404 the client **MUST** start a new session with a fresh `InitializeRequest`. A client leaving **SHOULD** send an **HTTP DELETE** with the `MCP-Session-Id` header to terminate; the server **MAY** answer with **HTTP 405** if it disallows client termination. - **`MCP-Protocol-Version` header** — if using HTTP, the client **MUST** include `MCP-Protocol-Version: ` on all subsequent requests, e.g. `MCP-Protocol-Version: 2025-11-25`. It **SHOULD** be the version negotiated during initialization (see [[concepts/lifecycle]]). If the server receives no such header and cannot otherwise determine the version, it **SHOULD** assume `2025-03-26`. An invalid or unsupported value **MUST** get **HTTP 400 Bad Request**. - **Resumability (`Last-Event-ID`)** — servers **MAY** attach an `id` to SSE events; if present it **MUST** be globally unique across all streams within the session and **SHOULD** encode enough info to identify the originating stream. To resume, the client **SHOULD** issue an HTTP GET including the `Last-Event-ID` header; the server **MAY** replay messages that would have followed on *that* stream, and **MUST NOT** replay messages from a different stream. Resumption is always via HTTP GET regardless of how the stream started. - **`retry` field** — if the server closes a connection without terminating the SSE stream, it **SHOULD** send a standard SSE `retry` field; the client **MUST** respect it, waiting that many milliseconds before reconnecting ("polling" the stream). - **Multiple connections** — the client **MAY** hold multiple SSE streams; the server **MUST** send each JSON-RPC message on only one stream and **MUST NOT** broadcast the same message across streams. ## When To Use - **Use stdio** for local integrations: the client launches the server on the same machine, giving optimal performance with no network overhead. Local servers using stdio typically serve a single client. Clients **SHOULD** support stdio whenever possible. - **Use Streamable HTTP** for remote servers and multi-client scenarios: it enables remote communication, supports standard HTTP authentication (bearer tokens, API keys, custom headers — MCP recommends OAuth to obtain tokens), and lets one server handle many clients. See [[concepts/authorization]] and [[syntheses/transport-decision]]. ## Risks & Pitfalls - **DNS rebinding attacks (Streamable HTTP).** Servers **MUST** validate the `Origin` header on all incoming connections; if present and invalid the server **MUST** respond **HTTP 403 Forbidden** (the body **MAY** be a JSON-RPC error response with no `id`). When running locally, servers **SHOULD** bind only to `localhost` (127.0.0.1), not all interfaces (0.0.0.0), and **SHOULD** implement proper authentication. Without these, remote websites could reach local MCP servers. See [[concepts/security-best-practices]]. - **Polluting stdout (stdio).** Any non-MCP bytes on `stdout` corrupt the stream; route all logging to `stderr`. - **Treating disconnection as cancellation.** SSE disconnection **SHOULD NOT** be interpreted as the client cancelling; to cancel, the client **SHOULD** send an explicit MCP `CancelledNotification` (see [[concepts/protocol-utilities]]). - **Parsing session IDs or cursors.** Session IDs must be handled securely to avoid session hijacking (see [[concepts/security-best-practices]]). - **Backwards compatibility.** To support old HTTP+SSE (`2024-11-05`) clients, servers can host both the old SSE/POST endpoints and the new MCP endpoint; clients probe by POSTing an `InitializeRequest` and, on 400/404/405, fall back to a GET expecting an `endpoint` event. ## Related Concepts - [[concepts/architecture]] - [[concepts/lifecycle]] - [[concepts/versioning]] - [[concepts/authorization]] - [[concepts/security-best-practices]] - [[concepts/protocol-utilities]] - [[syntheses/transport-decision]], [[syntheses/local-vs-remote-servers]] ## Sources - `raw/llms_txt_doc-transports.md` --- title: "MCP Versioning" type: concept tags: [protocol, versioning, compatibility, changelog, well-established] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-versioning.md", "raw/llms_txt_doc-key-changes.md"] confidence: high --- # MCP Versioning ## Definition MCP uses **string-based version identifiers in the format `YYYY-MM-DD`**, where the date indicates the last time backwards-incompatible changes were made. The version is **not** incremented for backwards-compatible updates — a "current" revision can keep receiving compatible changes without a new date. This scheme lets the protocol improve incrementally while preserving interoperability. The **current** protocol version is **`2025-11-25`**. ## How It Works **Revision states.** A revision may be marked as: - **Draft** — in-progress specification, not yet ready for consumption. - **Current** — the current protocol version, ready for use, and may still receive backwards-compatible changes. - **Final** — a past, complete specification that will not change. **Feature states.** Individual features may additionally be marked **Deprecated** under the feature lifecycle and deprecation policy: the feature stays in the spec but is scheduled for removal. Deprecated features document a migration path (or state none is required) and remain in the spec for **at least twelve months** — or **at least ninety days** under the policy's expedited-removal exception — before becoming eligible for removal, after which they may be **Removed** in a future revision. Currently deprecated features are tracked in the deprecated features registry. **Version negotiation.** Negotiation happens during [initialization](/specification/latest/basic/lifecycle#initialization) (see [[concepts/lifecycle]]). Clients and servers **MAY** support multiple protocol versions simultaneously, but they **MUST** agree on a single version for the session. If negotiation fails, the protocol provides error handling so clients can gracefully terminate connections when no compatible version exists. ## Key Parameters - **Format:** `YYYY-MM-DD` — the date of the last backwards-incompatible change. - **Current version:** `2025-11-25`. - **Previous revisions referenced by the spec:** `2025-06-18`, `2025-03-26` (the default a server assumes over HTTP when no `MCP-Protocol-Version` header is present — see [[concepts/transports]]), and `2024-11-05` (the version whose HTTP+SSE transport Streamable HTTP replaced). - **Deprecation windows:** 12 months standard; 90 days under expedited removal. - **HTTP header:** over HTTP, the negotiated version is carried on every request via `MCP-Protocol-Version` (see [[concepts/transports]] and [[concepts/lifecycle]]). ## Notable Changes in 2025-11-25 The `2025-11-25` revision lists these changes since `2025-06-18`. **Major changes:** 1. Enhance authorization server discovery with support for **OpenID Connect Discovery 1.0** (PR #797). 2. Allow servers to expose **icons** as additional metadata for tools, resources, resource templates, and prompts (SEP-973). 3. Enhance authorization flows with **incremental scope consent via `WWW-Authenticate`** (SEP-835). 4. Provide guidance on **tool names** (SEP-986). 5. Update `ElicitResult` and `EnumSchema` to a more standards-based approach supporting titled, untitled, single-select, and multi-select enums (SEP-1330). 6. Add support for **URL mode elicitation** (SEP-1036). 7. Add **tool calling support to sampling** via `tools` and `toolChoice` parameters (SEP-1577). 8. Add support for **OAuth Client ID Metadata Documents** as a recommended client registration mechanism (SEP-991, PR #1296). 9. Add **experimental support for tasks** — tracking durable requests with polling and deferred result retrieval (SEP-1686). **Minor changes (selected):** - Clarify that servers using stdio transport may use `stderr` for all types of logging, not just errors (PR #670). - Add an optional `description` field to the `Implementation` interface to align with the MCP registry `server.json` format (see [[entities/mcp-registry]]). - Clarify that servers **must respond with HTTP 403 Forbidden** for invalid `Origin` headers in Streamable HTTP transport (PR #1439). - Clarify that input validation errors should be returned as **Tool Execution Errors** rather than Protocol Errors, to enable model self-correction (SEP-1303). - Support **polling SSE streams** by allowing servers to disconnect at will (SEP-1699); resumption always via GET regardless of stream origin, event IDs encode stream identity (Issue #1847). - Align OAuth 2.0 Protected Resource Metadata discovery with **RFC 9728**, making `WWW-Authenticate` optional with fallback to `.well-known` (SEP-985). - Establish **JSON Schema 2020-12** as the default dialect for MCP schema definitions (SEP-1613). **Other schema changes:** decouple request payloads from RPC method definitions into standalone parameter schemas (SEP-1319, PR #1284). **Governance:** formalize MCP governance structure (SEP-932), community communication guidelines (SEP-994), Working/Interest Groups (SEP-1302), and an **SDK tiering system** with feature-support and maintenance requirements (SEP-1730). ## When To Use Consult versioning whenever compatibility matters: when a client and server negotiate; when deciding whether a feature you depend on exists in the peer's version; when reading a changelog to plan a migration; or when debugging a rejected connection. Because version dates only advance on breaking changes, a peer on an older date may still be fully compatible for the features you use. ## Risks & Pitfalls - **Assuming a higher date means "just newer."** A new `YYYY-MM-DD` marks a *backwards-incompatible* change — treat a version bump as potentially breaking, not merely additive. - **Not handling failed negotiation.** If no common version exists, clients should gracefully terminate; do not proceed with a mismatched version. - **Relying on deprecated features indefinitely.** Deprecated features are scheduled for removal after their 12-month (or 90-day expedited) window; plan migrations early. - **Forgetting the HTTP default.** Over HTTP with no `MCP-Protocol-Version` header and no other signal, a server assumes `2025-03-26` — an implicit default that may not match your intent. ## Related Concepts - [[concepts/lifecycle]] - [[concepts/transports]] - [[concepts/authorization]] - [[concepts/elicitation]] - [[concepts/sampling]] - [[concepts/protocol-utilities]] - [[entities/mcp-registry]] ## Sources - `raw/llms_txt_doc-versioning.md` - `raw/llms_txt_doc-key-changes.md` --- title: "What Is MCP" type: concept tags: [protocol, foundational, overview, architecture, well-established] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-what-is-the-model-context-protocol-mcp.md", "raw/llms_txt_doc-overview.md", "raw/llms_txt_doc-overview-2.md"] confidence: high --- # What Is MCP ## Definition The **Model Context Protocol (MCP)** is an open-source standard for connecting AI applications to external systems. Using MCP, AI applications like Claude or ChatGPT can connect to data sources (for example, local files and databases), tools (for example, search engines and calculators), and workflows (for example, specialized prompts) — enabling them to access key information and perform tasks. The canonical analogy from the spec: MCP is "like a USB-C port for AI applications." Just as USB-C provides a standardized way to connect electronic devices, MCP provides a standardized way to connect AI applications to external systems, so you can build an integration once and reuse it everywhere. ## How It Works MCP follows a **client-host-server architecture** where each host can run multiple client instances. Three participants do the work (see [[concepts/architecture]] for the full breakdown): - **MCP Host** — the AI application (for example, Claude Code, Claude Desktop, or Visual Studio Code) that coordinates and manages one or more MCP clients. - **MCP Client** — a component the host creates to maintain a connection to a single MCP server and obtain context from it. Each client has a 1:1 relationship with a particular server. - **MCP Server** — a program that provides context to MCP clients. A server can run **locally** (typically via the stdio transport) or **remotely** (typically via the Streamable HTTP transport). See [[concepts/transports]]. For example, Visual Studio Code acts as a host: when it connects to the Sentry MCP server it instantiates one client for that connection, and when it also connects to the local filesystem server it instantiates a second client. "MCP server" refers to the program that serves context data regardless of where it runs. Communication is built on **JSON-RPC 2.0** — every message between clients and servers follows that specification (see [[concepts/architecture]]). MCP is a **stateful session protocol**: a session begins with an `initialize` handshake that negotiates a protocol version and the capabilities each side supports (see [[concepts/lifecycle]]). The protocol is organized into several key components: - **Base Protocol** — core JSON-RPC message types. - **Lifecycle Management** — connection initialization, capability negotiation, and session control. - **Authorization** — authentication/authorization framework for HTTP-based transports (see [[concepts/authorization]]). - **Server Features** — resources, prompts, and tools exposed by servers (see [[concepts/resources]], [[concepts/prompts]], [[concepts/tools]]). - **Client Features** — sampling and root directory lists provided by clients (see [[concepts/sampling]], [[concepts/roots]], [[concepts/elicitation]]). - **Utilities** — cross-cutting concerns like logging and argument completion (see [[concepts/protocol-utilities]]). All implementations **MUST** support the base protocol and lifecycle management; other components **MAY** be implemented based on the application's needs. ## Key Parameters - **Open protocol** — MCP is an open standard, not tied to a single vendor. It is supported across many clients and servers. - **Broad ecosystem support** — AI assistants like Claude and ChatGPT, and development tools like Visual Studio Code, Cursor, and MCPJam, all support MCP, making it "build once and integrate everywhere." - **Scope boundary** — MCP focuses solely on the protocol for context exchange. It does **not** dictate how AI applications use LLMs or manage the provided context. - **Three server primitives** — Prompts, Resources, and Tools (each with a distinct control model; see below). ## When To Use Reach for MCP when an AI application needs to reach beyond its own context window into the outside world. Representative use cases from the spec: - Agents accessing your Google Calendar and Notion to act as a personalized assistant. - Claude Code generating an entire web app from a Figma design. - Enterprise chatbots connecting to multiple databases so users analyze data by chat. - AI models creating 3D designs in Blender and printing them on a 3D printer. Why it matters by audience: **developers** cut development time and complexity when building or integrating AI applications; **AI applications/agents** gain access to an ecosystem of data sources, tools, and apps; **end-users** get more capable assistants that can act on their behalf. The three server primitives map to a **control hierarchy** that helps decide what to expose: | Primitive | Control | Description | Example | | --- | --- | --- | --- | | Prompts | User-controlled | Interactive templates invoked by user choice | Slash commands, menu options | | Resources | Application-controlled | Contextual data attached and managed by the client | File contents, git history | | Tools | Model-controlled | Functions exposed to the LLM to take actions | API POST requests, file writing | See [[syntheses/server-feature-picker]] for choosing among them. ## Risks & Pitfalls - **Security boundaries are the host's job.** Because servers connect to real data and can take actions, the host enforces consent, authorization, and isolation. Servers should not be able to read the whole conversation or "see into" other servers (see [[concepts/architecture]] and [[concepts/security-best-practices]]). - **MCP does not manage your context or model.** It only standardizes the exchange; how the host feeds context to the LLM is out of scope. - **Not every feature is guaranteed.** Only base protocol and lifecycle are mandatory; everything else depends on negotiated capabilities, so clients must handle servers that lack a given feature. - **Version compatibility matters.** Client and server must agree on a protocol version during init or the connection should terminate (see [[concepts/versioning]]). ## Related Concepts - [[concepts/architecture]] - [[concepts/transports]] - [[concepts/lifecycle]] - [[concepts/versioning]] - [[concepts/protocol-utilities]] - [[concepts/resources]], [[concepts/tools]], [[concepts/prompts]] - [[concepts/sampling]], [[concepts/elicitation]], [[concepts/roots]] - [[concepts/building-a-server]], [[concepts/building-a-client]], [[concepts/connecting-to-servers]] - [[syntheses/local-vs-remote-servers]] ## Sources - `raw/llms_txt_doc-what-is-the-model-context-protocol-mcp.md` - `raw/llms_txt_doc-overview.md` - `raw/llms_txt_doc-overview-2.md` --- title: "MCP Apps" type: entity tags: [extension, ui, apps, iframe, interactive] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-mcp-apps.md", "raw/llms_txt_doc-build-an-mcp-app.md"] source_url: "https://modelcontextprotocol.io/extensions/apps/overview" confidence: high --- ## Overview **MCP Apps** are interactive HTML UI applications that a server can return and that render **inside** an MCP host (like Claude and Claude Desktop) — data visualizations, forms, dashboards — directly in the chat, instead of plain text. They are an **extension** to the core MCP spec, so host support varies by client. They are currently supported by Claude, Claude Desktop, VS Code GitHub Copilot, Microsoft 365 Copilot, Goose, Postman, MCPJam, and Archestra.AI. Why not just build a standalone web app and link to it? MCP Apps offer four properties a separate page can't match: **context preservation** (the app lives in the conversation), **bidirectional data flow** (the app can call server tools and the host can push fresh results), **integration with the host's capabilities** (delegate actions like "schedule this meeting" to tools the user already connected), and **security guarantees** (the app runs in a sandboxed iframe that can't touch the parent page, cookies, or storage). ## Characteristics - **Two primitives combined:** a [[concepts/tools|tool]] that declares a UI resource in its description (via `_meta.ui.resourceUri` pointing at a `ui://` resource), plus a UI [[concepts/resources|resource]] that renders data as interactive HTML. - **Lifecycle:** (1) UI preloading — the host can preload the `ui://` resource before the tool is even called; (2) resource fetch — the host fetches the HTML (often bundled with its JS/CSS); (3) sandboxed rendering — web hosts render it in a sandboxed iframe; (4) bidirectional communication — app and host talk over a JSON-RPC dialect of MCP transported via `postMessage` (`ui/`-prefixed methods plus shared ones like `tools/call`). - **Security model:** the sandbox prevents access to the parent DOM, host cookies/storage, parent navigation, and parent-context script execution. The host controls which capabilities (and which tools) the app may use; `_meta.ui` can request `permissions` (e.g. microphone, camera) and set a `csp`. - **Framework-agnostic:** built on standard web primitives, so any framework or none works. The `App` class from `@modelcontextprotocol/ext-apps` is a convenience wrapper, not a requirement. Starter templates exist for React, Vue, Svelte, Preact, Solid, and vanilla JS. - **Good fit for:** exploring complex data, configuring with many options, viewing rich media, real-time monitoring, and multi-step workflows. ## How to Use **Prerequisites:** Node.js 18+, and familiarity with MCP tools and resources (Apps combine both). The [[entities/typescript-sdk|TypeScript SDK]] helps you understand the server-side patterns. **Fastest path — scaffold with the `create-mcp-app` skill** (Claude Code): ``` /plugin marketplace add modelcontextprotocol/ext-apps /plugin install mcp-apps@modelcontextprotocol-ext-apps ``` Or across agents with the Vercel Skills CLI: ```bash npx skills add modelcontextprotocol/ext-apps ``` Then ask the agent, e.g. `Create an MCP App that displays a color picker`, and run it: ```bash npm install && npm run build && npm run serve ``` **Manual setup — install dependencies:** ```bash npm install @modelcontextprotocol/ext-apps @modelcontextprotocol/sdk npm install -D typescript vite vite-plugin-singlefile express cors @types/express @types/cors tsx ``` The server registers the tool (with `_meta.ui.resourceUri`) and serves the bundled HTML via `registerAppTool` / `registerAppResource` from `@modelcontextprotocol/ext-apps/server`. The UI uses the `App` class: ```typescript // src/mcp-app.ts import { App } from "@modelcontextprotocol/ext-apps"; const app = new App({ name: "Get Time App", version: "1.0.0" }); // Establish communication with the host app.connect(); // Handle the initial tool result pushed by the host app.ontoolresult = (result) => { const time = result.content?.find((c) => c.type === "text")?.text; serverTimeEl.textContent = time ?? "[ERROR]"; }; // Proactively call tools when users interact with the UI getTimeBtn.addEventListener("click", async () => { const result = await app.callServerTool({ name: "get-time", arguments: {} }); const time = result.content?.find((c) => c.type === "text")?.text; serverTimeEl.textContent = time ?? "[ERROR]"; }); ``` Key `App` methods: `app.connect()` (call once at init), `app.ontoolresult` (fires when the host pushes a tool result), and `app.callServerTool()` (proactively call a server tool — each call is a server round-trip). **Testing:** build and serve (`npm run build && npm run serve`; default `http://localhost:3001/mcp`). To render in Claude you must expose the server to the internet — e.g. tunnel with `npx cloudflared tunnel --url http://localhost:3001` and add the generated URL as a custom connector (paid Claude plans). Alternatively use the `basic-host` test host from the `ext-apps` repo: ```bash git clone https://github.com/modelcontextprotocol/ext-apps.git cd ext-apps/examples/basic-host npm install SERVERS='["http://localhost:3001/mcp"]' npm start ``` ## Related Entities - [[entities/typescript-sdk]] — the server side of an MCP App is a TypeScript MCP server - [[concepts/tools]] · [[concepts/resources]] — the two primitives an MCP App combines - [[concepts/building-a-server]] — building the server that hosts the App - [[syntheses/local-vs-remote-servers]] — Apps must be reachable over HTTP for hosts like Claude - [[concepts/security-best-practices]] — the sandbox/CSP model that isolates App UIs --- title: "MCP Inspector" type: entity tags: [tooling, debugging, testing, inspector, developer-tool] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-mcp-inspector.md"] source_url: "https://github.com/modelcontextprotocol/inspector" confidence: high --- ## Overview The **MCP Inspector** is an interactive developer tool for **testing and debugging** MCP servers. It gives you a UI to connect to a server, browse and exercise its [[concepts/resources|resources]], [[concepts/prompts|prompts]], and [[concepts/tools|tools]], and watch the log/notification stream — without wiring the server into a full host application first. It is the hands-on companion to the broader [[concepts/debugging|Debugging Guide]]. ## Characteristics The Inspector interface provides several panes for interacting with your server: - **Server connection pane** — select the [[concepts/transports|transport]] for connecting; for local servers, customize the command-line arguments and environment. - **Resources tab** — lists all available resources, shows resource metadata (MIME types, descriptions), allows content inspection, and supports subscription testing. - **Prompts tab** — displays available prompt templates, shows arguments and descriptions, enables testing with custom arguments, and previews generated messages. - **Tools tab** — lists available tools, shows tool schemas and descriptions, enables testing with custom inputs, and displays execution results. - **Notifications pane** — presents all logs recorded from the server and notifications received from it. It requires **no installation** — it runs directly through `npx`. ## How to Use Basic form (the Inspector wraps a command that launches your server): ```bash npx @modelcontextprotocol/inspector ``` ```bash npx @modelcontextprotocol/inspector ``` **Inspecting a published npm server package:** ```bash npx -y @modelcontextprotocol/inspector npx # For example npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem /Users/username/Desktop ``` **Inspecting a published PyPI server package:** ```bash npx @modelcontextprotocol/inspector uvx # For example npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/mcp/servers.git ``` **Inspecting a locally-developed server — TypeScript:** ```bash npx @modelcontextprotocol/inspector node path/to/server/index.js args... ``` **Inspecting a locally-developed server — Python:** ```bash npx @modelcontextprotocol/inspector \ uv \ --directory path/to/server \ run \ package-name \ args... ``` Always read any attached server README for the most accurate launch instructions. With the [[entities/python-sdk|Python SDK]] you can also launch the Inspector against a script directly via `uv run mcp dev server.py`. **Recommended development workflow:** (1) Start — launch the Inspector with your server, verify basic connectivity, check capability negotiation; (2) Iterate — make a change, rebuild, reconnect, test affected features, monitor messages; (3) Test edge cases — invalid inputs, missing prompt arguments, concurrent operations, and error handling/error responses. ## Related Entities - [[entities/python-sdk]] — `uv run mcp dev server.py` opens a Python server in the Inspector - [[entities/typescript-sdk]] — inspect a built Node server with `node path/to/server/index.js` - [[concepts/debugging]] — broader debugging strategies the Inspector is part of - [[concepts/building-a-server]] — the server you point the Inspector at - [[concepts/tools]] · [[concepts/resources]] · [[concepts/prompts]] — the primitives each Inspector tab exercises --- title: "The MCP Registry" type: entity tags: [registry, discovery, distribution, server-json, package-types] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-the-mcp-registry.md", "raw/llms_txt_doc-mcp-registry-supported-package-types.md", "raw/llms_txt_doc-mcp-registry-aggregators.md"] source_url: "https://modelcontextprotocol.io/registry/about" confidence: high --- ## Overview The **MCP Registry** is the official centralized **metadata repository** for publicly accessible MCP servers, backed by major trusted contributors to the MCP ecosystem such as Anthropic, GitHub, PulseMCP, and Microsoft. It provides a single place for server creators to publish metadata, namespace management through DNS verification, a REST API for clients and aggregators to discover servers, and standardized installation/configuration information. Crucially, the registry hosts **metadata that points to packages, not the packages themselves**. Package registries — npm, PyPI, Docker Hub — host the code and binaries; the MCP Registry maps a named server version to one of those artifacts (e.g. mapping "weather v1.2.0" to `npm:weather-mcp`). It is **currently in preview** — breaking changes or data resets may occur before general availability. ## Characteristics - **`server.json` metadata format** contains: the server's unique name (e.g. `io.github.user/server-name`), where to locate the server (npm package name, remote URL, etc.), execution instructions (CLI args, env vars), and discovery data (description, capabilities). - **Reverse-DNS namespaces + verification.** Names follow a reverse-DNS format (`io.github.username/server` or `com.example/server`) tied to verified GitHub accounts or domains, so only the legitimate owner can publish under a namespace. See [[entities/publishing-to-registry]] for the auth methods. - **Supports open- and closed-source servers**, as long as the install method is publicly available (public npm package, public Docker image) *or* the server itself is publicly accessible (a non-private-network remote server). It **does not** support private servers — self-host a private registry for those. - **Consumed by downstream aggregators** (marketplaces) which scrape the API on a regular but infrequent basis (~once per hour) and add curation, ratings, or security scans. The registry provides **no uptime or data durability guarantees**. - **Trust & security:** the registry focuses on namespace authentication and metadata hosting; it **delegates security scanning** to the underlying package registries and to downstream aggregators. Spam prevention relies on namespace auth, character limits/validation, and manual takedown. ### Supported package types Each type declares a `registryType` in `server.json` and has its own ownership-verification method: | `registryType` | Registry | Ownership verification | | --- | --- | --- | | `npm` | npm public registry only | `mcpName` in `package.json` **MUST** match the `server.json` name | | `pypi` | official PyPI only | `mcp-name: $SERVER_NAME` string in the package README (may be an HTML comment) | | `nuget` | official NuGet only | `mcp-name: $SERVER_NAME` string in the package README | | `oci` (Docker) | Docker Hub, ghcr.io, `*.pkg.dev`, `*.azurecr.io`, `mcr.microsoft.com` | `io.modelcontextprotocol.server.name` image annotation/`LABEL` matches the name | | `mcpb` | MCPB artifacts via GitHub/GitLab releases | URL must contain `"mcp"`; `server.json` must include a `fileSha256` (clients validate it before install) | Example npm entry in `server.json`: ```json "packages": [ { "registryType": "npm", "identifier": "@username/email-integration-mcp", "version": "1.0.0", "transport": { "type": "stdio" } } ] ``` ## How to Use **As a consumer/aggregator**, the read-only REST API base URL is `https://registry.modelcontextprotocol.io`. Endpoints (path params **must** be URL-encoded): - `GET /v0.1/servers` — list all servers (cursor-based pagination; aggregators mostly scrape this) - `GET /v0.1/servers/{serverName}/versions` — list all versions of a server - `GET /v0.1/servers/{serverName}/versions/{version}` — get a specific version (`latest` is a special value) ```bash curl "https://registry.modelcontextprotocol.io/v0.1/servers?limit=100" ``` Paginate by passing the response's `metadata.nextCursor` as the `cursor` query param. Filter incremental updates with `updated_since` (RFC 3339): ```bash curl "https://registry.modelcontextprotocol.io/v0.1/servers?updated_since=2025-10-23T00:00:00.000Z" ``` Server metadata is generally immutable except the `status` field (e.g. `"deprecated"`, `"deleted"`); aggregators should keep `status` up to date and may drop `"deleted"` servers. Aggregators that also implement the registry's OpenAPI spec become **subregistries** and can inject custom metadata (ratings, download counts, security-scan results) under a `_meta` key namespaced to themselves. **As a publisher**, you push a `server.json` up via the `mcp-publisher` CLI — see [[entities/publishing-to-registry]]. ## Related Entities - [[entities/publishing-to-registry]] — the operational how-to for pushing a `server.json` - [[entities/python-sdk]] · [[entities/typescript-sdk]] — build the servers you publish (PyPI / npm package types) - [[concepts/versioning]] — how registry version strings are parsed and sorted - [[concepts/architecture]] — where the registry sits relative to hosts, clients, and servers - [[syntheses/local-vs-remote-servers]] — the `packages` (local) vs. `remotes` (remote) install methods a `server.json` can carry --- title: "Publishing to the MCP Registry" type: entity tags: [registry, publishing, mcp-publisher, ci-cd, versioning] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-quickstart-publish-an-mcp-server-to-the-mcp-registry.md", "raw/llms_txt_doc-publishing-remote-servers.md", "raw/llms_txt_doc-how-to-automate-publishing-with-github-actions.md", "raw/llms_txt_doc-how-to-authenticate-when-publishing-to-the-official-mcp-regi.md", "raw/llms_txt_doc-versioning-published-mcp-servers.md"] source_url: "https://modelcontextprotocol.io/registry/quickstart" confidence: high --- ## Overview Publishing to the [[entities/mcp-registry|MCP Registry]] means pushing a `server.json` describing your server, using the official **`mcp-publisher`** CLI. Because the registry only hosts metadata, you first publish the underlying package to its package registry (npm, PyPI, etc.), then authenticate (which determines your namespace), then publish the `server.json`. This page covers the operational how-to: install, authenticate, publish, automate in CI, and version. ## Characteristics - **Two publishes, in order:** package to npm/PyPI/etc. **first**, then `server.json` to the MCP Registry. - **Namespace is set by your auth method.** GitHub auth → name must be `io.github.username/*` (or `io.github.orgname/*`). Domain auth → `com.example.*/*` (reverse-DNS of your domain). - **Name must match everywhere.** The `server.json` `name` must equal the package's ownership marker (`mcpName` in `package.json` for npm; an `mcp-name: $SERVER_NAME` string in the README for PyPI/NuGet). - **`mcp-publisher` commands:** `init` (create a `server.json` template), `login` (authenticate), `logout` (clear auth), `publish` (push `server.json`). ## How to Use **Install `mcp-publisher`** (pre-built binary or Homebrew): ```bash # macOS/Linux curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher && sudo mv mcp-publisher /usr/local/bin/ ``` ```bash brew install mcp-publisher ``` **Publish an npm-based server (end to end):** ```bash # 1. Add the ownership marker to package.json: "mcpName": "io.github.my-username/weather" # 2. Build and publish the package to npm first npm install npm run build npm adduser # if not authenticated npm publish --access public # 3. Generate and edit server.json mcp-publisher init # 4. Authenticate (GitHub device flow) — sets your namespace mcp-publisher login github # 5. Publish the server metadata mcp-publisher publish ``` `mcp-publisher init` produces a template like: ```json { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.my-username/weather", "description": "An MCP server for weather information.", "repository": { "url": "https://github.com/my-username/mcp-weather-server", "source": "github" }, "version": "1.0.1", "packages": [ { "registryType": "npm", "identifier": "@my-username/mcp-weather-server", "version": "1.0.1", "transport": { "type": "stdio" } } ] } ``` The `name` in `server.json` **must** match `mcpName` in `package.json`. Verify with `curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.my-username/weather"`. ### Authentication methods `mcp-publisher login` supports several methods; each maps to a namespace: - **GitHub (device OAuth):** `mcp-publisher login github` → `io.github.username/*`. - **GitHub OIDC (for CI):** `mcp-publisher login github-oidc` (no dedicated secret needed). - **GitHub PAT (for CI):** `mcp-publisher login github --token $TOKEN` (PAT needs `read:org` and `read:user` scopes). - **DNS:** `mcp-publisher login dns --domain example.com --private-key $KEY` — proves domain ownership via a `v=MCPv1; k=ed25519; p=...` TXT record (Ed25519 or ECDSA P-384; Google KMS / Azure Key Vault supported). - **HTTP:** `mcp-publisher login http --domain example.com --private-key $KEY` — proves ownership via a `/.well-known/mcp-registry-auth` file hosting the same `v=MCPv1;...` record. ### Publishing a remote (hosted) server Use the `remotes` property instead of (or alongside) `packages`. A remote server **MUST** be publicly accessible at its URL: ```json { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "com.example/acme-analytics", "version": "2.0.0", "remotes": [ { "type": "streamable-http", "url": "https://analytics.example.com/mcp" } ] } ``` `type` is `"streamable-http"` (recommended) or `"sse"`; a server can offer both at different URLs. `remotes` supports `{curly_brace}` URL template `variables` (with `description`, `isRequired`, `choices`, `default`, `isSecret`) for multi-tenant/regional endpoints, and a `headers` array to instruct clients to send specific HTTP headers (e.g. `X-API-Key`). `remotes` may coexist with `packages` so hosts can pick an install method. See [[syntheses/local-vs-remote-servers]]. ### Automating with GitHub Actions Create `.github/workflows/publish-mcp.yml` triggered on version tags. The recommended OIDC variant: ```yaml name: Publish to MCP Registry on: push: tags: ["v*"] # Triggers on version tags like v1.0.0 jobs: publish: runs-on: ubuntu-latest permissions: id-token: write # Required for OIDC authentication contents: read steps: - name: Checkout code uses: actions/checkout@v5 - name: Set up Node.js uses: actions/setup-node@v5 with: node-version: "lts/*" - name: Install dependencies run: npm ci - name: Build package run: npm run build --if-present - name: Publish package to npm run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Install mcp-publisher run: | curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher - name: Authenticate to MCP Registry run: ./mcp-publisher login github-oidc - name: Publish server to MCP Registry run: ./mcp-publisher publish ``` Secrets by method: **OIDC** — none (needs `id-token: write`); **PAT** — `MCP_GITHUB_TOKEN` (a PAT with `read:org`, `read:user`), authenticate with `./mcp-publisher login github --token ${{ secrets.MCP_GITHUB_TOKEN }}`; **DNS** — `MCP_PRIVATE_KEY` (Ed25519 private key). Also add `NPM_TOKEN` for the npm publish. Trigger by pushing a tag: ```bash git tag v1.0.0 git push origin v1.0.0 ``` ### Versioning The `version` string in `server.json` is **required**, **MUST be unique per publication**, and is **immutable once published**. [Semantic versioning](https://semver.org/) is recommended (any format is supported; unparseable versions are always marked "latest"). Version **ranges are prohibited** (`^1.2.3`, `~1.2.3`, `>=1.2.3`, `1.x`, `1.2.*`, `1 - 2`, etc.). Best practices: align the server version with the underlying package version (local servers) or the remote API version (remote servers); for registry-only metadata updates that don't change the package, use a semantic **prerelease** like `1.2.3-1` (note: prereleases sort *before* the matching release, so publishing one after the release won't be marked "latest"). ## Related Entities - [[entities/mcp-registry]] — what you are publishing to (metadata store, package types, aggregators) - [[entities/typescript-sdk]] · [[entities/python-sdk]] — the servers you package and publish - [[concepts/versioning]] — the protocol/version-awareness concept - [[concepts/authorization]] — OAuth for the *served* remote server (distinct from publish-time auth) - [[syntheses/local-vs-remote-servers]] — choosing `packages` vs. `remotes` in `server.json` --- title: "MCP Python SDK" type: entity tags: [sdk, python, fastmcp, server, client] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/github_doc-readme-md.md", "raw/github_doc-docs-client-index-md.md", "raw/github_doc-docs-advanced-index-md.md"] source_url: "https://github.com/modelcontextprotocol/python-sdk" confidence: high --- ## Overview The **MCP Python SDK** is the official Python implementation of the [[concepts/what-is-mcp|Model Context Protocol]]. With one package you can **build MCP servers** that expose [[concepts/tools|tools]], [[concepts/resources|resources]], and [[concepts/prompts|prompts]] to any MCP host, **build MCP clients** that connect to any MCP server, and speak every standard [[concepts/transports|transport]]: stdio, Streamable HTTP, and SSE. Its high-level convenience layer is the `MCPServer` class (the v2 successor to the "FastMCP" style), which turns type-hinted Python functions into fully-schema'd MCP primitives with no boilerplate. The package is published to PyPI as `mcp`. **Version note (as of 2026-07):** the `main`/v2 line is a **pre-release (alpha/beta)** — "Do not use v2 in production." Pre-releases ship as `2.0.0aN` / `2.0.0bN` and each may contain breaking changes. **v1.x is the only stable release line and remains recommended for production**; it lives on the `v1.x` branch. `pip`/`uv` won't select a pre-release unless you explicitly request one. If your package depends on `mcp`, add a `<2` upper bound (for example `mcp>=1.27,<2`) before the stable release lands. Stable v2 is targeted for 2026-07-27 alongside the 2026-07-28 spec release. ## Characteristics - **Requirements:** Python 3.10+. - **Convenience layer:** `MCPServer` — decorators `@mcp.tool()` and `@mcp.resource("uri://{param}")` derive JSON Schema straight from type hints and docstrings. No JSON Schema, request parsing, validation, or protocol handling written by hand. - **Client:** the same package ships a full `Client` that connects to a URL, a stdio subprocess, a custom transport, or (for tests) directly to a server object **in memory with no transport at all**. - **Escape hatches:** a low-level `Server` class (hand-written schemas, `on_*` handlers, custom JSON-RPC methods), plus middleware, pagination, extensions, and MCP Apps support live under the SDK's `advanced/` docs. "If you're not sure whether you need this section, you don't." - **Docs:** (Get started, What's new in v2, API reference, migration guide). - **License:** MIT. ## How to Use **Installation** (pin the pre-release while v2 is in pre-release; an unpinned install resolves to stable v1.x, which the v2 README does not describe): ```bash uv add "mcp[cli]==2.0.0b1" # or: pip install "mcp[cli]==2.0.0b1" ``` Use `uv run --with "mcp==2.0.0b1"` for one-off commands. Check [PyPI](https://pypi.org/project/mcp/#history) for the newest pre-release. **A server in 15 lines** — create a `server.py`: ```python from mcp.server import MCPServer mcp = MCPServer("Demo") @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers.""" return a + b @mcp.resource("greeting://{name}") def greeting(name: str) -> str: """Greet someone by name.""" return f"Hello, {name}!" ``` That is a complete MCP server: one tool, one templated resource. `a: int, b: int` *is* the schema — no JSON Schema, no request parsing, no validation code. Open it in the [[entities/mcp-inspector|MCP Inspector]]: ```bash uv run mcp dev server.py ``` **A client in 10 lines** — the same package is a full MCP client: ```python import asyncio from mcp import Client from server import mcp async def main() -> None: async with Client(mcp) as client: result = await client.call_tool("add", {"a": 1, "b": 2}) print(result.structured_content) # {'result': 3} asyncio.run(main()) ``` Swap `mcp` for `"http://localhost:8000/mcp"` and the exact same code talks to a remote server over Streamable HTTP. A `Client` is one object with one lifecycle: construct it, enter `async with` (which connects and negotiates), call typed `async` methods (`list_tools()`, `call_tool()`, `read_resource()`, `get_prompt()`). It cannot be reused after the block ends. A raising tool comes back as an ordinary result with `is_error=True`, not a Python exception. ## Related Entities - [[entities/typescript-sdk]] — the sibling official SDK for Node.js / Bun / Deno - [[entities/mcp-inspector]] — the debugging UI launched via `uv run mcp dev server.py` - [[entities/publishing-to-registry]] — publish a Python (PyPI) server to the registry - [[entities/mcp-registry]] — where published server metadata lives (PyPI package type) - [[concepts/building-a-server]] · [[concepts/building-a-client]] — the protocol-level concepts the SDK implements - [[syntheses/transport-decision]] — stdio vs. Streamable HTTP for a Python server --- title: "MCP TypeScript SDK" type: entity tags: [sdk, typescript, nodejs, server, client] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/github_doc-readme-md-2.md"] source_url: "https://github.com/modelcontextprotocol/typescript-sdk" confidence: high --- ## Overview The **MCP TypeScript SDK** is the official TypeScript implementation of the [[concepts/what-is-mcp|Model Context Protocol]]. It runs on **Node.js, Bun, and Deno** and ships MCP **server** libraries ([[concepts/tools|tools]]/[[concepts/resources|resources]]/[[concepts/prompts|prompts]], Streamable HTTP, stdio, auth helpers), MCP **client** libraries (transports, high-level helpers, OAuth helpers), optional **middleware packages** for specific runtimes/frameworks, and runnable examples. **Version note (as of 2026-07):** `main` is **v2 of the SDK, now in beta** (`@modelcontextprotocol/server`, `@modelcontextprotocol/client`), implementing the 2026-07-28 MCP spec. **v1.x remains the supported release for production** and keeps receiving bug fixes and security updates for at least 6 months after v2 ships. A stable v2 release is expected alongside the full 2026-07-28 spec release on July 28, 2026. v2 docs: ; v1 docs: . ## Characteristics - **Split packages (v2 monorepo):** `@modelcontextprotocol/server` (build servers) and `@modelcontextprotocol/client` (build clients). - **Schemas via Standard Schema:** tool and prompt schemas use [Standard Schema](https://standardschema.dev/) — bring Zod v4, Valibot, ArkType, or any compatible library. - **Optional middleware packages** (thin adapters that wire MCP into a runtime/framework — no new MCP functionality or business logic): - `@modelcontextprotocol/node` — Node.js Streamable HTTP transport wrapper for `IncomingMessage` / `ServerResponse` - `@modelcontextprotocol/express` — Express helpers (app defaults + Host header validation) - `@modelcontextprotocol/hono` — Hono helpers (app defaults + JSON body parsing hook + Host header validation) - **License:** Apache 2.0 for new contributions, existing code under MIT. ## How to Use **Installation — server:** ```bash npm install @modelcontextprotocol/server # or bun add @modelcontextprotocol/server # or deno add npm:@modelcontextprotocol/server ``` **Installation — client:** ```bash npm install @modelcontextprotocol/client # or bun add @modelcontextprotocol/client # or deno add npm:@modelcontextprotocol/client ``` **Optional middleware packages:** ```bash # Node.js HTTP (IncomingMessage/ServerResponse) Streamable HTTP transport: npm install @modelcontextprotocol/node # Express integration: npm install @modelcontextprotocol/express express # Hono integration: npm install @modelcontextprotocol/hono hono ``` **A minimal server over stdio** — exposes a single `greet` tool: ```typescript 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 someone by name', inputSchema: z.object({ name: z.string() }) }, async ({ name }) => ({ content: [{ type: 'text', text: `Hello, ${name}!` }] }) ); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); } main(); ``` The pattern is: construct an `McpServer` with a name/version, `registerTool(name, { description, inputSchema }, handler)`, then `server.connect(transport)`. For a remote server, connect a Streamable HTTP transport instead of `StdioServerTransport`. Step-by-step tutorials ("Build your first server" — a stdio weather-alert server; "Build your first client") live in the SDK's `docs/get-started/` and the [v2 documentation site](https://ts.sdk.modelcontextprotocol.io/v2/). > Note: the older `@modelcontextprotocol/sdk` package (single package, e.g. `@modelcontextprotocol/sdk/server/mcp.js`) is the v1 import path still seen in many examples such as the [[entities/mcp-apps|MCP Apps]] build guide. ## Related Entities - [[entities/python-sdk]] — the sibling official SDK for Python - [[entities/mcp-inspector]] — inspect a locally-developed server: `npx @modelcontextprotocol/inspector node path/to/server/index.js` - [[entities/mcp-apps]] — interactive UI apps built on the TypeScript server + `ext-apps` packages - [[entities/publishing-to-registry]] — publish a TypeScript (npm) server to the registry - [[concepts/building-a-server]] · [[concepts/building-a-client]] — the protocol concepts the SDK implements - [[syntheses/transport-decision]] — stdio vs. Streamable HTTP for a TypeScript server --- title: "Activity Log" type: log --- # Activity Log Append-only record of all wiki changes. ## Format Each entry follows this format: ``` ### YYYY-MM-DD HH:MM — [Action Type] - **Source/Trigger**: what initiated the action - **Pages created**: list of new pages - **Pages updated**: list of updated pages - **Notes**: any contradictions flagged, decisions made ``` --- ### 2026-04-08 00:00 — Setup - **Source/Trigger**: Repository initialized - **Pages created**: index.md, log.md, dashboard.md, analytics.md, flashcards.md - **Pages updated**: none - **Notes**: Empty knowledge base ready for first source ingestion --- title: "Local vs Remote MCP Servers" type: synthesis tags: [decision, deployment, local-servers, remote-servers, authorization] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-connect-to-local-mcp-servers.md", "raw/llms_txt_doc-connect-to-remote-mcp-servers.md", "raw/llms_txt_doc-authorization.md"] confidence: high --- ## Comparison An MCP server can run locally (a program on your own machine, launched by the client over [[concepts/transports|stdio]]) or remotely (internet-hosted, reached over Streamable HTTP). They expose the same primitives - [[concepts/tools|tools]], [[concepts/resources|resources]], [[concepts/prompts|prompts]] - but differ sharply in installation, reach, auth, and who bears the operational burden. | Dimension | Local server | Remote server | | --- | --- | --- | | Where it runs | On your machine, as a subprocess of the client | Internet-hosted, independent service | | Transport | [[concepts/transports|stdio]] | Streamable HTTP (or SSE) | | Install / connect | Edit a client config (e.g. `claude_desktop_config.json`) with `command` + `args`; restart the client | Add a Custom Connector URL in the client UI; authenticate | | Reach | This device only; reinstall per machine | Any MCP client with internet access; no per-device install | | Auth | Credentials from the environment (env vars); no OAuth | Usually OAuth 2.1 (or API keys); MCP authorization spec applies | | Access | Local resources (filesystem, local processes) with your user permissions | Server-side services, APIs, databases; server-side processing | | Discovery | Manual config entry; browse server catalogs | Custom Connector URL from provider; select tools/resources/prompts in UI | | Who operates it | You (the user) | The server developer / provider | | Registry install method | `packages` in `server.json` (npm/PyPI/OCI/etc.) | `remotes` in `server.json` (a public URL) | ## Analysis Local means direct machine access; remote means accessible from anywhere. A local server's whole point is reaching things on your computer. The Filesystem Server quickstart configures Claude Desktop to auto-launch `npx -y @modelcontextprotocol/server-filesystem ` via `mcpServers` in `claude_desktop_config.json`; the server then runs with your user account's permissions, so the docs warn to grant only directories you are comfortable exposing, and every action still requires explicit user approval. A remote server trades that direct access for accessibility: it is hosted once and available from any client with a connection, no per-device install - ideal for web-based hosts, shared teams, and anything needing server-side processing or centralized credentials. Installation and discovery friction is inverted. Local servers need per-machine setup (edit config, ensure Node.js/`npx` present, restart, debug `claude_desktop_config.json` syntax and absolute paths). Remote servers need essentially nothing on the client beyond pasting a URL and completing auth in the UI, after which the server's resources and prompts appear in the attachment menu and tools can be enabled per-connector - but the provider must build, host, secure, and operate the service. Discovery follows the same split: local servers are found by browsing catalogs and hand-adding config; remote servers are added as a Custom Connector from a URL the provider supplies. Authorization is the deepest split. For stdio/local, the authorization spec explicitly SHOULD NOT be used - servers retrieve credentials from the environment. For HTTP/remote, MCP defines an OAuth-2.1-based flow: the MCP server acts as an OAuth resource server, the client as an OAuth client, and a separate authorization server issues tokens. Concretely, remote servers MUST implement OAuth 2.0 Protected Resource Metadata (RFC 9728) for authorization server discovery; clients MUST use PKCE (`S256`), send the RFC 8707 `resource` parameter on every authorization and token request, and put the token in an `Authorization: Bearer` header on every HTTP request. The single most important security rule: a server MUST validate that a token was issued specifically for it (audience binding) and MUST NOT pass a client's token through to an upstream API (token passthrough is forbidden - it causes the "confused deputy" problem). None of this exists for local stdio servers, where trust is simply "you launched the binary." Distribution differs in the same `server.json`. In the [[entities/mcp-registry|MCP Registry]], a local server is described by a `packages` entry (npm/PyPI/NuGet/OCI/MCPB) that a host installs and runs; a remote server is described by a `remotes` entry pointing at a public HTTPS URL. The two can coexist in one `server.json` so a host can choose - see [[entities/publishing-to-registry]]. ## Recommendations - Choose a local server if it must touch local resources (files, local dev tools, machine state), you want no hosting cost or auth infrastructure, and single-machine/single-user use is fine. Accept the trade-offs: per-device install, full user-level permissions on the machine, and env-var credentials. Ship it as a `packages` entry; connect via `command`/`args` over stdio. - Choose a remote server if you need access from any device or web host, multi-user/team reach, server-side processing or centralized secrets, or you are a provider distributing a hosted integration. Accept the trade-offs: you operate the service and MUST implement OAuth 2.1 correctly (Protected Resource Metadata, PKCE, `resource` parameter, audience validation, no token passthrough) plus the HTTP transport hardening (`Origin` checks, secure sessions). - Offer both when practical: put `remotes` and `packages` in one `server.json` and let the host pick the preferred install method. Regardless of location, keep a human in the loop - local clients prompt per action; remote connectors let users configure per-tool permissions. The local/remote decision usually determines the transport - see [[syntheses/transport-decision]] for stdio vs Streamable HTTP in detail. ## Pages Compared - [[concepts/connecting-to-servers]] - [[concepts/authorization]] - [[concepts/transports]] - [[syntheses/transport-decision]] - [[concepts/building-a-server]] - building the server you will run locally or host - [[entities/mcp-registry]] and [[entities/publishing-to-registry]] - `packages` vs `remotes` distribution - [[concepts/security-best-practices]] - token passthrough, confused deputy, audience binding - [[concepts/what-is-mcp]], [[entities/python-sdk]], [[entities/typescript-sdk]] --- title: "Server Feature Picker: Resources vs Tools vs Prompts (and Sampling/Elicitation)" type: synthesis tags: [decision, server-features, tools, resources, prompts, sampling, elicitation] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-resources.md", "raw/llms_txt_doc-tools.md", "raw/llms_txt_doc-prompts.md", "raw/llms_txt_doc-sampling.md", "raw/llms_txt_doc-elicitation.md"] confidence: high --- ## Comparison MCP gives a server five ways to interact with a host, split by WHO CONTROLS the interaction. Getting this right is the single most common server-design decision. The three server primitives (resources, tools, prompts) are surfaced by the server; the two nested client capabilities (sampling, elicitation) let a server, mid-operation, reach back into the client. | Primitive | Who controls it | Direction | What it's for | Declares capability | Core methods | | --- | --- | --- | --- | --- | --- | | [[concepts/resources|Resources]] | Application-driven (host decides how to include context) | Server -> model, read-only | Expose data/context: files, DB schemas, docs, app state. Identified by URI. | `resources` (optional `subscribe`, `listChanged`) | `resources/list`, `resources/read`, `resources/templates/list`, `resources/subscribe` | | [[concepts/tools|Tools]] | Model-controlled (model discovers and invokes) | Model -> external system, action | Do or compute something with side effects or fresh data: call an API, run a query, transform input. | `tools` (optional `listChanged`) | `tools/list`, `tools/call` | | [[concepts/prompts|Prompts]] | User-controlled (user explicitly selects) | User -> model, template | Reusable, parameterized message templates, typically surfaced as slash commands. | `prompts` (optional `listChanged`) | `prompts/list`, `prompts/get` | | [[concepts/sampling|Sampling]] | Server requests, client/user approves | Server -> client's LLM | Let the server ask the client's model for a completion - agentic behavior nested in a server feature, no server API keys. | client declares `sampling` (`tools`, `context`) | `sampling/createMessage` | | [[concepts/elicitation|Elicitation]] | Server requests, user provides | Server -> user (via client) | Ask the user for structured input (form mode) or send them to a URL for sensitive/OAuth flows (URL mode). | client declares `elicitation` (`form`, `url`) | `elicitation/create` | ## Analysis The control axis decides most cases. If the model should decide when to trigger it, use a tool. If the user should explicitly pick it, use a prompt. If the host application should decide how or whether to pull it into context, use a resource. Resources are deliberately passive: they are "application-driven," meaning a host might show them in a picker, let the user search them, or auto-include them by heuristic - the server just makes them available at a URI. Read vs act is the tool/resource line. A resource is read-only context identified by a URI (`resources/read` never changes state). A tool does something and can have side effects. When a tool needs to hand back a large blob, it does not duplicate the resource system - it returns a `resource_link` or an embedded `resource` in its result. So "expose the contents of a file" is a resource; "search the filesystem and modify files" is a tool. Both can be templated: resources via URI templates (`file:///{path}`), tools via their `inputSchema`. Human-in-the-loop scales with power. Resources are safe reads. Tools SHOULD have a human able to deny each invocation, and clients should show tool inputs before calling. Sampling and elicitation both explicitly nest a human approval step: sampling requests should be reviewable and editable before they hit the model; elicitation must let users decline or cancel. The more the primitive can act on the user's behalf, the more the spec insists on consent. Sampling and elicitation invert the arrow. Normally the client drives the server. These two let the server, in the middle of handling a tool call or resource read, ask the client for something: sampling asks the client's LLM to generate (enabling agentic loops and tool use inside sampling, with `toolChoice` modes `auto`/`required`/`none`); elicitation asks the user for data. They only work if the client declared the matching capability - a server must never send a sampling or elicitation request to a client that did not advertise support (and must not send a mode the client did not declare). Form vs URL elicitation is a security boundary, not a convenience. Form mode collects flat, primitive structured data (string/number/boolean/enum, with optional formats like `email`/`uri`/`date`) directly through the client - and servers MUST NOT use it to request passwords, API keys, tokens, or payment credentials. Anything sensitive MUST use URL mode, which sends the user out-of-band to a trusted HTTPS page so secrets never transit the client or LLM context. URL mode is also how a server does third-party OAuth (acting as an OAuth client to another service), which is distinct from [[concepts/authorization|MCP authorization]] of the client to the server. ## Recommendations Pick the primitive by matching the need to the controller: - Pick a [[concepts/resources|Resource]] if you are exposing read-only data/context the host may want to include - a file, a schema, a document, live app state - and you want the application (or user) to decide when it enters context. Add `subscribe`/`listChanged` if the data changes and clients should be notified. Use a resource template when the resource is parameterized by a URI. - Pick a [[concepts/tools|Tool]] if the model should be able to trigger an action or computation on its own - side effects, fresh data, transforms. Add an `outputSchema` when code or the model benefits from typed results. Return `resource_link`/embedded resources for large payloads. Report recoverable failures as a result with `isError: true` (the model can self-correct), not a protocol error. - Pick a [[concepts/prompts|Prompt]] if you want to give the user a reusable, parameterized template/workflow to invoke explicitly (e.g. a `/code_review` slash command). Prompts render to messages the host hands straight to the model. - Add [[concepts/sampling|Sampling]] if your server needs the model to reason while handling a request (summarize, decide, run an agentic tool loop) and you want to use the client's model/credentials rather than your own API key. - Add [[concepts/elicitation|Elicitation]] if you must gather input mid-operation: use form mode for non-sensitive structured fields; use URL mode for credentials, payments, or third-party OAuth - never form mode for secrets. Common combination: a tool that, mid-execution, uses elicitation to collect a missing parameter (form) or connect a third-party account (URL), and sampling to have the client's model interpret an intermediate result, returning a `resource_link` to any large output. See also the UI-rendering combination in [[entities/mcp-apps]], which pairs a tool with a resource, and [[concepts/building-a-server|building a server]] for assembly. ## Pages Compared - [[concepts/resources]] - [[concepts/tools]] - [[concepts/prompts]] - [[concepts/sampling]] - [[concepts/elicitation]] - [[concepts/building-a-server]] - how these are assembled into a server - [[concepts/building-a-client]] - the client side that declares sampling/elicitation - [[concepts/authorization]] - MCP client-server auth, distinct from URL-mode elicitation - [[concepts/what-is-mcp]], [[concepts/architecture]], [[concepts/roots]], [[concepts/security-best-practices]] - [[entities/mcp-apps]], [[entities/python-sdk]], [[entities/typescript-sdk]], [[entities/mcp-inspector]] --- title: "Transport Decision: stdio vs Streamable HTTP" type: synthesis tags: [decision, transports, stdio, streamable-http, security] created: 2026-07-07 updated: 2026-07-07 sources: ["raw/llms_txt_doc-transports.md", "raw/llms_txt_doc-connect-to-local-mcp-servers.md", "raw/llms_txt_doc-connect-to-remote-mcp-servers.md"] confidence: high --- ## Comparison MCP defines two standard transports for client-server communication (both carry newline-delimited, UTF-8, JSON-RPC messages): stdio and Streamable HTTP (which replaced the older HTTP+SSE transport from protocol 2024-11-05). Custom transports are also allowed. Clients SHOULD support stdio whenever possible. | Dimension | stdio | Streamable HTTP | | --- | --- | --- | | How it runs | Client launches the server as a subprocess; JSON-RPC over the process's `stdin`/`stdout` (logs may go to `stderr`) | Server is an independent process exposing a single HTTP endpoint (e.g. `https://example.com/mcp`) supporting POST and GET | | Location | Same machine as the client (local) | Local or remote / internet-hosted | | Concurrency | One subprocess per client connection | One server handles multiple client connections | | Streaming | Inherent bidirectional pipe | Optional Server-Sent Events (SSE) for multi-message/server-initiated streams; can also return a single JSON response | | Sessions | Implicit (process lifetime) | Optional `MCP-Session-Id` header assigned at init; supports resumable streams via `Last-Event-ID` | | Auth | Credentials from the environment ([[concepts/authorization|MCP auth spec]] SHOULD NOT be used) | OAuth 2.1 per the authorization spec; `MCP-Protocol-Version` header on every request | | Key risks | Only as trusted as the launched binary; runs with your user permissions | DNS-rebinding, `Origin` spoofing, session hijacking, exposure to the network | | Typical setup | `command`/`args` in a client config (e.g. `claude_desktop_config.json`) | A URL added as a custom connector | ## Analysis stdio is the local default; Streamable HTTP is the networked one. With stdio the client is the process manager - it launches the server, writes requests to `stdin`, reads responses from `stdout`, and terminates the subprocess when done. That model is simple, has no ports or network surface, and is why the spec says clients should support stdio whenever possible. Streamable HTTP instead treats the server as a long-lived independent service that many clients can reach over HTTP, which is what you need for anything hosted or shared. Streaming and server-initiated messages are Streamable HTTP's reason to exist beyond "it's remote." Every client-server message is an HTTP POST. For a request, the server may answer with a single `application/json` response or upgrade to `text/event-stream` (SSE) to stream multiple messages, send server-to-client requests/notifications before the final response, and support resumability. A client may also issue a GET to open an SSE stream for unsolicited server messages. stdio gets this bidirectionality for free from the pipe; over HTTP it takes SSE. Security is where the two diverge most sharply. stdio's risk is trust in the binary you launch - it runs with your user's permissions and can do anything you can (the local-server filesystem quickstart warns to only grant directory access you are comfortable with). Streamable HTTP's risks are network-shaped and the spec mandates concrete mitigations: servers MUST validate the `Origin` header (respond `403` if invalid) to prevent DNS-rebinding attacks, SHOULD bind only to `127.0.0.1` when running locally (never `0.0.0.0`), and SHOULD implement proper authentication. Session IDs must be cryptographically secure and handled to resist hijacking. Without these, a remote website could reach a locally-running HTTP MCP server. Note the "local HTTP" middle case. Streamable HTTP is not only for remote servers - you can run it on localhost (e.g. an [[entities/mcp-apps|MCP App]] server on `http://localhost:3001/mcp`, then tunnel it). When you do, the DNS-rebinding/`Origin`/localhost-binding rules above are exactly the protections that matter. Backwards compatibility costs complexity. To support pre-2025 clients/servers a server can host both the old SSE+POST endpoints and the new MCP endpoint, and a client can probe (POST an `InitializeRequest`; on `400/404/405`, fall back to the old GET-opens-SSE flow). Prefer the plain Streamable HTTP path unless you must interoperate with the deprecated transport. ## Recommendations - Pick stdio if the server runs on the same machine as the client, is launched and owned by that client, and needs local resources (files, local tools). It is the simplest, port-free, lowest-attack-surface option and the spec's default preference. Credentials come from the environment; do not layer the OAuth authorization spec on stdio. Configure via `command`/`args` (see [[concepts/connecting-to-servers|connecting to servers]]). - Pick Streamable HTTP if the server is remote/hosted, must serve multiple clients, needs server-initiated messages or streaming, or should be reachable from web-based hosts. Accept the operational cost: OAuth 2.1 auth, `Origin` validation, localhost-only binding in dev, secure session handling, and the `MCP-Protocol-Version` header. - Running HTTP locally? Treat it as Streamable HTTP for security purposes - bind to `127.0.0.1`, validate `Origin`, and do not expose it to `0.0.0.0`. - Need a non-standard channel? Implement a custom transport, but preserve the JSON-RPC message format and lifecycle and document your connection/exchange pattern. This choice is tightly coupled to where the server lives - see [[syntheses/local-vs-remote-servers]] for the deployment/auth trade-offs that usually decide the transport for you. ## Pages Compared - [[concepts/transports]] - [[concepts/connecting-to-servers]] - [[syntheses/local-vs-remote-servers]] - [[concepts/authorization]] - required for HTTP transports, out of scope for stdio - [[concepts/lifecycle]] - initialization and version negotiation that seeds sessions - [[concepts/security-best-practices]] - DNS rebinding, session hijacking, Origin validation - [[entities/mcp-apps]], [[entities/mcp-inspector]], [[entities/python-sdk]], [[entities/typescript-sdk]]