Files
Skald-Circle/docs/mcp/specs/2025-11-25.md
T
2026-07-10 15:02:09 +01:00

17 KiB

MCP Specification — 2025-11-25 (Latest Stable)

Status: Latest Stable (current Latest release) Released: 2025-11-25 · repo tags 2025-11-25 (stable), 2025-11-25-RC (pre-release) Spec site: https://modelcontextprotocol.io/specification/2025-11-25 Authoritative schema: schema/2025-11-25/schema.ts

This is the current stable revision of the Model Context Protocol. It keeps the stateful, JSON-RPC 2.0 core of 2025-06-18 and refines authorization (adding OpenID Connect Discovery and OAuth Client ID metadata documents), introduces optional icons metadata across server primitives, URL-mode elicitation, incremental scope consent (step-up authorization), tool-calling in sampling, and ships an experimental Tasks mechanism for long-running, pollable operations.

At a glance

  • Protocol style: stateful connections
  • Capability negotiation: connection-level (initialize)
  • Transports: stdio; Streamable HTTP
  • Server features: Resources, Prompts, Tools, Logging
  • Client features: Sampling, Roots, Elicitation
  • Authorization: OAuth 2.1 + Resource Indicators (RFC 8707) + OIDC Discovery + Protected Resource Metadata (RFC 9728) + Client ID metadata documents + incremental scope consent
  • Experimental: Tasks

Architecture

Client-host-server topology built on JSON-RPC, focused on context exchange and sampling coordination.

  • Host: creates/manages multiple clients, enforces consent and security policy, aggregates context. Each client has a 1:1 relationship with one server and maintains isolation between servers.
  • Client: establishes one stateful session per server, negotiates capabilities, routes messages, owns subscriptions/notifications.
  • Server: exposes resources/tools/prompts, may request sampling/roots/elicitation through client interfaces; can be a local process or remote service.

Design principles: servers should be easy to build, highly composable, must not read the whole conversation or "see into" other servers, and features can be added progressively. Capability negotiation is the contract: server features (resources, prompts, tools, logging) and client features (sampling, roots, elicitation, tasks) must be advertised in capabilities to be usable.

Base Protocol

Messages

All messages MUST be JSON-RPC 2.0, UTF-8 encoded. Three kinds:

  • Requestsid (string|integer) REQUIRED; MUST NOT be null; the requestor MUST NOT reuse an id within a session.
  • Responsesresult (any object) on success; error (code integer + message) on failure. The id MUST match the originating request (except when the request id was unreadable due to malformation).
  • Notifications — one-way; MUST NOT carry an id; the receiver MUST NOT respond.

The _meta field is reserved for protocol-level and extension metadata; certain keys are reserved by MCP and implementers MUST NOT assume meaning for reserved keys. JSON Schema dialect: schemas without an explicit $schema default to JSON Schema 2020-12; implementations MUST support at least 2020-12 and SHOULD document any additional dialects. The icons property is a standardized optional visual-identifier array (src, mimeType, sizes) usable on implementations/resources/tools/prompts; icon payloads MAY contain executable content (e.g. scripted SVG) so consumers MUST fetch them without credentials and treat them as untrusted.

Lifecycle

Three phases: Initialization → Operation → Shutdown.

  1. Client sends initialize with its protocolVersion (this SHOULD be the latest the client supports), client capabilities, and clientInfo.
  2. Server responds with the negotiated protocolVersion, its capabilities, serverInfo (name/title/version/description/icons/websiteUrl), and optional instructions.
  3. Client sends an notifications/initialized notification; only then does normal operation begin. Before initialize is answered the client SHOULD NOT send non-ping requests; before initialized the server SHOULD NOT send non-ping/non-logging requests.

Version negotiation: if the server supports the requested version it echoes it; otherwise it returns the latest version it supports. If the client cannot accept that version it SHOULD disconnect. Over HTTP the client MUST send MCP-Protocol-Version: <version> on every subsequent request.

Transports

  • stdio — client launches the server as a subprocess; newline-delimited JSON-RPC on stdin/stdout; messages MUST NOT contain embedded newlines; stdout is reserved exclusively for valid MCP messages; stderr is for optional logging. Clients SHOULD support stdio whenever possible.
  • Streamable HTTP — the server exposes a single MCP endpoint supporting POST and GET. The client POSTs each JSON-RPC message with Accept: application/json, text/event-stream; the server answers synchronously (application/json) or opens an SSE stream. Session management: the server MAY assign an Mcp-Session-Id on the InitializeResult response; once issued, the client MUST send that header on subsequent requests and the server MAY reject mismatches with 404. Resumability: servers MAY attach SSE ids; clients resume after disconnect via HTTP GET with Last-Event-ID. Servers MUST validate the Origin header (403 on mismatch) and SHOULD bind to localhost locally to prevent DNS-rebinding. Replaces the deprecated HTTP+SSE transport from 2024-11-05.

