Files
2026-07-10 15:02:09 +01:00

115 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MCP Specification — 2026-07-28 Draft (RC)
> **Status:** Draft / Release Candidate (pre-release). Subject to change — not final.
> **Tag:** `2026-07-28-RC` · rendered at `/specification/draft`
> **Spec site:** https://modelcontextprotocol.io/specification/draft
> **Authoritative schema:** [schema/draft/schema.ts](https://github.com/modelcontextprotocol/specification/blob/main/schema/draft/schema.ts)
The `2026-07-28` draft is a **foundational redesign** of the Model Context Protocol, not an incremental revision. It moves from the prior stateful-connection model to a **stateless base protocol with self-contained requests**, replaces connection-level capability negotiation (the `initialize` handshake) with **per-request capability negotiation**, and introduces a formal **extensions framework** for opt-in modular functionality. Several older client/server features are deprecated under a new feature-lifecycle policy. This is the direction future Skald MCP work should anticipate; the per-request shift and the Tasks extension are the most impactful changes to plan for.
## At a glance
- **Protocol style:** stateless, self-contained requests (no session state inferred across requests)
- **Capability negotiation:** per-request, via `_meta.io.modelcontextprotocol/clientCapabilities`
- **Transports:** **stdio** (newline-delimited JSON-RPC over a client-launched subprocess) and **Streamable HTTP** (single MCP endpoint; `POST` per message, request-scoped SSE for replies). Custom transports **MAY** be defined. (HTTP+SSE was deprecated earlier, in `2025-03-26`.)
- **Server features:** Resources, Prompts, Tools
- **Client features (core):** **Elicitation only**. (Sampling and Roots are deprecated — see below.)
- **Extensions (opt-in):** Tasks (`io.modelcontextprotocol/tasks`), MCP Apps (`io.modelcontextprotocol/ui`), Skills over MCP (in Working Group / experimental), OAuth client-credentials, enterprise-managed authorization, …
- **Authorization:** OAuth 2.1 + PKCE, HTTP transports only; stdio uses environment credentials
## The redesign (why this matters)
Three structural changes define this draft:
1. **Stateless base protocol.** All information needed to process a request is contained in the request itself — protocol version, client identity, and capabilities travel in the `_meta` field on every request. Servers **MUST NOT** rely on prior requests to establish context, and **SHOULD** handle requests associated with multiple tasks/threads/conversations.
2. **Per-request capability negotiation.** The connection-level `initialize` handshake is gone for modern clients; capabilities are declared on each request, and the server's capabilities are discoverable via `server/discover`. This replaces session-scoped negotiation entirely.
3. **Extensions framework.** Optional, always opt-in, modular capabilities (Tasks, MCP Apps, …) negotiated through the `extensions` field of capabilities. Core client features are trimmed to Elicitation; Sampling, Roots, and Logging move to **deprecated** status under a formal lifecycle policy (not silent removal).
## Architecture
The client-host-server topology is retained. A **host** creates and manages multiple **client** instances; each client has a 1:1 relationship with exactly one **server** and enforces isolation (a server cannot see the whole conversation or other servers). The change is that clients now "attach protocol version and capabilities to every request" rather than establishing a session. Servers expose resources/tools/prompts and **MAY** request client input (sampling/elicitation/roots) by returning an `InputRequiredResult` within a reply. Design principles are unchanged: servers should be easy to build, highly composable, mutually isolated, and progressively extensible.
## Base Protocol
### Messages
All messages **MUST** be [JSON-RPC 2.0](https://www.jsonrpc.org/specification), UTF-8 encoded. Three kinds: **Requests** (with a string/integer `id`; the id **MUST NOT** be `null` and **MUST NOT** match any in-flight request id), **Responses**, and **Notifications** (no `id`; receiver **MUST NOT** reply). A notable addition is **polymorphic results**: every result **MUST** include a `resultType` field — `"complete"` (final content), `"input_required"` (an `InputRequiredResult`, driving a multi-round-trip request), or extension-defined values; an absent `resultType` **MUST** be treated as `"complete"` for backward compatibility. JSON-RPC's reserved server-error range is now partitioned: `-32000``-32019` is legacy (new codes **MUST NOT** be allocated there); `-32020``-32099` is reserved for the MCP specification. Defined codes: `-32020` `HeaderMismatch`, `-32021` `MissingRequiredClientCapability`, `-32022` `UnsupportedProtocolVersion`. Three message patterns are supported: **Request/Response**, **Multi Round-Trip Requests (MRTR)**, and **Subscribe/Notify** (`subscriptions/listen`).
### Lifecycle / Negotiation
There is **no negotiation handshake** in the modern protocol. Every request declares its protocol version in `_meta` (also mirrored in the `MCP-Protocol-Version` header on HTTP). If the server does not support the requested version it **MUST** respond `UnsupportedProtocolVersionError` (`-32022`) listing its `supported` versions; the client **SHOULD** pick a mutually supported version and retry. Servers **MUST** implement `server/discover`; clients **MAY** call it first to learn supported versions and capabilities up front, but are free to invoke any RPC inline and handle the error. Capability negotiation is therefore **per-request**: clients advertise capabilities in `_meta.io.modelcontextprotocol/clientCapabilities`; servers expose theirs through `server/discover`. Extensions are advertised the same way, via a `capabilities.extensions` map keyed by extension identifier.
### Transports
A transport is a binding (framing + metadata + cancellation signalling); message semantics are identical on every transport. Two standard bindings:
- **stdio** — newline-delimited JSON-RPC over a client-launched subprocess; `notifications/cancelled` abandons an in-flight request. Clients **SHOULD NOT** tie the subprocess lifetime to a single task/thread/conversation.
- **Streamable HTTP** — every client message is a `POST` to a single MCP endpoint; a reply arrives as a JSON object or a request-scoped SSE stream. Selected `_meta` fields are mirrored into HTTP headers so intermediaries can route without parsing the body (body remains source of truth). Cancellation closes the response stream.
Custom transports **MAY** be defined but **MUST** preserve JSON-RPC format, the message patterns, and the per-request metadata model; those over a reliable byte stream **SHOULD** reuse stdio framing.
### Authorization
Optional. For HTTP transports it is built on **OAuth 2.1** with PKCE; stdio **SHOULD NOT** use it and instead retrieves credentials from the environment. The MCP server is an OAuth 2.1 *resource server* and **MUST** implement OAuth 2.0 Protected Resource Metadata ([RFC 9728](https://www.rfc-editor.org/rfc/rfc9728.html)), signalling the metadata URL via `WWW-Authenticate` on `401`. Authorization servers **MUST** provide discovery via OAuth 2.0 Authorization Server Metadata ([RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414)) or OIDC Discovery; clients **MUST** support both. Client registration priority: **Client ID Metadata Documents** (new, preferred) → pre-registered → **Dynamic Client Registration** ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591), now **deprecated**). Resource Indicators ([RFC 8707](https://www.rfc-editor.org/rfc/rfc8707.html)) and the `iss` parameter ([RFC 9207](https://datatracker.ietf.org/doc/html/rfc9207)) apply. Servers **SHOULD** advertise required `scope` in the `WWW-Authenticate` challenge; clients follow a least-privilege scope-selection strategy with step-up authorization.
### Versioning
Protocol versions are date strings (e.g. `2026-07-28`). Terminology: **Modern** = per-request metadata (this revision and later); **Legacy** = `initialize`-handshake versions (`2025-11-25` and earlier); **Dual-era** = implementations supporting both. A dual-era server selects behaviour from how the client opens: a request carrying modern `_meta` is served statelessly; an `initialize` request selects legacy semantics. Clients detect a server's era via transport-specific probing (stdio: `server/discover` and fall back on any non-modern error; HTTP: attempt a modern request and inspect a `400` body). The era is a property of the server and **SHOULD** be cached for the process/origin lifetime. A full compatibility matrix (Modern/Legacy/Dual-era × client/server) is specified.
## Server Features
Servers advertise implemented primitives in their capabilities. Control model unchanged: **Prompts** user-controlled, **Resources** application-controlled, **Tools** model-controlled.
### Resources
Context/data exposed by the server, addressed by URI. Discovery and reading are RPC-driven; clients open a `subscriptions/listen` stream to receive `notifications/*` (tagged with a `subscriptionId`) when resources change. The old `-32002` "resource not found" code is replaced by `-32602`; clients **SHOULD** still accept `-32002` from legacy servers.
### Prompts
Templated messages/workflows invoked by user choice (e.g. slash commands, menu options). Listed and fetched on demand; the model does not pick them autonomously.
### Tools
Functions exposed to the LLM (model-controlled). Tool invocation requires the server to declare tool capabilities. Tools **MAY** return structured output, and — via extensions such as MCP Apps — can reference interactive UI resources.
### Utilities
Cross-cutting concerns now consist of **Configuration**, **Progress tracking**, **Cancellation**, and **Error reporting**. **Logging is no longer a core utility: it is deprecated** (SEP-2577). The migration path is to log to `stderr` for stdio transports and to use [OpenTelemetry](https://opentelemetry.io/) for observability.
## Client Features
### Elicitation
The **only core client feature**. Servers **MAY** request user input during request processing by returning an `InputRequiredResult` containing an `elicitation/create` request. Two modes:
- **Form mode** — in-band structured data with optional JSON-Schema validation. Schemas are restricted to flat objects of primitive properties (string/number/integer/boolean/enum). Servers **MUST NOT** use form mode to request secrets (passwords, API keys, tokens, payment credentials).
- **URL mode** — out-of-band interaction via URL navigation; data (other than the URL) is **not** exposed to the client. Servers **MUST** use URL mode for sensitive information.
Clients supporting elicitation **MUST** declare `_meta.io.modelcontextprotocol/clientCapabilities.elicitation` (with `form` and/or `url` sub-capabilities; empty object ≡ `form` only) on each request. Clients **MUST** make clear which server is asking, and provide decline/cancel options.
## Extensions (new)
### Overview
Extensions are optional additions beyond the core protocol — modular, specialized, or experimental. They are identified by `{vendor-prefix}/{extension-name}` (official ones use `io.modelcontextprotocol/`), advertised in the `capabilities.extensions` map (per-request), and **always disabled by default** — requiring explicit opt-in from both sides. If one side supports an extension the other lacks, it **MUST** fall back to core behaviour or reject with an appropriate error. Extensions evolve independently and **SHOULD** use capability flags or in-extension versioning rather than new identifiers for breaking changes. Official extensions live in `ext-*` repositories; experimental ones (incubating in Working/Interest Groups) use the `experimental-ext-` prefix.
### Tasks
Extension `io.modelcontextprotocol/tasks` (repo `ext-tasks`). Lets a server return a durable handle instead of blocking on long-running operations (CI pipelines, batch jobs, human approvals). Flow: the client declares the extension per-request; when a request will be long-running the server returns a `CreateTaskResult` (`resultType: "task"`) carrying a `taskId`, initial status, TTL, and suggested `pollIntervalMs`; the client polls `tasks/get`; if status becomes `input_required`, the response carries `inputRequests` which the client fulfils via `tasks/update`; terminal states are `completed` / `failed` / `cancelled`. The client **MAY** send `tasks/cancel` (cooperative). Servers **MAY** push `notifications/tasks` via `subscriptions/listen`; polling remains the default. Task IDs are durable and survive client disconnect/restart.
### Skills over MCP
An emerging extension (Skills Over MCP Working Group; current direction is SEP-2640, a Resources-based Extensions-Track proposal; reference work in `experimental-ext-skills`). It defines how "agent skills" — rich, structured instructions for agent workflows — are discovered, distributed, and consumed through MCP. **Not yet a finalized official extension** at the time of this draft.
### MCP Apps
Extension `io.modelcontextprotocol/ui` (repo `ext-apps`). Lets a server return interactive HTML (charts, forms, video players, dashboards) rendered inline in the conversation. A tool declares a UI reference via `_meta.ui.resourceUri` pointing at a `ui://` resource; the host fetches and renders the HTML inside a **sandboxed iframe**, isolated from the parent page. Communication uses a JSON-RPC dialect over `postMessage` with a `ui/` method prefix (e.g. `ui/initialize`); `_meta.ui.csp` and `_meta.ui.permissions` control loading and capabilities. Already supported by several clients (Claude, Claude Desktop, VS Code Copilot, Microsoft 365 Copilot, Goose, Postman, and others).
## Changes vs 2025-11-25
- **Stateless base protocol**: requests are self-contained; servers **MUST NOT** rely on connection/session state.
- **Per-request capability negotiation** replaces the `initialize` handshake; `server/discover` provides up-front discovery.
- **Polymorphic results** (`resultType`: `complete` / `input_required` / extension values) and a formal MRTR pattern via `InputRequiredResult`.
- **New spec-reserved error range** (`-32020``-32099`) and codes (`HeaderMismatch`, `MissingRequiredClientCapability`, `UnsupportedProtocolVersion`).
- **Elicitation is the only core client feature**; **Sampling and Roots are deprecated** (SEP-2577), retained ≥12 months, eligible for removal in the first revision released on/after **2027-07-28**. Migration: Roots → tool parameters/resource URIs/server configuration; Sampling → integrate directly with LLM provider APIs.
- **Logging deprecated** as a utility (SEP-2577) → `stderr` / OpenTelemetry.
- **Dynamic Client Registration deprecated** (→ Client ID Metadata Documents).
- **Extensions framework** introduced; **Tasks** stabilized as an official extension (`io.modelcontextprotocol/tasks`), **MCP Apps** added (`io.modelcontextprotocol/ui`), **Skills over MCP** incubating.
## Skald relevance
Skald's MCP surface lives in `crates/mcp-client/` (the `McpServer` stdio wrapper, `McpHttpServer`, and the `McpServerClient` trait), `src/core/mcp/` (`McpManager`), and `src/core/elicitation/` (`ElicitationManager` + bridge, surfaced in the Inbox). Two draft changes matter most for future planning: (1) the **stateless / per-request** shift means capability and version metadata must be attached to every request rather than assumed from a session, and `server/discover` becomes the discovery primitive; (2) the **Tasks extension** maps closely onto Skald's async/background work and would let MCP servers return durable, pollable handles for long-running operations. Skald's existing elicitation bridge already corresponds to the one remaining core client feature, so that path forward is well aligned. Until the draft finalizes, treat Sampling/Roots/Logging as deprecated-but-present for interop only.
## References
- [Specification (draft)](https://modelcontextprotocol.io/specification/draft)
- [Architecture](https://modelcontextprotocol.io/specification/draft/architecture)
- [Base protocol](https://modelcontextprotocol.io/specification/draft/basic)
- [Versioning and compatibility](https://modelcontextprotocol.io/specification/draft/basic/versioning)
- [Transports](https://modelcontextprotocol.io/specification/draft/basic/transports)
- [Authorization](https://modelcontextprotocol.io/specification/draft/basic/authorization)
- [Server features](https://modelcontextprotocol.io/specification/draft/server)
- [Client features — Elicitation](https://modelcontextprotocol.io/specification/draft/client/elicitation)
- [Deprecated features registry](https://modelcontextprotocol.io/specification/draft/deprecated)
- [Extensions overview](https://modelcontextprotocol.io/extensions/overview)
- [Tasks extension](https://modelcontextprotocol.io/extensions/tasks/overview)
- [MCP Apps extension](https://modelcontextprotocol.io/extensions/apps/overview)
- [Skills over MCP Working Group](https://modelcontextprotocol.io/community/working-groups/skills-over-mcp)
- [Schema (schema.ts)](https://github.com/modelcontextprotocol/specification/blob/main/schema/draft/schema.ts)
- [Release 2026-07-28-RC](https://github.com/modelcontextprotocol/modelcontextprotocol/releases/tag/2026-07-28-RC)