Authorization

Authorization is OPTIONAL. HTTP-based implementations SHOULD conform; stdio SHOULD NOT (use environment credentials instead). The model: the MCP server is an OAuth 2.1 resource server; the MCP client is the OAuth 2.1 client; a separate authorization server issues tokens.

  • Built on OAuth 2.1 (draft-ietf-oauth-v2-1-13) with PKCE and Resource Indicators (RFC 8707).
  • Protected Resource Metadata (RFC 9728) — MCP servers MUST implement it; clients MUST use it for authorization-server discovery (via WWW-Authenticate: resource_metadata=… on 401, or a .well-known/oauth-protected-resource URI). Servers SHOULD advertise required scope in the 401 challenge.
  • Authorization-server metadata — the authorization server MUST expose either OAuth 2.0 Authorization Server Metadata (RFC 8414) or OpenID Connect Discovery 1.0 (.well-known/openid-configuration); clients MUST support both, trying RFC 8414 first.
  • OAuth Client ID Metadata Documents (draft-ietf-oauth-client-id-metadata-document-00) — clients/servers SHOULD support this public-client identification mechanism; RFC 7591 Dynamic Client Registration MAY be supported.
  • Incremental scope consent — the step-up / scope-challenge flow: clients start with the minimal scopes_supported (or the 401 scope) and request additional scopes only when the server returns an insufficient-scope error (WWW-Authenticate with a narrowed challenge), satisfying least-privilege progressively.

Versioning

There is no dedicated versioning page in this revision; protocol-version agreement is defined within Lifecycle (the initialize handshake and the MCP-Protocol-Version header). The version string for this revision is 2025-11-25. The spec site's /basic/versioning URL does not resolve for 2025-11-25.

Server Features

Resources

Application-driven context exposed by URI. Capability resources with optional subscribe and listChanged. Operations: resources/list (paginated), resources/read, resources/templates/list (RFC 6570 URI templates, auto-completable). Resources carry uri, name, optional title/description/mimeType/icons/annotations (audience, priority, lastModified). Changes are signalled via notifications/resources/*; resource links let any text content embed typed links to other resources through their URI. Clients MUST obtain user consent before exposing resource data.

Prompts

User-controlled templates (e.g. slash commands). Capability prompts with optional listChanged. Operations: prompts/list (paginated), prompts/get (with arguments). A prompt has name, optional title/description/arguments/icons; messages are role + typed content (text/image/audio/embedded-resource), each supporting annotations.

Tools

Model-controlled functions. Capability tools with optional listChanged. Operations: tools/list (paginated) and tools/call. A tool defines name, optional title/description/icons, inputSchema (defaults to JSON Schema 2020-12), optional outputSchema, and annotations (e.g. readOnlyHint, destructiveHint, idempotentHint, openWorldHint). Structured output: when outputSchema is present, the server MUST return conforming results as a JSON object in structuredContent, and SHOULD also mirror it in a TextContent block for backwards compatibility; clients SHOULD validate against the schema. Results return content[], an isError flag, and the optional structuredContent. A human SHOULD remain in the loop to authorize invocations.

Utilities / Logging

Cross-cutting utilities: pagination (cursor/nextCursor on list ops), completion (completion/complete for argument auto-complete), ping (ping), cancellation (notifications/cancelled), progress (notifications/progress), and logging — capability logging; clients configure level via logging/setLevel, servers emit notifications/message with severity, logger name, and structured data.

Client Features

Sampling

Server-initiated LLM completions via sampling/createMessage. Clients MUST declare sampling; human-in-the-loop review of the prompt and result is RECOMMENDED. Requests carry messages, optional systemPrompt, modelPreferences (hints, intelligencePriority/speedPriority), maxTokens, and (when the client advertises sampling.tools) a tools array plus optional toolChoice. Tool-calling support: the client's LLM may emit tool_use; the server executes the tool and re-issues sampling/createMessage with the tool results, looping until stopReason: "endTurn". The legacy includeContext: "thisServer"|"allServers" values (gated behind sampling.context) are soft-deprecated.

Roots

Server-initiated discovery of filesystem boundaries. Capability roots (optional listChanged). Server sends roots/list; client returns uri (currently MUST be a file:// URI) plus optional name. Clients emit notifications/roots/list_changed when the set changes. Clients MUST validate root URIs against path traversal and SHOULD prompt for consent before exposing them.

Elicitation

Server-initiated requests for user information via elicitation/create. Capability elicitation with sub-modes form and url (an empty object is equivalent to form-only; at least one mode MUST be supported). Two modes:

  • Form mode — in-band structured input. requestedSchema is restricted to a flat object of primitive properties (string/number/integer/boolean/enum, including oneOf/multi-select arrays); formats email, uri, date, date-time. Response action is accept (with content), decline, or cancel.
  • URL mode (new in 2025-11-25) — out-of-band interaction for sensitive data (secrets, OAuth, payments) that must not transit the client. Parameters: mode: "url", url, elicitationId, message. The client only collects consent and opens the URL; the response is action: "accept" with no content. Servers MAY fire notifications/elicitation/complete and MAY return error -32042 (URLElicitationRequiredError) carrying required elicitations. Servers MUST use URL mode (never form mode) for passwords/API keys/tokens/credentials.

Privacy: clients MUST show which server is asking, provide clear decline/cancel controls, let users review form responses before sending, and never log/retain secrets.

Experimental: Tasks

Introduced in 2025-11-25 as experimental. Tasks are durable state machines that wrap a request for pollable, deferred-result execution (expensive computation, batch jobs, external job APIs). Either party may be a requestor or receiver. A task is created by adding a task field (with optional ttl) to an augmentable request; the receiver returns a CreateTaskResult with a taskId, status (workingcompleted/failed/cancelled, plus input_required), pollInterval, and timestamps. The real result is fetched later via tasks/result; status via tasks/get, optional notifications/tasks/status, listing via tasks/list, termination via tasks/cancel. Capability tasks is structured per request category (e.g. tasks.requests.tools.call server-side; tasks.requests.sampling.createMessage / tasks.requests.elicitation.create client-side), with tool-level negotiation through execution.taskSupport (required/optional/forbidden). The design may be formalized or modified in future revisions.

Changes vs 2025-06-18

  • OpenID Connect Discovery 1.0 added as a first-class authorization-server metadata mechanism (clients must support it alongside RFC 8414).
  • Icons metadata — optional icons[] on implementations, resources, tools, and prompts.
  • Incremental scope consent — step-up authorization via scope challenges (request additional scopes only on insufficient-scope errors).
  • URL-mode elicitation (mode: "url", URLElicitationRequiredError -32042, notifications/elicitation/complete) for sensitive out-of-band interactions.
  • Sampling tool-callingsampling.tools capability; servers may pass tools/toolChoice and run a multi-turn tool loop.
  • OAuth Client ID metadata documents (draft-ietf-oauth-client-id-metadata-document-00) for public-client identification.
  • Experimental Tasks — durable, pollable, deferred-result request augmentation.
  • Unchanged: stateful JSON-RPC 2.0 core (batching already removed in 2025-06-18), connection-level capability negotiation, stdio + Streamable HTTP transports, structured tool output (outputSchema/structuredContent, from 2025-06-18), elicitation form mode, resource links.

Skald relevance

This is the revision Skald's MCP client targets. The client lives in crates/mcp-client/ (stdio + Streamable HTTP, with an elicitation integration test); runtime connection management is src/core/mcp/mod.rs (McpManager); server-initiated elicitation/create is handled by src/core/elicitation/mod.rs (ElicitationManager + bridge), surfaced in the unified Inbox, with secrets never logged or persisted. Non-text tool-result content (image/audio/resource/resource_link) is now preserved rather than dropped: it is persisted under data/mcp_media/ and surfaced as a /api/mcp-media/ URL in a markdown result (see ../../mcp.mdMedia tool results).

Cancellation (notifications/cancelled) is implemented: an abandoned tools/call (a /stop that drops the work future, or the 120 s timeout) now tells the server to stop via a per-transport drop-guard, instead of leaving it working on abandoned output. Tasks are polled synchronously (block-and-poll): call_tool opts a task-capable tool in with the task field, then poll_task polls tasks/get until terminal and fetches the real result via tasks/result — so a task-mode call no longer hits the 120 s wall — sending tasks/cancel cooperatively if the call is dropped. Both are documented in ../../mcp.mdCancellation & Tasks. The block-and-poll variant holds the session for the task's duration and doesn't survive a self-restart; the detached/durable poller (DB-persisted tasks + background delivery via inject_async_result/resume_turn) is the tracked follow-up. Still unimplemented from this revision: sampling, roots, URL-mode elicitation, mid-task input_required, progress/completion/logging utilities, and OAuth authorization (HTTP transport).

References