Follow Discord
Sweep 22 Oct 2026 · 21:04Z Build v2.1.309 528 read Stable v2.1.308 Latest v2.1.309 Next v2.1.309 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One capture · mcp

One read of Model Context Protocolmcp-20260814T095811Z

144 pages moved out of 144 read.

Pages moved 144 significant first
Pages read 144 in this capture
Captured 09:58 UTC
Corpus hash ce1a231d9896 full baseline · corpus-hash

What this read moved

76-100 of 144, page 4 of 6

This capture is too large to show at once. Changes 76-100 of 144 are below, significant first; the rest are on the following screens.

seps/1302-formalize-working-groups-and-interest-groups-in-mc First recorded · 251 lines, first recorded

# SEP-1302: Formalize Working Groups and Interest Groups in MCP Governance ## Abstract ## Motivation ## Specification ### Interest Groups (IG) \[Problems] ### Working Groups (WG) \[Solutions] ### WG/IG Facilitators ## Rationale ### Considerations #### Clear on-ramp for community involvement #### Minimal changes to existing governance structure #### Alignment with current status quo #### Nature of requests for gathering spaces #### Potential for overlap in scope #### Path to retiring stale groups ### Alternatives Considered #### Hierarchy between IGs and WGs #### A single WG concept (instead of both WG and IG) #### Free-for-all WG/IG creation process ## Backward Compatibility ## Reference Implementation ### Steering Working Groups ### Community Working Groups

The first capture of this source. The page was already there, and this is what it said.

# SEP-1302: Formalize Working Groups and Interest Groups in MCP Governance

> Formalize Working Groups and Interest Groups in MCP Governance

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1302                                                                            |
| **Title**     | Formalize Working Groups and Interest Groups in MCP Governance                  |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-08-05                                                                      |
| **Author(s)** | tadasant                                                                        |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1302](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1302) |

***

## Abstract

*A short (\~200 word) description of the technical issue being addressed.*

In [SEP-994](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1002), we introduced a notion of “Working Groups” and “Interest Groups” that facilitate MCP sub-communities for discussion and collaboration. This SEP aims to formally define those two terms: what they are meant to achieve, how groups can be created, how they are governed, and how they can be retired.

Interest Groups work to define *problems* that MCP should solve by facilitating *discussions*, while Working Groups push forward specific *solutions* by collaboratively producing *deliverables* (in the form of SEPs or community-owned implementations of the specification). Interest Group input is a welcome (but not required) justification for creation of a Working Group. Interest Group or Working Group input is collectively a welcome (but not required) input into a SEP.

## Motivation

*The motivation should clearly explain why the existing protocol specification is inadequate to address the problem that the SEP solves.*

The community has already been self-organizing into several disparate systems for these collaborative groups:

* The Steering group has had a long-standing practice of managing a handful of collaborative groups through Discord channels (e.g. security, auth, agents). See [bottom of MAINTAINERS.md](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/MAINTAINERS.md).
* The “CWG Discord” has had a [semi-formal process](https://github.com/modelcontextprotocol-community/working-groups) for pushing equivalent grassroots initiatives, mostly in pursuit of creating artifacts for SEP consideration (e.g. hosting, UI, tool-interfaces, search-tools)

With SEP-994 resulting in the merging of the Discord communities, we have a need to:

* Merge the existing initiatives into one unified approach, so when we reference “working group” or “interest group”, everyone knows what that means and what kind of weight the reference might carry
* Standardize a process around the creation (and eventual retirement) of such groups
* Properly distinguish between “working” and “interest” groups; the CWG experience has shown two very different motivations for starting a group worth treating with different expectations and lifecycle. Put succinctly, “interest” groups are about brainstorming possible *problems*, and “working” groups are about pushing forward specific *solutions*.

These groups exist to:

* **Facilitate high signal spaces for discussion** such that those opting into notifications and meetings feel most content is relevant to them and they can meaningfully contribute their experience and learn from others
* **Create norms, expectations, and single points of involved leadership** around making collaborative progress towards concrete deliverables that help evolve MCP

It will also form the foundation for cross-group initiatives, such as maintaining a calendar of live meetings.

## Specification

*The technical specification should describe the syntax and semantics of any new protocol feature. The specification should be detailed enough to allow competing, interoperable implementations. A PR with the changes to the specification should be provided.*

### Interest Groups (IG) \[Problems]

**Goal**: facilitate discussion and knowledge-sharing among MCP community members with similar interests surrounding some MCP sub-topic or context. The focus is on collecting *problems* that may or may not be worth solving with SEPs or other community artifacts.

**Expectations**:

* At least one substantive thread / conversation per month
* AND/OR a live meeting attended by 3+ unaffiliated individuals

**Examples**:

* Security in MCP (currently: #security)
* Auth in MCP (currently: #auth)
* Using MCP in an internal enterprise setting (currently: #enterprise-wg)
* Tooling and practices surrounding hosting MCP servers (currently: #hosting-wg)
* Tooling and practices surrounding implementing MCP clients (currently: #client-implementors)

**Lifecycle**:

* Creation begins by filling out a template in #wg-ig-group-creation Discord channel
* A community moderator will review and call for a vote in the (private) #community-moderators Discord channel. Majority positive vote by members over a 72h period approves creation of the group. Can be reversed at any time (e.g. after more input comes in). Core and lead maintainers can veto.
* Facilitator(s) and Maintainer(s) responsible for organizing IG into meeting expectations
  * Facilitator is an informal role responsible for shepherding or speaking for a group
  * Maintainer is an official representative from the MCP steering group (not required for every group to have this)
* IG is retired only when community moderators or core+ maintainers decide it is not meeting expectations
  * This means successful IG’s will live on in perpetuity

**Creation Template**:

* Facilitator(s)
* Maintainer(s) (optional)
* Flag potential overlap with other IG’s
* How this IG differentiates itself from the related IG’s
* First topic you want to discuss

There is no requirement to be part of an IG to start a WG, or even to start a SEP. However, forming consensus in IG’s to support justifying the creation of a WG is often a good idea. Similarly, citing IG or WG support of a SEP helps the SEP as well.

### Working Groups (WG) \[Solutions]

**Goal**: facilitate MCP community collaboration on a specific SEP, themed series of SEPs, or officially endorsed Project.

**Expectations**:

* Minimum monthly progress towards at least one SEP or spec-related implementation OR holds maintenance responsibilities for a Project
* Facilitator(s) is/are responsible for fielding status update requests by community moderators or maintainers

**Examples**:

* Registry
* Inspector
* Tool Filtering
* Server Identity

**Lifecycle**:

* Creation begins by filling out a template in #wg-ig-group-creation Discord channel
* A community moderator will review and call for a vote in the (private) #community-moderators Discord channel. Majority positive vote by members over a 72h period approves creation of the group. Can be reversed at any time (e.g. after more input comes in). Core and lead maintainers can veto.
* Facilitator(s) and Maintainer(s) responsible for organizing WG into meeting expectations
  * Facilitator is an informal role responsible for shepherding or speaking for a group
  * Maintainer is an official representative from the MCP steering group (not required for every group to have this)
* WG is retired when either:
  * Community moderators or core+ maintainers decide it is not meeting expectations
  * The WG does not have a WIP Issue/PR for at least a month, or has completed all Issues/PRs it intends to pursue.

**Creation Template**:

* Facilitator(s)
* Maintainer(s) (optional)
* Explanation of interest/use cases (ideally from an IG but can come from anywhere)
* First Issue/PR/SEP you intend to procure

### WG/IG Facilitators

A “Facilitator” role in a WG or IG does *not* result in a [maintainership role](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/MAINTAINERS.md) across the MCP organization. It is an informal role into which anyone can self-nominate, responsible for helping shepherd discussions and collaboration within the group.

Core Maintainers reserve the right to modify the list of Facilitators and Maintainers for any WG/IG at any time.

PR for the changes to our documentation we'd want to enact this SEP: [https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1350](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1350)

## Rationale

*The rationale explains why particular design decisions were made. It should describe alternate designs that were considered and related work. The rationale should provide evidence of consensus within the community and discuss important objections or concerns raised during discussion.*

The design above comes from experience in facilitating the creation of + observing the behavior of informal “Community Working Groups” in the CWG Discord, and leading one of / participating in / observing the “Steering Committee Working Groups”. While the Steering WG’s were usually informally created by Lead Maintainers, the CWG Discord had a lightweight WG-creation process that involved similar steps to the proposal above (community members would propose WG’s in #working-group-ideation, and moderators would create channels from that collaboration).

As precedent, the WG and IG concepts here are similar to W3C’s notion of [Working Groups](https://www.w3.org/groups/wg/) and [Interest Groups](https://www.w3.org/groups/ig/).

### Considerations

In proposing the WG/IG design, we took the following into consideration:

#### Clear on-ramp for community involvement

A very common question for folks looking to invest in the MCP ecosystem is, "how do I get involved?"

These IG and WG abstractions help provide an elegant on-ramp:

1. Join the Discord, follow the conversation in IGs relevant to you. Attend live calls. Participate.
2. Offer to facilitate calls. Contribute your use cases in SEP proposals and other work.
3. When you're comfortable contributing to deliverables, jump in to contribute to WG work.
4. Do this for a period of time, get noticed by WG maintainers to get nominated as a new maintainer.

#### Minimal changes to existing governance structure

We did not want this change to introduce new elections, appointments, or other notions of leadership. We leverage community moderators to thumbs-up creation of new groups, allow core maintainers to veto, maintainership status stays unchanged, and the notion of "facilitator" is new but self-nominated, so does not introduce any new governance processes.

#### Alignment with current status quo

There is a clear "migration" path for the existing "CWG" working groups and Steering working groups - just a matter of sorting out what is "working" vs. "interest", but functionally this proposal stays out of the way of changing anything that has been working within each group's existing structure.

#### Nature of requests for gathering spaces

It has been clear from the requests to CWG that some groups form with a motivation to collaborate on some deliverable (e.g. `search-tools`), and others form due to common interests and a want for sub-community but not yet specific deliverables (e.g. `enterprise`). Hence, we separate the motivations into Working Groups vs. Interest Groups.

#### Potential for overlap in scope

In the requests for new group spaces, it is sometimes non-obvious why a new one needs to exist. For example, the stated motivation for `enterprise` at times sounded like it may just be another flavor of `hosting`. We ultimately settled on a distinction that made it clear one was not a direct subset of the other, but the concern of making clear boundaries between groups (and letting community moderators / maintainers centralize the decision-making around "what are the right layers of abstraction") is what led to the questions in the creation templates around e.g. "flag potential overlap with other IG’s".

#### Path to retiring stale groups

Many working groups in the old CWG and Steering models have gone stale since creation. They serve no real purpose and should be retired. For this, we introduce the formal concept of facilitators and optional maintainers in groups; and the community moderator right to retire them. By having at least informal leadership in place per group, a moderator can easily make the decision to retire a group if everyone is in agreement to proceed.

### Alternatives Considered

#### Hierarchy between IGs and WGs

We considered *requiring* that WGs be owned or spawned by a "sponsor" IG, for the purpose of more clearly exhibiting a progression of ideas to the community; but decided against this requiring to avoid adding a new layer of governance and alignment with how the less formal groups works today.

#### A single WG concept (instead of both WG and IG)

There has been regular tension in both CWG and the Steering group around the question of "is XYZ really a working group? how will maintainership work?" By making IG's explicitly discussion-oriented and maintainership involvement optional, we create a space to drive those discussions without requiring some formal expectation of deliverables like we might in a well-defined WG.

#### Free-for-all WG/IG creation process

While very community-driven, the concern of group overlap would quickly fragment the conversations and collaboration to an untenable level; we need a centralized point of discernment here.

## Backward Compatibility

*All SEPs that introduce backward incompatibilities must include a section describing these incompatibilities and their severity. The SEP must explain how the author proposes to deal with these incompatibilities.*

There is no major change suggested in the day to day of existing groups - the expectations laid out of IGs and WGs are easily met by existing active groups as long as they keep doing as they are doing.

A migration path for all groups is laid out below.

## Reference Implementation

*The reference implementation must be completed before any SEP is given status “Final”, but it need not be completed before the SEP is accepted. While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of “rough consensus and running code” is still useful when it comes to resolving many discussions of protocol details.*

The below is the suggested migration path for each group. "Migration" just involves acknowledgement of this SEP and the expectations of each group, plus methodology for possible eventual retirement (or immediate retirement, in some cases).

After this SEP is approved, we can ping each of the groups to confirm they are on board with the migration plan.

### Steering Working Groups

* All official SDK groups --> Working Groups
* Registry --> Working Group
* Documentation --> Working Group
* Inspector --> Working Group
* Auth --> Interest Group + some WGs: client-registration, improve-devx, profiles, tool-scopes
* Agents --> Working Group \[Long Running / Async Tool Calls; unless we want an Agents IG on top of that?]
* Connection Lifetime --> Retire
* Streaming --> Retire
* Spec Compliance --> Retire (good idea but stale; would be good for someone to spearhead a new Working Group)
* Security --> Interest Group (perhaps with Security Best Practices WG?)
* Transports --> Interest Group
* Server Identity --> Working Group
* Governance --> Working Group (or Retire if no more work here?)

### Community Working Groups

* agent-comms --> Retire
* enterprise --> Interest Group (request a proposal to start)
* hosting --> Interest Group (request a proposal to start)
* load-balancing --> Retire
* model-awareness --> Working Group (request a proposal to start)
* search-tools (tool-filtering) --> Working Group
* server-identity --> merge with Steering equivalent
* security --> merge with Steering equivalent
* server-identity --> merge with Steering equivalent
* tool-interfaces --> Retire
* ui --> Interest Group
* schema-validation --> Retire (same as Steering equivalent)

seps/1303-input-validation-errors-as-tool-execution-errors First recorded · 205 lines, first recorded

# SEP-1303: Input Validation Errors as Tool Execution Errors ## Abstract ## Motivation ### Problem Statement ### Benefits of This Proposal ## Specification ### Current Behavior ### Proposed Change ### Specification Text Changes ## Implementation ### Before (Protocol Error) ### After (Tool Execution Error) ## Backwards Compatibility ## References

The first capture of this source. The page was already there, and this is what it said.

# SEP-1303: Input Validation Errors as Tool Execution Errors

> Input Validation Errors as Tool Execution Errors

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1303                                                                            |
| **Title**     | Input Validation Errors as Tool Execution Errors                                |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-08-05                                                                      |
| **Author(s)** | [@fredericbarthelet](https://github.com/fredericbarthelet)                      |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1303](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1303) |

***

## Abstract

This SEP proposes treating tools input validation errors as Tool Execution Errors rather than Protocol Errors. This change would enable language models to receive validation error feedback in their context window, allowing them to self-correct and successfully complete tasks without human intervention, significantly improving task completion rate.

## Motivation

Language models can learn from tool input validation error messages and retry a tools/call with corrected parameters accordingly, but only if they receive the error feedback in their context window. Protocol Errors are catch at the application level by the MCP Client. Only Tool Execution Errors are forwarded back to the model as JSON-RPC responses. With the current specifications, models cannot see these error messages and thus cannot self-correct, leading to repeated failures and poor user experiences.

### Problem Statement

Consider a flight booking tool that validates departure dates using the following `zod` validation schema:

```typescript theme={null}
departureDate: z.string()
  .regex(/^\d{2}\/\d{2}\/\d{4}$/, "date must be in dd/mm/yyyy format")
  .superRefine((dateStr, ctx) => {
    const date = parseDateFr(dateStr);
    if (date.getTime() < Date.now()) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message:
          "Dates must be in the future. Current date is " +
          formatDateFr(new Date()),
      });
    }
    return true;
  })
  .describe("Departure date in dd/mm/yyyy format");
```

Tool expected input JSON schema can only describe the regex statement. The actual programmatic check that the date is in the past cannot be expressed here as JSON schema.
Even when a model provides a syntactically correct date that passes JSON schema validation, there is no guarantee it will be in the future. When a validation error is raised and returned as a Protocol Error:

1. The model doesn't receive the error message explaining why the date was rejected
2. The model repeats the same mistake multiple times (e.g., Cursor typically consistently sends dates in 2024 when the user only specify day and month or relative date and repeats the same tools/call request 3 times without getting any information as to why the tools call fails)
3. The task fails despite the model being capable of correcting itself if given proper feedback
4. Users experience frustration and must manually intervene

### Benefits of This Proposal

1. **Higher Task Completion Rates**: Models can self-correct validation errors without human intervention
2. **Better User Experience**: Reduced failures and faster task completion
3. **Leverages Model Capabilities**: Modern LLMs excel at understanding and responding to error messages
4. **Reduced API Calls**: Fewer retry attempts as models correct themselves on the first error

## Specification

### Current Behavior

The [tool errors specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#error-handling) currently provides ambiguous guidance:

* "Invalid arguments" should be treated as Protocol Error
* "Invalid input data" should be treated as Tool Execution Error

This ambiguity leads to inconsistent implementations where valuable error feedback is lost.

### Proposed Change

Clarify the specification with the following changes:

1. Removes the "invalid argument" category from **Protocol Errors**.
2. **Tool Execution Errors** should be used for all tool argument validation failures (merging `invalid argument` and `invalid input data` under a new `input validation errors` category)

### Specification Text Changes

Update the error handling section to include:

```
## Error Handling

Tools use two error reporting mechanisms:

1. **Protocol Errors**: Standard JSON-RPC errors for issues like:

   - Unknown tools
   - Server errors

2. **Tool Execution Errors**: Reported in tool results with `isError: true`:
   - API failures
   - Input validation errors
   - Business logic errors
```

## Implementation

### Before (Protocol Error)

```typescript theme={null}
// Model submits past date
request: {
  ...
  method: "tools/call",
  params: {
    name: "book_flight",
    arguments: {
      departureDate: "12/12/2024"  // Past date
    }
  }
}

// Server returns Protocol Error
response: {
  ...
  error: {
    code: -32602,
    message: "Invalid params"
  }
}

// Model retries blindly with another past date
// This cycle repeats until failure
```

### After (Tool Execution Error)

```typescript theme={null}
// Model submits past date
request: {
  ...
  method: "tools/call",
  params: {
    name: "book_flight",
    arguments: {
      departureDate: "12/12/2024"  // Past date
    }
  }
}

// Server returns Tool Execution Error (visible to model)
response: {
  ...
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Dates must be in the future. Current date is 08/08/2025"
      }
    ],
    "isError": true
  }
}

// Model understands the error and corrects itself
request: {
  method: "tools/call",
  params: {
    name: "book_flight",
    arguments: {
      departureDate: "12/12/2025"  // Future date
    }
  }
}
```

## Backwards Compatibility

This change is backwards compatible as it:

* Does not alter the protocol structure
* Only clarifies existing ambiguous behavior
* Maintains all existing error types and formats
* Improves behavior without breaking existing implementations

Servers implementing the clarified behavior will provide better model self-recovery while continuing to work with all existing clients.

## References

* [MCP Tools Error Handling Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools#error-handling)
* [Better MCP tools/call Error Responses: Help Your AI Recover Gracefully](https://dev.to/alpic/better-mcp-toolscall-error-responses-help-your-ai-recover-gracefully-15c7)
* Related Issue: [https://github.com/modelcontextprotocol/typescript-sdk/pull/824](https://github.com/modelcontextprotocol/typescript-sdk/pull/824)

seps/1319-decouple-request-payload-from-rpc-methods-definiti First recorded · 110 lines, first recorded

# SEP-1319: Decouple Request Payload from RPC Methods Definition ## Abstract ## Motivation ## Specification ### Current Approach (Inline Definition): ### Proposed Approach (Decoupled Definition): ## Rationale ## Backward Compatibility

The first capture of this source. The page was already there, and this is what it said.

# SEP-1319: Decouple Request Payload from RPC Methods Definition

> Decouple Request Payload from RPC Methods Definition

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1319                                                                            |
| **Title**     | Decouple Request Payload from RPC Methods Definition                            |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-08-08                                                                      |
| **Author(s)** | [@kurtisvg](https://github.com/kurtisvg)                                        |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1319](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1319) |

***

## Abstract

This SEP proposes a structural refactoring of the Model Context Protocol (MCP) specification. The core change is to define payload of requests (e.g., CallToolRequest) as independent definitions and have the RPC method definitions refer to these models. This decouples the definition of the data payload from the definition of the remote procedure that transports it, leading to a clearer, more modular, and more maintainable specification.

## Motivation

The current MCP specification tightly couples the data payload of a request with the JSON-RPC method that transports it. This design presents several challenges:

* **Reduced Clarity:** It forces developers to mentally parse the JSON-RPC transport structure just to understand the core data being exchanged. This increases cognitive load and makes the specification difficult to read and implement correctly.
* **Hindered Maintainability:** Defining data structures inline prevents their reuse across different methods, leading to redundancy and making future updates to the protocol more complex and error-prone.
* **Tightly Coupled to JSON-RPC:** Most critically, this tight coupling to JSON-RPC is the primary blocker for defining bindings for other transport protocols. To support transports like **gRPC** (which is currently a [popular ask from the community](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/966)), a transport-agnostic definition of its request and response messages. The current structure makes this practically impossible.

By refactoring the specification to separate the data model (the "what") from the RPC method (the "how"), this proposal will create a clearer, more modular specification. This change will immediately improve the developer experience and, most importantly, pave the way for the future evolution of MCP across multiple transports.

## Specification

The proposal introduces the following principle: All data structures used as parameters (params) or results (result) for RPC methods should be defined as standalone, named schemas. The RPC method definitions will then use references to these schemas.

### Current Approach (Inline Definition):

The RPC method definition contains the full structure of its parameters and results.

```ts theme={null}
export interface CallToolRequest extends Request {
  method: "tools/call";
  params: {
    name: string;
    arguments?: { [key: string]: unknown };
  };
}
```

### Proposed Approach (Decoupled Definition):

First, the data models for the request and response are defined as top-level schemas.

```ts theme={null}
/**
 * Parameters for a `tools/call` request.
 *
 * @category tools/call
 */
export interface CallToolRequestParams extends RequestParams {
  name: string;
  arguments?: { [key: string]: unknown };
}
```

Then, the RPC method definition becomes much simpler, merely referring to these models.

```ts theme={null}
export interface CallToolRequest extends Request {
  method: "tools/call";
  params: CallToolRequestParams;
}
```

## Rationale

The proposed solution—separating payload definitions from the RPC method—was chosen as the most direct and non-disruptive path to achieving the goals outlined in the motivation.

This approach establishes a clear architectural boundary between two distinct concerns:

1. **The Data Layer:** The transport-agnostic payload definition (e.g., `CallToolRequestParams`), which represents the core information being exchanged.
2. **The Transport Layer:** The protocol-specific wrapper (e.g., the JSON-RPC `CallToolRequest` object), which describes how the data is sent.

This architectural separation is superior to maintaining separate, parallel specifications for each transport (e.g., one for JSON-RPC, another for gRPC), which would introduce significant maintenance overhead and risk inconsistencies.

Crucially, this design refactors the specification document itself but intentionally **leaves the on-the-wire format unchanged**. This makes the proposal fully backward-compatible, requiring no changes from existing, compliant clients and servers. In short, this change is a strategic, foundational improvement that enables future growth without penalizing the current ecosystem.

## Backward Compatibility

This proposal is a **non-breaking change** for existing implementations. It is a refactoring of the *specification document itself* and does not alter the on-the-wire JSON format of the protocol messages. A client or server that is compliant with the old specification structure will remain compliant with the new one, as the resulting JSON payloads are identical.

The primary impact is on developers who read the specification and on tools that parse the specification to generate code or documentation.

seps/1330-elicitation-enum-schema-improvements-and-standards First recorded · 445 lines, first recorded

# SEP-1330: Elicitation Enum Schema Improvements and Standards Compliance ## Abstract ## Motivation ## Specification ### 1. Mark Current `EnumSchema` with Non-Standard `enumNames` Property as "Legacy" ### 2. Define Single Selection Enums (with Titled and Untitled varieties) ### 3. Introduce Multiple Selection Enums (with Titled and Untitled varieties) ### 4. Combine All Varieties as `EnumSchema` ### 5. Extend ElicitResult ## Instance Schema Examples ### Single-Select Without Titles (No change) ### Legacy Single Select With Titles ### Single-Select with Titles ### Multi-Select Without Titles ### Multi-Select with Titles ## Rationale ## Backwards Compatibility ## Reference Implementation ## Security Considerations ## Appendix ### Validations #### Legacy Single Selection #### Single Selection #### Multiple Selection ### JSON meta-schema

The first capture of this source. The page was already there, and this is what it said.

# SEP-1330: Elicitation Enum Schema Improvements and Standards Compliance

> Elicitation Enum Schema Improvements and Standards Compliance

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1330                                                                            |
| **Title**     | Elicitation Enum Schema Improvements and Standards Compliance                   |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-08-11                                                                      |
| **Author(s)** | chughtapan                                                                      |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1330](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1330) |

***

## Abstract

This SEP proposes improvements to enum schema definitions in MCP, deprecating the non-standard `enumNames` property in favor of JSON Schema-compliant patterns, and introducing additional support for multi-select enum schemas in addition to single choice schemas. The new schemas have been validated against the JSON specification.

**Schema Changes:** [https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1148](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1148)
Typescript SDK Changes: [https://github.com/modelcontextprotocol/typescript-sdk/pull/1077](https://github.com/modelcontextprotocol/typescript-sdk/pull/1077)
Python SDK Changes: [https://github.com/modelcontextprotocol/python-sdk/pull/1246](https://github.com/modelcontextprotocol/python-sdk/pull/1246)
**Client Implementation:** [https://github.com/evalstate/fast-agent/pull/324/files](https://github.com/evalstate/fast-agent/pull/324/files)
**Working Demo:** [https://asciinema.org/a/anBvJdqEmTjw0JkKYOooQa5Ta](https://asciinema.org/a/anBvJdqEmTjw0JkKYOooQa5Ta)

## Motivation

The existing schema for enums uses a non-standard approach to adding titles to enumerated values. It also limits use of enums in Elicitation (and any other schema object that should adopt `EnumSchema` in the future) to a single selection model. It is a common pattern to ask the user to select multiple entries. In the UI, this amounts to the difference between using checkboxes or radio buttons.

For these reasons, we propose the following non-breaking minor improvements to the `EnumSchema` for improving user and developer experience.

* Keep the existing `EnumSchema` as "Legacy"
  * It uses a non-standard approach for adding titles to enumerated values
  * Mark it as Legacy but still support it for now.
  * As per @dsp-ant When we have a proper deprecation strategy, we'll mark it deprecated
* Introduce the distinction between Untitled and Titled enums.
  * If the enumerated values are sufficient, no separate title need be specified for each value.
  * If the enumerated values are not optimal for display, a title may be specified for each value.
* Introduce the distinction between Single and Multi-select enums.
  * If only one value can be selected, a Single select schema can be used
  * If more than one value can be selected, a Multi-select schema can be used
* In `ElicitResponse`, add array as an `additionalProperty` type
  * Allows multiple selection of enumerated values to be returned to the server

## Specification

### 1. Mark Current `EnumSchema` with Non-Standard `enumNames` Property as "Legacy"

The current MCP specification uses a non-standard `enumNames` property for providing display names for enum values. We propose to mark `enumNames` property as legacy, suggest using `TitledSingleSelectEnum`, a standards compliant enum type we define below.

```typescript theme={null}
// Continue to support the current EnumSchema as Legacy

/**
 * Legacy: Use TitledSingleSelectEnumSchema instead.
 * This interface will be removed in a future version.
 */
export interface LegacyEnumSchema {
  type: "string";
  title?: string;
  description?: string;
  enum: string[];
  enumNames?: string[]; // Titles for enum values (non-standard, legacy)
}
```

### 2. Define Single Selection Enums (with Titled and Untitled varieties)

Enums may or may not need titles. The enumerated values may be human readable and fine for display. In which case an untitled implementation using the JSON Schema keyword `enum` is simpler. Adding titles requires the `enum` array to be replaced with an array of objects using `const` and `title`.

```typescript theme={null}
// Single select enum without titles
export type UntitledSingleSelectEnumSchema = {
  type: "string";
  title?: string;
  description?: string;
  enum: string[]; // Plain enum without titles
};

// Single select enum with titles
export type TitledSingleSelectEnumSchema = {
  type: "string";
  title?: string;
  description?: string;
  oneOf: Array<{
    const: string; // Enum value
    title: string; // Display name for enum value
  }>;
};

// Combined single selection enumeration
export type SingleSelectEnumSchema =
  UntitledSingleSelectEnumSchema | TitledSingleSelectEnumSchema;
```

### 3. Introduce Multiple Selection Enums (with Titled and Untitled varieties)

While elicitation does not support arbitrary JSON types like arrays and objects so clients can display the selection choice easily, multiple selection enumerations can be easily implemented.

```typescript theme={null}
// Multiple select enums without titles
export type UntitledMultiSelectEnumSchema = {
  type: "array";
  title?: string;
  description?: string;
  minItems?: number; // Minimum number of items to choose
  maxItems?: number; // Maximum number of items to choose
  items: {
    type: "string";
    enum: string[]; // Plain enum without titles
  };
};

// Multiple select enums with titles
export type TitledMultiSelectEnumSchema = {
  type: "array";
  title?: string;
  description?: string;
  minItems?: number; // Minimum number of items to choose
  maxItems?: number; // Maximum number of items to choose
  items: {
    oneOf: Array<{
      const: string; // Enum value
      title: string; // Display name for enum value
    }>;
  };
};

// Combined Multiple select enumeration
export type MultiSelectEnumSchema =
  UntitledMultiSelectEnumSchema | TitledMultiSelectEnumSchema;
```

### 4. Combine All Varieties as `EnumSchema`

The final `EnumSchema` rolls up the legacy, multi-select, and single-select schemas as one, defined as:

```typescript theme={null}
// Combined legacy, multiple, and single select enumeration
export type EnumSchema =
  SingleSelectEnumSchema | MultiSelectEnumSchema | LegacyEnumSchema;
```

### 5. Extend ElicitResult

The current elicitation result schema only allows returning primitive types. We extend this to include string arrays for MultiSelectEnums:

```typescript theme={null}
export interface ElicitResult extends Result {
  action: "accept" | "decline" | "cancel";
  content?: { [key: string]: string | number | boolean | string[] }; // string[] is new
}
```

## Instance Schema Examples

### Single-Select Without Titles (No change)

```json theme={null}
{
  "type": "string",
  "title": "Color Selection",
  "description": "Choose your favorite color",
  "enum": ["Red", "Green", "Blue"],
  "default": "Green"
}
```

### Legacy Single Select With Titles

```json theme={null}
{
  "type": "string",
  "title": "Color Selection",
  "description": "Choose your favorite color",
  "enum": ["#FF0000", "#00FF00", "#0000FF"],
  “enumNames”: ["Red", "Green", "Blue"],
  "default": "Green"
}
```

### Single-Select with Titles

```json theme={null}
{
  "type": "string",
  "title": "Color Selection",
  "description": "Choose your favorite color",
  "oneOf": [
    { "const": "#FF0000", "title": "Red" },
    { "const": "#00FF00", "title": "Green" },
    { "const": "#0000FF", "title": "Blue" }
  ],
  "default": "#00FF00"
}
```

### Multi-Select Without Titles

```json theme={null}
{
  "type": "array",
  "title": "Color Selection",
  "description": "Choose your favorite colors",
  "minItems": 1,
  "maxItems": 3,
  "items": {
    "type": "string",
    "enum": ["Red", "Green", "Blue"]
  },
  "default": ["Green"]
}
```

### Multi-Select with Titles

```json theme={null}
{
  "type": "array",
  "title": "Color Selection",
  "description": "Choose your favorite colors",
  "minItems": 1,
  "maxItems": 3,
  "items": {
    "anyOf": [
      { "const": "#FF0000", "title": "Red" },
      { "const": "#00FF00", "title": "Green" },
      { "const": "#0000FF", "title": "Blue" }
    ]
  },
  "default": ["Green"]
}
```

## Rationale

1. **Standards Compliance**: Aligns with official JSON Schema specification. Standard patterns work with existing JSON Schema validators
2. **Flexibility**: Supports both plain enums and enums with display names for single and multiple choice enums.
3. **Client Implementation:** shows that the additional overhead of implementing a group of checkboxes v/s a single checkbox is minimal: [https://github.com/evalstate/fast-agent/pull/324/files](https://github.com/evalstate/fast-agent/pull/324/files)

## Backwards Compatibility

The `LegacyEnumSchema` type maintains backwards compatible during the migration period. Existing implementations using `enumNames` will continue to work until a protocol-wide deprecation strategy is implemented, and this schema is removed.

## Reference Implementation

**Schema Changes:** [https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1148](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1148)
Typescript SDK Changes: [https://github.com/modelcontextprotocol/typescript-sdk/pull/1077](https://github.com/modelcontextprotocol/typescript-sdk/pull/1077)
Python SDK Changes: [https://github.com/modelcontextprotocol/python-sdk/pull/1246](https://github.com/modelcontextprotocol/python-sdk/pull/1246)
**Client Implementation:** [https://github.com/evalstate/fast-agent/pull/324/files](https://github.com/evalstate/fast-agent/pull/324/files)
**Working Demo:** [https://asciinema.org/a/anBvJdqEmTjw0JkKYOooQa5Ta](https://asciinema.org/a/anBvJdqEmTjw0JkKYOooQa5Ta)

## Security Considerations

No security implications identified. This change is purely about schema structure and standards compliance.

## Appendix

### Validations

Using stored validations in the JSON Schema Validator at [https://www.jsonschemavalidator.net/](https://www.jsonschemavalidator.net/) we validate:

* All of the example instance schemas from this document against the proposed JSON meta-schema `EnumSchema` in the next section.
* Valid and invalid values against the example instance schemas from this document.

#### Legacy Single Selection

* `EnumSchema` validating a [legacy single select instance schema with titles](https://www.jsonschemavalidator.net/s/lsK7Bn0C)
* The legacy titled single select instance schema validating [a correct single selection](https://www.jsonschemavalidator.net/s/GSk7rnRe)
* The legacy titled single select instance schema validating [an incorrect single selection](https://www.jsonschemavalidator.net/s/3kYvxsVP)

#### Single Selection

* `EnumSchema` validating a [single select instance schema without titles](https://www.jsonschemavalidator.net/s/MBlHW5IQ)
* `EnumSchema` validating a [single select instance schema with titles](https://www.jsonschemavalidator.net/s/s38xt4JV)
* The untitled single select instance schema validating [a correct single selection](https://www.jsonschemavalidator.net/s/M0hkYoeG)
* The untitled single select instance schema invalidating [an incorrect single selection](https://www.jsonschemavalidator.net/s/3Try4BCt)
* The titled single select instance schema validating [a correct single selection](https://www.jsonschemavalidator.net/s/4oDbv9yt)
* The titled single select instance schema invalidating [an incorrect single selection](https://www.jsonschemavalidator.net/s/A2KlNzLH)

Cut at 300 lines. The page has the rest.

seps/1577--sampling-with-tools First recorded · 395 lines, first recorded

# SEP-1577: Sampling With Tools ## Abstract ## Motivation ## Specification ### Overview ### Protocol changes ### Schema changes ## Possible Follow ups ### Streaming support ### Cache friendliness updates ### Allow client to call the server’s tools by itself in an agentic loop ### Allow client to call any other MCP servers’ tools by itself in an agentic loop ### Allow server to list & call clients’ tools (client/server → p2p) ### Simplify structured outputs use case

The first capture of this source. The page was already there, and this is what it said.

# SEP-1577: Sampling With Tools

> Sampling With Tools

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1577                                                                            |
| **Title**     | Sampling With Tools                                                             |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-09-30                                                                      |
| **Author(s)** | Olivier Chafik ([@ochafik](https://github.com/ochafik))                         |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1577) |

***

## Abstract

This SEP introduces `tools` & `toolChoice` params to `sampling/createMessage` and soft-deprecates `includeContext` (fences `thisServer` & `allServers` under a capability). This allows MCP servers to run their own agentic loops using the client's tokens (still under the user supervision), and reduces the complexity of client implementations (context support becoming explicitly optional).

## Motivation

* [Sampling](https://modelcontextprotocol.io/specification/2025-06-18/client/sampling) doesn't support tool calling, although it's a cornerstone of modern agentic behaviour. Without explicit support for it, MCP servers that use Sampling can either try and emulate tool calling w/ complex prompting / custom parsing of the outputs, or are limited to simpler, non-agentic requests. Adding support for tool calling could unlock many novel use cases in the MCP ecosystem.

* Context inclusion is ambiguously defined (see [this doc](https://docs.google.com/document/d/1KUsloHpsjR4fdXdJuofb9jUuK0XWi88clbRm9sWE510/edit?tab=t.0#heading=h.edw7oyac2e87)): it makes it particularly tricky to fully implement sampling, which along with other precautions needed for sampling (unaffected by this SEP) may have contributed to [low adoption of the feature in clients](https://modelcontextprotocol.io/clients#feature-support-matrix) (feature was introduced in the MCP Nov 2024 spec).

Please note some related work:

* [MCP Sampling](https://docs.google.com/document/d/1KUsloHpsjR4fdXdJuofb9jUuK0XWi88clbRm9sWE510/edit?tab=t.0#heading=h.5diekssgi3pq) (@jerome3o-anthropic): extremely similar proposal:
  * Add same tools semantics,
  * Deprecate `includeContext` (doc explains why its semantics are ambiguous)
  * (goes further to suggest explicit context sharing, which is out of scope from this proposal)
* [Allow Prompt/Sampling Messages to contain multiple content blocks. #198](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/198)
  * In this PR we've made `{CreateMessageResult,SamplingMessage}.content` to accept a single content or an array of contents. The `result.content` change is backwards incompatible but is required to support parallel tool calls. The `SamplingMessage.content` change then makes it much more natural to write a tool loop (see example in reference implementation: [toolLoopSampling.ts](https://github.com/modelcontextprotocol/typescript-sdk/blob/ochafik/sep1577/src/examples/server/toolLoopSampling.ts))

In the "Possible Follow ups" Section below, we give examples of features that were kept out of scope from this SEP but which we took care to make this SEP reasonably compatible with.

## Specification

### Overview

* Add traditional tool call support in [CreateMessageRequest](https://modelcontextprotocol.io/specification/2025-06-18/schema#createmessagerequest) w/ `tools` (w/ JSON schemas) & `toolChoice` params, requiring a server-side tool loop
  * Sampling may now yield ToolCallBlock responses
  * Server needs to call tools by itself
  * Server calls sampling again with ToolResultParamBlock to inject tool results
  * `toolChoice.mode` can be `“auto" | "required" | "none"` to allow common structured outputs use case (see below for possible follow up improvements)
  * Fenced by new capability (`sampling { tools {} }`)
* Fix/update underspecified strings in [CreateMessageResult](https://modelcontextprotocol.io/specification/2025-06-18/schema#createmessageresult):
  * `stopReason: “endTurn" | "stopSequence" | “toolUse" | “maxToken" | string` (explicit enums + open string for compat)
  * `role: “assistant”`
* Soft-deprecate [CreateMessageRequest.params.includeContext](https://modelcontextprotocol.io/specification/2025-06-18/schema#createmessagerequest) != ‘none’ (now fenced by capability)
  * Incentivize context-free sampling implementation

### Protocol changes

* `sampling/createMessage`
  * ~~MUST throw an error when `includeContext is “thisServer” | “allServers”` but `clientCapabilities.sampling.context` is missing~~
  * MUST throw an error when `tool` or `toolChoice` are defined but `clientCapabilities.sampling.tools` is missing
  * Servers SHOULD avoid `[includeContext](https://modelcontextprotocol.io/specification/2025-06-18/schema#createmessagerequest)` != ‘none’`as values`“thisServer”`and`“allServers”\` may be removed in future spec releases.
  * `CreateMessageRequest.messages` MUST balance any “assistant” message w/ a `ToolUseContent` (and `id: $id1`) w/ a “user” message w/ a ToolResultContent (and `tool_result_id: $id1`)
    * Note: this is a requirement for Claude API implementation (parallel tool call must all be responded to in one go)
  * SamplingMessage with tool result content blocks MUST NOT contain other content types.

### Schema changes

* [ClientCapabilities](https://modelcontextprotocol.io/specification/2025-06-18/schema#clientcapabilities)

  ```typescript theme={null}
  interface ClientCapabilities {
    ...
    sampling?: {
      context?: object; // NEW: Allows CreateMessageRequest.params.includeContext != "none"
      tools?: object;   // NEW: Allows CreateMessageRequest.params.{tools,toolChoice}
    };
  }
  ```

* [CreateMessageRequest](https://modelcontextprotocol.io/specification/2025-06-18/schema#createmessagerequest) (use existing [Tool](https://modelcontextprotocol.io/specification/2025-06-18/schema#tool))

  ```typescript theme={null}
  interface CreateMessageRequest {
    method: “sampling/createMessage”;
    params: {
      ...
      messages: SamplingMessage[]; // Note: type updated, see below
      
      tools?: Tool[] // NEW (existing type)

      toolChoice?: ToolChoice // NEW
    };
  }

  interface ToolChoice { // NEW
    mode?: “auto” | "required" | "none";
    // disable_parallel_tool_use?: boolean; // Update (Nov 10): removed, see below
  }
  ```

  * Notes:
    * OpenAI vs. Anthropic API idioms to avoid parallel tool calls:
      * OpenAI: `parallel_tool_calls: false` (top-level param)
      * Anthropic: `tool_choice.disable_parallel_tool_use: true`
        * Preferred here as default value if unset is false (e.g. parallel tool calls allowed)
    * OpenAI vs. Anthropic API re/ `tool_choice` `"none"` vs. `tools`:
      * OpenAI: `tools: [$Foo], tool_choice: "none"` forbids any tool call
        * Preferred behaviour here
      * Anthropic: `tools: [$Foo], tool_choice: {mode: "none"}` may still call tool `Foo`
    * Gemini vs. OAI / Anthropic re/ `disable_parallel_tool_use`:
      * Gemini API has no way to disable parallel tool calls atm (unlike OAI / Anthropic APIs). Removing this flag for now, to be reintroduced when Gemini has any way of supporting it. Otherwise clients would get unexpected multiple tool calls (or alternatively if implemented that way, unexpected failures / costly retry until a single tool call is emitted)
      * Gemini API's [Function calling modes](https://ai.google.dev/gemini-api/docs/function-calling?example=meeting#function_calling_modes) have an `ANY` value that should match the proposed `required`

* [SamplingMessage](https://modelcontextprotocol.io/specification/2025-06-18/schema#samplingmessage):

  ```typescript theme={null}
  /*
    BEFORE:
    
    interface SamplingMessage {
      content: TextContent | ImageContent | AudioContent
      role: Role;
    }
  */

  type SamplingMessage = UserMessage | AssistantMessage; // NEW

  type AssistantMessageContent =
    TextContent | ImageContent | AudioContent | ToolUseContent;
  type UserMessageContent =
    TextContent | ImageContent | AudioContent | ToolResultContent;
  interface AssistantMessage {
    // NEW
    role: "assistant";
    content: AssistantMessageContent | AssistantMessageContent[];
  }

  interface ToolUseContent {
    // NEW
    type: "tool_use";
    name: string;
    id: string;
    input: object;
  }

  interface UserMessage {
    // NEW
    role: "user";
    content: UserMessageContent | UserMessageContent[];
  }

  interface ToolResultContent {
    // NEW
    _meta?: { [key: string]: unknown };
    type: "tool_result";
    toolUseId: string;
    content: ContentBlock[];
    structuredContent: object;
    isError?: boolean;
  }
  ```

* Notes:
  * Differences of role vs. content type when it comes to tool calling between APIs:
    * OpenAI: `role: “system" | “user" | “assistant" | “tool"` (where tool is for tool results), while tool calls are nested in assistant messages, content is then typically null but some “OpenAI compatible” APIs accept non-null values
      * ```typescript theme={null}
        [
          { role: "user", content: "what is the temperature in london?" },
          {
            role: "assistant",
            content: "Let me use a tool...",
            tool_calls: [
              {
                id: "call_1",
                type: "function",
                function: {
                  name: "get_weather",
                  arguments: '{"location": "London"}',
                },
              },
            ],
          },
          {
            role: "tool",
            content: '{"temperature": 20, "condition": "sunny"}',
            tool_call_id: "call_1",
          },
        ];
        ```
    * Claude API: `role: “user" | “assistant"`, tool use and result are passed through specially-typed message content parts:
      * ```typescript theme={null}
        [
          {
            "role": "user",
            "content": [
              {
                "type": "text",
                "text": "what is the temperature in london?"
              }
            },
          {
            "role": "assistant",
            "content": [
              {
                "type": "text",
                "text": "Let me use a tool..."
              },
              {
                "type": "tool_use",
                "id": "call_1",
                "name": "get_weather",
                "input": {"location": "London"}
              }
            ]
          },
          {
            "role": "user",
            "content": [
              {
                "type": "tool_result",
                "tool_call_id": "call_1",
                "content": {"temperature": 20, "condition": "sunny"}
              }
            ]
          }
        ]
        ```
    * Gemini API:
      * `function` role (similar to OAI's `tool` role)
      * No tool call id concept ([function calling](https://ai.google.dev/gemini-api/docs/function-calling?example=meeting#parallel_function_calling): Gemini requires tool results to be provided in the exact same order as the tool use parts. An implementation could generate the tool call ids and use them to reorder the tool results if needed.

* [CreateMessageResult](https://modelcontextprotocol.io/specification/2025-06-18/schema#createmessageresult)

  ```typescript theme={null}
  /*
    BEFORE:

    interface CreateMessageResult {
      _meta?: { [key: string]: unknown };
      content: TextContent | ImageContent | AudioContent;
      role: Role;
      stopReason?: string;
      [key: string]: unknown;
  }
  */
  interface CreateMessageResult {
    _meta?: { [key: string]: unknown };

    content: AssistantMessageContent | AssistantMessageContent[] // UPDATED

    role: "assistant"; // UPDATED

    stopReason?: “endTurn" | "stopSequence" | “toolUse" | “maxToken" | string // UPDATED

    [key: string]: unknown;
  }
  ```

  * Notes:
    * Backwards compatibility issue: returning CreateMessageResult.content as an array of contents OR a single content is problematic, so we propose:
      * `sampling/createMessage` MUST NOT return an array in `CreateMessageResult.content` before spec version Nov 2025.
        * This guarantees wire-level backwards-compatibility
      * Existing code that uses sampling may break w/ new SDK releases as it will need to test content to know if it's an array or a single block, and act accordingly.
      * This seems reasonable(?)
    * `CreateMessageResult.stopReason` field is currently defined as an open `string`, and the spec only mentions the `endTurn` as example value.
    * OpenAI vs. Anthropic API idioms
      * Finish/stop reason
        * OpenAI’s [ChatCompletion](https://platform.openai.com/docs/api-reference/chat/object): `finish_reason: “stop” | “length” | “tool_use”` (…?)
        * [Anthropic](https://docs.claude.com/en/api/handling-stop-reasons): `stop_reason: “end_turn” | “max_tokens” | “stop_sequence” | “tool_use” | “pause_turn” | “refusal”`

## Possible Follow ups

These are out of scope for this SEP, but care was taken not to preclude them, so where appropriate we give examples of how they could be implemented on top of / after this SEP.

### Streaming support

See: [Streaming tool use results #117](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/117)

This could be important for some longer-running use cases or when latency is important, but would play better w/ streaming support in MCP tools.

A possible way to implement this would be to use notifications w/ payload, and possibly create a new method `sampling/createMessageStreamed`. Both should be orthogonal w/ this SEP (but we'd need to create delta types for results, similar to streaming APIs in inference API such as Claude API and OpenAI API).

### Cache friendliness updates

Cut at 300 lines. The page has the rest.

seps/1613-establish-json-schema-2020-12-as-default-dialect-f First recorded · 198 lines, first recorded

# SEP-1613: Establish JSON Schema 2020-12 as Default Dialect for MCP ## Abstract ## Motivation ## Specification ### 1. Default Dialect ### 2. Explicit Dialect Declaration ### 3. Schema Validation Requirements ### 4. Scope of Application ### 5. Implementation Requirements ## Rationale ### Why 2020-12? ### Why allow explicit declaration? ### Alternatives considered ## Backward Compatibility ## Reference Implementation ### SDK Implementations ## Security Implications ## Related Work ### [SEP-1330: Elicitation Enum Schema Improvements](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330) ### [SEP-834: Full JSON Schema 2020-12 Support](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/834) ## Open Questions

The first capture of this source. The page was already there, and this is what it said.

# SEP-1613: Establish JSON Schema 2020-12 as Default Dialect for MCP

> Establish JSON Schema 2020-12 as Default Dialect for MCP

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1613                                                                            |
| **Title**     | Establish JSON Schema 2020-12 as Default Dialect for MCP                        |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-10-06                                                                      |
| **Author(s)** | Ola Hungerford                                                                  |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1613](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1613) |

***

## Abstract

This SEP establishes JSON Schema 2020-12 as the default dialect for embedded schemas within MCP messages (tool `inputSchema`/`outputSchema` and elicitation `requestedSchema` fields). Schemas may explicitly declare alternative dialects via the `$schema` field. This resolves ambiguity that has caused compatibility issues between implementations.

## Motivation

The MCP specification does not explicitly state which JSON Schema version to use for embedded schemas. This has caused:

* Validation failures between clients and servers assuming different versions
* Implementation divergence across SDK ecosystems
* Developer uncertainty requiring arbitrary version choices

Community discussion (GitHub Discussion #366, PR #655) revealed that implementations were split between draft-07 and 2020-12, with multiple maintainers and community members expressing strong preference for 2020-12 as the default.

## Specification

### 1. Default Dialect

Embedded JSON schemas within MCP messages **MUST** conform to [JSON Schema 2020-12](https://json-schema.org/draft/2020-12/schema) when no `$schema` field is present.

### 2. Explicit Dialect Declaration

Schemas **MAY** include an explicit `$schema` field to declare a different dialect:

```json theme={null}
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "name": { "type": "string" }
  }
}
```

### 3. Schema Validation Requirements

* Schemas **MUST** be valid according to their declared or default dialect
* The `inputSchema` field **MUST NOT** be `null`

**For tools with no parameters**, use one of these valid approaches:

* `true` - accepts any input (most permissive)
* `{}` - equivalent to `true`, accepts any input
* `{ "type": "object" }` - accepts any object with any properties
* `{ "type": "object", "additionalProperties": false }` - accepts only empty objects `{}`

**Example** for a tool with no parameters:

```json theme={null}
{
  "name": "get_current_time",
  "description": "Returns the current server time",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false
  }
}
```

### 4. Scope of Application

This specification applies to:

* `tools/list` response: `inputSchema` and `outputSchema`
* `prompts/elicit` request: `requestedSchema`
* Future MCP features embedding JSON Schema definitions

### 5. Implementation Requirements

**Servers MUST:**

* Generate schemas conforming to 2020-12 by default
* Include explicit `$schema` when using non-default dialects

**Clients MUST:**

* Validate schemas according to declared or default dialect
* Support at least JSON Schema 2020-12

## Rationale

### Why 2020-12?

1. **Ecosystem alignment**: Python SDK (via Pydantic) and Go SDK implementations prefer/use 2020-12
2. **Modern features**: Better validation capabilities and composition support
3. **Community preference**: Multiple maintainers and community members in PR #655 discussion advocated for 2020-12 over draft-07
4. **Current standard**: 2020-12 is the stable version as of 2025

### Why allow explicit declaration?

* Supports migration paths for existing schemas
* Provides flexibility without protocol changes
* Follows JSON Schema best practices

### Alternatives considered

* **Draft-07 as default**: Rejected after community feedback; older version with less capability
* **No default**: Rejected as unnecessarily verbose; adds boilerplate
* **Multiple equal versions**: Rejected; creates unpredictability and fragmentation

## Backward Compatibility

This is technically a **clarification**, and not a breaking change:

* Existing schemas without `$schema` default to 2020-12
* Servers can add explicit `$schema` during transition
* Basic schemas (type, properties, required) work across versions

**Migration may be needed for schemas assuming draft-07 by default:**

* Schemas using `dependencies` (→ `dependentSchemas` + `dependentRequired`)
* Positional array validation (→ `prefixItems`)

**Migration strategy:** Add explicit `$schema: "http://json-schema.org/draft-07/schema#"` during transition, then update to 2020-12 features.

## Reference Implementation

### SDK Implementations

**Python SDK** - Already compatible:

* Uses Pydantic for schema generation
* Pydantic defaults to 2020-12 via `.model_json_schema()`

**Go SDK** - Implemented 2020-12:

* Explicit 2020-12 implementation completed
* Confirmed by @samthanawalla in PR #655 discussion

**Other SDKs:**

* May require updates but based on other examples, there should be straightforward or out-of-the-box options to support this. I can add more examples here or we can create issues to follow up on these after acceptance.

## Security Implications

No specific security implications have been identified from establishing 2020-12 as the default dialect. The clarification reduces ambiguity that could lead to validation mismatches between implementations, which is a minor security improvement through increased predictability.

Implementations should use well-maintained JSON Schema validator libraries and keep them updated, as with any dependency.

## Related Work

### [SEP-1330: Elicitation Enum Schema Improvements](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1330)

**SEP-1330** proposes deprecating the non-standard `enumNames` property in favor of JSON Schema 2020-12 compliant patterns. This work is directly enabled by establishing 2020-12 as the default dialect.

**Implementation Consideration:**\
As noted in SEP-1330 discussion, there is some concern about parsing complexity with advanced JSON Schema features like `oneOf` and `anyOf`. However, these features are part of the JSON Schema standard and well-supported by mature validator libraries. Implementations can balance standards compliance with their parsing needs by using well-tested JSON Schema validation libraries.

### [SEP-834: Full JSON Schema 2020-12 Support](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/834)

This SEP establishes the foundation (default dialect) while SEP-834 addresses comprehensive support for 2020-12 features.

## Open Questions

The schema for the spec itself references `draft-07` and the `typescript-json-schema` package we use to generate it only supports draft-07.

Options:

1. Update schema generation script to patch to 2020-12 after generation (this is what I did in the current PR)
2. Switch to a different schema generator that supports 2020-12
3. Leave as-is since it doesn't actually conflict with the spec?

Personally I'd prefer (1) in the short term and then (2) as a follow-up.

seps/1686-tasks First recorded · 1110 lines, first recorded

# SEP-1686: Tasks ## Abstract ## Motivation ## Specification ### 1. User Interaction Model ### 2. Capabilities ### 3. Protocol Messages #### 3.1. Creating Tasks #### 3.2. Getting Tasks #### 3.3. Retrieving Task Results #### 3.4. Task Creation Notification #### 3.5. Listing Tasks #### 3.6 Deleting Tasks ### 4. Behavior Requirements #### 4.1. Task Support and Handling #### 4.2. Task ID Requirements #### 4.3. Task Status Lifecycle #### 4.4. Input Required Status #### 4.5. Keep-Alive and Resource Management #### 4.6. Result Retrieval #### 4.7. Associating Task-Related Messages #### 4.8. Task Cancellation #### 4.9. Task Listing #### 4.10 Task Deletion ### 5. Message Flow ### 6. Data Types #### Task #### Task Status #### Task Metadata #### Task Creation Notification #### Task Get Request #### Task Get Response #### Task Result Request #### Task Result Response #### Task List Request #### Task List Response #### Related Task Metadata ### 7. Error Handling #### 7.1. Protocol Errors #### 7.2. Task Execution Errors ### 8. Security Considerations #### 8.1. Task Isolation and Access Control #### 8.2. Resource Management #### 8.3. Audit and Logging ## Rationale ### Design Decision: Generic Task Primitive ### Design Decision: Metadata-Based Augmentation ### Design Decision: Client-Generated Task IDs ### Design Decision: Task Creation Notification ### Design Decision: No Capabilities Declaration ### Alternative Designs Considered ### Backward Compatibility ## Future Work ### Push Notifications ### Intermediate Results ### Nested Task Execution

The first capture of this source. The page was already there, and this is what it said.

# SEP-1686: Tasks

> Tasks

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1686                                                                            |
| **Title**     | Tasks                                                                           |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-10-20                                                                      |
| **Author(s)** | Surbhi Bansal, Luca Chang                                                       |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1686](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1686) |

***

## Abstract

> This SEP is preserved as a historical record of the experimental tasks feature shipped in the `2025-11-25` specification. The code examples below are non-normative pseudocode written against the v1 SDKs. The draft specification moves tasks out of the core protocol and into the `io.modelcontextprotocol/tasks` extension ([SEP-2663](./2663-tasks-extension.md)).

This SEP improves support for task-based workflows in the Model Context Protocol (MCP). It introduces both the **task primitive** and the associated **task ID**, which can be used to query the state and results of a task, up to a server-defined duration after the task has completed. This primitive is designed to augment other requests (such as tool calls) to enable call-now, fetch-later execution patterns across all requests for servers that support this primitive.

## Motivation

The current MCP specification supports tool calls that execute a request and eventually receive a response, and tool calls can be passed a progress token to integrate with MCP’s progress-tracking functionality, enabling host applications to receive status updates for a tool call via notifications. However, there is no way for a client to explicitly request the status of a tool call, resulting in states where it is possible for a tool call to have been dropped on the server, and it is unknown if a response or a notification may ever arrive. Similarly, there is no way for a client to explicitly retrieve the result of a tool call after it has completed — if the result was dropped, clients must call the tool again, which is undesirable for tools expected to take minutes or more. This is particularly relevant for MCP servers abstracting existing workflow-based APIs, such as AWS Step Functions, Workflows for Google Cloud, or APIs representing CI/CD pipelines, among other applications.

Today, it is possible for individual MCP servers to represent tools in a way that enables this, with certain compromises. For example, a server may expose a `long_running_tool` and wish to support this pattern, splitting it into three separate tools to accommodate this:

1. `start_long_running_tool`: This would start the work represented by `long_running_tool` and return a tracking token of some kind, such as a job ID.
2. `get_long_running_tool_status(token)`: This would accept the tracking token and return the current status of the tool call, informing the caller that the operation is still ongoing.
3. `get_long_running_tool_result(token)`: This would accept the tracking token and return the result of the tool call, if it is available.

Representing a tool in this way seems to solve for the use case, but it introduces a new problem: Tools are generally-expected to be orchestrated by an agent, and agent-driven polling is both unnecessarily expensive and inconsistent — it relies on prompt engineering to steer an agent to poll at all. In the original `long_running_tool` case, the client had no way of knowing if a response would ever be received, while in the `start_long_running_tool` case, the application has no way of knowing if the agent will orchestrate tools according to the specific contract of the server.

It is also impossible for the host application to take ownership of this orchestration, as this tool-splitting is both conventions-based and may be implemented in different ways across MCP servers — one server may have three tools for one conceptual operation (as in our example), or it may have more, in the case of more complex, multi-step operations.

On the other hand, if active task polling is not needed, existing MCP servers can fully-wrap a workflow API in a single tool call that polls for a result, but this introduces an undesirable implementation cost: an MCP server wrapping an existing workflow API is a server that only exists for polling other systems.

**Affected Customer Use Cases**
These concerns are backed by real use cases that Amazon has seen both internally and with their external customers (identities redacted where non-public):

**1. Healthcare & Life Sciences Data Analysis**
***Challenge:*** Amazon’s customers in the healthcare and life sciences industry are attempting to use MCP to wrap existing computational tools to analyze molecular properties and predict drug interactions, processing hundreds of thousands of data points per job from chemical libraries through multiple inference models simultaneously. These complex, multi-step workflows require a way to actively check statuses, as they take upwards of several hours, making retries undesirable.
***Current Workaround:*** Not yet determined.
***Impact:*** Cannot integrate with real-time research workflows, prevents interactive drug discovery platforms, and blocks automated research pipelines. These customers are looking for best practices for workflow-based tool calls and have noted the lack of first-class support in MCP as a concern. If these customers do not have a solution for long-running tool calls, they will likely forego MCP and continue using their existing platforms.
***Ideal:*** Concurrent and poll-able tool calls as an answer for operations executing in the range of a few minutes, and some form of push notification system to avoid blocking their agents on long analyses on the order of hours. This SEP supports the former use case, and offers a framework that could extend to support the latter.

**2. Enterprise Automation Platforms**
***Challenge:*** Amazon’s large enterprise customers are looking to develop internal MCP platforms to automate SDLC processes across their organizations, extending to sales, customer service, legal, HR, and cross-divisional teams. They have noted they have long-running agent and agent-tool interactions, supporting complex business process automation.
***Current Workaround:*** Not yet determined. Considering an application-level system outside of MCP backed by webhooks.
***Impact:*** Limitations related to the host application being unaware of tool execution state prevent complex business process automation and limit sophisticated multi-step operations. These customers want to dispatch processes concurrently and collect their results later, and are noting the lack of explicit late-retrieval as a concern — and are considering involved application-level notification systems as a possible workaround.
***Ideal:*** Built-in mechanisms for actively checking the status of ongoing work to avoid needing to implement notification systems specific to their own tool conventions themselves.

**3. Code Migration Workflows**
***Challenge*:** Amazon has automated code migration and transformation tools to perform upgrades across its own codebases and those of external customers, and is attempting to wrap those tools in MCP servers. These migrations analyze dependencies, transform code to avoid deprecated runtime features, and validate changes across multiple repositories. These migrations range from minutes to hours depending on migration scope, complexity, and validation requirements.
***Current Workaround:*** Developers implement manual tracking by splitting a job into `create` and `get` tools, forcing models to manage state and repeatedly poll for completion.
***Impact:*** Poor developer experience due to needing to replicate this hand-rolled polling mechanism across many tools. One team had to debug an issue where the model would hallucinate job names if it hadn’t listed them first. Validating that this does not happen across many tools in a large toolset is time-consuming and error-prone.
***Ideal:*** Support natively polling tool state at the data layer to support pushing a tool to the background and avoiding blocking other tasks in the chat session, while still supporting deterministic polling and result retrieval. The team needs the same pattern across many tools in their MCP servers, and wants a common solution across them, which this SEP directly supports.

**4. Test Execution Platforms**
***Challenge:*** Amazon’s internal test infrastructure executes comprehensive test suites including thousands of cases, integration tests across services, and performance benchmarks. They have built an MCP server wrapping this existing infrastructure.
***Current Workaround:*** For streaming test logs, the MCP server exposes a tool that can read a range of log lines, as it cannot effectively notify the client when the execution is complete. There is not yet any workaround for executing test runs.
***Impact:*** Cannot run a test suite and stream its logs simultaneously without a single hours-long tool call, which would time out on either the client or the server. This prevents agents from looking into test failures in an incomplete test run until the entire test suite has completed, potentially hours later.
***Ideal:*** Support host application-driven tool polling for intermediate results, so a client can be notified when a long-running tool is complete. This SEP does not fully-support this use case (it does enable polling), but the Task execution model can be extended to do so, as discussed in the “Future Work” section.

**5. Deep Research**
***Challenge:*** Deep research tools spawn multiple research agents to gather and summarize information about topics, going through several rounds of search and conversation turns internally to produce a final result for the caller application. The tool takes an extended amount of time to execute, and it is not always clear if the tool is still executing.
***Current Workaround:*** The research tool is split into a separate `create` tool to create a report job and a `get` tool to get the status/result of that job later.
***Impact:*** When using this with host applications, the agent sometimes runs into issues calling the `get` tool repeatedly — in particular, it calls the tool once before ending its conversation turn, claiming to be "waiting" before calling the tool again. It cannot resume until receiving a new user message. This also complicates expiration times, as it is not possible to predict when the client will retrieve the result when this occurs. It is possible to work around this by adding a `wait` tool for the model, but this prevents the model from doing anything else concurrently.
***Ideal:*** Support polling a tool call’s state in a deterministic way and notify the model when a result is ready, so the tool result can be immediately retrieved and deleted from the server. Other than notifying the model (a host application concern), this SEP fully supports this use case.

**6. Agent-to-Agent Communication (Multi-Agent Systems)**
***Challenge:*** One of Amazon’s internal multi-agent systems for customer question answering faces scenarios where agents require significant processing time for complex reasoning, research, or analysis. When agents communicate through MCP, slow agents cause cascading delays throughout this system, as agents are forced to wait on their peers to complete their work.
***Current Workaround:*** Not yet determined.
***Impact:*** Communication pattern creates cascading delays, prevents parallel agent processing, and degrades system responsiveness for other time-sensitive interactions.
***Ideal:*** Some method to allow agents to perform other work concurrently and get notified once long-running tasks complete. This SEP supports this use case by enabling host applications to implement background polling for select tool calls without blocking agents.

These use cases demonstrate that a mechanism to actively track tool calls and defer results is a real requirement for these types of MCP deployments in production environments.

**Integration with Existing Architectures**
Many workflow-driven systems already provide active execution-tracking capabilities with built-in status metadata, monitoring, and data retention policies. This proposal enables MCP servers to expose these existing APIs with thin MCP wrappers while maintaining their existing reliability.

**Benefits for Existing Architectures:**

* **Leverage Existing State Management:** Systems like AWS Step Functions, Workflows for Google Cloud, and CI/CD platforms already maintain execution state, logs, and results. MCP servers can expose these systems' existing APIs without pushing the responsibility of polling to a fallible agent.
* **Preserve Native Monitoring:** Existing monitoring, alerting, and observability tools continue to work unchanged. The execution happens almost entirely within the existing workflow-management system.
* **Reduce Implementation Overhead:** Server implementers don't need to build new state management, persistence, or monitoring infrastructure. They can focus on the MCP protocol mapping of their existing APIs to tasks.

This SEP simplifies integration with existing workflows and allows workflow services to continue to manage their own state while delivering a quality customer experience, rather than offloading to agent-polling or building MCP servers that do nothing but poll other services.

## Specification

This SEP introduces a mechanism for requestors (which can be either clients or servers, depending on the direction of communication) to augment their requests with **tasks**. Tasks are durable state machines that carry information about the underlying execution state of the request they wrap, and are intended for requestor polling and deferred result retrieval. Each task is uniquely identifiable by a requestor-generated **task ID**.

### 1. User Interaction Model

Tasks are designed to be **application-driven**—receivers tightly-control which requests (if any) support task-based execution and manage the lifecycles of those tasks; meanwhile, requestors own the responsibility for augmenting requests with tasks, and for polling on the results of those tasks.

Implementations are free to expose tasks through any interface pattern that suits their needs—the protocol itself does not mandate any specific user interaction model.

### 2. Capabilities

Servers and clients that support task-augmented requests **MUST** declare a `tasks` capability during initialization. The `tasks` capability is structured by request category, with boolean properties indicating which specific request types support task augmentation.

Refer to [https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1732](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1732) for details.

### 3. Protocol Messages

#### 3.1. Creating Tasks

To create a task, requestors send a request with the `modelcontextprotocol.io/task` key included in `_meta`, with a `taskId` value representing the task ID. Requestors **MAY** include a `keepAlive`, with a value representing how long after completion the requestor would like the task results to be kept for.

**Request:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "some_method",
  "params": {
    "_meta": {
      "modelcontextprotocol.io/task": {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
        "keepAlive": 60000
      }
    }
  }
}
```

#### 3.2. Getting Tasks

To retrieve the state of a task, requestors send a `tasks/get` request:

**Request:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tasks/get",
  "params": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
    "_meta": {
      "modelcontextprotocol.io/related-task": {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
      }
    }
  }
}
```

**Response:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
    "keepAlive": 30000,
    "pollFrequency": 5000,
    "status": "submitted",
    "_meta": {
      "modelcontextprotocol.io/related-task": {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
      }
    }
  }
}
```

#### 3.3. Retrieving Task Results

To retrieve the result of a completed task, requestors send a `tasks/result` request:

**Request:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "tasks/result",
  "params": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
    "_meta": {
      "modelcontextprotocol.io/related-task": {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
      }
    }
  }
}
```

**Response:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
      }
    ],
    "isError": false,
    "_meta": {
      "modelcontextprotocol.io/related-task": {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
      }
    }
  }
}
```

#### 3.4. Task Creation Notification

When a receiver creates a task, it **MUST** send a `notifications/tasks/created` notification to inform the requestor that the task has been created and polling can begin.

**Notification:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "method": "notifications/tasks/created",
  "params": {
    "_meta": {
      "modelcontextprotocol.io/related-task": {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840"
      }
    }
  }
}
```

The task ID is conveyed through the `modelcontextprotocol.io/related-task` metadata key. The notification parameters are otherwise empty.

This notification resolves the race condition where a requestor might attempt to poll for a task before the receiver has finished creating it. By sending this notification immediately after task creation, the receiver signals that the task is ready to be queried via `tasks/get`.

Receivers that do not support tasks (and thus ignore task metadata in requests) will not send this notification, allowing requestors to fall back to waiting for the original request response.

#### 3.5. Listing Tasks

To retrieve a list of tasks, requestors send a `tasks/list` request. This operation supports pagination.

**Request:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "tasks/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}
```

**Response:**

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "tasks": [
      {
        "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
        "status": "working",
        "keepAlive": 30000,
        "pollFrequency": 5000
      },
      {
        "taskId": "abc123-def456-ghi789",
        "status": "completed",
        "keepAlive": 60000
      }
    ],
    "nextCursor": "next-page-cursor"

Cut at 300 lines. The page has the rest.

seps/1699-support-sse-polling-via-server-side-disconnect First recorded · 71 lines, first recorded

# SEP-1699: Support SSE polling via server-side disconnect ## Abstract ## Motivation ## Specification ## Rationale ## Backward Compatibility ## Additional Information

The first capture of this source. The page was already there, and this is what it said.

# SEP-1699: Support SSE polling via server-side disconnect

> Support SSE polling via server-side disconnect

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1699                                                                            |
| **Title**     | Support SSE polling via server-side disconnect                                  |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-10-22                                                                      |
| **Author(s)** | Jonathan Hefner ([@jonathanhefner](https://github.com/jonathanhefner))          |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1699](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1699) |

***

## Abstract

This SEP proposes changes to the Streamable HTTP transport in order to mitigate issues regarding long-running connections and resumability.

## Motivation

The Streamable HTTP transport spec [does not allow](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/04c6e1f0ea6544c7df307fb2d7c637efe34f58d3/docs/specification/draft/basic/transports.mdx?plain=1#L109-L111) servers to close a connection while computing a result. In other words, barring client-side disconnection, servers must maintain potentially long-running connections.

## Specification

When a server starts an SSE stream, it MUST immediately send an SSE event consisting of an [`id`](https://html.spec.whatwg.org/multipage/server-sent-events.html#:~:text=field%20name%20is%20%22id%22) and an empty [`data`](https://html.spec.whatwg.org/multipage/server-sent-events.html#:~:text=field%20name%20is%20%22data%22) string in order to prime the client to reconnect with that event ID as the `Last-Event-ID`.

Note that the SSE standard explicitly [permits setting `data` to an empty string](https://html.spec.whatwg.org/multipage/server-sent-events.html#:~:text=data%20buffer%20is%20an%20empty%20string), and says that the appropriate client-side handling is to record the `id` for `Last-Event-ID` but otherwise ignore the event (i.e., not call the event handler callback).

At any point after the server has sent an event ID to the client, the server MAY disconnect at will. Specifically, [this part of the MCP spec](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/04c6e1f0ea6544c7df307fb2d7c637efe34f58d3/docs/specification/draft/basic/transports.mdx?plain=1#L109-L111) will be changed from:

> The server **SHOULD NOT** close the SSE stream before sending the JSON-RPC *response* for the received JSON-RPC *request*

To:

> The server **MAY** close the connection before sending the JSON-RPC *response* if it has sent an SSE event with an event ID to the client

If a server disconnects, the client will interpret the disconnection the same as a network failure, and will attempt to reconnect. In order to prevent clients from reconnecting / polling excessively, the server SHOULD send an SSE event with a [`retry`](https://html.spec.whatwg.org/multipage/server-sent-events.html#:~:text=field%20name%20is%20%22retry%22) field indicating how long the client should wait before reconnecting. Clients MUST respect the `retry` field.

## Rationale

Servers may disconnect at will, avoiding long-running connections. Sending a `retry` field will prevent the client from hammering the server with inappropriate reconnection attempts.

## Backward Compatibility

* **New Client + Old Server**: No changes. No backward incompatibility.
* **Old Client + New Server**: Client should interpret an at-will disconnect the same as a network failure. `retry` field is part of the SSE standard. No backward incompatibility if client already implements proper SSE resuming logic.

## Additional Information

This SEP supersedes (in part) [SEP-1335](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1335).

seps/1730-sdks-tiering-system First recorded · 274 lines, first recorded

# SEP-1730: SDKs Tiering System ## Abstract ## Motivation ## Specification ### Tier Definitions #### Tier 1: fully supported #### Tier 2: commitment to be fully supported #### Tier 3: Experimental ### Conformance Testing ### Tier Advancement Process ### Tier Relegation Process ### Requirements matrix ## Rationale ### Why Three Tiers? ### Why Time-Based Commitments? ### Why Not Just Feature Matrices? ## Alternatives Considered ### 1. Feature Matrix Only ### 2. Percentage-Based Scoring ### 3. Properties-Based System ### 4. Latest Version Listing Only ### 5. No Formal System ## Backward Compatibility ## Security Implications ## Implementation Plan ## Community Impact ### SDK Maintainers ### SDK Users ### Ecosystem ## References ## Appendix ### Simplified conformance tests

The first capture of this source. The page was already there, and this is what it said.

# SEP-1730: SDKs Tiering System

> SDKs Tiering System

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 1730                                                                            |
| **Title**     | SDKs Tiering System                                                             |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-10-29                                                                      |
| **Author(s)** | Inna Harper, Felix Weinberger                                                   |
| **Sponsor**   | None                                                                            |
| **PR**        | [#1730](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1730) |

***

## Abstract

This SEP proposes a tiering system for Model Context Protocol (MCP) SDKs to establish clear expectations for feature support, maintenance commitments, and quality standards. The system defines three tiers of SDK support with objective, measurable criteria for classification.

## Motivation

The MCP ecosystem needs SDK harmonization to help users make informed decisions. Users currently face challenges:

* **Feature Support Uncertainty**: No standardized way to know which SDKs support specific MCP features (OAuth, client/server/system features, like sampling, transports)
* **Maintenance Expectations**: Unclear commitment levels for bug fixes, security patches, and feature updates
* **Implementation Timelines**: No visibility into when SDKs will support new protocol versions and features

## Specification

### Tier Definitions

#### Tier 1: fully supported

SDKs in this tier provides full protocol implementation and is well supported

**Requirements:**

* **Feature complete and full support of the protocol**
  * All conformance tests pass
  * New protocol features before the new spec version release. (There is two week window between Release Candidate and the new protocol version release)
* **SDK maintenance**
  * Acknowledge and triage issues within two business days
  * Resolve security and critical bugs within seven days
  * Stable release and SDK versioning clearly documented
* **Documentation**
  * Comprehensive documentation with examples for all features
  * Published dependency update policy

#### Tier 2: commitment to be fully supported

SDKs with established implementations actively working toward full protocol support.

**Requirements:**

* **Feature complete and full support of the protocol**
  * 80% of conformance tests pass
  * New protocol features implemented within six months
* **SDK maintenance**
  * Active issue tracking and management
  * At least one stable release
* **Documentation**
  * Basic documentation covering core features
  * Published dependency update policy
* **Commitment to move to Tier1**
  * Published roadmap showing intent to achieve Tier 1 or, if SDK will remain in Tier 2 indefinitely, a transparent roadmap about the direction of the SDK and reasons for not being feature complete

#### Tier 3: Experimental

Early-stage or specialized SDKs exploring the protocol space.

**Characteristics:**

* No feature completeness guarantees
* No stable release requirement
* May focus on specific use cases or experimental features
* No timeline commitments for updates
* Suitable for niche implementations that may remain at this tier

### Conformance Testing

All SDKs must undergo conformance testing using protocol trace validation: for details see [Conformance Testing RFC (forthcoming)](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1627). This SEP is not focusing on Conformance testing. For the initial version of tiering, we will go with the simplified version where we would have an Example server for each SDK and run simplified conformance tests against those.

```mermaid theme={null}
sequenceDiagram
    participant SDK
    participant Test Suite
    participant Validator

    Test Suite->>SDK: Execute test scenario
    SDK->>Test Suite: Protocol messages
    Test Suite->>Validator: Submit trace
    Validator->>Test Suite: Compliance report
    Test Suite->>SDK: Pass/Fail result
```

**Compliance Scoring:**

* SDKs receive a percentage score based on test results
* Scores can be displayed as badges (e.g., "90% MCP Compliant")
* Tier 1: 100% compliance required
* Tier 2: 80% compliance required
* Tier 3: No minimum requirement

### Tier Advancement Process

1. **Self-Assessment:** Maintainers evaluate their SDK against tier criteria
2. **Application:** Submit tier advancement request with evidence
3. **Review:** Community review period (2 weeks)
4. **Validation:** Automated conformance testing, github stats on issues
5. **Decision:** Tier assignment by MCP maintainers

### Tier Relegation Process

1. **Auto validation:**
   1. compliance tests continuously not passing for four week for Tier 1
   2. 20% of compliance tests continuously not passing for four week for Tier 2
2. Issues:
   1. Issues are not addressed within two months

### Requirements matrix

| Feature                                           | SDK A   | SDK B    | SDK C  |
| :------------------------------------------------ | :------ | :------- | :----- |
| **Protocol Features support (Conformance tests)** | 85%     | 60%%     | 100%   |
| **GitHub support stats**                          | 10 days | 100 days | 5 days |
| **Documentation (self reported)**                 | Good    | Minimal  | Good   |
| **Tier (computed from above)**                    | Tier 2  | Tier 3   | Tier 1 |

## Rationale

### Why Three Tiers?

* **Tier 1** ensures users have well supported, fully-featured SDK
* **Tier 2** provides a clear pathway for improving SDKs
* **Tier 3** allows experimentation without creating barriers to entry

### Why Time-Based Commitments?

While the community raised concerns about rigid timelines, they provide:

* Clear expectations for users
* Measurable goals for maintainers
* Flexibility through tier progression

### Why Not Just Feature Matrices?

Feature matrices alone don't communicate:

* Maintenance commitment
* Quality standards
* Support expectations

The tiering system combines feature support with quality guarantees.

## Alternatives Considered

### 1. Feature Matrix Only

**Rejected because:** Doesn't communicate maintenance commitments or quality standards

### 2. Percentage-Based Scoring

**Rejected because:** Too granular and doesn't capture qualitative aspects like support

### 3. Properties-Based System

**Rejected because:** Multiple overlapping properties could confuse users

### 4. Latest Version Listing Only

**Rejected because:** Simply listing "supports MCP date" fails to capture critical information:

* Version support may be incomplete (e.g., supports \<date> except OAuth)
* No indication of maintenance commitment or issue response times
* Lacks information about security patch timelines
* Doesn't communicate dependency update policies
* Version numbers alone don't indicate production readiness

### 5. No Formal System

**Rejected because:** Current ad-hoc approach creates uncertainty for users

## Backward Compatibility

This proposal introduces a new classification system with no breaking changes:

* Existing SDKs continue to function
* Classification is opt-in initially
* Grace period for existing SDKs to achieve tier status

## Security Implications

* Tier 1 SDKs must address security issues within 7 days
* All tiers encouraged to follow security best practices
* Conformance tests include security validation

## Implementation Plan

* [ ] Finalize simplified conformance test suite - Nov 4, 2025
* [ ] SDK maintainers self-assess and apply for tiers - Nov 14, 2025
* [ ] Initial tier assignments - before the November spec release
* [ ] Implement full compliance tests
* [ ] Implement automatic issue tracking analysis for SDKs

## Community Impact

### SDK Maintainers

* Clear goals for improvement
* Recognition for quality implementations
* Structured pathway for advancement

### SDK Users

* Informed selection of SDKs
* Clear expectations for support
* Confidence in tier 1 implementations

### Ecosystem

* Improved overall SDK quality
* Standardized feature support
* Healthy competition between implementations

## References

* [SDK Maintainer Meeting Notes (#1648)](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1648)
* [SDK Harmonization Goals (#1444)](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1444)
* [Conformance Testing SEP (DRAFT)](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1627)

## Appendix

### Simplified conformance tests

While we are working on a [comprehensive proposal for conformance testing](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1627) which will take some time to implement, we want to move forward with at least some automated way to check if SDK has a full set of features. We will start from Servers features set, as we have many more servers than clients and the vast majority of developers using SDKs are Server implementers.

The most straightforward approach is to have an Example Server for each SDK, similar to to [Everything Server](https://github.com/modelcontextprotocol/servers/tree/main/src/everything). Then we will have Conformance Test Client with all the test cases we want to be able to test, for example:

* execute “hello world” tool
* Get prompt
* Get completion
* Get resource template
* Receive notifications

**What is needed form SDKs maintainers:** implement everything server based on a spec. Spec will look like:

* Tool “say\_hello” to return simple text
* Tool “show\_image” to return and image
* Tool “tool\_with\_logging” to return structured output in a format \<> and log three events: start, process, end
* Tool "tool\_with\_notifications" to return structured output in a format \<> and have two notifications \<>

Given well defined spec for the server and SDK documentation, it should be easy to implement it with the help of any coding agent. We want to check it into each SDKs repo as it will serve as an example for server implementers.

Once each SDK has an Everything server, we will run the Conformance Test Client against it.

seps/1850-pr-based-sep-workflow First recorded · 210 lines, first recorded

# SEP-1850: PR-Based SEP Workflow ## Abstract ## Motivation ## Specification ### 1. Canonical Location ### 2. Author Workflow ### 3. Sponsor Responsibilities ### 4. Review Flow ### 5. Documentation ### 6. SEP File Structure ### 7. Status Management via PR Labels ### 8. Legacy Considerations ## Rationale ### Why File-Based? ### Why PR Numbers? ### Why PR Labels? ### Making This the Primary Process ## Backward Compatibility ## Security Implications ## Reference Implementation # Vote

The first capture of this source. The page was already there, and this is what it said.

# SEP-1850: PR-Based SEP Workflow

> PR-Based SEP Workflow

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Process
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                                                              |
| ------------- | ------------------------------------------------------------------------------------------------------------------ |
| **SEP**       | 1850                                                                                                               |
| **Title**     | PR-Based SEP Workflow                                                                                              |
| **Status**    | Final                                                                                                              |
| **Type**      | Process                                                                                                            |
| **Created**   | 2025-11-20                                                                                                         |
| **Accepted**  | 2025-11-28, 8 Yes, 0 No, 0 Absent per vote in Discord.                                                             |
| **Author(s)** | Nick Cooper ([@nickcoai](https://github.com/nickcoai)), David Soria Parra ([@davidsp](https://github.com/davidsp)) |
| **Sponsor**   | David Soria Parra ([@davidsp](https://github.com/davidsp))                                                         |
| **PR**        | [#1850](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1850)                                    |

***

## Abstract

This SEP formalizes the pull request-based SEP workflow that stores proposals as markdown files in the `seps/` directory of the Model Context Protocol specification repository. The workflow assigns SEP numbers from pull request numbers, maintains version history in Git, and replaces the previous GitHub Issues-based process. This establishes a file-based approach as the canonical way to author, review, and accept SEPs.

## Motivation

The issue-based SEP process introduced several challenges:

* **Dispersed content**: Proposal content was scattered across GitHub issues, linked documents, and pull requests, making review and archival difficult.
* **Difficult collaboration**: Maintaining long-form specifications in issue bodies made iterative edits and multi-contributor collaboration harder.
* **Limited version control**: GitHub issues don't provide the same version control capabilities as Git-managed files.
* **Unclear status management**: The process lacked clear mechanisms for tracking status transitions and ensuring consistency between different sources of truth.

A file-based workflow addresses these issues by:

* Keeping every SEP in version control alongside the specification itself
* Providing Git's built-in review tooling, history, and searchability
* Linking SEP numbers to pull requests to eliminate manual bookkeeping
* Surfacing all discussion in the pull request thread
* Using PR labels in conjunction with file status for better discoverability

## Specification

### 1. Canonical Location

* Every SEP lives in `seps/{NUMBER}-{slug}.md` in the specification repository
* The SEP number is always the pull request number that introduces the SEP file
* The `seps/` directory serves as the single source of truth for all SEPs

### 2. Author Workflow

1. **Draft the proposal** in `seps/0000-{slug}.md` using `0000` as a placeholder number
2. **Open a pull request** containing the draft SEP and any supporting materials
3. **Request a sponsor** from the Maintainers list; tag potential sponsors from [MAINTAINERS.md](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/MAINTAINERS.md)
4. **After the PR number is known**, amend the commit to rename the file to `{PR-number}-{slug}.md` and update the header (`SEP-{PR-number}` and `PR: #{PR-number}`)
5. **Wait for sponsor assignment**: Once a sponsor agrees, they will assign themselves and update the status to `Draft`

### 3. Sponsor Responsibilities

A Sponsor is a Core Maintainer or Maintainer who champions the SEP through the review process. The sponsor's responsibilities include:

* **Reviewing the proposal** and providing constructive feedback
* **Requesting changes** based on community input
* **Managing status transitions** by:
  * Ensuring that the `Status` field in the SEP markdown file is accurate
  * Applying matching PR labels to keep them in sync with the file status
  * Communicating status changes via PR comments
* **Initiating formal review** when the SEP is ready (moving from `Draft` to `In-Review`)
* **Raising to Core-Maintainers** ensuring the SEP is presented at the Core Maintainer meeting and that author and sponsor present.
* **Ensuring quality standards** are met before advancing the proposal
* **Tracking implementation** progress and ensuring reference implementations are complete before `Final` status

### 4. Review Flow

Status progression follows: `Draft → In-Review → Accepted → Final`

Additional terminal states: `Rejected`, `Withdrawn`, `Superseded`, `Dormant`

**Dormant status**: If a SEP does not find a sponsor within six months, Core Maintainers may close the PR and mark the SEP as `dormant`.

Reference implementations must be tracked via linked pull requests or issues and must be complete before marking a SEP as `Final`.

### 5. Documentation

* `docs/community/sep-guidelines.mdx` serves as the contributor-facing instructions
* `seps/README.md` provides the concise reference for formatting, naming, sponsor responsibilities, and acceptance criteria
* Both documents must reflect this workflow and be kept in sync

### 6. SEP File Structure

Each SEP must include:

```markdown theme={null}
# SEP-{NUMBER}: {Title}

- **Status**: Draft | In-Review | Accepted | Rejected | Withdrawn | Final | Superseded | Dormant
- **Type**: Standards Track | Informational | Process
- **Created**: YYYY-MM-DD
- **Author(s)**: Name <email> (@github-username)
- **Sponsor**: @github-username (or "None" if seeking sponsor)
- **PR**: https://github.com/modelcontextprotocol/specification/pull/{NUMBER}

## Abstract

## Motivation

## Specification

## Rationale

## Backward Compatibility

## Security Implications

## Reference Implementation
```

### 7. Status Management via PR Labels

To improve discoverability and filtering:

* Sponsors must apply PR labels that match the SEP status (`draft`, `in-review`, `accepted`, `final`, etc.)
* Both the markdown `Status` field and PR labels should be kept in sync
* The markdown file serves as the canonical record (versioned with the proposal)
* PR labels enable easy filtering and searching for SEPs by status
* Only sponsors should modify status fields and labels; authors should request changes through their sponsor

### 8. Legacy Considerations

* Contributors may optionally open a GitHub Issue for early discussion, but the authoritative SEP text lives in `seps/`
* Issues should link to the relevant file once a pull request exists
* SEP numbers are derived from PR numbers, not issue numbers

## Rationale

### Why File-Based?

Storing SEPs as files keeps authoritative specs versioned with the code, mirroring successful processes used by PEPs (Python Enhancement Proposals) and other standards bodies. This approach:

* Provides built-in version control via Git
* Enables standard code review workflows
* Maintains clear history of all changes
* Supports multi-contributor collaboration
* Integrates naturally with the specification repository

### Why PR Numbers?

Using pull request numbers:

* Eliminates race conditions around manual numbering
* Creates natural traceability between proposal and discussion
* Prevents number conflicts
* Simplifies the contribution process
* Maintains a single discussion thread for review

### Why PR Labels?

Adding PR labels alongside the file status:

* Enables quick filtering of SEPs by status without opening files
* Provides immediate visibility of SEP states in PR lists
* Supports GitHub's search and filter capabilities
* Complements the canonical markdown status field
* Reduces friction for maintainers managing multiple SEPs

### Making This the Primary Process

Maintaining two overlapping canonical processes risked divergence and created confusion for contributors. Establishing the file-based approach as the primary method:

* Reduces cognitive overhead for new contributors
* Ensures consistency in the SEP corpus
* Simplifies maintenance for sponsors
* Aligns with industry best practices

## Backward Compatibility

* Existing issue-based SEPs remain valid and require no migration
* Historical GitHub Issue links continue to work
* Future SEPs should reference the new file locations in `seps/`
* Maintainers may optionally backfill historical SEPs into `seps/` for archival purposes

## Security Implications

No new security considerations beyond the standard code review process for pull requests.

## Reference Implementation

* This pull request (#1850) implements the canonical instructions in both `seps/README.md` and `docs/community/sep-guidelines.mdx`
* The process has been updated to reflect the PR-based workflow with status management via labels
* This SEP document itself serves as an example of the new format

# Vote

This SEP was accepted unanimously by the MCP Core Maintainers with a vote of 8 yes's, 0 no's and 0 absent votes on Friday December 28th, 2025 in a Discord poll.

seps/1865-mcp-apps-interactive-user-interfaces-for-mcp First recorded · 171 lines, first recorded

# SEP-1865: MCP Apps - Interactive User Interfaces for MCP ## Abstract ## Motivation ## Specification ## Rationale ### Predeclared resources vs. inline embedding ### Reusing MCP JSON-RPC instead of a custom protocol ### HTML-only MVP ## Backward Compatibility ## Security Implications ## Reference Implementation

The first capture of this source. The page was already there, and this is what it said.

# SEP-1865: MCP Apps - Interactive User Interfaces for MCP

> MCP Apps - Interactive User Interfaces for MCP

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Extensions Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **SEP**       | 1865                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| **Title**     | MCP Apps - Interactive User Interfaces for MCP                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| **Status**    | Final                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| **Type**      | Extensions Track                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| **Created**   | 2025-11-21                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| **Author(s)** | Ido Salomon ([@idosal](https://github.com/idosal)), Liad Yosef ([@liadyosef](https://github.com/liadyosef)), Olivier Chafik ([@olivierchafik](https://github.com/olivierchafik)), Jerome Swannack ([@jeromeswannack](https://github.com/jeromeswannack)), Jonathan Hefner ([@jonathanhefner](https://github.com/jonathanhefner)), Anton Pidkuiko ([@antonpidkuiko](https://github.com/antonpidkuiko)), Nick Cooper ([@nickcooper](https://github.com/nickcooper)), Bryan Ashley ([@bryanashley](https://github.com/bryanashley)), Alexi Christakis ([@alexichristakis](https://github.com/alexichristakis)) |
| **Sponsor**   | None (seeking sponsor)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| **PR**        | [#1865](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1865)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |

***

## Abstract

This SEP proposes an extension to MCP (per SEP-1724) that enables servers to deliver interactive
user interfaces to hosts. MCP Apps introduces a standardized pattern for declaring UI resources via
the `ui://` URI scheme, associating them with tools through metadata, and facilitating
bi-directional communication between the UI and the host using MCP's JSON-RPC base protocol. This
extension addresses the growing community need for rich, interactive experiences in MCP-enabled
applications, maintaining security, auditability, and alignment with MCP's core architecture. The
initial specification focuses on HTML resources (`text/html;profile=mcp-app`) with a clear path for
future extensions.

## Motivation

MCP lacks a standardized way for servers to deliver rich, interactive user interfaces to hosts.
This gap blocks many use cases that require visual presentation and interactivity that go beyond
plain text or structured data. As more hosts adopt this capability, the risk of fragmentation and
interoperability challenges grows.

[MCP-UI](https://mcpui.dev/) has demonstrated the viability and value of MCP apps built on UI
resources and serves as a community playground for the UI spec and SDK. Fueled by a dedicated
community, it developed the bi-directional communication model and the HTML, external URL, and
remote DOM content types. MCP-UI's adopters, including hosts and providers such as Postman,
HuggingFace, Shopify, Goose, and ElevenLabs, have provided critical insights and contributions to
the community.

OpenAI's [Apps SDK](https://developers.openai.com/apps-sdk/), launched in November 2025, further
validated the demand for rich UI experiences within conversational AI interfaces. The Apps SDK
enables developers to build rich, interactive applications inside ChatGPT using MCP as its
backbone.

The architecture of both the Apps SDK and MCP-UI has significantly informed the design of this
specification.

However, without formal standardization:

* Servers cannot reliably expect UI support via MCP
* Each host may implement slightly different behaviors
* Security and auditability patterns are inconsistent
* Developers must maintain separate implementations or adapters for different hosts (e.g., MCP-UI
  vs. Apps SDK)

This SEP addresses the current limitations through an optional, backwards-compatible extension that
unifies the approaches pioneered by MCP-UI and the Apps SDK into a single, open standard.

## Specification

The full specification can be found at
[modelcontextprotocol/ext-apps](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx).

At a high level, MCP Apps extends the Model Context Protocol to enable servers to deliver
interactive user interfaces to hosts. This extension introduces:

* **UI Resources:** Predeclared resources using the `ui://` URI scheme
* **Resource Discovery:** Tools reference UI resources via metadata
* **Bi-directional Communication:** UI iframes communicate with hosts using standard MCP JSON-RPC
  protocol
* **Security Model:** Mandatory iframe sandboxing with auditable communication

This specification focuses on HTML content (`text/html;profile=mcp-app`) as the initial content
type, with extensibility for future formats.

As an extension, MCP Apps is optional and must be explicitly negotiated between clients and servers
through the extension capabilities mechanism (see Capability Negotiation section in the
[full specification](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx)).

## Rationale

### Predeclared resources vs. inline embedding

UI is modeled as predeclared resources (`ui://`), referenced by tools via metadata. This allows:

* Hosts to prefetch templates before tool execution, improving performance
* Separation of presentation (template) from data (tool results), facilitating caching
* Security review of UI resources

**Alternatives considered:**

* **Embedded resources:** Current MCP-UI approach, where resources are returned in tool results.
  Although it's more convenient for server development, it was deferred due to the gaps in
  performance optimization and the challenges in the UI review process.
* **Resource links:** Predeclare the resources but return links in tool results. Deferred due to
  the gaps in performance optimization.

### Reusing MCP JSON-RPC instead of a custom protocol

Reuses existing MCP infrastructure (type definitions, SDKs, etc.). JSON-RPC offers advanced
capabilities (timeouts, errors, etc.).

**Alternatives considered:**

* **Custom message protocol:** Current MCP-UI approach with message types like tool, intent,
  prompt, etc. These message types can be translated to a subset of the proposed JSON-RPC messages.
* **Global API object:** Rejected because it requires host-specific injection and doesn't work with
  external iframe sources. Syntactic sugar may still be added on the server/UI side.

### HTML-only MVP

* HTML is universally supported and well-understood
* Simplest security model (standard iframe sandbox)
* Allows screenshot/preview generation (e.g., via html2canvas)
* Sufficient for most observed use cases
* Provides a clear baseline for future extensions

**Alternatives considered:**

* **Include external URLs in MVP:** This is one of the easiest content types for servers to adopt,
  as it's possible to embed regular apps. However, it was deferred due to concerns around model
  visibility, inability to screenshot content, and review process. It may effectively be supported
  with the SEP's new `externalIframes` capability.

## Backward Compatibility

The proposal is an optional extension to the core protocol. Existing implementations continue
working without changes.

## Security Implications

Hosting interactive UI content from potentially untrusted MCP servers requires careful security
consideration.

Based on the threat model, MCP Apps proposes the following mitigations:

* **Iframe sandboxing**: All UI content runs in sandboxed iframes with restricted permissions
* **Predeclared templates**: Hosts can review HTML content before rendering
* **Auditable messages**: All UI-to-host communication goes through loggable JSON-RPC
* **User consent**: Hosts can require explicit approval for UI-initiated tool calls

A full threat model analysis and mitigations are available in the
[full specification](https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx).

## Reference Implementation

* [MCP-UI](https://github.com/idosal/mcp-ui) client and server SDKs support the patterns proposed
  in this spec.
* [ext-apps](https://github.com/modelcontextprotocol/ext-apps) repository contains a prototype
  implementation by Olivier Chafik.

seps/2085-governance-succession-and-amendment First recorded · 113 lines, first recorded

# SEP-2085: Governance Succession and Amendment Procedures ## Abstract ## Motivation ## Specification ### Succession ### Amendment ## Rationale ### Succession Process Design ### Amendment Process Design ### Alternatives Considered ## Backward Compatibility ## Security Implications ## Reference Implementation

The first capture of this source. The page was already there, and this is what it said.

# SEP-2085: Governance Succession and Amendment Procedures

> Governance Succession and Amendment Procedures

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Process
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2085                                                                            |
| **Title**     | Governance Succession and Amendment Procedures                                  |
| **Status**    | Final                                                                           |
| **Type**      | Process                                                                         |
| **Created**   | 2025-12-05                                                                      |
| **Author(s)** | David Soria Parra ([@dsp-ant](https://github.com/dsp-ant))                      |
| **Sponsor**   | David Soria Parra ([@dsp-ant](https://github.com/dsp-ant))                      |
| **PR**        | [#2085](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2085) |

***

## Abstract

This SEP establishes formal procedures for Lead Maintainer succession and governance amendment within the Model Context Protocol project. It defines clear processes for leadership transitions when a Lead Maintainer leaves their role and establishes requirements for proposing and approving changes to the governance structure itself.

## Motivation

The current MCP governance structure defines roles and responsibilities but lacks explicit procedures for two critical scenarios:

1. **Leadership Succession**: The governance document identifies Justin Spahr-Summers and David Soria Parra as Lead Maintainers (BDFLs) but does not specify what happens if one or both leave their roles. Without a defined succession process, an unexpected departure could create uncertainty about project leadership and decision-making authority.

2. **Governance Evolution**: As the MCP project grows and the community evolves, the governance structure may need to adapt. Currently, there is no defined process for how the governance document itself can be amended, which could lead to ad-hoc changes without proper community input or unclear authority for making such changes.

Establishing these procedures now, while the project leadership is stable, ensures continuity and provides clear guidance for future scenarios.

## Specification

The following sections shall be added to the MCP Governance document.

### Succession

If a Lead Maintainer leaves their role for any reason, the succession process begins upon their written notice or, if unable to provide notice, upon a determination by the remaining Lead Maintainer(s) or Core Maintainers that the Lead Maintainer is unable to continue serving.

If one or more Lead Maintainer(s) remain, they shall appoint a successor (by majority vote if multiple), and the remaining Lead Maintainer(s) will continue to govern until a successor is appointed.

If no Lead Maintainers remain, the Core Maintainers shall appoint a successor by majority vote within 30 days, and the project operates by two-thirds vote of Core Maintainers until a new Lead Maintainer is appointed.

### Amendment

Amendments to this governance structure may only be proposed by Lead Maintainers. Any proposed amendment must be approved by a two-thirds (2/3) majority of all Core Maintainers to take effect.

Amendment proposals shall:

1. Be submitted in writing with clear rationale for the proposed change
2. Include specific language describing the modification to existing governance provisions
3. Allow for a minimum comment period of five (5) days before voting
4. Be decided by recorded vote of Core Maintainers

## Rationale

### Succession Process Design

The succession process is designed with several principles in mind:

* **Continuity**: Remaining Lead Maintainers can continue operating and appoint successors without disruption to project governance.
* **Fallback Authority**: If all Lead Maintainers depart, Core Maintainers have clear authority to select new leadership, preventing a governance vacuum.
* **Time-Bound Process**: The 30-day requirement ensures succession happens promptly while allowing adequate time for deliberation.
* **Supermajority Interim Governance**: Two-thirds voting during interregnum periods ensures major decisions have broad support during transitional periods.

### Amendment Process Design

The amendment process balances stability with adaptability:

* **Lead Maintainer Proposal Authority**: Limiting proposal authority to Lead Maintainers prevents governance churn from frequent amendment proposals while ensuring those with deepest project investment can drive necessary changes.
* **Core Maintainer Approval**: Requiring two-thirds Core Maintainer approval ensures amendments have broad support from those actively governing the project.
* **Comment Period**: The five-day minimum comment period allows affected parties to review and provide input before voting.
* **Recorded Votes**: Transparency in voting ensures accountability and provides a historical record of governance decisions.

### Alternatives Considered

**Succession by Election**: An open election process was considered but rejected as potentially disruptive and slow during critical transition periods. The current proposal allows for quick succession while maintaining checks through the existing maintainer structure.

**Amendment by Any Maintainer**: Allowing any maintainer to propose amendments was considered but could lead to governance instability. The current approach balances stability with the ability to evolve.

**Longer Comment Periods**: Longer comment periods (e.g., 30 days) were considered but deemed excessive for a project that already has regular bi-weekly Core Maintainer meetings. Five days allows for at least one meeting cycle while enabling timely decisions.

## Backward Compatibility

This SEP adds new procedures without modifying existing governance structures. No backward compatibility concerns exist.

## Security Implications

This SEP has no direct security implications. However, clear succession procedures indirectly support security by ensuring continuous responsible stewardship of the project, including security-related decisions.

## Reference Implementation

Upon acceptance, this SEP will be implemented by adding the Succession and Amendment sections to `docs/community/governance.mdx`. The new sections will be inserted after the "Lead Maintainers (BDFL)" section and before the "Decision Process" section.

A draft pull request implementing these changes will be linked here once available.

seps/2106-json-schema-2020-12 First recorded · 434 lines, first recorded

# SEP-2106: Tools `inputSchema` & `outputSchema` Conform to JSON Schema 2020-12 ## Abstract ## Motivation ### Real-World Impact ### Schema Composition Use Cases ## Specification ### 1. Loosen inputSchema ### 2. Loosen outputSchema ### 3. Loosen structuredContent ### 4. Documentation Updates ### 5. Examples #### Tool returning an array of objects: #### Tool with composition schema: ## Rationale ### Why not just allow arrays? ### Why not require a wrapper object? ### Real-World API Patterns ### Alignment with JSON Schema 2020-12 ### SDK Ecosystem Evidence ### OpenAPI Precedent ## Backward Compatibility ### Compatibility Matrix ### TypeScript / SDK Migration ### Migration Path ## Security Implications ### `$ref` Dereferencing (SSRF and Fetch-DoS) ### Composition-Keyword Resource Use ## Reference Implementation ### TypeScript SDK ### Everything Server Demo Tools ### Related Links ### Implementation Guidance ## Acknowledgments

The first capture of this source. The page was already there, and this is what it said.

# SEP-2106: Tools `inputSchema` & `outputSchema` Conform to JSON Schema 2020-12

> Tools `inputSchema` & `outputSchema` Conform to JSON Schema 2020-12

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                                                                                                                         |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **SEP**       | 2106                                                                                                                                                                          |
| **Title**     | Tools `inputSchema` & `outputSchema` Conform to JSON Schema 2020-12                                                                                                           |
| **Status**    | Final                                                                                                                                                                         |
| **Type**      | Standards Track                                                                                                                                                               |
| **Created**   | 2026-01-06                                                                                                                                                                    |
| **Author(s)** | John McBride ([@jpmcb](https://github.com/jpmcb)) — original proposal; Ola Hungerford ([@olaservo](https://github.com/olaservo)) — current shepherd, post-SEP-1850 conversion |
| **Sponsor**   | Ola Hungerford ([@olaservo](https://github.com/olaservo))                                                                                                                     |
| **PR**        | [#2106](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2106)                                                                                               |

***

## Abstract

This SEP proposes loosening the restrictions on `inputSchema`, `outputSchema`, and `structuredContent` to better support JSON Schema 2020-12. Specifically:

* **`inputSchema`**: Keeps `type: "object"` required (since tool arguments are objects), but allows any additional JSON Schema properties to support powerful validation compositions (`anyOf`, `oneOf`, `allOf`, etc.)
* **`outputSchema`**: Fully supports JSON Schema 2020-12 since MCP servers may return any valid JSON
* **`structuredContent`**: Accepts any JSON value validated by `outputSchema`

This proposal enables MCP servers to leverage the expressiveness of JSON Schema 2020-12 while maintaining backward compatibility with existing implementations.

## Motivation

The current MCP specification restricts tool schemas in ways that conflict with full JSON Schema support:

1. **inputSchema restriction**: Currently only allows `type`, `properties`, and `required` fields. This prevents use of composition keywords like `anyOf`, `oneOf`, and `allOf` for sophisticated object validation patterns.

2. **outputSchema restriction**: Also restricted to `type: "object"` with only `properties` and `required`, despite the specification claiming to support "JSON Schema."

3. **structuredContent restriction**: Defined as `{ [key: string]: unknown }` (an object with string keys), which prevents returning arrays—a common API response pattern.

### Real-World Impact

Consider a weather API tool that returns hourly forecasts:

```json theme={null}
[
  { "hour": "09:00", "temp": 68, "conditions": "sunny" },
  { "hour": "10:00", "temp": 72, "conditions": "partly cloudy" },
  { "hour": "11:00", "temp": 75, "conditions": "cloudy" }
]
```

Currently, this natural array response is **impossible** because `structuredContent` must be an object. Developers are forced to wrap arrays in unnecessary container objects:

```json theme={null}
{
  "forecasts": [
    { "hour": "09:00", "temp": 68, "conditions": "sunny" },
    ...
  ]
}
```

This artificial constraint:

* Adds unnecessary nesting to responses
* Conflicts with common REST API patterns
* Prevents direct schema validation of array responses

### Schema Composition Use Cases

The current `inputSchema` restriction prevents legitimate schema patterns. With this SEP, tools can use composition keywords alongside `type: "object"`:

```json theme={null}
{
  "type": "object",
  "oneOf": [
    { "properties": { "id": { "type": "string" } }, "required": ["id"] },
    { "properties": { "name": { "type": "string" } }, "required": ["name"] }
  ]
}
```

This pattern allows a tool to accept either an ID-based or name-based lookup—a common API design that is currently unsupported because the schema only allows `type`, `properties`, and `required` fields.

## Specification

### 1. Loosen inputSchema

**Current definition:**

```typescript theme={null}
inputSchema: {
  type: "object";
  properties?: { [key: string]: object };
  required?: string[];
};
```

**Proposed definition:**

```typescript theme={null}
inputSchema: {
  $schema?: string;
  type: "object";
  [key: string]: unknown;
};
```

The `inputSchema` field retains the `type: "object"` requirement (since tool arguments are always objects), but now accepts any additional JSON Schema properties. This enables:

* Composition keywords: `anyOf`, `oneOf`, `allOf`, `not`
* Conditional schemas: `if`/`then`/`else`
* Reference schemas: `$ref`, `$defs`
* Any other valid JSON Schema 2020-12 keywords

### 2. Loosen outputSchema

**Current definition:**

```typescript theme={null}
outputSchema?: {
  type: "object";
  properties?: { [key: string]: object };
  required?: string[];
};
```

**Proposed definition:**

```typescript theme={null}
outputSchema?: {
  $schema?: string;
  [key: string]: unknown;
};
```

The `outputSchema` field accepts any valid JSON Schema 2020-12 object, enabling schemas that validate arrays, primitives, or complex compositions. Unlike `inputSchema`, there is no `type: "object"` requirement since tool outputs can be any valid JSON.

### 3. Loosen structuredContent

**Current definition:**

```typescript theme={null}
structuredContent?: { [key: string]: unknown };
```

**Proposed definition:**

```typescript theme={null}
structuredContent?: unknown;
```

The `structuredContent` field accepts any valid JSON value that conforms to the tool's `outputSchema`. This includes:

* Objects: `{ "key": "value" }`
* Arrays: `[1, 2, 3]` or `[{ "id": "abc" }, { "id": "xyz" }]`
* Primitives: `"string"`, `42`, `true`, `null`

### 4. Documentation Updates

Update `docs/specification/draft/server/tools.mdx`:

* Remove statement that `structuredContent` is "returned as a JSON object"
* Clarify that `structuredContent` can be any JSON value conforming to `outputSchema`
* Add examples demonstrating array responses

### 5. Examples

#### Tool returning an array of objects:

```json theme={null}
{
  "name": "list_users",
  "description": "List all users in the system",
  "inputSchema": {
    "type": "object",
    "properties": {
      "limit": { "type": "integer", "minimum": 1, "maximum": 100 }
    }
  },
  "outputSchema": {
    "type": "array",
    "items": {
      "type": "object",
      "properties": {
        "id": { "type": "string" },
        "name": { "type": "string" },
        "email": { "type": "string", "format": "email" }
      },
      "required": ["id", "name"]
    }
  }
}
```

Response:

```json theme={null}
{
  "content": [
    {
      "type": "text",
      "text": "Found 2 users: Alice (u1, [email protected]) and Bob (u2, [email protected])."
    }
  ],
  "structuredContent": [
    { "id": "u1", "name": "Alice", "email": "[email protected]" },
    { "id": "u2", "name": "Bob", "email": "[email protected]" }
  ]
}
```

#### Tool with composition schema:

```json theme={null}
{
  "name": "find_resource",
  "description": "Find a resource by ID or name",
  "inputSchema": {
    "type": "object",
    "oneOf": [
      {
        "properties": { "id": { "type": "string", "format": "uuid" } },
        "required": ["id"]
      },
      {
        "properties": { "name": { "type": "string", "minLength": 1 } },
        "required": ["name"]
      }
    ]
  }
}
```

## Rationale

### Why not just allow arrays?

While we could simply extend `structuredContent` to allow arrays, this would be an incomplete solution. The root cause is that the schema types are artificially restricted to `type: "object"`. By allowing any valid JSON Schema, we:

1. Enable the full power of JSON Schema 2020-12
2. Align with the specification's claim of JSON Schema support
3. Provide a consistent, principled approach rather than piecemeal fixes

### Why not require a wrapper object?

Requiring arrays to be wrapped in objects (e.g., `{ "items": [...] }`) was considered but rejected because:

1. It adds unnecessary complexity to responses
2. It conflicts with common API design patterns
3. It prevents direct schema validation of the actual response structure
4. JSON Schema already handles array validation elegantly

### Real-World API Patterns

Many production APIs return arrays directly:

* **GitHub Events API**: Returns arrays of event objects
* **AccuWeather Search API**: Returns arrays of location matches
* **REST collection endpoints**: Standard `GET /users` returns `[{...}, {...}]`

Forcing wrapper objects creates friction for developers integrating existing APIs with MCP. Generic JSON Schema validation libraries should work without MCP-specific customization.

### Alignment with JSON Schema 2020-12

JSON Schema 2020-12 provides powerful features for schema composition and validation. By removing artificial restrictions, MCP aligns with industry standards (OpenAPI 3.1 uses JSON Schema 2020-12) and enables developers to leverage existing JSON Schema knowledge and tooling.

### SDK Ecosystem Evidence

The friction caused by current restrictions is not theoretical. FastMCP, one of the most popular Python SDKs for MCP, has implemented extensive workarounds:

1. **Explicit error messages** acknowledge the limitation:

   ```python theme={null}
   raise ValueError(
       f"Output schemas must represent object types due to MCP spec limitations."
   )
   ```

2. **Auto-wrapping infrastructure** adds complexity:
   * A `_WrappedResult` dataclass wraps non-object returns
   * A custom `x-fastmcp-wrap-result` extension enables client-side unwrapping
   * Both SDK and client need matching wrap/unwrap logic

Cut at 300 lines. The page has the rest.

seps/2133-extensions First recorded · 289 lines, first recorded

# SEP-2133: Extensions ## Abstract ## Motivation ## Specification ### Definition ### Official Extensions ### Experimental Extensions ### Lifecycle #### Creation #### Iteration #### Promotion to Core Protocol (Optional) ### Spec Recommendation ### SDK Implementation ### Evolution ### Negotiation #### Client Capabilities #### Server Capabilities #### Server-Side Capability Checking #### Graceful Degradation ### Legal Requirements #### Trademark Policy #### Antitrust #### Licensing #### Contributor License Grant #### No Other Rights ### Not Specified ## Rationale ## Backward Compatibility ## Security Implications ## Reference Implementation

The first capture of this source. The page was already there, and this is what it said.

# SEP-2133: Extensions

> Extensions

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2133                                                                            |
| **Title**     | Extensions                                                                      |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2025-01-21                                                                      |
| **Author(s)** | Peter Alexander ([@pja-ant](https://github.com/pja-ant))                        |
| **Sponsor**   | None (seeking sponsor)                                                          |
| **PR**        | [#2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133) |

***

## Abstract

This SEP establishes a lightweight framework for extending the Model Context Protocol through optional, composable extensions. This proposal defines a governance model and presentation structure for extensions that allows the MCP ecosystem to evolve while maintaining core protocol stability. Extensions enable experimentation with new capabilities without forcing adoption across all implementations, providing clear extension points for the community to propose, review, and adopt enhanced functionality.

This SEP defines both official extensions (maintained by MCP maintainers) and experimental extensions (an incubation pathway for Working Groups and Interest Groups to prototype and collaborate on extension ideas before formal acceptance). Externally maintained extensions will likely come at a later stage.

## Motivation

MCP currently lacks any form of guidance on how extensions are to be proposed or adopted. Without a process, it is unclear how these extensions are governed, what expectations there are around implementation, how they should be referenced in the specification, etc.

## Specification

### Definition

An MCP extension is an optional addition to the specification that defines capabilities beyond the core protocol. Extensions enable functionality that may be modular (e.g., distinct features like authentication), specialized (e.g., industry-specific logic), or experimental (e.g., features being incubated for potential core inclusion).

Extensions are identified using a unique *extension identifier* with the format: `{vendor-prefix}/{extension-name}`, e.g. `io.modelcontextprotocol/oauth-client-credentials` or `com.example/websocket-transport`. The names follow the same rules as the [\_meta keys](https://modelcontextprotocol.io/specification/draft/basic/index#meta), except that the prefix is mandatory.

To prevent identifier collisions, the vendor prefix SHOULD be a reversed domain name that the extension author owns or controls (similar to Java package naming conventions). For example, a company owning `example.com` would use `com.example/` as their prefix.

Breaking changes MUST use a new identifier, e.g. `io.modelcontextprotocol/oauth-client-credentials-v2`. A breaking change is any modification that would cause existing compliant implementations to fail or behave incorrectly, including: removing or renaming fields, changing field types, altering the semantics of existing behavior, or adding new required fields.

Extensions may have settings that are sent in client/server messages for fine-grained configuration.

This SEP defines *Official Extensions* and *Experimental Extensions*. Experimental extensions are maintained within the MCP organization as an incubation pathway but are not yet officially accepted. *Unofficial extensions* are not recognized by MCP governance and may be introduced and governed by developers outside the MCP organization.

### Official Extensions

Official extensions live inside the MCP github org at [https://github.com/modelcontextprotocol/](https://github.com/modelcontextprotocol/) and are officially developed and recommended by MCP maintainers. Official extensions use the `io.modelcontextprotocol` vendor prefix in their extension identifiers.

An *extension repository* is a repository within the official modelcontextprotocol github org with the `ext-` prefix, e.g. [https://github.com/modelcontextprotocol/ext-auth](https://github.com/modelcontextprotocol/ext-auth).

* Extension repositories are created at the core maintainers discretion with the purpose of grouping extensions in a specific area (e.g. auth, transport, financial services).
* A repository has a set of maintainers (identified by MAINTAINERS.md) appointed by the core maintainers that are responsible for the repository and extensions within it (e.g. [ext-auth MAINTAINERS.md](https://github.com/modelcontextprotocol/ext-auth/blob/main/MAINTAINERS.md), [ext-apps MAINTAINERS.md](https://github.com/modelcontextprotocol/ext-apps/blob/main/MAINTAINERS.md)).
* Extensions SHOULD have an associated working group or interest group to guide their development and gather community input.

An *extension* is a versioned specification document within an extension repository, e.g. [https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/draft/oauth-client-credentials.mdx](https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/draft/oauth-client-credentials.mdx)

* Extension specifications MUST use the same language as the core specification (i.e. \[[BCP 14](https://www.rfc-editor.org/info/bcp14)] \[[RFC2119](https://datatracker.ietf.org/doc/html/rfc2119)] \[[RFC8174](https://datatracker.ietf.org/doc/html/rfc8174)]) and SHOULD be worded as if they were part of the core specification.

While day-to-day governance is delegated to extension repository maintainers, the core maintainers retain ultimate authority over official extensions, including the ability to modify, deprecate, or remove any extension.

### Experimental Extensions

Experimental extensions provide an incubation pathway for Working Groups (WGs) and Interest Groups (IGs) to facilitate discovery, prototype ideas, and collaborate on extension concepts before formal SEP submission. Experimental extensions allow cross-company collaboration under neutral governance with clear anti-trust protection and IP clarity.

An *experimental extension repository* is a repository within the official modelcontextprotocol github org with the `experimental-ext-` prefix, e.g. `https://github.com/modelcontextprotocol/experimental-ext-interceptors`.

* Any maintainer MAY create an experimental extension repository while the associated SEP is still in draft state (or before a SEP has been submitted).
* Experimental extensions MUST be associated with a Working Group or Interest Group, whose maintainers are responsible for day-to-day governance of the repository.
* Experimental extension repositories MUST clearly indicate their experimental/non-official status (e.g., in the README) to avoid confusion with official extensions.
* Any published packages from experimental extensions MUST use naming that clearly indicates their experimental status.
* Core maintainers retain oversight of experimental extension repositories, including the ability to archive or remove them.

To graduate an experimental extension to official status, the standard SEP process (Extensions Track) applies. The experimental repository and any reference implementations developed during incubation MAY be referenced in the SEP to demonstrate the extension's practicality.

### Lifecycle

#### Creation

Extensions MAY optionally begin as experimental extensions (see *Experimental Extensions* section) to facilitate prototyping and collaboration before formal submission. This incubation period is encouraged but not required.

To become an official extension, extensions are created via a SEP in the [main MCP repository](https://github.com/modelcontextprotocol/modelcontextprotocol/) using the [standard SEP guidelines](https://modelcontextprotocol.io/community/sep-guidelines) but with a new type: **Extensions Track**. This type follows the same review and acceptance process as Standards Track SEPs, but clearly indicates that the proposal is for an extension rather than a core protocol addition. The SEP must identify the Working Group and Extension Maintainers that will be responsible for the extension. See [SEP-2148](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2148) for how maintainers are appointed.

Extension SEPs:

* SHOULD be discussed and iterated on in a relevant working group prior to submission.
* MUST have at least one reference implementation in an official SDK prior to review to ensure the extension is practical and implementable.
* MAY reference an existing experimental extension repository and implementations developed during incubation.
* Will be reviewed by the Core Maintainers, who have the final authority over its inclusion as an Official Extension.

Once approved, the author SHOULD produce a PR that introduces the extension to the extension repository and reference in the main spec (see *Spec Recommendation* section). Approved extensions MAY be implemented in additional clients / servers / SDKs (see *SDK Implementation*).

#### Iteration

Once accepted, extensions may be iterated on without further review from the Core Maintainers. The extension repository maintainers are responsible for the review and acceptance of changes to an extension and SHOULD coordinate change via the relevant working group(s). As extensions are independent of the core protocol, extensions may be updated and deployed at any time, but changes MUST ensure they account for backwards compatibility in their design.

#### Promotion to Core Protocol (Optional)

Eventually, some extensions MAY transition to being core protocol features. This SHOULD be treated as a Standards Track SEP with separate core maintainer review. Note that not all extensions are suitable for inclusion in the core protocol (e.g. those specific to an industry) and may remain as extensions indefinitely.

### Spec Recommendation

Extensions will be referenced from a new page on the MCP website at [modelcontextprotocol.io/extensions](http://modelcontextprotocol.io/extensions) (to be created) with links to their specification.

Links to relevant extensions MAY also be added to the core specification as appropriate (e.g. [https://modelcontextprotocol.io/specification/draft/basic/authorization](https://modelcontextprotocol.io/specification/draft/basic/authorization) may link to ext-auth extensions), but they MUST be clearly advertised as optional extensions and SHOULD be links only (not copies of specification text).

### SDK Implementation

SDKs MAY implement extensions. Where implemented, extensions MUST be disabled by default and require explicit opt-in. SDK documentation SHOULD list supported extensions.

SDK maintainers have full autonomy over extension support in their SDKs:

* Maintainers are solely responsible for the implementation and maintenance of any extensions they choose to support.
* Maintainers are under no obligation to implement any extension or accept contributed implementations. Extension support is not required for 100% protocol conformance or the upcoming SDK conformance tiers.
* This SEP does not prescribe how SDKs should structure or package extensions. Maintainers may provide extension points, plugin systems, or any other mechanism they see fit.

### Evolution

All extensions evolve **independently** of the core protocol, i.e. a new version of an extension MAY be published without review by the core maintainers. Minor updates, bug fixes, and non-breaking enhancements to an extension do not require a new SEP; these changes are managed by the extension repository maintainers.

Extensions SHOULD be versioned, but exact versioning approach is not specified here.

### Negotiation

Clients and servers advertise their support for extensions in the [ClientCapabilities](https://modelcontextprotocol.io/specification/2025-06-18/schema#clientcapabilities) and [ServerCapabilities](https://modelcontextprotocol.io/specification/2025-06-18/schema#servercapabilities) fields respectively, and in the [Server Card](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1649) (currently in progress).

A new "extensions" field will be introduced to each that is a map of *extension identifiers* to per-extension settings objects. Each extension specifies the schema of its settings object; an empty object indicates no settings.

#### Client Capabilities

Clients advertise extension support in the `initialize` request:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "roots": {
        "listChanged": true
      },
      "extensions": {
        "io.modelcontextprotocol/ui": {
          "mimeTypes": ["text/html;profile=mcp-app"]
        }
      }
    },
    "clientInfo": {
      "name": "ExampleClient",
      "version": "1.0.0"
    }
  }
}
```

#### Server Capabilities

Servers advertise extension support in the `initialize` response:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "tools": {},
      "extensions": {
        "io.modelcontextprotocol/ui": {}
      }
    },
    "serverInfo": {
      "name": "ExampleServer",
      "version": "1.0.0"
    }
  }
}
```

#### Server-Side Capability Checking

Servers SHOULD check client capabilities before offering extension-specific features:

```typescript theme={null}
const hasUISupport = clientCapabilities?.extensions?.[
  "io.modelcontextprotocol/ui"
]?.mimeTypes?.includes("text/html;profile=mcp-app");

if (hasUISupport) {
  // Register tools with UI features
} else {
  // Register text-only fallback
}
```

#### Graceful Degradation

If one party supports an extension but the other does not, the supporting party MUST either revert to core protocol behavior or reject the request with an appropriate error if the extension is mandatory. Extensions SHOULD document their expected fallback behavior. For example, a server offering UI-enhanced tools should still return meaningful text content for clients that do not support the UI extension, while a server requiring a specific authentication extension MAY reject connections from clients that do not support it.

### Legal Requirements

#### Trademark Policy

* Use of MCP trademarks in extension identifiers does not grant trademark rights. Third parties may not use 'MCP', 'Model Context Protocol', or confusingly similar marks in ways that imply endorsement or affiliation.
* MCP makes no judgment about trademark validity of terms used in extensions.

#### Antitrust

* Extension developers acknowledge that they may compete with other participants, have no obligation to implement any extension, are free to develop competing extensions and protocols, and may license their technology to third parties including for competing solutions.
* Status as an official extension does not create an exclusive relationship.
* Extension repository maintainers act in individual capacity using best technical judgment.

#### Licensing

Official extensions MUST be available under the Apache 2.0 license.

#### Contributor License Grant

By submitting a contribution to an official MCP extension repository, you represent that:

1. You have the legal authority to grant the rights in this agreement
2. Your contribution is your original work, or you have sufficient rights to submit it
3. You grant to Linux Foundation and recipients of the specification a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license to:
   * Reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the contribution
   * Make, have made, use, offer to sell, sell, import, and otherwise transfer implementations

#### No Other Rights

Except as explicitly set forth in this section, no other patent, trademark, copyright, or other intellectual property rights are granted under this agreement, including by implication, waiver, or estoppel.

### Not Specified

This SEP does not specify all aspects of an extension system. The following is an incomplete list of what this SEP does not address:

* **Schema**: we do not specify a mechanism for extensions to advertise how they modify the schema.
* **Dependencies**: we do not specify if/how extensions may have dependencies on specific core protocol versions, or interdependencies with other extensions (or versions of extensions).
* **Profiles**: we do not specify a way of grouping extensions.

These are omitted not because they are unimportant, but because they may be added later and the goal of this SEP is simply to get some initial extension structure off the ground and defers detailed technical discussion around more complex/debatable aspects of extensions.

## Rationale

This design for extensions uses the following principles:

* **Start simple**: the intention is to have a relatively simple mechanism that allows people to start building and proposing extensions in a structured way.
* **Clear governance**: For now, the focus is on clear governance and less on implementation details.
* **Refine later**: Over time, once we have more experience with extensions, we can adjust the approach appropriately.

Some specific design choices:

* **Why extension repositories instead of individual/independent extensions?** Repositories provide a natural group and governance structure that allows for the repository maintainers to enforce structure and conformity to extensions. It avoids a failure case of different extensions in an area working in incompatible ways. Also provides a way to delegate much of the governance work.
* **Why not require core maintainer review for official extensions?** Delegated reviews allows for extensions to evolve autonomously without being bottlenecked on core maintainer review, which is already a (often months) long process.
* **Why separate versioning?** Extensions are additions to the spec and optional so there is no need to tie versions together. Separate versions allow for more rapid iteration.

## Backward Compatibility

The extension framework itself is purely additive to the core protocol, so there are no backwards compatibility concerns with the core specification.

The design described in this SEP is consistent with existing official extensions ([ext-apps](https://github.com/modelcontextprotocol/ext-apps) and [ext-auth](https://github.com/modelcontextprotocol/ext-auth)), which already use the patterns specified here for capability negotiation and extension identifiers.

However, individual extensions may have their own backwards compatibility concerns. Extensions MUST consider and account for backwards compatibility in their design, both across core protocol versions and extension versions. Breaking changes within an extension MUST use a new extension identifier (see *Definition* section). Extensions SHOULD also document their approach to backwards compatibility and stability (e.g. an extension MAY advertise itself as "experimental" indicating that it may break without notice).

## Security Implications

Extensions MUST implement all related security best practices in the area that they extend.

Clients and servers SHOULD treat any new fields or data introduced as part of an extension as untrusted and SHOULD comprehensively validate them.

## Reference Implementation

To be provided.

seps/2148-contributor-ladder First recorded · 539 lines, first recorded

# SEP-2148: MCP Contributor Ladder ## Abstract ## Motivation ## Specification ### Guiding Principles ### Role Definitions ### Contributor ### Member ### Maintainer ### Core Maintainer ### Lead Maintainer ### Succession ### Advancement Process #### Self-Nomination vs. Recognition #### Process Steps ### Decision-Making & Escalation #### Delegation as Default #### Escalation Matrix ### Contribution Pathways #### Code Contributions #### Specification Work #### Documentation #### Community Building #### Quality & Security ### Working Group and Interest Group Leadership ### Community Moderators ### Recognition and Visibility ### Stepping Down and Emeritus Status ## Rationale ### Why a Formal Ladder? ### Why Minimum Timelines? ### Why Two-Organization Sponsorship? ### Model Inspiration ## Backward Compatibility ## Security Implications ## Reference Implementation ## Appendix: Checklist Templates ### Member Nomination Checklist ### Maintainer Nomination Checklist ### Community Moderator Nomination Checklist

The first capture of this source. The page was already there, and this is what it said.

# SEP-2148: MCP Contributor Ladder

> MCP Contributor Ladder

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Process
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                                                                        |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **SEP**       | 2148                                                                                                                         |
| **Title**     | MCP Contributor Ladder                                                                                                       |
| **Status**    | Final                                                                                                                        |
| **Type**      | Process                                                                                                                      |
| **Created**   | 2026-01-15                                                                                                                   |
| **Author(s)** | David Soria Parra ([@dsp-ant](https://github.com/dsp-ant)), Sarah Novotny ([@sarahnovotny](https://github.com/sarahnovotny)) |
| **Sponsor**   | David Soria Parra ([@dsp-ant](https://github.com/dsp-ant))                                                                   |
| **PR**        | [#2148](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2148)                                              |

***

## Abstract

This SEP establishes a formal contributor ladder for the Model Context Protocol project, defining clear roles, responsibilities, and advancement criteria from first-time contributor through Core Maintainer. The ladder provides transparent pathways for community members to understand how they can grow their involvement and influence within the project.

This SEP is a companion to [SEP-2149: MCP Group Governance and Charter Template](./2149-working-group-charter-template.md), which defines how Working Groups and Interest Groups operate. The two SEPs intersect: WG/IG leadership requires Member status on this ladder, and group participation is a recognized pathway to ladder advancement.

## Motivation

As MCP adoption grows, the project needs a clear framework for:

1. **Contributor Development**: Community members lack visibility into how to grow their involvement and influence within the MCP project. A defined ladder shows the path from first contribution to project leadership.

2. **Trust Building**: Merge rights and other high-privilege responsibilities are earned through demonstrated commitment and good judgment over time. A graduated system ensures contributors are set up for success and are trusted by existing maintainers and broader community before taking on greater ownership of the project.

3. **Organizational Diversity**: With multiple organizations contributing to MCP, the project needs mechanisms to prevent organizational capture while welcoming participation from outside Anthropic.

4. **Scalability**: Core Maintainer bandwidth is limited. Delegating authority to Maintainers and Working/Interest Group Leads through clear scope definitions enables the project to scale.

5. **Recognition**: Contributors invest significant effort in MCP. Formal recognition through defined roles acknowledges their contributions and encourages sustained engagement.

Without a contributor ladder, advancement decisions become ad-hoc, potentially inconsistent, and opaque to the community.

## Specification

### Guiding Principles

The contributor ladder operates under these principles:

* **Earned Trust**: Advancement based on demonstrated meaningful contributions that align with the project goals, good judgment, and sustained engagement, not tenure alone
* **Multiple Growth Pathways**: Code, specification work, documentation, and community building all lead to advancement
* **Transparency**: Criteria for advancement are explicit and consistently applied
* **Alignment With MCP Goals**: Individual contributors must demonstrate commitment to advance and evolve MCP project components beyond one's employer's interests

### Role Definitions

| Role                                             | Summary                                       | Key Privileges                                                            | Minimum Timeline                                      |
| ------------------------------------------------ | --------------------------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------- |
| [**Contributor**](#contributor)                  | Anyone who contributes to MCP                 | Submit issues, PRs, participate in discussions                            | Immediate                                             |
| [**Member**](#member)                            | Established, active contributor               | GitHub org membership, triage rights, eligible for WG/IG leadership       | 2-3 months of meaningful contributions                |
| [**Maintainer**](#maintainer)                    | Area steward with operational responsibility  | Merge rights, release participation                                       | 6+ months as Member                                   |
| [**Core Maintainer**](#core-maintainer)          | Technical leadership and protocol stewardship | Final decision authority, governance participation                        | By invitation after sustained Maintainer contribution |
| [**Lead Maintainer**](#lead-maintainer)          | Ultimate project authority (founders)         | All Core Maintainer privileges, veto authority, appoints Core Maintainers | Reserved for project founders — succession only       |
| [**Community Moderator**](#community-moderators) | CoC enforcement and community health          | Moderation rights on community platforms, incident handling               | Parallel track — Member status + appointment          |

*Timelines listed are minimum contribution periods, not guarantees of advancement. They exist to protect the project from rapid privilege escalation and to ensure a high bar of demonstrated commitment. Actual advancement is discretionary and may take longer in practice; the only guarantee is that advancement will not happen on a shorter timescale than documented. Exceptions require explicit Core Maintainer approval with documented rationale.*

### Contributor

Anyone who has contributed to MCP in any form is a contributor. This includes:

* Opening issues or discussions
* Submitting pull requests
* Participating in working group discussions
* Improving documentation
* Helping other community members

**No formal requirements**, we welcome all contributions.

**How to get started:**

* Review the [Contributing Guide](https://modelcontextprotocol.io/community/contributing)
* Join community channels (Discord, GitHub Discussions)
* Look for issues tagged `good-first-issue` or `help-wanted`
* Attend working group meetings

### Member

Members are established contributors who have demonstrated ongoing commitment to the success and growth of MCP.

**Requirements:**

* Multiple contributions to MCP (code, documentation, and/or community)
* At least one merged PR or accepted contribution
* Ongoing engagement with the MCP community and not just one-off contributions
* Enabled two-factor authentication on GitHub
* No objections from existing Members within 7 days

**Sponsorship:**

* Sponsored by two existing Members or Maintainers from different organizations
* or sponsored by one Core Maintainer or Lead Maintainer

**Minimum timeline:** 2-3 months of active participation

**Responsibilities:**

* Continue contributing in good faith
* Be responsive to assigned issues and PRs
* Follow community guidelines and code of conduct
* Help onboard new contributors when possible

**Privileges:**

* GitHub organization membership with triage rights
* Can be assigned to issues and PRs
* Can use shortcut approval or review commands on PRs, such as `/lgtm`
* Listed in community membership roster
* Can create PRs in restricted repositories
* Eligible for Working Group Lead or Interest Group Facilitator roles

**Inactivity:** Members with no contributions for 3 months may be moved to emeritus status. Re-engagement follows a simplified re-familiarization process.

### Maintainer

Maintainers are trusted stewards who take operational responsibility for specific areas.

**Requirements:**

* Member for at least 6 months with sustained, high-quality contributions
* Demonstrated leadership in working groups or significant initiatives
* Shown ability to represent MCP's interests above an individual employer's or organization's interests
* Deep understanding of the MCP vision, roadmap, and design principles
* Understands how their area impacts real-world AI integration and model interaction patterns
* Completed security and governance onboarding

**Sponsorship & Approval:**

* Sponsored by an existing Maintainer or Core Maintainer
* Approved by Core Maintainers

**Responsibilities:**

* Operational ownership of area health (test stability, documentation currency)
* Responsible for the release processes and milestone planning of their respective scope
* Provide timely review of escalated decisions
* Active participation in governance discussions
* Mentor Members and develop future Maintainers
* Represent MCP in external contexts when appropriate
* Engage with the area ecosystem and stakeholders, understanding real-world usage, and representing community needs
* Ensure proposals reaching Core Maintainers are refined, well-considered, and account for ecosystem-wide impact
* Active participation in discussions on communication channels (GitHub issues, Discord)

**Privileges:**

* Merge privileges for owned areas
* Can sponsor new Maintainers
* Participate in roadmap and prioritization discussions
* Listed in `MAINTAINERS.md`
* Release participation

All pathways can lead to Maintainer, though the specific scope will align with the contribution type.

**Inactivity:** Maintainers with no contributions for 6 months may be moved to emeritus status following review by Core Maintainers. Merge rights are revoked upon emeritus transition. Re-engagement requires re-completing security and governance onboarding.

### Core Maintainer

Core Maintainers hold final decision-making authority for the MCP technical direction. This is the highest level of trust in the community.

*Note: The Core Maintainer role is intentionally limited to ensure coherent technical vision while the project scales. Core Maintainer bandwidth concerns are addressed through clearer delegation to Maintainers, Working Group Leads, and Interest Group Facilitators, not expansion of Core Maintainer numbers.*

**Requirements:**

* Sustained contribution as Maintainer or similar roles over at least 6 months
* Demonstrated judgment on complex, project-wide decisions
* Trust and respect across organizational boundaries
* Deep commitment to MCP's long-term success

**Appointment:**

* Nominated by majority of Core Maintainers, approved by Lead Maintainers
* Or direct appointment by Lead Maintainers

When evaluating candidates, Core Maintainers should consider whether the current composition adequately represents the breadth of the MCP ecosystem, including enterprise adopters deploying MCP in production domains.

**Responsibilities:**

* Final technical decision authority for contested or cross-cutting issues
* Stewardship of project vision and design principles
* Governance and policy decisions
* External representation of MCP
* Succession planning and community health
* Ensure restraint and sustainability in protocol evolution
* Participation in Core Maintainer meetings and Core Maintainer meetups

**Privileges:**

* Final approval on breaking changes and major spec revisions
* Voting rights on [SEPs](https://modelcontextprotocol.io/community/sep-guidelines) (Specification Enhancement Proposals)
* Approval of Maintainers
* Governance voting rights / expectation of governance participation
* Administrative rights to all MCP GitHub repositories
* Listed in `MAINTAINERS.md` as Core Maintainer

**Inactivity:** Core Maintainers with no participation in governance or technical decisions for 6 months may be moved to emeritus status following review by Lead Maintainers. Given the trust and visibility of this role, Core Maintainers are expected to proactively communicate reduced availability.

### Lead Maintainer

Lead Maintainers hold ultimate authority over MCP's direction and governance. This is a lifetime appointment reserved for project founders. There is no defined advancement path to this role; it is only assumed through succession when necessary (see [Succession](#succession)).

**Responsibilities:**

* All Core Maintainer responsibilities
* Appointment and removal of Core Maintainers
* Final authority on contested governance decisions
* Project-wide strategic direction

**Privileges:**

* Can act alone where Core Maintainers require multiple approvals
* Veto authority over any decision
* Appointment of successor

### Succession

If a Lead Maintainer leaves their role for any reason, the succession process begins upon their written notice or, if unable to provide notice, upon a determination by the remaining Lead Maintainer(s) or Core Maintainers that the Lead Maintainer is unable to continue serving.

If one or more Lead Maintainer(s) remain, they shall appoint a successor (by majority vote if multiple), and the remaining Lead Maintainer(s) will continue to govern until a successor is appointed.

If no Lead Maintainers remain, the Core Maintainers shall appoint a successor by majority vote within 30 days, and the project operates by two-thirds vote of Core Maintainers until a new Lead Maintainer is appointed.

### Advancement Process

#### Self-Nomination vs. Recognition

Contributors may either:

1. **Self-nominate** when they believe they meet the requirements
2. **Be nominated** by a sponsor who has observed their contributions

Both paths are equally valid. Self-nomination is encouraged and preferred, as it demonstrates initiative and self-awareness of the contribution scope.

#### Process Steps

1. **Nomination**: Nominee or sponsor opens an issue using the nomination template, including links to contributions demonstrating requirements and sponsor confirmations
2. **Community Review**: 7-day period for community input
3. **Decision**: Approving authority reviews and decides
4. **Onboarding**: New role-holder receives appropriate access and onboarding

| Advancement To      | Approved By                                                                     |
| ------------------- | ------------------------------------------------------------------------------- |
| Member              | 2 existing Members+ from different organizations, **or** 1 Core/Lead Maintainer |
| Maintainer          | 1 Maintainer or Core Maintainer sponsor + Core Maintainer approval              |
| Core Maintainer     | Lead Maintainers                                                                |
| Community Moderator | 1 Core Maintainer or Lead Maintainer                                            |

Self-nomination is encouraged, but nominees must still secure the required sponsorship. Sponsors confirm support in the nomination issue.

### Decision-Making & Escalation

#### Delegation as Default

MCP operates on a principle of delegation: decisions should be made at the lowest appropriate level. This enables the project to move quickly while preserving Core Maintainer bandwidth for cross-cutting concerns.

* **Maintainers, WG Leads, and IG Facilitators** handle day-to-day decisions within scope
* **Core Maintainers** intervene on escalation, cross-cutting issues, or when required (spec changes, Maintainer approval)
* **Lead Maintainer** intervenes only on contested governance decisions or when Core Maintainers cannot reach consensus

When in doubt, make the decision at your level and document it. Escalate only when blocked, when the decision has project-wide implications, or when explicitly required by process.

The detailed escalation procedure for Working Group and Interest Group disputes — including the designation of a Core Maintainer without shared organizational affiliation to resolve the issue — is defined in [SEP-2149 §1.5](./2149-working-group-charter-template.md).

#### Escalation Matrix

| Issue Type                                 | First Escalation    | Second Escalation | Timeline         |
| ------------------------------------------ | ------------------- | ----------------- | ---------------- |
| Technical disagreement in PR               | Maintainer in scope | Core Maintainer   | 5 business days  |
| Technical disagreement in WG               | WG Lead             | Core Maintainer   | 5 business days  |
| Technical disagreement in IG               | IG Facilitator      | Core Maintainer   | 5 business days  |
| Disagreement with WG Lead / IG Facilitator | Core Maintainer     | Lead Maintainer   | 7 business days  |
| Disagreement with Maintainer decision      | Core Maintainer     | Lead Maintainer   | 7 business days  |
| Core Maintainer disagreement               | Lead Maintainer     | N/A               | 10 business days |
| Code of Conduct violation                  | Community Moderator | Core Maintainer   | Immediate        |
| Security issue                             | Core Maintainer     | Lead Maintainer   | Immediate        |

**Escalation process:**

Cut at 300 lines. The page has the rest.

seps/2149-working-group-charter-template First recorded · 441 lines, first recorded

# SEP-2149: MCP Group Governance and Charter Template ## Abstract ## Motivation ## Specification ### Part 1: Group Governance #### 1.1 Leadership #### 1.2 Leadership Responsibilities #### 1.3 Participation Levels #### 1.4 Decision-Making Process #### 1.5 Escalation Path #### 1.6 Meeting Requirements #### 1.7 Communication Channels #### 1.8 Reporting #### 1.9 Lifecycle #### 1.10 Charter Amendments ### Part 2: Charter Template #### 1. Group Type #### 2. Mission Statement #### 3. Scope #### 4. Leadership #### 5. Authority & Decision Rights (WG only) #### 6. Membership #### 7. Operations #### 8. Deliverables & Success Metrics (WG only) #### 9. Changelog ## Rationale ### Why Separate Governance from Charter Template? ### Why Cover Both WGs and IGs? ### Why a Standardized Template? ### Why Explicit Authority Tables? ### Why Tiered Participation? ### Why Lazy Consensus as Default? ### Model Inspiration ## Backward Compatibility ### Transition for Existing Groups ## Security Implications ## Reference Implementation

The first capture of this source. The page was already there, and this is what it said.

# SEP-2149: MCP Group Governance and Charter Template

> MCP Group Governance and Charter Template

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Process
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                                                                        |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **SEP**       | 2149                                                                                                                         |
| **Title**     | MCP Group Governance and Charter Template                                                                                    |
| **Status**    | Final                                                                                                                        |
| **Type**      | Process                                                                                                                      |
| **Created**   | 2025-01-15                                                                                                                   |
| **Author(s)** | David Soria Parra ([@dsp-ant](https://github.com/dsp-ant)), Sarah Novotny ([@sarahnovotny](https://github.com/sarahnovotny)) |
| **Sponsor**   | David Soria Parra ([@dsp-ant](https://github.com/dsp-ant))                                                                   |
| **PR**        | [#2149](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2149)                                              |

***

## Abstract

This SEP establishes governance rules and a standardized charter template for MCP's two collaborative group types: **Working Groups (WGs)** and **Interest Groups (IGs)**. Working Groups produce concrete deliverables — SEPs, implementations, and code. Interest Groups facilitate discussion and knowledge-sharing to identify problems and gather requirements. The governance rules define the requirements that all groups must follow, with lighter expectations for IGs where appropriate. The charter template defines the structure each group uses to document its specific mission, scope, leadership, and work. Together they address community feedback about unclear authority delegation and inconsistent processes across groups.

This SEP is a companion to [SEP-2148: MCP Contributor Ladder](./2148-contributor-ladder.md), which defines the org-wide contributor roles (Member, Maintainer, Core Maintainer, Lead Maintainer) referenced throughout this document. Group leadership roles intersect with the contributor ladder: WG Leads and IG Facilitators must hold at least Member status on the ladder, and group participation is a recognized pathway to ladder advancement.

## Motivation

Community interviews and feedback identified several challenges with the current group structure:

1. **Unclear Authority**: It's not always clear what decisions a working group can make autonomously versus what requires Core Maintainer approval. This leads to hesitation and bottlenecks.

2. **Inconsistent Decision-Making**: Different groups operate with different norms. Decisions made in one meeting may be contradicted in another, with no clear process for resolution.

3. **Participation Confusion**: Community members are uncertain about who should participate in groups, what levels of involvement exist, and how to become more involved.

4. **Scope Creep**: Without explicit boundaries, groups may gradually expand into areas owned by other groups or outside their mandate.

5. **Missing Escalation Paths**: When groups get stuck, there's no clear path to resolution, leading to prolonged disagreements or abandoned initiatives.

6. **WG/IG Distinction**: The difference between Working Groups and Interest Groups is not always clear to participants, leading to mismatched expectations about outputs and commitment.

A standardized charter template and shared governance rules address these issues by establishing consistent processes across all groups while requiring each group to explicitly define its specific scope and boundaries.

## Specification

MCP maintains two types of collaborative groups:

* **Working Groups (WGs)** produce concrete deliverables — SEPs, reference implementations, and code. Active contribution is expected.
* **Interest Groups (IGs)** facilitate discussion and knowledge-sharing around a topic area. They produce problem statements, use cases, and recommendations. Active contribution is expected.

This specification has two parts:

1. **Group Governance** — rules that apply to all MCP groups (WGs and IGs), with differences noted where applicable
2. **Charter Template** — the structure each group fills in to define its specific mission, scope, and operations

***

### Part 1: Group Governance

The following rules apply to all MCP Working Groups and Interest Groups. Individual charters cannot override these requirements. Where rules differ between WGs and IGs, this is noted explicitly.

#### 1.1 Leadership

Each group has one or more **Leads** (referred to as **Facilitators** for Interest Groups).

**Requirements for all Leads and Facilitators:**

* Hold at least Member status on the [MCP Contributor Ladder](./2148-contributor-ladder.md)
* Demonstrated sustained engagement with the group's scope area
* Ability to facilitate across organizational boundaries
* Commitment to running the group's operations
* Group and its leadership sponsored by at least two Core Maintainers or one Lead Maintainer

**Additional requirements for WG Leads:**

* Commitment to 2-3 hours/week for WG activities

#### 1.2 Leadership Responsibilities

**All Leads are responsible for:**

* Schedule and facilitate regular meetings
* Set agendas in collaboration with participants and publish them in advance
* Ensure meeting notes are published within 48 hours
* Maintain the group's documentation
* Maintain a members list and respective access list in [https://github.com/modelcontextprotocol/access](https://github.com/modelcontextprotocol/access)
* Proactively recruit and retain broad, representative membership across organizations and perspectives

**WG Leads are additionally responsible for:**

* Drive proposals through the [SEP](https://modelcontextprotocol.io/community/sep-guidelines) (Specification Enhancement Proposal) process to resolution
* Triage SEPs in the WG's scope area, including closing SEPs that do not fit the roadmap (with documented rationale; authors may appeal to Core Maintainers)
* Escalate blocked decisions to Core Maintainers with clear context
* Maintain the working group's roadmap
* Solicit feedback from one or more Core Maintainers on the general direction of the group on a continuous basis
* Provide quarterly status updates to the Community and Core Maintainer Group

#### 1.3 Participation Levels

All groups use the following participation tiers. Note that **WG Member** is a group-specific participation level distinct from the org-wide **Member** role defined in the [Contributor Ladder](./2148-contributor-ladder.md) — an individual may be a WG Member in a specific group without holding org-wide Member status, and vice versa.

| Level                | Description                                       | Privileges                                                         |
| -------------------- | ------------------------------------------------- | ------------------------------------------------------------------ |
| **Observer**         | Anyone interested in following the group's work   | Read access, may attend meetings, limited discussion participation |
| **Participant**      | Active contributor to group discussions           | Can propose agenda items, participate in async votes               |
| **WG Member**        | Sustained contributor with demonstrated expertise | Counted for quorum (WGs only)                                      |
| **Lead/Facilitator** | Operational leadership of the group               | Sets agenda, facilitates, escalates                                |

Interest Groups primarily operate with Observers, Participants, and Facilitators. IGs may adopt the WG Member tier if their work warrants formal decision-making, but are not required to.

**Becoming a WG Member (WGs, and IGs that adopt the WG Member tier):**

* Sustained participation over 3 months
* Meaningful contributions (code, spec text, reviews, or documentation)
* Nomination by existing WG Member or Lead
* No objections from Leads, Core Maintainers, or Lead Maintainers within 7 days

**WG Member Responsibilities:**

* Continue contributing in good faith
* Maintain name, organization, and Discord name in the respective group's member list

**Active vs. Emeritus:** WG Members who do not participate for 3 consecutive months are moved to emeritus status and may return by demonstrating renewed participation.

#### 1.4 Decision-Making Process

This section applies primarily to Working Groups, which make binding decisions (consensus on technical designs, spec changes, etc.). Interest Groups typically operate by rough consensus in discussions and do not make binding decisions — their output is recommendations, problem statements, and use cases. IGs that adopt the WG Member tier may use this process for internal decisions.

**WG Consensus** is achieved through the following progression. Each step is attempted before moving to the next:

**Step 1: Lazy Consensus (default)**

* Proposals announced with clear deadline (5 days minimum for minor items, 10 days for significant items)
* Silence is consent
* Any WG Member may block with documented objection
* Blocks must propose alternatives or clear criteria for resolution
* If no blocks are raised by the deadline, the proposal is accepted

**Step 2: Formal Vote (when lazy consensus is blocked)**

A formal vote is triggered when:

* A WG Member blocks during the lazy consensus period
* A Lead or three or more WG Members request a formal vote

Voting rules:

* Quorum: 50% of active WG Members
* Passage: Simple majority for routine matters; 2/3 majority for scope changes
* Core Maintainer feedback is advisory unless explicitly stated as binding
* All votes documented with rationale

**Step 3: Escalation (when voting does not resolve)**

If a vote fails to resolve the matter (no quorum, does not pass, or the result is contested), the Lead escalates to Core Maintainers following the escalation path defined below.

#### 1.5 Escalation Path

For technical and design disagreements within a group's scope, groups should resolve disagreements locally before involving Core Maintainers. For WGs, this means using the decision-making progression (lazy consensus → vote → escalation). For IGs, the Facilitator should attempt to find rough consensus before escalating.

Some disagreements are not appropriate for group-level resolution and should be escalated directly to Core Maintainers:

* Scope disputes (whether a topic falls within the group's charter)
* Authority disputes (whether the group has the right to decide a matter)
* Cross-group conflicts (disagreements spanning multiple WGs or IGs)
* Code of conduct or behavioral concerns
* Membership or participation disputes

When escalation is necessary:

1. Lead documents the decision, options considered, and points of disagreement
2. Lead presents the escalation to the Core Maintainer group with a clear ask
3. The Core Maintainer group designates a CM—who should not share organizational affiliation with the parties involved—to resolve the issue and report back to the group
4. The designated CM either: (a) provides binding guidance, (b) requests more information, or (c) recommends the full Core Maintainer group deliberate
5. Timeline: Escalations should receive initial response within 5 business days

#### 1.6 Meeting Requirements

Leads determine meeting frequency, format, and duration based on the group's current needs and lifecycle stage. There is no fixed cadence requirement — a WG near a specification release may meet weekly, while an IG in early exploration may meet monthly or work primarily asynchronously.

Regardless of format or frequency, all group meetings must:

* Be open to all community participants (no closed or organization-internal meetings)
* Be published on [meet.modelcontextprotocol.io](https://meet.modelcontextprotocol.io) at least 7 days in advance
* Have agendas published and publicly available. The agenda or a link to the agenda should be published as a [GitHub Discussion in the Meeting Notes category](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/)
* Have notes published within 48 hours to the same discussion

Leads should actively involve WG Members and Participants in operational duties such as preparing agendas, taking meeting notes, and facilitating discussions.

#### 1.7 Communication Channels

All groups use the following channels:

| Channel                              | Purpose                        | Response Expectation |
| ------------------------------------ | ------------------------------ | -------------------- |
| Discord `#{name}-wg` or `#{name}-ig` | Quick questions, coordination  | Best effort          |
| GitHub Discussions                   | Long-form technical discussion | Weekly triage        |

In addition to Discord, groups can establish a discussion category in the [GitHub Discussions](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/). Leads will be granted the appropriate roles to manage and moderate discussions.

#### 1.8 Reporting

**Working Groups** provide quarterly updates (end of January, April, July, October) including:

* Progress against deliverables
* Blocked items and escalations
* Membership changes
* Upcoming priorities
* Resource needs

The quarterly updates are provided as a document posted in the [GitHub Discussions](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/) category of the Working Group. They are optionally discussed
with the Core Maintainers in a core maintainer meeting.

**Interest Groups** do not have formal reporting requirements but should keep their charter and member list current.

#### 1.9 Lifecycle

**Working Group Formation:**

* There must be a widely acknowledged concern requiring coordination
* PR for creation of WG into `docs/community/<name>/overview.mdx`, gated by CODEOWNERS requiring approval by Maintainers
* PR for charter into `docs/community/<name>/charter.mdx`, gated by CODEOWNERS requiring approval from a single Core Maintainer (who should notify all Core Maintainers)
* Initial member list approved by WG Lead

**Interest Group Formation:**

* Fill out the creation template in the `#wg-ig-group-creation` channel on [Discord](https://discord.gg/6CSzBmMkjX)
* A Core Maintainer reviews the proposal; the IG and its Facilitator(s) must be sponsored by at least two Core Maintainers or one Lead Maintainer
* Once sponsored, the Facilitator(s) organize the IG and create a charter

**Retirement:**

* **WGs**: WG Lead or Core Maintainer proposes retirement with rationale; Core Maintainer or Lead Maintainer approval required. WGs are also retired when they have no active work for a sustained period or have completed all planned deliverables.
* **IGs**: Core Maintainers or Lead Maintainers may retire an IG that is no longer active or needed.
* In both cases, documentation is archived and channels are marked inactive.

#### 1.10 Charter Amendments

Changes to a group's charter (WG or IG) require:

* Proposal by Lead/Facilitator or Core Maintainer
* Approval by Core Maintainers

***

### Part 2: Charter Template

Every MCP Working Group and Interest Group must maintain a charter document following this template structure. Charters are stored as MDX files at `docs/community/<group-name>/charter.mdx` in the modelcontextprotocol repository and added to the `docs/docs.json` file. A copyable version of this template is published at [`docs/community/charter-template.mdx`](/community/charter-template).

The charter captures information specific to each group. Governance rules from Part 1 apply automatically and do not need to be repeated in the charter. Sections marked **(WG only)** are required for Working Groups but optional for Interest Groups.

#### 1. Group Type

State whether this is a **Working Group** or an **Interest Group**.

#### 2. Mission Statement

A 2-3 sentence summary of the group's purpose, articulating:

* The problem space being addressed
* Why cross-cutting collaboration is needed
* For WGs: what concrete deliverables the group will produce
* For IGs: what discussions and knowledge-sharing the group will facilitate

*WG Example:*

> The Transport Working Group exists to evolve MCP's transport mechanisms to support diverse deployment scenarios—from local subprocess communication to horizontally-scaled cloud deployments—while maintaining protocol coherence and backward compatibility.

*IG Example:*

> The Enterprise IG explores the challenges of deploying MCP in enterprise environments, gathering use cases and requirements to inform future specification work.

#### 3. Scope

**In Scope**: Enumerated responsibilities.

For WGs, this includes:

* Specification Work: Specific spec sections or SEPs owned
* Reference Implementations: SDK components or reference implementations
* Cross-Cutting Concerns: Areas requiring coordination with other groups
* Documentation: Documentation responsibilities

For IGs, this includes:

Cut at 300 lines. The page has the rest.

seps/2164-resource-not-found-error First recorded · 109 lines, first recorded

# SEP-2164: Standardize Resource Not Found Error Code ## Abstract ## Motivation ## Specification ## Rationale ### Why `-32602` (Invalid Params)? ### Why Not a Custom Error Code? ## Backward Compatibility ### Migration Path ## Security Implications

The first capture of this source. The page was already there, and this is what it said.

# SEP-2164: Standardize Resource Not Found Error Code

> Standardize Resource Not Found Error Code

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2164                                                                            |
| **Title**     | Standardize Resource Not Found Error Code                                       |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2026-01-28                                                                      |
| **Author(s)** | Peter Alexander ([@pja-ant](https://github.com/pja-ant))                        |
| **Sponsor**   | None (seeking sponsor)                                                          |
| **PR**        | [#2164](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2164) |

***

## Abstract

The current MCP specification [recommends `-32002`](https://modelcontextprotocol.io/specification/draft/server/resources#error-handling) as the error code for resource not found. However, `-32002` falls within the JSON-RPC "server error" range (`-32000` to `-32099`) which is reserved for implementation-defined errors, not protocol-level semantics. Additionally, SDK implementations are inconsistent — only 4 of 6 official SDKs use `-32002`, while the TypeScript SDK uses `-32602` and the Python SDK uses `0`.

This SEP standardizes on `-32602` (Invalid Params), the correct JSON-RPC error code for this case, and aligns the specification with the JSON-RPC standard.

## Motivation

Current SDK implementations vary in their error handling for resource not found:

| SDK        | Current Error Code                     | Source                                                                                                                                                                                    |
| ---------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| TypeScript | `-32602` (InvalidParams)               | [mcp.ts#L561](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/packages/server/src/server/mcp.ts#L561)                                                                    |
| Python     | `0` (generic)                          | [server.py#L790](https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/lowlevel/server.py#L790)                                                                     |
| C#         | `-32002` (custom RESOURCE\_NOT\_FOUND) | [McpServerImpl.cs#L289](https://github.com/modelcontextprotocol/csharp-sdk/blob/main/src/ModelContextProtocol.Core/Server/McpServerImpl.cs#L289)                                          |
| Rust       | `-32002` (custom RESOURCE\_NOT\_FOUND) | [model.rs#L450](https://github.com/modelcontextprotocol/rust-sdk/blob/main/crates/rmcp/src/model.rs#L450)                                                                                 |
| Java       | `-32002` (custom RESOURCE\_NOT\_FOUND) | [McpAsyncServer.java#L732](https://github.com/modelcontextprotocol/java-sdk/blob/main/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java#L732)                     |
| Go         | `-32002` (custom RESOURCE\_NOT\_FOUND) | [server.go#L786](https://github.com/modelcontextprotocol/go-sdk/blob/main/mcp/server.go#L786)                                                                                             |
| Kotlin     | `-32603` (INTERNAL\_ERROR)             | [Server.kt#L618-L621](https://github.com/modelcontextprotocol/kotlin-sdk/blob/main/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt#L618-L621) |
| PHP        | `-32002` (custom RESOURCE\_NOT\_FOUND) | [Error.php#L37](https://github.com/modelcontextprotocol/php-sdk/blob/main/src/Schema/JsonRpc/Error.php#L37)                                                                               |
| Ruby       | N/A (left to implementor)              | [server.rb#L375-L379](https://github.com/modelcontextprotocol/ruby-sdk/blob/main/lib/mcp/server.rb#L375-L379)                                                                             |
| Swift      | N/A (no built-in handler)              | N/A                                                                                                                                                                                       |

This inconsistency means clients cannot reliably detect resource-not-found conditions across implementations. Of the 8 SDKs with built-in resource handling, four different error codes are used: `-32002` (C#, Rust, Java, Go, PHP), `-32602` (TypeScript), `-32603` (Kotlin), and `0` (Python). Ruby and Swift leave error handling to the server implementor. Clients that need to distinguish "resource not found" from other errors must handle all variants.

## Specification

If the requested resource does not exist, servers MUST return a JSON-RPC error with code `-32602` (Invalid Params):

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 2,
  "error": {
    "code": -32602,
    "message": "Resource not found",
    "data": {
      "uri": "file:///nonexistent.txt"
    }
  }
}
```

The `data` field SHOULD include the `uri` that was not found.

Servers MUST NOT return an empty `contents` array for a non-existent resource. An empty array is ambiguous — it could mean the resource exists but has no content, or that it doesn't exist at all.

## Rationale

### Why `-32602` (Invalid Params)?

`-32602` is the standard JSON-RPC error code for invalid parameters. A non-existent URI is semantically an invalid parameter — the client provided a URI that doesn't correspond to any resource. This aligns with the TypeScript SDK's existing behavior and avoids introducing custom error codes outside the JSON-RPC reserved range.

### Why Not a Custom Error Code?

Several SDKs use `-32002` (RESOURCE\_NOT\_FOUND), but:

* Custom codes in the `-32000` to `-32099` range are "reserved for implementation-defined server errors" per JSON-RPC spec, not for protocol-level semantics
* Adding a protocol-defined custom code requires all clients to be updated to recognize it
* `-32602` already has the correct meaning and is universally understood by JSON-RPC libraries

## Backward Compatibility

This changes what is specified — the current spec recommends `-32002`, and this SEP changes it to `-32602`. However, since the current recommendation is not consistently followed across SDKs (only 5 of 10 use `-32002`), clients cannot rely on any single error code today. This means the practical impact on clients is minimal — any client robust enough to work across existing SDKs already handles multiple error codes or treats all errors generically.

### Migration Path

1. SDKs should update their resource-not-found error code to `-32602`
2. During the transition, clients SHOULD handle both `-32602` and `-32002` as resource-not-found
3. The specification should document `-32602` as the canonical error code

## Security Implications

None. This change only affects error code values, not access control or data exposure.

seps/2207-oidc-refresh-token-guidance First recorded · 218 lines, first recorded

# SEP-2207: OIDC-Flavored Refresh Token Guidance ## Abstract ## Motivation ## Specification ### MCP Client Requirements ### MCP Server (Resource Server) Requirements ## Rationale ### Why not require `offline_access` in the 401 response? ### Why check client metadata for grant types? Why not always issue refresh tokens? ### Why allow `offline_access` as an alternative signal? ### Alternative approaches considered ## Backward Compatibility ## Security Implications ### Positive security implications ### Considerations ## Reference Implementation ## Acknowledgments

The first capture of this source. The page was already there, and this is what it said.

# SEP-2207: OIDC-Flavored Refresh Token Guidance

> OIDC-Flavored Refresh Token Guidance

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2207                                                                            |
| **Title**     | OIDC-Flavored Refresh Token Guidance                                            |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2026-02-04                                                                      |
| **Author(s)** | Wils Dawson ([@wdawson](https://github.com/wdawson))                            |
| **Sponsor**   | Paul Carleton ([@pcarleton](https://github.com/pcarleton))                      |
| **PR**        | [#2207](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2207) |

***

## Abstract

This proposal provides guidance for MCP implementations regarding refresh token
issuance and requests, particularly when Authorization Servers support the
`offline_access` scope. The `offline_access` scope originated in OIDC but can be
adopted by any OAuth 2.1 Authorization Server as a mechanism to let clients
explicitly request refresh tokens. This SEP clarifies the expected behavior for
both Authorization Servers and MCP Clients when working with this pattern.

## Motivation

MCP's authorization mechanism is based on OAuth 2.1, but many real-world
deployments use Authorization Servers that also implement OpenID Connect (OIDC).
A key difference between pure OAuth and OIDC is how refresh tokens are handled:

* In **pure OAuth 2.1**, there is no standard mechanism for a client to
  explicitly request a refresh token. The Authorization Server determines
  whether to issue one based on the client's capabilities (e.g., the
  `refresh_token` grant type in client metadata) and its own policies.
* In **OIDC** (and Authorization Servers that adopt this convention), the
  `offline_access` scope exists to allow clients to explicitly request refresh
  tokens, in addition to the OAuth logic.

This creates several problems in the MCP ecosystem:

1. **Clients aren't requesting refresh tokens**: Major MCP clients (Cursor,
   Claude, VS Code, etc.) aren't explicitly asking for refresh tokens via the
   `offline_access` scope because they don't know whether the Authorization
   Server supports, expects, or requires it.

2. **Resource servers shouldn't specify `offline_access`**: The `offline_access`
   scope is not a resource-specific scope—it's a concern between the client and
   Authorization Server. Including it in the `WWW-Authenticate` header's `scope`
   parameter or in the Protected Resource Metadata's `scopes_supported` would be
   semantically incorrect since it implies the resource *requires* refresh
   tokens, which it never would.

3. **Authorization Servers can be inconsistent**: When processing an
   authorization code grant, different Authorization Servers may have different
   behavior when issuing refresh tokens to different clients, especially when
   the client doesn't specify `refresh_token` as a grant type or request the
   `offline_access` scope.

4. **Interoperability gap**: Without this guidance, implementations may behave
   inconsistently, leading to poor user experience (frequent re-authentication)
   or security issues (issuing refresh tokens to clients that can't securely
   store them).

## Specification

### MCP Client Requirements

MCP Clients that intend to use refresh tokens and are capable of storing them
securely **SHOULD** follow these guidelines:

1. **Advertise capability**: Clients **SHOULD** include `refresh_token` in their
   `grant_types` client metadata to indicate they support refresh tokens.

2. **Scope augmentation**: When the client desires a refresh token and the
   Authorization Server metadata contains `offline_access` in its
   `scopes_supported` field, the client **MAY** add the `offline_access` scope
   to the list of scopes from the resource server before making authorization
   requests to the Authorization Server.

3. **No guarantee**: Clients **MUST NOT** assume that advertising support or
   requesting `offline_access` guarantees they will receive a refresh token. The
   Authorization Server retains discretion based on its policies.

### MCP Server (Resource Server) Requirements

MCP Servers (acting as OAuth 2.0 Protected Resources):

1. **SHOULD NOT** include `offline_access` in the `scope` parameter of
   `WWW-Authenticate` headers, as refresh tokens are not a resource requirement.

2. **SHOULD NOT** include `offline_access` in `scopes_supported` in Protected
   Resource Metadata, as it is not a resource-specific scope.

## Rationale

### Why not require `offline_access` in the 401 response?

The `offline_access` scope is fundamentally different from resource-specific
scopes. It represents a client's desire for long-lived access, not a
requirement of the resource. Per
[OAuth 2.1 Section 5.3.1](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13#section-5.3.1),
the `scope` attribute in `WWW-Authenticate` indicates "the required scope of the
access token for accessing the requested resource." Since the resource doesn't
require `offline_access`, including it would be semantically incorrect.

### Why check client metadata for grant types? Why not always issue refresh tokens?

OAuth 2.1 requires clients to register their supported grant types. A client
that doesn't support the `refresh_token` grant either:

* Cannot securely store refresh tokens
* Has no mechanism to use them

Issuing refresh tokens to such clients wastes Authorization Server resources
(tracking tokens that will never be used) and may pose security risks if the
tokens are leaked.

### Why allow `offline_access` as an alternative signal?

Some Authorization Servers—whether fully OIDC-compliant or simply adopting this
convention—only issue refresh tokens when `offline_access` is explicitly
requested. Supporting this pattern provides a compatible path for such
deployments. Clients can detect Authorization Servers that support this
convention by checking for `offline_access` in `scopes_supported` in the
Authorization Server Metadata and adapt their behavior accordingly.

### Alternative approaches considered

1. **Mandate `offline_access` in resource responses**: Rejected because it
   misrepresents the resource's requirements and creates an anti-pattern.

2. **Always issue refresh tokens**: Rejected because it ignores client
   capabilities and Authorization Server security policies.

3. **Separate OIDC-specific specification**: Rejected in favor of a unified
   approach that works for both pure OAuth and OIDC deployments.

4. **Provide guidance for Authorization Servers**: Rejected in favor of
   relying on OAuth and OIDC specs for this guidance as it can vary.

## Backward Compatibility

This proposal is fully backward-compatible:

* Clients that already request `offline_access` continue to work
* Authorization Servers that already check client capabilities continue to work
* MCP Servers are not required to make any changes
* The guidance is additive and does not change existing required behavior

Implementations that don't follow this guidance may experience suboptimal
behavior (missing refresh tokens or unnecessary token issuance) but will remain
functional.

## Security Implications

### Positive security implications

1. **Reduced token leakage risk**: By not issuing refresh tokens to clients that
   don't advertise support, we reduce the risk of long-lived tokens being stored
   insecurely.

2. **Defense in depth**: The risk-based assessment step gives Authorization Servers
   flexibility to implement additional security controls.

### Considerations

1. **Client metadata may not be sufficient**: Since client metadata is
   self-reported, a malicious actor could register a client claiming
   `refresh_token` grant support to obtain long-lived tokens. Authorization
   Servers MAY use the risk-based assessment step (see Specification) to apply
   additional restrictions—such as domain allowlists, reputation checks, or
   verification requirements—rather than solely relying on client metadata
   claims when deciding whether to issue refresh tokens.

2. **Scope injection**: Clients adding `offline_access` should ensure this
   doesn't interfere with other scope-related logic or create unexpected
   authorization prompts.

## Reference Implementation

Reference implementations demonstrating this guidance will be provided in the
official MCP SDKs:

* **TypeScript SDK**: Client-side `offline_access` scope handling
* **Python SDK**: Client-side `offline_access` scope handling
* **Authorization Server example**: Demonstration of client capability checking
* **Client conformance test**: Allowing for easy validation of SDK implementations

Links to implementations will be added once the SEP is accepted.

## Acknowledgments

This proposal was developed through discussion in the MCP Discord's
authorization channel, with input from:

* Aaron Parecki (OAuth/OIDC expertise)
* Paul Carleton (MCP authorization guidance)
* Simon Russell (OIDC deployment experience)

seps/2243-http-standardization First recorded · 811 lines, first recorded

# SEP-2243: HTTP Header Standardization for Streamable HTTP Transport ## Abstract ## Motivation ## Specification ### Standard Headers #### Example: tools/call Request #### Example: resources/read Request #### Example: prompts/get Request #### Example: Other Request Methods #### Example: Notification ### Custom Headers from Tool Parameters #### Schema Extension #### Example: Geo-Distributed Database #### Example: Multi-Tenant SaaS Application #### Example: Priority-Based Request Handling ### Header Processing #### Value Encoding #### Client Behavior #### Server Behavior ## Rationale ### Headers vs Path ### Infrastructure Support ### Explicit Header Names in x-mcp-header ### Placement Within JSON Schema ### Scope: Tools Only ### No Specification-Level Header Size Limit ### Encoding Approach for Unsafe Values ## Backward Compatibility ### Standard Headers ### Custom Headers from Tool Parameters ## Security Implications ### Header Injection ### Header Spoofing ### Information Disclosure ### Trusting Header Values ## Conformance Test Cases ### Standard Header Edge Cases #### Case Sensitivity #### Header/Body Mismatch #### Special Characters in Values ### Custom Header Edge Cases #### x-mcp-header Name Conflicts #### Invalid x-mcp-header Values #### Value Encoding Edge Cases #### Type Restriction Violations ### Server Validation Edge Cases #### Base64 Decoding #### Null and Missing Values #### Missing Custom Header with Value in Body ## Reference Implementation ## Changes since SEP became Final

The first capture of this source. The page was already there, and this is what it said.

# SEP-2243: HTTP Header Standardization for Streamable HTTP Transport

> HTTP Header Standardization for Streamable HTTP Transport

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2243                                                                            |
| **Title**     | HTTP Header Standardization for Streamable HTTP Transport                       |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2026-02-04                                                                      |
| **Author(s)** | MCP Transports Working Group                                                    |
| **Sponsor**   | None                                                                            |
| **PR**        | [#2243](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243) |

***

## Abstract

This SEP proposes exposing critical routing and context information in standard HTTP header locations for the Streamable HTTP transport. By mirroring key fields from the JSON-RPC payload into HTTP headers, network intermediaries such as load balancers, proxies, and observability tools can route and process MCP traffic without deep packet inspection, reducing latency and computational overhead.

## Motivation

Current MCP implementations over HTTP bury all routing information within the JSON-RPC payload. This creates friction for network infrastructure:

* **Load balancers** must terminate TLS and parse the entire JSON body to extract routing information (e.g., region, tool name)
* **Proxies and gateways** cannot make routing decisions without deep packet inspection
* **Observability tools** have limited visibility into MCP traffic patterns
* **Rate limiters and WAFs** cannot apply policies based on MCP-specific fields

By exposing key fields in HTTP headers, we enable standard network infrastructure to work with MCP traffic using existing, well-supported mechanisms.

## Specification

### Standard Headers

The Streamable HTTP transport will require POST requests to include the following headers mirrored from the request body:

| Header Name  | Source Field                  | Required For                                           |
| ------------ | ----------------------------- | ------------------------------------------------------ |
| `Mcp-Method` | `method`                      | All requests and notifications                         |
| `Mcp-Name`   | `params.name` or `params.uri` | `tools/call`, `resources/read`, `prompts/get` requests |

These headers are **required** for compliance with the MCP version in which they are introduced.

**Server Behavior**: Servers that process the request body MUST reject requests where the values specified in the headers do not match the values in the request body.

> **Rationale**: This requirement prevents potential security vulnerabilities and error conditions that could arise when different components in the network rely on different sources of truth. For example, a load balancer or gateway might use the header values to make routing decisions, while the MCP server uses the body values for execution. This requirement applies to any network intermediary that processes the message body, as well as the MCP server itself.

> **Implementation Note**: When validating integer parameter values, servers SHOULD compare the header value and the body value numerically rather than as strings (e.g., `42.0` and `42` are considered equal).

**Case Sensitivity**: Header names (called "field names" in [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-field-names)) are case-insensitive. Clients and servers MUST use case-insensitive comparisons for header names.

#### Example: tools/call Request

```http theme={null}
POST /mcp HTTP/1.1
Content-Type: application/json
Mcp-Session-Id: 1f3a4b5c-6d7e-8f9a-0b1c-2d3e4f5a6b7c
Mcp-Method: tools/call
Mcp-Name: get_weather

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "location": "Seattle, WA"
    }
  }
}
```

#### Example: resources/read Request

```http theme={null}
POST /mcp HTTP/1.1
Content-Type: application/json
Mcp-Session-Id: 1f3a4b5c-6d7e-8f9a-0b1c-2d3e4f5a6b7c
Mcp-Method: resources/read
Mcp-Name: file:///projects/myapp/config.json

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "resources/read",
  "params": {
    "uri": "file:///projects/myapp/config.json"
  }
}
```

#### Example: prompts/get Request

```http theme={null}
POST /mcp HTTP/1.1
Content-Type: application/json
Mcp-Session-Id: 1f3a4b5c-6d7e-8f9a-0b1c-2d3e4f5a6b7c
Mcp-Method: prompts/get
Mcp-Name: code_review

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "prompts/get",
  "params": {
    "name": "code_review",
    "arguments": {
      "language": "python"
    }
  }
}
```

#### Example: Other Request Methods

For requests that don't involve tools, resources, or prompts, only the `Mcp-Method` header is required:

```http theme={null}
POST /mcp HTTP/1.1
Content-Type: application/json
Mcp-Method: initialize

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {},
    "clientInfo": {
      "name": "ExampleClient",
      "version": "1.0.0"
    }
  }
}
```

#### Example: Notification

Notifications also require the `Mcp-Method` header:

```http theme={null}
POST /mcp HTTP/1.1
Content-Type: application/json
Mcp-Session-Id: 1f3a4b5c-6d7e-8f9a-0b1c-2d3e4f5a6b7c
Mcp-Method: notifications/initialized

{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}
```

### Custom Headers from Tool Parameters

MCP servers MAY designate specific tool parameters to be mirrored into HTTP headers using an `x-mcp-header` extension property in the parameter's schema within the tool's `inputSchema`.

**Client Requirement**: While the use of `x-mcp-header` is optional for servers, clients MUST support this feature. When a server's tool definition includes `x-mcp-header` annotations, conforming clients MUST mirror the designated parameter values into HTTP headers as specified in this document.

#### Schema Extension

The `x-mcp-header` property specifies the name portion used to construct the header name `Mcp-Param-{name}`.

**Constraints on `x-mcp-header` values**:

* MUST NOT be empty
* MUST match HTTP field-name token syntax (`1*tchar`, [RFC 9110 Section 5.1](https://datatracker.ietf.org/doc/html/rfc9110#section-5.1))
* MUST NOT contain control characters, including carriage return (CR, `\r`) or line feed (LF, `\n`)
* MUST be case-insensitively unique among all `x-mcp-header` values in the `inputSchema`
* MUST only be applied to parameters with primitive types (integer, string, boolean). Parameters with type `number` are not permitted. Integer values MUST be within the safe range for JavaScript (−2^53+1 to 2^53−1)
* MAY be applied to properties at any nesting depth within the `inputSchema`, not only top-level properties

Clients using the Streamable HTTP transport MUST reject tool definitions where any `x-mcp-header` value violates these constraints. Rejection means the client MUST exclude the invalid tool from the result of `tools/list`. Clients SHOULD log a warning when rejecting a tool definition, including the tool name and the reason for rejection. This behavior ensures that a single malformed tool definition does not prevent other valid tools from being used. Clients using other transports (e.g., stdio) MAY ignore `x-mcp-header` annotations entirely.

**Example Tool Definition**:

```json theme={null}
{
  "name": "execute_sql",
  "description": "Execute SQL on Google Cloud Spanner",
  "inputSchema": {
    "type": "object",
    "properties": {
      "region": {
        "type": "string",
        "description": "The region to execute the query in",
        "x-mcp-header": "Region"
      },
      "query": {
        "type": "string",
        "description": "The SQL query to execute"
      }
    },
    "required": ["region", "query"]
  }
}
```

#### Example: Geo-Distributed Database

Consider a server exposing an `execute_sql` tool for Google Cloud Spanner, which requires a `region` parameter.

**Tool Definition**:

```json theme={null}
{
  "name": "execute_sql",
  "description": "Execute SQL on Google Cloud Spanner",
  "inputSchema": {
    "type": "object",
    "properties": {
      "region": {
        "type": "string",
        "description": "The region to execute the query in",
        "x-mcp-header": "Region"
      },
      "query": {
        "type": "string",
        "description": "The SQL query to execute"
      }
    },
    "required": ["region", "query"]
  }
}
```

**Scenario**: A client requests to execute SQL in `us-west1`.

**Current Friction**: The global load balancer receives the request but must terminate TLS and parse the entire JSON body to find `"region": "us-west1"` before it knows whether to route the packet to the Oregon or Belgium cluster.

**With This Proposal**: The client detects the `x-mcp-header` annotation and automatically adds the header `Mcp-Param-Region: us-west1` to the HTTP request. The load balancer can now route based on the header without parsing the body.

**Request**:

```http theme={null}
POST /mcp HTTP/1.1
Content-Type: application/json
Mcp-Session-Id: 1f3a4b5c-6d7e-8f9a-0b1c-2d3e4f5a6b7c
Mcp-Method: tools/call
Mcp-Name: execute_sql
Mcp-Param-Region: us-west1

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "execute_sql",
    "arguments": {
      "region": "us-west1",
      "query": "SELECT * FROM users"
    }
  }
}
```

#### Example: Multi-Tenant SaaS Application

A SaaS platform exposes tools that operate on different customer tenants. By exposing the tenant ID in a header, the platform can route requests to tenant-specific infrastructure.

**Tool Definition**:

```json theme={null}
{
  "name": "query_analytics",
  "description": "Query analytics data for a tenant",
  "inputSchema": {
    "type": "object",
    "properties": {
      "tenant_id": {
        "type": "string",
        "description": "The tenant identifier",
        "x-mcp-header": "TenantId"
      },
      "metric": {
        "type": "string",
        "description": "The metric to query"
      },
      "start_date": {

Cut at 300 lines. The page has the rest.

seps/2260-Require-Server-requests-to-be-associated-with-Client-requests First recorded · 306 lines, first recorded

# SEP-2260: Require Server requests to be associated with a Client request. ## Abstract ## Motivation ### Current Specification ### Design Intent ### Simplification Benefits ## Specification Changes ### 1. Add Warning Blocks to Feature Documentation ### 2. Clarify Transport Layer Constraints ## Backward Compatibility ### Impact Assessment ### What's Disallowed ### What Remains Supported ## Implementation Guidance ### For Server Implementers ### Timeout Considerations ### For Client Implementers ### For Transport Implementers ## Timeline ## Alternatives Considered ### 1. Soft Deprecation ### 2. Keep Current Ambiguity ### 3. Create a Capability Flag ## References

The first capture of this source. The page was already there, and this is what it said.

# SEP-2260: Require Server requests to be associated with a Client request.

> Require Server requests to be associated with a Client request.

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2260                                                                            |
| **Title**     | Require Server requests to be associated with a Client request.                 |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2026-02-16                                                                      |
| **Author(s)** | MCP Transports Working Group                                                    |
| **Sponsor**   | [@CaitieM20](https://github.com/CaitieM20) - Caitie McCaffrey                   |
| **PR**        | [#2260](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2260) |

***

## Abstract

This SEP clarifies that `roots/list`, `sampling/createMessage`, and
`elicitation/create` requests **MUST** be associated with an originating
client-to-server request (e.g., during `tools/call`, `resources/read`, or
`prompts/get` processing). Standalone server-initiated requests of these types
outside notifications **MUST NOT** be implemented.

Although not enforced in the current MCP Data Layer, logically these requests
**MUST** be associated with a valid client-to-server JSON-RPC Request Id.

The operational server-to-client **Ping** is excepted from this restriction.

## Motivation

### Current Specification

The current specification uses **SHOULD** language in the transport layer:

In context of responding to a POST Request in the Streamable HTTP transport [(2025-11-25/basic/transports.mdx:121-L123)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/2025-11-25/docs/specification/2025-11-25/basic/transports.mdx?plain=1#L121-L123):

> * "The server **MAY** send JSON-RPC *requests* and *notifications* before sending the JSON-RPC *response*. These messages **SHOULD** relate to the originating client *request*."

For the optional GET SSE Stream [(2025-11-25/basic/transports.mdx:146-L148)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/2025-11-25/docs/specification/2025-11-25/basic/transports.mdx?plain=1#L146C1-L148C32):

> * "The server **MAY** send JSON-RPC *requests* and *notifications* on the stream."
> * "These messages **SHOULD** be unrelated to any concurrently-running JSON-RPC *request* from the client."

Although the GET stream allows "unsolicited" requests, its use is entirely optional and cannot be relied upon by MCP Server authors.

### Design Intent

The design intent of MCP Server Requests is to operate reactively **nested within** other MCP operations:

* **Sampling** enables servers to request LLM assistance while processing a tool call, resource request, or prompt
* **Elicitation** enables servers to gather additional user input needed to complete an operation
* **List Roots** enables servers to identify shared storage locations

**Ping** has a special status as it is primarily intended as a keep-alive/health-check mechanism.

For Streamable HTTP Servers this enables SSE Streams to be maintained for extended periods if no Notifications or Requests are available to be sent. For client-to-server Requests they are associable. Future transport implementations will remove the need for dissociated Pings.

The current specification already describes this pattern:

> "Sampling in MCP allows servers to implement agentic behaviors, by enabling LLM calls to occur *nested* inside other MCP server features."

However, the normative requirements don't enforce this constraint.

### Simplification Benefits

Making this constraint explicit:

1. **Simplifies transport implementations** - Transports don't need to support arbitrary server-initiated request/response flows, which require a persistent connection from Server to Client; they only need request-scoped bidirectional communication
2. **Clarifies user experience** - Users understand that sampling/elicitation happens *because* they initiated an action, not spontaneously
3. **Reduces security surface** - Ensures client has context for what scope the additional requested information will be used for. This allows clients to make better informed decisions on whether to provide the requested info.
4. **Aligns with practice** - Based on a scan of GitHub all existing implementations already follow this pattern, except one repo owned by the SEP author with a contrived scenario.

## Specification Changes

### 1. Add Warning Blocks to Feature Documentation

**In `client/sampling.mdx` (after existing security warning):**

```markdown theme={null}
<Warning>

**Request Association Requirement**

Servers **MUST** send `sampling/createMessage` requests only in association with an originating client request (e.g., during `tools/call`, `resources/read`, or `prompts/get` processing).

Standalone server-initiated sampling on independent communication streams (unrelated to any client request) is not supported and **MUST NOT** be implemented. Future transport implementations are not required to support this pattern.

</Warning>
```

**In `client/elicitation.mdx` (after existing security warning):**

```markdown theme={null}
<Warning>

**Request Association Requirement**

Servers **MUST** send server-to-client requests (such as `roots/list`,
`sampling/createMessage`, or `elicitation/create`) only in association with an
originating client request (e.g., during `tools/call`, `resources/read`, or
`prompts/get` processing).

Standalone server-initiated requests of these types on independent
communication streams (unrelated to any client request) are not supported and
**MUST NOT** be implemented. Future transport implementations are not required
to support this pattern.

</Warning>
```

**In `client/roots.mdx` (in `User Interaction Model` section):**

```markdown theme={null}
<Warning>

Servers **MUST** send server-to-client requests (such as `roots/list`,
`sampling/createMessage`, or `elicitation/create`) only in association with an
originating client request (e.g., during `tools/call`, `resources/read`, or
`prompts/get` processing).

Standalone server-initiated requests of these types on independent
communication streams (unrelated to any client request) are not supported and
**MUST NOT** be implemented. Future transport implementations are not required
to support this pattern.

</Warning>
```

**In `basic/utilities/ping.mdx` (In `Overview` section):**

```markdown theme={null}
<Warning>

`ping` is an MCP-level liveness check and **MAY** be sent by either party at
any time on an established session/connection.

In Streamable HTTP, implementations **SHOULD** prefer transport-level SSE
keepalive mechanisms for idle-connection maintenance; `ping` remains available
for protocol-level responsiveness checks.

Request-association requirements for `roots/list`, `sampling/createMessage`,
and `elicitation/create` do not apply to `ping`.

</Warning>
```

### 2. Clarify Transport Layer Constraints

**In `basic/transports.mdx`, POST-initiated SSE streams (line \~121):**

```diff theme={null}
- The server **MAY** send JSON-RPC _requests_ and _notifications_ before sending the
- JSON-RPC _response_. These messages **SHOULD** relate to the originating client
- _request_.
+ The server **MAY** send JSON-RPC _requests_ and _notifications_ before sending the
+ JSON-RPC _response_. These messages **MUST** relate to the originating client
+ _request_.
```

**In `basic/transports.mdx`, GET-initiated standalone SSE streams (line \~147):**

```diff theme={null}
- The server **MAY** send JSON-RPC _requests_ and _notifications_ on the stream.
- These messages **SHOULD** be unrelated to any concurrently-running JSON-RPC
- _request_ from the client.
+ The server **MAY** send JSON-RPC _notifications_ and _pings_ on the stream.
+ These messages **SHOULD** be unrelated to any concurrently-running JSON-RPC
+ _request_ from the client, **except** that `roots/list`,
+ `sampling/createMessage`, and `elicitation/create` requests **MUST NOT** be
+ sent on standalone streams.
```

## Backward Compatibility

### Impact Assessment

This change is expected to have **minimal to no impact** on existing implementations:

1. **Common usage patterns are preserved** - Sampling/elicitation within tool execution, resource reading, and prompt handling remain fully supported
2. **No known implementations affected** - Research conducted on GitHub has shown only one implementation of this pattern. This singular implementation is owned by the SEP author.

### What's Disallowed

The following pattern, which was never explicitly documented or recommended, is now explicitly prohibited:

```python theme={null}
# ❌ PROHIBITED: Standalone server push
async def background_task():
    while True:
        await asyncio.sleep(60)
        # Try to initiate sampling without any client request context
        await session.create_message(...)  # NOT ALLOWED
```

### What Remains Supported

The canonical pattern remains fully supported:

```python theme={null}
# ✅ SUPPORTED: Sampling during tool execution
@mcp.tool()
async def analyze_data(data: str, ctx: Context) -> str:
    # Request LLM analysis while processing the tool call
    result = await ctx.session.create_message(
        messages=[SamplingMessage(role="user", content=...)]
    )
    return result.content.text
```

## Implementation Guidance

### For Server Implementers

**No changes required** if your server:

* Only uses server-to-client requests within tool handlers
* Only uses server-to-client requests within resource/prompt handlers
* Uses server-to-client requests synchronously as part of processing a client request

**Changes required** if your server:

* Attempts to initiate server-to-client requests on standalone HTTP GET streams
* Attempts to send server-to-client requests requests independent of client operations
* Has background tasks that try to invoke server-to-client requests

Alternative designs will need to be implemented for the "Changes Required" case.

Implementors performing unsolicited server-to-client requests (typically URL Elicitation) immediately following initialization are encouraged to lazily perform these requests within the scope of a client-to-server request that requires that information from the client.

### Timeout Considerations

When an MCP Server initiates a "nested" request inside a client request, the duration of the parent request extends to include the user's response time.

Implementers **MUST** ensure that:

1. Transport timeouts (e.g. HTTP Request Timeout) are sufficient to accommodate "Human-in-the-loop" delays, which may be unbounded.
2. Short timeouts enforced by infrastructure (e.g. Load Balancers) may result in
   connection termination before the user responds. For Streamable HTTP,
   transport-level SSE keepalive mechanisms **SHOULD** be used to keep
   connections alive and reset timers; `ping` requests **MAY** additionally be
   used for protocol-level responsiveness checks.

### For Client Implementers

**No changes required** - Clients should already handle sampling/elicitation requests in the context of their own outbound requests. Potential to simplify implementations if out-of-band is currently supported.

Clients receiving server-to-client requests with no associated outbound request **SHOULD** respond with a `-32602` (Invalid Params) error.

### For Transport Implementers

Future transport implementations can rely on the guarantee that:

* Sampling/elicitation requests only occur within the scope of a client-initiated request
* Transports don't need to support arbitrary server-initiated request/response flows on standalone channels
* Request correlation and lifecycle management is simplified

## Timeline

(This SEP intends to serve as a public notice of the change prior to future protocol versions that will not be compatible with this usage)

## Alternatives Considered

### 1. Soft Deprecation

Use **SHOULD NOT** language to discourage but not prohibit the pattern.

**Rejected because:** The behavior was never intentionally supported, and leaving it ambiguous prevents transport simplification.

### 2. Keep Current Ambiguity

Leave the existing **SHOULD** language unchanged.

**Rejected because:** This blocks future transport implementations and leaves implementers uncertain about whether the pattern is supported.

### 3. Create a Capability Flag

Add a `sampling.standalone` or similar capability for servers that want this behavior.

**Rejected because:** This adds complexity for a use case with no known demand, and contradicts the "nested" design principle.

Cut at 300 lines. The page has the rest.

seps/2322-MRTR First recorded · 1394 lines, first recorded

# SEP-2322: Multi Round-Trip Requests ## Abstract ## Motivation ## Specification ### Schema Changes ### Server-Initiated Request Support for Client Requests ### Ephemeral Tool Workflow #### Real-World Example for Ephemeral Workflow #### Use Cases for Request State ##### Use Case 1: Rolling Upgrades ##### Use Case 2: Load Shedding #### Protocol Requirements for Ephemeral Workflow ### Persistent Tool Workflow #### Protocol Requirements for Persistent Workflow ### Interactions Between Ephemeral and Persistent Workflows ### Guidance for Error Handling ## Rationale ## Backward Compatibility ## Security Implications ## Reference Implementation ### Acknowledgments

The first capture of this source. The page was already there, and this is what it said.

# SEP-2322: Multi Round-Trip Requests

> Multi Round-Trip Requests

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                                                                                                                            |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **SEP**       | 2322                                                                                                                                                                             |
| **Title**     | Multi Round-Trip Requests                                                                                                                                                        |
| **Status**    | Final                                                                                                                                                                            |
| **Type**      | Standards Track                                                                                                                                                                  |
| **Created**   | 2026-02-03                                                                                                                                                                       |
| **Author(s)** | Mark D. Roth ([@markdroth](https://github.com/markdroth)), Caitie McCaffrey ([@CaitieM20](https://github.com/CaitieM20)), Gabriel Zimmerman ([@gjz22](https://github.com/gjz22)) |
| **Sponsor**   | Caitie McCaffrey ([@CaitieM20](https://github.com/CaitieM20))                                                                                                                    |
| **PR**        | [#2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)                                                                                                  |

***

## Abstract

This proposal specifies a simple way to handle server-initiated requests
in the context of a client-initiated request (e.g., an elicitation
request in the context of a tool call) without requiring a shared
storage layer shared across server instances or statefulness in
load balancing, which will significantly reduce the cost of operating
MCP servers at scale in the common case. It also reduces the HTTP
transport's dependence on SSE streams, which cause problems in a lot of
environments that cannot support long-lived connections.

This proposed way of handling server-initiated requests will replace the current approach of sending server-initiated requests. This is a breaking change.

This SEP also specifies the subset of client requests that a server can
send a server-initiated request on. This is a reduced scope compared to the current spec and is also a breaking change.

Making a breaking change here is necessary since adoption of server-initiated request features like Elicitation, Sampling and ListRoots is very low or blocked for many Remote MCP servers or Server Hosted Clients due to the operational complextity of supporting the SSE streams and server-side state.

## Motivation

Note: This SEP is intended to provide a generic mechanism for handling
any server-initiated request in the context of any client-initiated
request. For clarity, throughout this document, we will specifically
discuss tool calls as a proxy for any client-initiated request, but it
should be read as applying equally to (e.g.) resource or prompt
requests; similarly, we will discuss elicitation requests as a proxy for
any server-initiated request, but it should be read as applying equally
to (e.g.) sampling requests.

We start with the observation that there are two types of MCP tools:

1. **Ephemeral**: No state is accumulated on the server side.
   * If server needs more info to process the tool call, it can start from
     scratch when it gets that additional info.
   * Examples: weather app, accessing email
2. **Persistent**: State is accumulated on the server side.
   * Server may generate a large amount of state before requesting more
     info from the client, and it may need to pick up that state to
     continue processing after it receives the info from the client.
   * Server may need to continue processing in the background while
     waiting for more info from the client, in which case server-side
     state is needed to track that ongoing processing.
   * Examples: accessing an agent, spinning up a VM and needing user
     interaction to manipulate the VM

The vast majority of MCP tools will be ephemeral, and it is extremely
common for tools to be deployed in a horizontally scaled, load balanced
service, so we need to optimize for this case.

Today, if a tool needs to send an elicitation request in order to make
progress, the workflow works like this:

1. Client sends tool call request. For this example, let's assume that
   the load balancers happen to send this request to server instance A.
2. Server A opens an SSE stream and sends the elicitation request on that
   stream.
3. Client sends the elicitation response as a separate request, for which
   the load balancers will choose a server instance completely
   independently of the one they chose in step 1. In this example,
   let's assume that the load balancers happen to send this request to
   server instance B.
4. Server A must somehow discover the elicitation response delivered to
   server B.
5. Server A then sends the tool call result on the SSE stream opened in
   step 2.

```mermaid theme={null}
sequenceDiagram
    participant C as Client
    participant LB as Load Balancer
    participant SA as Server Instance A
    participant SB as Server Instance B
    Note over C,SA: 1. Initial Request
    C->>LB: Tool Call (Start)
    LB->>SA: Route to Instance A
    activate SA
    SA-->>C: Elicitation Request (SSE Stream Open)
    Note right of SA: Server A holds memory,<br/>waiting for response...

    Note over C,SB: 2. User Responds
    C->>LB: Elicitation Result
    LB->>SB: Route to Instance B (Stateless LB)
    activate SB

    Note over SA,SB:  A is waiting, but  B has the data.
    Note over SA,SB: Requires Shared Storage to bridge this gap.

    deactivate SA
    deactivate SB
```

The difficult part here is step 4, which requires some sort of
statefulness on the server side. The main way to solve this problem
today is to have a storage layer shared across all server instances, so
that multiple server instances can match up the elicitation response
on one server instance with the original ongoing tool call on a
different server instance.

There are two main approaches that can be used to solve this problem today:

* **Persistent Storage Layer Shared Across Server Instances**: Servers can
  deploy and manage a persistent storage layer (e.g., PostgreSQL, Redis,
  DynamoDB), which allow multiple server instances to match up the
  elicitation response on one server instance with the original ongoing
  tool call on a different server instance. This approach has a number
  of drawbacks:
  * The persistent storage layer is **extremely expensive**, especially for
    ephemeral tools that may not already have such a layer (e.g., a weather
    tool).
  * The persistent storage layer imposes significant reliability concerns:
    it becomes a critical dependency and therefore a potential single
    point of failure. To avoid that, it must provide high availability,
    replication, and backup mechanisms.
  * The persistent storage layer becomes a bottleneck, limiting horizontal
    scalability. Geographic distribution requires either expensive
    global replication or sticky routing.
  * The persistent storage layer also imposes significant operational
    complexity. In horizontally scaled deployments, it requires
    distributed locking or consensus protocols. It also requires special
    garbage collection logic to determine when shared can be cleaned up,
    which requires careful trade-offs: cleaning up state too aggressively
    can reduce storage costs but limit how long users have to respond,
    whereas cleaning up less aggressively accommodates slow users but
    increases storage costs.
  * This approach requires special behavior in the tool implementation to
    integrate with the persistent storage layer. The MCP SDKs today do
    not have any special hooks for this sort of storage layer integration,
    which means that it's very hard to write in-line code via the SDKs.
* **Statefulness in Load Balancing**: With the use of cookies, it is
  possible for the load balancing layer to ensure that the elicitation
  request in step 3 is delivered to the same server instance that the
  original request was delivered to in step 1. This approach, while
  often cheaper than a persistent storage layer, has the following
  drawbacks:
  * It requires special configuration and behavior in the load
    balancers, which is often difficult to manage.
  * It breaks normal load balancing models, resulting in uneven load
    distribution, thus increasing the cost of running the service.
  * It requires special behavior in clients to propagate the cookies
    used for statefulness.
  * It requires the tool implementation to match up the elicitation
    request with the ongoing tool call. (The MCP SDKs have some code to
    handle this, but it's still a very strange pattern in the HTTP
    world.)
  * It is not fault tolerant. If the server instance goes down, all
    state is lost, and the tool call would need to start over from
    scratch. (This doesn't necessarily matter for ephemeral tools,
    but it is an issue for persistent tools.)

Also, both of these approaches rely on the use of an SSE stream, which
causes problems in environments that cannot support long-lived
connections. They also require an instance of the tool to stay in memory
in a particular server instance indefinitely. This is particularly
problematic for elicitation requests specifically, since the result may
not come from the user for an unbounded amount of time (e.g., it could
be days or months, or maybe even never).

The goal of this SEP is to propose a simpler way to handle the pattern
of server-initiated requests within the context of a client-initiated
request. Specifically, we need to make it cheaper to support this pattern
in the common case of an ephemeral tool in a horizontally scaled, load
balanced deployment. This means that we need a solution that does not
depend on an SSE stream and does not require either a persistent storage
layer or stateful load balancing, which in turn means that we need to
avoid dependencies between requests: servers must be able to process
each individual request using no information other than what is present
in that individual request.

Note that while the goal here is to optimize the common case of ephemeral
tools, we do want to continue to support persistent tools, which generally
already require a persistent storage layer.

## Specification

This SEP proposes a new mechanism for handling server requests in the
context of a client request. This new mechanism will have a slightly
different workflow for ephemeral tools and persistent tools, the latter
of which will leverage Tasks. However, both workflows will use the same
data structures.

### Schema Changes

First, we introduce the notion of `InputRequests`, which represents
a set of one or more server-initiated request to be sent to the client,
and `InputResponses`, which represents the client's responses to
those requests. Both requests and responses are stored in a map with
string keys. For `InputRequests`, the map values are server-initiated
requests (e.g., elicitation or sampling requests), whereas for `InputResponses`, the map values are the responses to those requests. Here's
how that would look in the typescript MCP schema:

```typescript theme={null}
export type InputRequest =
  CreateMessageRequest | ElicitRequest | ListRootsRequest;

export interface InputRequests {
  [key: string]: InputRequest;
}

export type InputResponse =
  CreateMessageResult | ElicitResult | ListRootsResult;

export interface InputResponses {
  [key: string]: InputResponse;
}
```

The keys are assigned by the server when issuing the requests. The client
will send the response for each request using the corresponding key.
For example, a server might send the following input requests:

```json5 theme={null}
"inputRequests": {
  // Elicitation request.
  "github_login": {
    "method": "elicitation/create",
    "params": {
      "mode": "form",
      "message": "Please provide your GitHub username",
      "requestedSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          }
        },
        "required": ["name"]
      }
    }
  },
  // Sampling request.
  "capital_of_france" : {
    "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
    }
  }
}
```

The client would then send the responses in the following form:

```json5 theme={null}
"inputResponses": {
  // Elicitation response (ElicitResult).
  "github_login": {
    "action": "accept",

Cut at 300 lines. The page has the rest.

seps/2468-recommend-issuer-claim-for-auth First recorded · 110 lines, first recorded

# SEP-2468: Recommend Issuer (iss) Parameter in MCP Auth Responses ## Abstract ## Motivation ## Specification ### Issuer Parameter Requirement ### Client Validation Requirements ## Rationale ### Alternatives considered ## Backward Compatibility ## Security Implications ## Reference Implementation ### Acknowledgments

The first capture of this source. The page was already there, and this is what it said.

# SEP-2468: Recommend Issuer (iss) Parameter in MCP Auth Responses

> Recommend Issuer (iss) Parameter in MCP Auth Responses

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2468                                                                            |
| **Title**     | Recommend Issuer (iss) Parameter in MCP Auth Responses                          |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2026-03-25                                                                      |
| **Author(s)** | Emily Lauber ([@EmLauber](https://github.com/EmLauber))                         |
| **Sponsor**   | [@pcarleton](https://github.com/pcarleton)                                      |
| **PR**        | [#2468](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2468) |

***

## Abstract

This SEP proposes recommending the inclusion and requiring the validation of an explicit issuer (iss) parameter in Model Context Protocol (MCP) authorization responses to mitigate authorization mix‑up attacks. By binding authorization responses to a specific authorization server identity, MCP clients can reliably detect and reject responses originating from an unexpected issuer, improving protocol robustness in multi‑identity provider (IdP) environments. This SEP follows the specifications defined in [RFC9207](https://datatracker.ietf.org/doc/rfc9207/).

## Motivation

The Model Context Protocol increasingly operates in environments where multiple authorization servers, identity providers, and intermediaries coexist. In such environments, OAuth mix‑up attacks become a realistic threat. Mix-up attacks are when an attacker causes a client to associate an authorization response with the wrong authorization server, potentially leading to token leakage or privilege escalation.

OAuth specifications describe two mitigations for mix‑up attacks: requiring issuer (*iss*) parameter or using a unique redirect\_uri for each issuer a client interacts with. A unique redirect\_uri per issuer is not possible with Client ID Metadata Documents (the recommended registration approach) and is operationally expensive with Dynamic Client Registration. As such, the recommendation is for MCP environments to leverage the issuer mitigation.

Requiring an explicit iss parameter in MCP authorization responses provides a simple, interoperable, and well‑understood mechanism to bind responses to the correct authorization server and prevent mix‑up attacks by construction. Since not every authorization server sends the issuer parameter though, this SEP proposes a MUST for clients to validate issuer if provided and a SHOULD for authorization servers supporting MCP scenarios. Future SEPs and releases may change the SHOULD to a MUST.

## Specification

### Issuer Parameter Requirement

MCP authorization servers SHOULD include an issuer (*iss*) parameter in authorization responses, including error responses, as defined in [RFC9207](https://datatracker.ietf.org/doc/html/rfc9207#section-2). Authorization servers that do so MUST advertise it by setting `authorization_response_iss_parameter_supported: true` in their authorization server metadata.

The `iss` parameter MUST:

* Exactly match the issuer identifier advertised via metadata discovery
* Be a URL that uses the `https` scheme without query or fragment components ([RFC 8414 Section 2](https://datatracker.ietf.org/doc/html/rfc8414#section-2))

### Client Validation Requirements

MCP clients MUST validate the *iss* parameter in authorization responses by:

* Determining the expected issuer for the authorization request
* Comparing the received *iss* value against the expected issuer
* Rejecting the authorization response if the values do not match exactly

If issuer validation fails, the client **MUST** treat the response as invalid and abort the authorization flow.

## Rationale

The iss value is already used in OpenID Connect and JWT‑based token validation. Extending its use to MCP authorization responses:

* Leverages existing ecosystem knowledge and tooling
* Avoids introducing MCP‑specific security mechanisms
* Provides a clear and auditable security for deployments

### Alternatives considered

Introducing MCP‑specific issuer binding fields

* Rejected in favor of reusing established OAuth/OIDC mechanisms.

Requiring unique redirect\_uri per issuer

* CIMD metadata documents are static and cannot enumerate every issuer; with DCR it is technically possible but DCR has operational drawbacks in MCP deployments that make it undesirable to depend on for a security property. RFC 9207 works uniformly across registration approaches.

Discarding `iss` when the server does not advertise support (strict RFC 9207 §2.4 SHOULD)

* RFC 9207 §2.4 recommends that clients SHOULD discard responses carrying `iss` from servers that do not set `authorization_response_iss_parameter_supported`, but explicitly leaves the decision to local policy ("specific guidance is out of scope"). This SEP specifies comparison instead. The recorded issuer always comes from a metadata document the client has already validated per RFC 8414 §3.3, so a present `iss` can be checked against an authentic baseline; rejection on mismatch remains unconditional, so the only behavioral difference is accepting a response whose `iss` matches that baseline — which is not a relaxation. In practice, authorization servers often begin emitting `iss` before their metadata is updated, and discarding in that window would reject legitimate flows without security benefit.

## Backward Compatibility

The `iss` parameter is additive on the wire. Client validation introduces a behavioral change for hosts whose authorization server advertises `authorization_response_iss_parameter_supported: true` but whose callback handling does not yet pass `iss` to the SDK; those flows will be rejected until the host extracts `iss` from the redirect URI alongside `code`. SDKs are expected to widen callback signatures additively (e.g., an optional `iss` argument) so existing call sites continue to compile. Authorization servers that do not advertise support are unaffected. The accompanying RFC 8414 Section 3.3 metadata-validation requirement restates an existing RFC MUST; clients that were not already enforcing it may surface latent issuer misconfigurations on upgrade.

## Security Implications

This proposal is a mitigation against mix-up attacks; the security considerations for the mechanism itself are documented in [RFC9207 Section 4](https://datatracker.ietf.org/doc/html/rfc9207#section-4). In particular, the mitigation depends on clients establishing the expected issuer before redirecting and on the comparison being an exact simple string comparison. See also the MCP [security best practices](/docs/tutorials/security/security_best_practices).

## Reference Implementation

* Go SDK: [modelcontextprotocol/go-sdk#859](https://github.com/modelcontextprotocol/go-sdk/pull/859)
* TypeScript SDK: [modelcontextprotocol/typescript-sdk#1957](https://github.com/modelcontextprotocol/typescript-sdk/pull/1957)

Both record the expected issuer before redirect and compare any received `iss`, rejecting on absence only when the server advertises support.

***

### Acknowledgments

Thanks to Sam Morrow, Max Gerber, Aaron Parecki, Stephen Halter, Nate Barbettini, Karl McGuinness, and Den Delimarsky for reviews and discussion in the Auth Mix-Up Attack Prevention working group.

seps/2484-conformance-tests-required-for-final-seps First recorded · 203 lines, first recorded

# SEP-2484: Require Conformance Tests for Standards Track SEPs to Reach Final Status ## Abstract ## Motivation ### The gap between specification and implementation ### Why the existing reference implementation requirement is insufficient ### Keeping the conformance suite alive ## Specification ### Scope ### The requirement ### Traceability file ### Who writes the tests ### Specification text is authoritative ### Conformance test disputes ### Test stability and tiering ### Sponsor responsibilities ### Relationship to SEP-1730 (SDK Tiering) ### Relationship to SEP-1627 (Conformance Testing) ## Rationale ### Why gate `Final` rather than `Accepted`? ### Why a traceability file? ### Why put the authorship obligation on the sponsor? ### Alternatives considered ## Backward Compatibility ## Security Implications ## Reference Implementation ## Prerequisites for Final status

The first capture of this source. The page was already there, and this is what it said.

# SEP-2484: Require Conformance Tests for Standards Track SEPs to Reach Final Status

> Require Conformance Tests for Standards Track SEPs to Reach Final Status

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Process
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2484                                                                            |
| **Title**     | Require Conformance Tests for Standards Track SEPs to Reach Final Status        |
| **Status**    | Final                                                                           |
| **Type**      | Process                                                                         |
| **Created**   | 2026-03-27                                                                      |
| **Author(s)** | Paul Carleton ([@pcarleton](https://github.com/pcarleton))                      |
| **Sponsor**   | None                                                                            |
| **PR**        | [#2484](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2484) |

***

## Abstract

This SEP adds a conformance test requirement to the `Accepted → Final` transition for Standards Track SEPs. Before a Standards Track SEP that changes observable protocol behavior can be marked `Final`, a conformance scenario covering its normative requirements must be merged into the conformance repository, accompanied by a structured traceability file mapping each MUST/MUST NOT and SHOULD/SHOULD NOT to a check or a documented exclusion. This keeps the conformance suite synchronized with the specification as it evolves, gives SDK maintainers an executable target for implementation, and makes SEP-1730's tier percentages a meaningful measure of spec coverage. Process and Informational SEPs are exempt, as are Standards Track SEPs with no observable protocol behavior.

## Motivation

### The gap between specification and implementation

The MCP specification is written in English. SDK maintainers translate that English into code, and every translation is an opportunity for drift. SEP-1730 (SDK Tiering) already depends on conformance tests (Tier 1 requires 100% pass rate, Tier 2 requires 80%), but there is no mechanism keeping the suite synchronized with the spec. When a SEP reaches `Final`, SDK maintainers implement from prose and hope they interpreted it the same way every other SDK did. Conformance tests arrive later, if at all, and when they do they sometimes reveal that two "compliant" SDKs disagree.

### Why the existing reference implementation requirement is insufficient

A **reference implementation** proves the feature can be built: one valid interpretation. A **conformance test** defines what every implementation must do: the normative requirements as executable assertions. A TypeScript reference implementation tells a Rust maintainer little about whether their code is correct. A conformance test tells them precisely, and when it doesn't, the disagreement surfaces an ambiguity in the spec itself.

### Keeping the conformance suite alive

The conformance suite is the yardstick SEP-1730's tier percentages measure against. If it falls behind, an SDK could be "100% compliant" while missing major specification features. Tying tests to the SEP lifecycle creates a forcing function: the suite grows exactly as fast as the spec does.

## Specification

### Scope

This requirement applies **only** to Standards Track SEPs that introduce or modify **observable protocol behavior**: behavior a conformant peer can detect by inspecting messages on the wire, transport-observable side effects (HTTP status codes, headers, connection lifecycle, OAuth redirects), or process-observable side effects for local transports (stdio stream content, exit codes).

The following are **exempt**:

* **Process SEPs** (governance, workflow, community structure)
* **Informational SEPs** (guidelines, best practices without normative force)
* **Standards Track SEPs with no observable protocol behavior**, for example:
  * Documentation-only clarifications of existing behavior
  * Schema annotations that do not change validation or runtime behavior
  * Security recommendations describing implementation hardening rather than wire-level requirements

The conformance suite itself is not restricted to official SDKs. Any implementation (official SDK, community SDK, or custom deployment) may run it and report a compliance percentage.

### The requirement

For a Standards Track SEP in scope to transition from `Accepted` to `Final`:

1. **A conformance scenario** tagged with the SEP number is merged into the conformance repository, targeting the conformance repository's draft spec-version tag for the upcoming release.
2. **A traceability file** accompanies the scenario. See below.
3. **The scenario passes** against the SEP's reference implementation.

When that spec version is released, the scenario's spec-version tag is updated from the draft tag to the dated version as part of the normal release process. The conformance harness and the SDK under test must both recognize the draft tag as a negotiable protocol version so that the new requirements are actually exercised.

### Traceability file

The traceability file is a structured file (`sep-NNNN.yaml`) in the conformance repository. It maps each normative requirement in the SEP's Specification section to the check that exercises it, or documents why it is excluded:

```yaml theme={null}
sep: 1234
spec_url: https://modelcontextprotocol.io/specification/draft/section#anchor
requirements:
  - check: sep-1234-foo-present
    text: "MUST include `foo` in the response"
  - check: sep-1234-bar-absent
    text: "MUST NOT send `bar` before initialization"
  - check: sep-1234-qux-present
    text: "SHOULD include `qux` when available"
  - check: sep-1234-baz-rejected
    text: "MUST reject requests with invalid `baz`"

  - text: "MUST retry on 503"
    excluded: "Requires fault injection; not currently supported by framework"
    issue: https://github.com/modelcontextprotocol/conformance/issues/N
  - text: "MUST be rendered in a monospace font"
    excluded: "Client rendering; not observable at the protocol level"
```

Structured data lets tooling link check failures back to spec sections and lets the conformance CLI report coverage per SEP.

Exclusions come in two flavors. **Framework gaps** (the behavior is observable but the framework can't express it yet) should link a tracking `issue`. **Not protocol-observable** (the requirement governs client rendering, implementation internals, or similar) needs only the `excluded` reason. A SEP whose requirements are all the second kind is exempt and doesn't need a scenario at all.

The sponsor verifies the traceability file is complete: every MUST, MUST NOT, SHOULD, and SHOULD NOT (and RFC 2119 equivalents: SHALL, REQUIRED, RECOMMENDED) in the SEP's Specification section has a row. Checks for SHOULD-level requirements report as warnings rather than failures. MAY requirements do not need rows. The sponsor does not review test code; that is the conformance repository's normal PR review. What counts as a normative requirement is the sponsor's call.

### Who writes the tests

The **sponsor** is responsible for ensuring a conformance scenario is written. Scenarios are authored in TypeScript; contributors unfamiliar with the conformance repository should start with its [CONTRIBUTING guide](https://github.com/modelcontextprotocol/conformance/blob/main/CONTRIBUTING.md). In practice the SEP author is often best positioned, since writing the test surfaces ambiguities in the normative language that are cheaper to fix before `Final` than after.

### Specification text is authoritative

Conformance tests are derived from and **subordinate to** the specification text. Where a test and the spec disagree, the spec is authoritative and the test is a bug.

### Conformance test disputes

If an implementer believes a merged conformance test contradicts the spec, they open an issue in the conformance repository citing the specific spec text. A test is considered disputed once a conformance maintainer applies the `disputed` label; disputed tests do not affect SEP-1730 tier assessments until resolved.

Most disputes resolve through normal issue triage: the test is fixed, the spec is clarified, or the dispute is closed with rationale. If the disagreement is fundamental (the disputing party and the conformance maintainers cannot agree on what the spec means), either party may escalate unilaterally to Core Maintainers for a ruling, though joint escalation is preferred since the goal is to resolve ambiguity rather than win an argument. The same escalation path is available to a sponsor if a scenario PR is blocked on non-technical grounds.

### Test stability and tiering

SEP-1730 tier assessments are run against a **pinned conformance release version**, not the tip of the conformance repository. New checks added to a SEP's scenario after the SEP is `Final` (whether additional edge cases or coverage of previously-excluded requirements) land in the conformance repository's main branch but only affect tier percentages when the next tiering assessment adopts a newer conformance release.

This means SDK maintainers have a stable target between tiering waves, and the conformance suite can evolve continuously without surprise regressions in tier status.

### Sponsor responsibilities

SEP-1850 makes the sponsor responsible for tracking reference implementation progress before marking a SEP as `Final`. This SEP extends that responsibility: for Standards Track SEPs in scope, the sponsor also confirms that a conformance scenario tagged with the SEP number is merged with a complete traceability file, or that an exemption is documented in the SEP.

### Relationship to SEP-1730 (SDK Tiering)

This SEP strengthens SEP-1730's foundation without changing its tier definitions or thresholds. Tier assessments use pinned conformance releases, so new checks do not retroactively affect tier status. Disputed tests do not count toward tier percentages until resolved.

Scenario contributions covering existing spec behavior (not tied to a new SEP) remain welcome and are not required to carry a traceability file.

### Relationship to SEP-1627 (Conformance Testing)

This SEP **supersedes** SEP-1627 by accepting the conformance repository as the canonical home for conformance tests and formalizing its role in the SEP lifecycle. SEP-1627's golden-trace approach was not carried forward; the scenario-and-checks model trades language-neutral fixtures for runtime expressiveness. SEP-1627's protocol-debugger ideas remain valuable future work.

## Rationale

### Why gate `Final` rather than `Accepted`?

Gating `Accepted` would require tests before Core Maintainers have agreed the feature belongs in the spec, wasting effort on rejected SEPs.

That said, writing a conformance test *during* SEP drafting is often valuable: it forces precision in MUST/MUST NOT language and surfaces edge cases the prose glosses over. Authors are **encouraged** to draft a conformance scenario before Core Maintainer review, especially for SEPs with complex behavioral requirements. It is not required, because small SEPs may not justify the upfront effort, and a rejected SEP's test is wasted work.

Gating `Final` places the hard requirement where the reference implementation requirement already sits: the SEP has consensus, and the remaining work is implementation.

### Why a traceability file?

Without a defined coverage bar, "has a conformance test" would be relitigated on every SEP: does one check suffice, or must every MUST be covered? The traceability file makes coverage auditable: every normative statement has a row, and every row is either a check or a documented exclusion. "Sufficient" becomes "the file is complete."

The file also makes gaps visible. A SEP with ten MUSTs and eight exclusions is a signal: either the SEP is genuinely hard to test (the tracking issues say why) or the test author stopped early (the sponsor should push back).

### Why put the authorship obligation on the sponsor?

The sponsor already shepherds the SEP through review, tracks the reference implementation, and manages status transitions. Adding "ensure a conformance test is written" is a small marginal addition to an existing role, with a clear owner.

### Alternatives considered

**Require conformance tests in the SEP PR itself.** Rejected: couples two independent review processes with different maintainers and CI.

**Gate only "major" SEPs.** Rejected: "major" is subjective. The observable-behavior scope is objective: either a conformant peer can detect the change, or it cannot.

**Make conformance maintainers the sufficiency judges.** Rejected: concentrates veto power in a group not elected to approve spec changes. The traceability-file model lets the sponsor verify completeness without reading test code.

## Backward Compatibility

This SEP is **not retroactive**. SEPs that reached `Final` before this SEP takes effect are not required to add conformance tests, though contributions are welcome.

## Security Implications

None directly. Conformance tests that exercise security-relevant behavior (auth flows, input validation, transport security) improve the ecosystem's security posture by catching regressions, but this SEP does not mandate security-specific coverage beyond what the underlying SEP's MUSTs require.

## Reference Implementation

The conformance repository already demonstrates the scenario-tagging pattern this SEP formalizes:

* [`JsonSchema2020_12Scenario`](https://github.com/modelcontextprotocol/conformance/blob/main/src/scenarios/server/json-schema-2020-12.ts) — SEP-1613
* [`ElicitationDefaultsScenario`](https://github.com/modelcontextprotocol/conformance/blob/main/src/scenarios/server/elicitation-defaults.ts) — SEP-1034
* [`ServerSSEPollingScenario`](https://github.com/modelcontextprotocol/conformance/blob/main/src/scenarios/server/sse-polling.ts) — SEP-1699
* [`ElicitationEnumsScenario`](https://github.com/modelcontextprotocol/conformance/blob/main/src/scenarios/server/elicitation-enums.ts) — SEP-1330

The structured traceability file format and the scenario scaffolding tool (`npx @modelcontextprotocol/conformance new-scenario --sep <number>`) will be added to the conformance repository before this SEP reaches `Final`.

The process change is implemented by updating `docs/community/sep-guidelines.mdx` to add the conformance check to the `Accepted → Final` transition (see the accompanying changes in this PR).

## Prerequisites for Final status

Before this SEP itself can be marked `Final`, the following conformance-repository work must be complete:

* Structured traceability file format (`sep-NNNN.yaml`) and schema
* Scenario scaffolding tool
* Conformance harness supports a draft spec-version tag as a negotiable protocol version
* `MAINTAINERS.md` published and the repository listed in MCP governance documentation

These are this SEP's own reference implementation checklist, not ongoing process requirements.

seps/2549-TTL-for-list-results First recorded · 230 lines, first recorded

# SEP-2549: TTL for List Results ## Abstract ## Motivation ## Specification ### New interface: `CacheableResult` #### Schema change (TypeScript) ### Semantics #### Freshness calculation ### Cache scope ### Interaction with notifications ### Interaction with pagination ### Error handling ## Rationale ### Why not replace `list_changed` notifications? ### Why integer milliseconds for TTL? ### Why not use HTTP caching directly? ## Backward Compatibility ## Reference Implementation ## Security Implications

The first capture of this source. The page was already there, and this is what it said.

# SEP-2549: TTL for List Results

> TTL for List Results

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2549                                                                            |
| **Title**     | TTL for List Results                                                            |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2026-04-09                                                                      |
| **Author(s)** | Caitie McCaffrey ([@CaitieM20](https://github.com/CaitieM20))                   |
| **Sponsor**   | [@CaitieM20](https://github.com/CaitieM20)                                      |
| **PR**        | [#2549](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549) |

***

## Abstract

This SEP proposes adding fields to support caching result objects returned by `tools/list`, `prompts/list`, `resources/list`, `resources/read`, and `resources/templates/list`. Two fields will be added `ttlMs` and `cacheScope`. The TTL tells clients how long the response may be considered fresh before re-fetching. This allows clients to cache feature lists and reduce reliance on server-push notifications while remaining fully backward compatible. The `cacheScope` field controls who may cache a response. TTL supplements rather than replaces the existing notification mechanism — both can coexist.

## Motivation

Today, MCP clients discover server features by invoking methods on the server. These calls return the current set of features. To learn about changes, clients rely on push notifications from the server. The below table maps the Server Method to Notification Type.

| Server Methods             | Notification Type                      |
| -------------------------- | -------------------------------------- |
| `tools/list`               | `notifications/tools/list_changed`     |
| `prompts/list`             | `notifications/prompts/list_changed`   |
| `resources/list`           | `notifications/resources/list_changed` |
| `resources/templates/list` | `notifications/resources/list_changed` |
| `resources/read`           | `notifications/resources/updated`      |

This approach has several limitations:

1. **HTTP-based transports require SSE Streams**: Many clients and servers have challenges supporting long lived SSE streams which are necessary for notifications. The goal is to make SSE streams an optional optimization, but support protocol functionality without them. A TTL allows clients to poll on a predictable schedule without relying on server-push notifications.

2. **Implementation complexity**: Both clients and servers must implement notification subscription and delivery infrastructure. Many simple servers have feature lists that change infrequently (or never), yet must still support the notification machinery if they want clients to stay current.

3. **No freshness signal**: Even clients that can receive notifications have no indication of how "stable" a list is. A server whose tool list changes once a day and one whose list changes every second look identical to the client — both simply send notifications when changes occur. A TTL provides an explicit freshness hint.

4. **Alignment with web standards**: HTTP caching (`Cache-Control: max-age`) and DNS TTLs have long demonstrated that time-based freshness hints are a simple, well-understood mechanism for reducing unnecessary refetches. MCP can benefit from the same pattern.

Adding a TTL field to list responses solves all of these problems with a minimal, backward-compatible protocol change.

## Specification

### New interface: `CacheableResult`

A new `CacheableResult` interface is introduced as a standalone type extending `Result`. It owns the `ttlMs` and `cacheScope` fields.

#### Schema change (TypeScript)

```typescript theme={null}
/**
 * A result that supports a time-to-live (TTL) hint for client-side caching.
 *
 * @internal
 */
export interface CacheableResult extends Result {
  /**
   * A hint from the server indicating how long (in milliseconds) the
   * client MAY cache this response before re-fetching. Semantics are
   * analogous to HTTP Cache-Control max-age.
   *
   * - If 0, The response SHOULD be considered immediately stale, The client
   *   MAY re-fetch every time the result is needed.
   * - If positive, the client SHOULD consider the result fresh for this many
   *   milliseconds after receiving the response.
   */
  ttlMs: number & { readonly minimum: 0 };

  /**
   * Indicates the intended scope of the cached response, analogous to HTTP
   * Cache-Control: public vs Cache-Control: private.
   *
   * - "public": Any client or intermediary (e.g., shared gateway, proxy)
   *   MAY cache the response and serve it to any user.
   * - "private": Only the requesting user's client MAY cache the response.
   *   Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached
   *   copy to a different user.
   *
   * Defaults to "public" if absent.
   */
  cacheScope: "public" | "private";
}
```

### Semantics

A TTL is a freshness estimate, not a guarantee. Servers MAY change the underlying list before the TTL expires; servers that do so and have advertised listChanged SHOULD send the corresponding notification.

Servers MUST provide a `ttlMs` on `Results` returned by `tools/list`, `prompts/list`, `resources/list`, `resources/read`, and `resources/templates/list`.

`ttlMs` MUST be >= 0. If a server returns a negative value, clients SHOULD ignore it and treat it as 0 (immediately stale).

| Condition                                          | Client behavior                                                                                               |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `ttlMs` = 0                                        | The response SHOULD be considered immediately stale, The Client MAY re-fetch every time the result is needed. |
| `ttlMs` > 0                                        | Client SHOULD consider the response fresh for `ttlMs` milliseconds from receipt.                              |
| Relevant notification received while TTL is active | The notification invalidates the cached response. Client SHOULD re-fetch regardless of remaining TTL.         |
| `cacheScope` = `"public"`                          | Any client or shared intermediary (gateway, proxy) MAY cache and serve the response to any user.              |
| `cacheScope` = `"private"`                         | Only the requesting user's client MAY cache. Shared caches MUST NOT serve a cached copy to a different user.  |

#### Freshness calculation

A client records the local time at which the response was received (`t_received`). The response is considered **fresh** while `now < t_received + ttlMs`. Once the TTL expires the response is **stale** and the client SHOULD re-fetch on next access.

Clients SHOULD NOT treat TTL as a polling interval that triggers automatic background refetches. The TTL is a **freshness hint**: the client checks freshness when it needs the list, and re-fetches only if stale. Implementations that do choose to poll SHOULD apply jitter and backoff.

Clients MAY re-fetch if they have reason to believe the data has changed, even if the TTL has not yet expired. Examples include receiving an unexpected error on a tool call indicating that the the method was not found or the parameters were invalid.

Clients MAY serve stale responses if errors occur in re-fetching results(e.g., network issues, server downtime). The TTL is a hint for how long the client can safely rely on the data, but real-world conditions may require flexibility.

### Cache scope

The `cacheScope` field controls who may cache a response:

* **`"public"`**: The response does not contain user-specific data. Any client, shared gateway, or caching proxy MAY store and serve the cached response to any user. This is appropriate for lists of tools, prompts, and resource templates that are identical for all users.
* **`"private"`**: The response contains user-specific data. Only the requesting user's client MAY cache it. Shared caches (e.g., multi-tenant API gateways) MUST NOT serve a `"private"` cached response to a different user. This is appropriate for `resources/read` results that depend on the authenticated user, or for filtered list results that vary per user.

This design mirrors HTTP `Cache-Control: public` vs `Cache-Control: private`, applying the same well-understood semantics at the MCP protocol level.

### Interaction with notifications

TTL and server-push notifications are complementary:

* A server MAY provide `ttlMs` without advertising `listChanged: true` in its capabilities. In this case the client relies entirely on TTL.
* A server MAY advertise `listChanged: true` **and** provide `ttlMs`. In this case the client can use the TTL to avoid unnecessary refetches between notifications, and the notification acts as an immediate invalidation signal.

```mermaid theme={null}
sequenceDiagram
    participant C as Client
    participant S as Server

    C->>S: tools/list
    S-->>C: { tools: [...], ttlMs: 300000 }
    Note over C: Cache response, fresh for 5 min

    Note over C: 2 minutes later...
    C->>C: Need tools list → cache still fresh, use cached

    Note over C: 3 minutes later (TTL expired)...
    C->>C: Need tools list → cache stale
    C->>S: tools/list
    S-->>C: { tools: [...], ttlMs: 300000 }

    Note over S: Tools change before TTL expires
    S-->>C: notifications/tools/list_changed
    Note over C: Invalidate cache immediately
    C->>S: tools/list
    S-->>C: { tools: [...], ttlMs: 300000 }
```

### Interaction with pagination

When a list result is paginated (includes `nextCursor`), each page is an independently cacheable response — consistent with how HTTP `Cache-Control` treats paginated resources. Specifically:

* Each page response carries its own `ttlMs` value. The freshness clock for each page starts at the time that page was received.
* Servers MAY return different `ttlMs` values on different pages (e.g., a longer TTL for early pages of a stable list, a shorter TTL for the final page).
* There is no cross-page consistency guarantee. If the underlying data changes between page fetches, clients may observe duplicates or gaps — the same trade-off that applies to HTTP paginated APIs.
* Clients that require a consistent snapshot of the full list SHOULD re-fetch from the beginning (without a cursor).
* If a cursor becomes invalid (e.g., the server returns an error for a previously valid cursor), the client SHOULD discard all cached pages and re-fetch from the beginning.

Servers MUST apply the same cacheScope to all response pages for a given list request. For example, if the first page of a `tools/list` response has `cacheScope: "private"`, all subsequent pages for that request MUST also be treated as `"private"`.

### Error handling

* For backwards compatibility, If `ttlMs` is missing, clients SHOULD assume a default `ttlMs` of `0` (immediately stale) and rely on their own caching heuristics or notifications.
* If `ttlMs` is present but is a negative integer, the client SHOULD ignore it and behave as if it were 0 (immediately stale).

## Rationale

### Why not replace `list_changed` notifications?

Notifications provide immediate invalidation which is valuable for long-lived connections. TTL provides a complementary mechanism optimized for stateless transports and for reducing unnecessary polling. Both mechanisms serve different use cases and coexist naturally.

### Why integer milliseconds for TTL?

We chose integer milliseconds over seconds as we want one unit for ttl across the MCP protocol. Tasks has uses cases for sub-second TTLs, and using milliseconds allows for a consistent representation across all TTLs in MCP.

Many existing systems use integer seconds for TTLs, but some (e.g., gRPC retry pushback) use milliseconds. The key is to choose a single, consistent unit for all TTLs in MCP. Integer milliseconds provides the necessary precision while remaining simple to implement and understand.

| System                        | Mechanism             | Notes                                                            |
| ----------------------------- | --------------------- | ---------------------------------------------------------------- |
| HTTP `Cache-Control: max-age` | Integer seconds       | The most widely deployed freshness hint in web infrastructure    |
| DNS TTL                       | Integer seconds       | Controls how long resolvers cache DNS records                    |
| GraphQL `@cacheControl`       | `maxAge` integer secs | Per-field cache hints in GraphQL responses                       |
| gRPC `grpc-retry-pushback-ms` | Milliseconds          | Server-provided retry hint (different use case, similar pattern) |

### Why not use HTTP caching directly?

MCP is transport-agnostic. While HTTP-based transports could theoretically use `Cache-Control` headers, MCP also operates over stdio, and supports pluggable transports where HTTP headers may not be available. Embedding the TTL in the JSON response body ensures it works uniformly across all transports.

## Backward Compatibility

* Existing servers that do not provide it continue to work unchanged. If a `ttlMs` field is missing, clients SHOULD assume a default ttlMs of 0 (immediately stale) and rely on their own caching heuristics or notifications, which is the current behavior.
* Existing clients that do not understand the field will ignore it, as MCP result objects permit additional properties via `[key: string]: unknown` on the `Result` base type.
* `cacheScope` is required because there is no safe default for older servers. The server must explicitly declare the intended cache scope to prevent unintended caching of user-specific data.
* No existing fields or behaviors are modified or removed.
* No capability negotiation is required.
* SDK Maintainers can choose to add defaults for ttl and cacheScope in their SDKs to simplify adoption, but this is not required for compliance.

## Reference Implementation

*No reference implementation yet.*

***

## Security Implications

A misconfigured or malicious serer could set an excessively long TTL, causing clients to cache stale data for longer than desired. However, since the TTL is a hint and clients can choose to ignore it or re-fetch if they suspect changes, the security risk is minimal. Clients should be designed to handle unexpected TTL values gracefully.

seps/2567-sessionless-mcp First recorded · 302 lines, first recorded

# SEP-2567: Sessionless MCP via Explicit State Handles ## Abstract ## Motivation ### What sessions scope today ### Problems with session scoping #### Session lifetime is undefined, and servers can't design around it #### List endpoints cannot be cached across sessions #### Cardinality is fixed at one per session ## Specification ### Summary of changes ### Explicit state handles #### Pattern #### Guidance for servers #### Guidance for clients ### Session-independent list endpoints ### Consequential spec edits ## Rationale ### Why remove sessions rather than just default them off? ### Expressiveness ### Resumption ### Anticipated objections #### Garbage collection #### Models have to carry the IDs forward #### IDs in chat history #### Breaking change ## Backward Compatibility ## Security Implications ### Handle exposure ## Reference Implementation ## Future Work

The first capture of this source. The page was already there, and this is what it said.

# SEP-2567: Sessionless MCP via Explicit State Handles

> Sessionless MCP via Explicit State Handles

<div className="flex items-center gap-2 mb-4">
  <Badge color="green" shape="pill">
    Final
  </Badge>

  <Badge color="gray" shape="pill">
    Standards Track
  </Badge>
</div>

<Note>
  This SEP has reached Final status and is preserved as a historical record of
  the design as accepted. Changes made to the protocol after finalization are
  not reflected here. Refer to the [current
  specification](/specification/latest) and its changelog for authoritative
  requirements.
</Note>

| Field         | Value                                                                           |
| ------------- | ------------------------------------------------------------------------------- |
| **SEP**       | 2567                                                                            |
| **Title**     | Sessionless MCP via Explicit State Handles                                      |
| **Status**    | Final                                                                           |
| **Type**      | Standards Track                                                                 |
| **Created**   | 2026-03-11                                                                      |
| **Author(s)** | Peter Alexander ([@pja-ant](https://github.com/pja-ant))                        |
| **Sponsor**   | Peter Alexander ([@pja-ant](https://github.com/pja-ant))                        |
| **PR**        | [#2567](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2567) |

***

## Abstract

This proposal removes the protocol-level session concept from MCP, replacing implicit session-scoped state with explicit, server-minted state handles that the model carries and threads through subsequent calls. [SEP-2575] removes the `initialize` handshake and carries protocol version and capabilities per-request; this proposal is the complementary change that removes sessions and the `Mcp-Session-Id` header. Together they make MCP stateless at the protocol layer.

After more than a year in the spec, sessions have not converged on a consistent meaning across clients: some scope them per tool call, some per application launch, some per page load, and almost none resume them. A server author cannot predict what scope or lifetime a session will have when their server is connected to an arbitrary client, which has made the session unreliable as a container for application state. This proposal holds that application state can be served by explicit identifiers, and that the session abstraction adds constraints (fixed cardinality, undefined lifetime, uncacheable list endpoints across session boundaries) without corresponding benefit.

Under this proposal, a server that currently scopes a shopping cart (for example) to the session instead exposes a tool `create_basket()` that returns a `basket_id` and threads that ID through subsequent tool calls, e.g. `add_item(basket_id, ...)`. The model decides what is shared and what is isolated; list endpoints become cacheable across what used to be session boundaries; and agent orchestrators can freely share or not share application state as needed. Explicit state handles are not a new protocol construct — there is no schema or wire format for them. They are a tool-design pattern; the protocol change is the removal of sessions, which leaves handles as the way to express cross-call state.

[SEP-2575]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575

[SEP-2322]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322

[SEP-2549]: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549

## Motivation

### What sessions scope today

The current spec is imprecise about which behaviors are session-bound, but in practice five categories of things attach to a session's lifetime:

1. **Negotiated capabilities and protocol version.** The result of `initialize` — which protocol version is in use and which optional capabilities each side supports — is established once per session and assumed for its duration. [SEP-2575] resolves this by removing `initialize` and carrying version/capability information per-request, so this proposal treats it as already addressed.

2. **Elicitation and sampling intermediate state.** When a tool call triggers an `elicitation/create` or `sampling/createMessage` round-trip, the server has to correlate the eventual response with the original in-flight tool call — state that today lives implicitly in the session. [SEP-2322] (Multi Round-Trip Requests) resolves this by carrying the correlation state explicitly through the request/response cycle, so this proposal treats it as already addressed.

3. **Application state.** The canonical example is a shopping cart: `add_item()`, `add_item()`, `checkout()`, with the cart existing implicitly per-session. This generalizes to any stateful workflow — a Playwright browser instance, a database transaction, an open file descriptor.

4. **Mutable list endpoints.** `tools/list` (and `resources/list`, `prompts/list`) can legally return different results over a session's lifetime. For example, a database server could expose a `connect_database` tool that, once called, makes `query` and `list_tables` appear in subsequent `tools/list` results.

5. **Resource subscriptions.** Subscription lifetime is tied to session lifetime. ([SEP-2575] introduces `messages/listen` as the delivery channel for server-to-client notifications; subscription lifetime under that model is not re-examined here.)

With (1), (2), and (5) handled by other SEPs, this proposal addresses (3) and (4).

### Problems with session scoping

The issues below apply whether sessions are mandatory (the current spec) or made optional.

#### Session lifetime is undefined, and servers can't design around it

The spec does not say when a session begins or ends, because it depends on the host application. In practice, deployed clients vary widely and few scope sessions to a conversation: ChatGPT creates a fresh session for every individual tool call, and Claude.ai did the same until recently;[^per-call] most desktop and IDE clients create one at application launch and keep it for the process lifetime; web clients typically create one per page load. Almost no clients resume a prior session after a disconnect or restart, and on the server side the reference TypeScript SDK provides no public API for reconstructing a session on a different node, so multi-node deployments cannot honor resumption even when a client attempts it.[^ts-sdk-resume] A subagent might share its parent's session or get its own — there is no convention.

[^per-call]: [microsoft/playwright-mcp#1045](https://github.com/microsoft/playwright-mcp/issues/1045), Sep 2025 — server author reports both ChatGPT and Claude.ai closing the session after each tool call, dropping browser state; ["Connector tool calls generating fresh MCP session each invocation"](https://community.openai.com/t/connector-tool-calls-generating-fresh-mcp-session-each-invocation/1364975), OpenAI Developer Community, Nov 2025.

[^ts-sdk-resume]: [modelcontextprotocol/typescript-sdk#1658](https://github.com/modelcontextprotocol/typescript-sdk/issues/1658), Mar 2026 — `StreamableHTTPServerTransport` stores session state in private instance fields with no API to rehydrate from external storage.

This matters because server authors are the ones deciding what to scope to the session, and they need to know what a session corresponds to in order to do that correctly. A Playwright server that ties a browser instance to the session needs to know whether that means one user turn, one agent process, or one long-lived chat. The spec does not specify this and different hosts give different answers, so the server is designing against an abstraction whose semantics it does not control.

The practical consequence is that session-scoped application state often does not survive. Against a per-tool-call client it is destroyed before the next call; against a per-app-launch client it is shared across every conversation in the window and then lost on restart; against any client that does not resume, it is gone when the app restarts. Servers that appear to be using session state successfully are usually stdio servers relying on process lifetime, which is a property of the transport rather than the protocol.

#### List endpoints cannot be cached across sessions

Because `tools/list` may be session-dependent, a client cannot assume a result fetched in one session is valid in the next. Every new session must re-fetch, even when the server's tool set is fixed at build time and never changes, which is the common case.

The Python SDK's own design issue for client-side list caching lists "what is the cache key — per-session or per-server-URL?" as an open question,[^py-sdk-cache] and gateway implementers have shipped per-session caching specifically because they could not assume cross-session validity from the spec.[^agentgateway-cache] Every list endpoint must be treated as potentially session-scoped, so each must be re-fetched per session to be safe.

[^py-sdk-cache]: [modelcontextprotocol/python-sdk#2108](https://github.com/modelcontextprotocol/python-sdk/issues/2108), Feb 2026.

[^agentgateway-cache]: [agentgateway/agentgateway#1510](https://github.com/agentgateway/agentgateway/issues/1510), Apr 2026.

For hosts that regularly spawn subagents, this is a multiplier on the hot path. The possibility that a server is session-scoped forces `O(subagents × servers)` calls to `tools/list`: every subagent, for every server, every time, even if the underlying tool set has not changed since the orchestrator first connected. The client cannot skip the call because it cannot know in advance which servers are session-scoped. For an orchestrator spawning many short-lived subagents, this overhead can exceed the protocol traffic of the actual tool calls. Under this proposal the same workload is `O(servers)`: the orchestrator fetches each list once and every subagent reuses the cached result.

If list endpoints were a function only of the server deployment and the authenticated principal, clients could cache them and invalidate on an explicit signal. [SEP-2549] specifies such a signal (a server-advertised TTL plus `notifications/*/list_changed`), but its caching model is only sound if the list does not also vary per session. Removing sessions makes that model safe; a subagent can then inherit its parent's cached lists at zero cost.

#### Cardinality is fixed at one per session

Session state has a cardinality of exactly one per session. The model gets one cart, one browser, one of whatever the server scopes to the session; it cannot have two, and it cannot have zero.

This is a problem when different pieces of state need different scopes. Consider an orchestrator that spawns several subagents to independently research products to buy. The subagents should add to the same shopping cart (they are collaborating on one order) but each needs its own browser state (they are browsing different sites in parallel).

No session boundary satisfies both:

| Session model            | Cart (want: shared) | Browser (want: isolated) |
| ------------------------ | :-----------------: | :----------------------: |
| Subagents share parent's |       ✓ shared      |    ✗ shared (clobbers)   |
| Subagents get their own  |      ✗ isolated     |        ✓ isolated        |

With explicit IDs the orchestrator calls `create_basket()` once, passes the resulting `basket_id` to each subagent, and each subagent separately calls `create_browser()` for its own `browser_id`. The model decides what is shared and what is isolated per piece of state, rather than having one scope imposed on everything.

The same lack of an identifier also means session state is not addressable from outside the session that created it. A cart created in one chat is invisible to another chat; if a user wants to resume work in a new conversation, hand something off to a different agent, or share state with a colleague, the session model provides nothing to refer to it by. An explicit `basket_id` can be passed to any of those.

## Specification

### Summary of changes

1. **Remove the session concept from the protocol.** The `Mcp-Session-Id` header is removed and the spec language describing session lifecycle and session-scoped behavior is deleted. The protocol is sessionless at every layer. ([SEP-2575] removes the `initialize` handshake but explicitly defers session removal to this proposal.)

2. **List endpoints are session-independent.** With no session, the results of `tools/list`, `resources/list`, and `prompts/list` have no per-session or per-connection scope to depend on. Lists can still change for other reasons (server deployment, auth changes); caching and invalidation mechanics for those are specified separately in [SEP-2549].

3. **Stateful workflows use explicit handles.** With sessions gone, servers that need to maintain state across tool calls do so by returning an identifier from a creation tool and accepting it as a parameter on subsequent calls.

That third point is **not a protocol change**. There is no `handles/*` method, no handle type in the schema, no wire-level concept of a handle at all. From the protocol's perspective a handle is a string in a tool result and a string in a tool argument, indistinguishable from any other tool data. "Explicit state handles" is a tool-design pattern that the spec documents and recommends — in the same way it might document pagination or error-message conventions — not something it implements. The normative content of this SEP is the removal in (1); (2) follows from it, and (3) is the guidance that fills the gap.

### Explicit state handles

#### Pattern

Where a server would previously have relied on implicit session-scoped state — `add_item` calls operating on a per-session cart — it instead exposes an explicit creation tool that returns a handle:

```jsonc theme={null}
// → tools/call
{ "name": "create_basket", "arguments": {} }

// ← result
{ "content": [{ "type": "text", "text": "Created basket bsk_a1b2c3" }],
  "structuredContent": { "basket_id": "bsk_a1b2c3" } }
```

The model then threads that handle through subsequent calls as an ordinary argument:

```jsonc theme={null}
// → tools/call
{ "name": "add_item",
  "arguments": { "basket_id": "bsk_a1b2c3", "sku": "shoes" } }

// ← result
{ "content": [{ "type": "text", "text": "Added shoes to bsk_a1b2c3 (1 item)" }] }

// → tools/call
{ "name": "checkout",
  "arguments": { "basket_id": "bsk_a1b2c3" } }
```

Nothing here is a protocol extension: `basket_id` is an ordinary string field in `structuredContent` and an ordinary string argument to subsequent tools. This pattern is already the norm in widely-deployed remote MCP servers that manage durable resources:

| Server (official, remote)                                   | Create tool → returned ID         | Operate tools taking that ID                                     |
| ----------------------------------------------------------- | --------------------------------- | ---------------------------------------------------------------- |
| [Linear](https://linear.app/docs/mcp)                       | `create_issue` → issue id         | `get_issue`, `update_issue`, `create_comment`                    |
| [Notion](https://developers.notion.com/docs/mcp)            | `notion-create-pages` → page id   | `notion-update-page`, `notion-move-pages`                        |
| [GitHub](https://github.com/github/github-mcp-server#tools) | `create_pull_request` → PR number | `pull_request_read`, `update_pull_request`, `merge_pull_request` |
| [Stripe](https://docs.stripe.com/mcp)                       | `create_customer` → customer id   | `create_invoice`, `list_subscriptions`                           |

The approach can be adopted for less-persistent objects (a browser context, an in-progress cart) by giving the created object a limited lifetime, and/or limiting its discoverability to the principal that created it. The server owns the state, the client holds a name for it, and authorization is checked on every call.

#### Guidance for servers

None of the following is normative. Handles are a tool-design pattern, not a protocol feature, and servers are free to shape them however fits their domain. The pattern works best when:

* **Handles are opaque.** A handle that encodes internal structure (`cart_user42_2026-03-11`) invites clients to parse it or models to guess it; an opaque handle such as `bsk_a1b2c3` does not.
* **Possession is not authorization (where auth exists).** For authenticated servers, validate `(handle, auth_context)` on every call; handles will end up in chat logs, copy-paste buffers, and subagent prompts. For unauthenticated servers, where the handle is necessarily a bearer token, generate it with at least 128 bits of cryptographically secure entropy and bound its lifetime. See [Security Implications](#security-implications).
* **Durability is documented in the tool description.** Handles outlive connections by design, so "the state lasts until the connection closes" is no longer applicable. Put the policy in the `create_*` tool's description — "returns a basket\_id; baskets expire after 24h idle" — so it is visible to the model when it decides to create state. A policy only in server documentation is not visible to the model.
* **Expired handles return useful errors.** When a tool receives a handle for state that has expired or been destroyed, the error should say so — "basket `bsk_a1b2c3` has expired" rather than "invalid argument". A clear expiry error lets the model recover by calling `create_*` again; an opaque error typically leads to retries or failure.
* **Creation takes parameters.** `create_context(cluster="staging")` is preferable to `create_context()` followed by `set_cluster(ctx, "staging")`: one round-trip instead of two, and the state cannot exist half-configured.
* **Cleanup is available.** A `destroy_*(handle)` tool lets models release resources. A `list_*()` tool lets a model recover after losing track of what it created. Neither is required.

#### Guidance for clients

From the client's perspective, a handle is an ordinary string in a tool result. The main client responsibility is ensuring that string survives context compaction; if the conversation is summarized and the handle is in the discarded portion, the state is orphaned. Clients that track tool-call results across compaction boundaries handle this already.

### Session-independent list endpoints

With sessions removed, list endpoints no longer have a session to vary against. This is the only constraint this SEP places on `tools/list`, `resources/list`, and `prompts/list`: there is no longer a per-session or per-connection scope for their results to depend on. This does not preclude varying the list by the authorization presented on the request: credentials are carried on each request, so a server returning different tool sets to different principals or scopes is relying on per-request input, not connection state. Lists can also still change over time for other reasons — a server deploys a new version, a user's plan or granted scopes change — and this SEP does not enumerate or restrict those.

How clients learn that a cached list has gone stale is the subject of [SEP-2549], which defines a server-advertised TTL on list responses and the interaction with `notifications/*/list_changed`. The two SEPs are complementary: this one removes the session as a source of variation, so there is a stable thing to cache; [SEP-2549] specifies how long to cache it and when to invalidate.

One consequence of the constraint above is that servers can no longer mutate list results as a side effect of other requests; the pattern from the Motivation — where calling `connect_database()` makes `query` and `list_tables` appear in subsequent `tools/list` results — is no longer permitted. For the same effect, the server exposes `query` and `list_tables` unconditionally at list time and has them take a `connection_id` argument returned by `connect_database()`. A `query` call without a valid `connection_id` fails with an error directing the model to call `connect_database()` first; the dependency is expressed in the tool's input schema and description rather than in the list result.

### Consequential spec edits

Beyond removing the §Session Management section itself, several other places in the current spec define behavior in terms of session scope and need re-scoping:

* **JSON-RPC request ID uniqueness.** The spec currently requires that a request `id` "MUST NOT have been previously used by the requestor within the same session." The purpose of `id` is for the sender to correlate an incoming response with the request that produced it; the receiver only echoes it. With sessions removed, the constraint is re-scoped accordingly: a sender MUST NOT issue a request whose `id` matches that of another request it has sent and not yet received a response for. This is transport-agnostic, sufficient for correlation under every transport, and is what the TypeScript and Python SDKs already do via a monotonically increasing counter per client object. ([JSON-RPC 2.0 §4](https://www.jsonrpc.org/specification#request_object) itself imposes no uniqueness requirement — it only requires the receiver to echo the `id` — so this remains an MCP-level constraint.)
* **SSE event ID uniqueness.** The spec currently scopes SSE event IDs as "globally unique across all streams within that session." With sessions removed, the constraint is simply that the ID is globally unique across all streams the server manages, so that a `Last-Event-ID` resolves to a single stream. The existing guidance that event IDs encode the originating stream already implies this.
* **Pagination cursor validity.** The spec currently advises clients not to "persist cursors across sessions." With sessions removed, this advice disappears. Cursor stability and snapshot consistency are outside the scope of this proposal.
* **List-endpoint variability.** The `tools/list`, `resources/list`, and `prompts/list` pages each say results "MAY change over the lifetime of the connection." These are re-scoped per [§Session-independent list endpoints](#session-independent-list-endpoints): results MAY change over time but MUST NOT vary per-connection or as a side effect of other requests on the connection.
* **Wording.** A handful of phrases that use "session" descriptively — "stateful session protocol" in the architecture overview, "available during the session" in capability negotiation, "same logical session" in authorization, the elicitation prohibition on associating state "with session IDs alone," and similar — are reworded or removed. These carry no semantic change beyond the session removal itself.

## Rationale

### Why remove sessions rather than just default them off?

[SEP-2575] already addresses making MCP work behind load balancers and without sticky routing by removing the `initialize` handshake. The reasons for also removing sessions, rather than retaining them as an opt-in capability, are:

* **Opt-in sessions still prevent list caching.** A client cannot cache `tools/list` across session boundaries unless it knows the server does not opt into session-scoped mutation, and it cannot know that in advance. The client therefore re-fetches per session per server even though few servers opt in. The `O(subagents × servers)` cost from the Motivation section is caused by sessions being possible, not by sessions being used, so making them optional does not remove it.
* **The primitive influences server design.** Offering session-scoped state in the spec leads server authors to use it for workflows that would be better served by explicit IDs.
* **Fewer primitives reduce implementation surface.** Every protocol concept must be implemented by SDK authors, documented, and learned by new users.

### Expressiveness

A session provides exactly one scope per connection. Explicit IDs provide as many scopes as the model creates, and each can be shared or isolated independently. Anything expressible with a session is expressible with a single ID the model creates at the start of the conversation; the converse does not hold.

### Resumption

Because handles appear in tool results, they are part of the chat transcript. Any client that persists its chats — which is most of them — therefore persists the handles automatically. Reopening a conversation after an app restart, a page reload, or on a different device puts the handle back in front of the model with no additional resumption machinery, and this behavior is consistent across clients. Session-based state, by contrast, requires the client to persist and resend `Mcp-Session-Id` out of band, which (as covered in the Motivation) almost no clients do.

### Anticipated objections

#### Garbage collection

Sessions provide a lifecycle signal — when the session ends, state is freed. Without it, the model might forget to call `destroy_basket()`, and state leaks.

However, sessions do not deliver this reliably in practice. As covered in the Motivation, real clients either never end the session (per-app-launch), end it constantly (per-tool-call), or end it at moments uncorrelated with the conversation (page reload, network blip). Stateless HTTP servers behind load balancers never see a connection-close. Servers already rely on TTL-based expiry today; the session boundary is not what performs cleanup.

Explicit IDs with a documented durability policy ("baskets expire after 24h idle") is the same mechanism, made explicit.

#### Models have to carry the IDs forward

With implicit session state, the server tracks the identifier; with explicit IDs, the model is responsible for threading `basket_abc123` through every relevant call. The failure modes are hallucinating a slightly-wrong ID, or the ID falling out of context when the conversation is compacted.

Models already carry opaque identifiers through conversations routinely — file paths, URLs, commit hashes, PR numbers, UUIDs returned from prior tool calls — and current models do this reliably. Compaction is the harder case, but it affects any long-horizon state: if the compactor drops live tool-call results, the model loses track of what is in the session-scoped cart as well, not just the cart's ID.

#### IDs in chat history

A `basket_id` that can be pasted anywhere could become an unauthenticated capability in the user's chat log.

For authenticated servers, the ID should be a name, with the server checking `(id, auth_context)` on every call. Google Doc IDs sit in URLs and browser history; access is controlled by ACL, not ID secrecy. The same applies here.

For servers without authentication, the ID is necessarily a bearer token — possession is the only thing the server can check. In that case the handle should follow standard practice for unguessable capability tokens: generated from a cryptographically secure random source with at least 128 bits of entropy (e.g. UUIDv4, or 22+ characters of URL-safe base64), never derived from predictable inputs, and given a bounded lifetime. This is the same posture as other ephemeral public IDs in common use — "anyone with the link" share URLs, password-reset tokens, Stripe Checkout session IDs — and carries the same tradeoff: convenient, but anyone who obtains the token has access for its lifetime.

#### Breaking change

Sessions are in the spec today; removing them breaks anyone relying on them.

An automated survey of a 1000-repo random sample of open source MCP servers (classified by per-repo LLM analysis) found:

| Category                                                      | Share | Migration                                            |
| ------------------------------------------------------------- | ----: | ---------------------------------------------------- |
| No application-level reference to MCP session ID              | 90.0% | None                                                 |
| `Map<sessionId, Transport>` routing (TS SDK boilerplate)      |  3.5% | Removed by a sessionless SDK transport               |
| Transport setup only (`sessionIdGenerator`, never read)       |  2.8% | Delete one constructor option                        |
| **Session-keyed application state**                           |  2.5% | Migrate to explicit handles or auth principal        |
| **Proxy / gateway sticky routing**                            |  0.7% | Needs designed replacement                           |
| **Auth binding** (JWT claims, PKCE verifier keyed on session) |  0.5% | Replace with server-generated nonce or token subject |

The bolded rows are the repos that use the session ID for application semantics. The hardest-hit category — gateways that spawn one upstream per session — needs a designed replacement rather than a mechanical edit; see [Backward Compatibility](#backward-compatibility).

## Backward Compatibility

This is a **breaking change** for servers that rely on protocol-level session state. The migration path depends on server category:

**Stdio servers using process-lifetime state.** These are the most common stateful servers today. Mechanically they are not broken by this proposal in their default deployment — the process lifetime still exists, and a server that keeps a single in-memory browser instance per process continues to function with a stdio client that spawns one process. However, such servers SHOULD NOT rely on process-lifetime state and SHOULD migrate to explicit handles. Process lifetime has the same undefined-scope problem this SEP removes for HTTP (whether the process corresponds to one conversation, one application launch, or something else is up to the host), and a server that depends on it cannot offer equivalent behavior over HTTP, where there is no process per client. Stdio servers never had `Mcp-Session-Id`, so the header removal itself does not affect them.

**HTTP servers using `Mcp-Session-Id`.** These are less common and must migrate to explicit handles. The migration is mechanical: replace the session-scoped state map with a handle-keyed state map, add a `create_*` tool, add the handle as a parameter to stateful tools.

**Servers using session ID as a telemetry key.** Some servers tag traces, logs, or rate-limit buckets with the session ID to correlate activity within a session. This already worked inconsistently across clients — against per-tool-call clients every event lands in its own bucket, and against clients that don't resume the correlation breaks at every restart. These use cases need to move to a different scoping mechanism, typically the authenticated principal (bearer token subject, API key) or a request-level correlation ID.

**Proxies and gateways using session ID for sticky routing.** Gateways that route by `Mcp-Session-Id` lose their routing key — but they only needed one because their upstreams were stateful. If the upstream is stateless (or migrates to explicit handles, where the state key is in the tool arguments and any replica can serve it from shared storage), the gateway needs no sticky routing at all. The residual case is gateways that bridge HTTP to stdio by spawning one subprocess per session; those need a different correlation key, which is a transport-layer concern (route by authenticated principal, or a cookie / gateway-issued header) rather than something this SEP defines.

**Servers binding auth artifacts to session ID.** A small number of servers store OAuth PKCE verifiers, session→user pinning maps, or JWT claims keyed on the session ID. In the PKCE case the server is already passing a correlation value through the OAuth `state` parameter (the browser callback is not an MCP request and never carried `Mcp-Session-Id`), so the change is to put a server-generated nonce in `state` instead of the session ID. Session→user pinning was a defense against the session-routing/auth decoupling described in [Security Implications](#security-implications) and is not needed once every request is independently authenticated. The migration is mostly mechanical, though worth a review since auth code is involved.

**Clients.** Clients become simpler: they no longer track or resend session identifiers, or need to determine whether a given server is stateful. List-endpoint caching becomes safe.

Rollout is a clean break: sessions are removed in the next spec version, with no deprecation window. Servers that currently rely on session-scoped state stay on the current protocol version until they have migrated to explicit handles. Protocol version negotiation already handles mixed-version deployments — a client that supports both versions speaks the old protocol to an unmigrated server and the new one to everyone else. This avoids shipping a version where clients support both modes simultaneously, which would prevent the caching benefit (a client cannot cache list endpoints if any connected server might be session-scoped).

## Security Implications

### Handle exposure

The main security consideration introduced by this SEP is that handles will end up in places session IDs did not — chat logs, subagent prompts, copy-paste buffers, potentially other users' screens.

This is a change in exposure surface, not a new class of vulnerability. Session IDs are already capability-bearing in practice: the Python SDK's stateful session manager, for example, routes by `Mcp-Session-Id` alone without verifying that the authenticated identity on the request matches the one that created the session, so a leaked session ID allows hijack by any other authenticated principal.[^py-sdk-hijack] The "validate `(id, auth_context)` on every call" guidance below applies equally to today's session IDs and to explicit handles; this SEP makes the requirement more visible because handles are more visible.

[^py-sdk-hijack]: [modelcontextprotocol/python-sdk#2100](https://github.com/modelcontextprotocol/python-sdk/issues/2100).

For authenticated servers, the recommended posture is the same one Google Doc IDs and GitHub PR numbers take: the ID identifies the resource, and the auth context on the request determines access. Servers that validate `(handle, auth_context)` on every call are unaffected by handle exposure.

For unauthenticated servers there is no auth context to check, so the handle is a capability token. These should be generated with at least 128 bits of cryptographically secure entropy, never derived from predictable inputs, and given a bounded lifetime — the same practice as "anyone with the link" share URLs or password-reset tokens. Exposure of such a handle grants access for its lifetime; servers should size that lifetime accordingly.

This is guidance, not a protocol requirement, since the protocol has no handle concept to enforce against.

## Reference Implementation

All official SDKs except PHP already provide a stateless mode, implemented as not generating a session ID (e.g. `sessionIdGenerator: undefined` in the TypeScript SDK, `stateless_http=True` in the Python SDK). This SEP makes that mode the only option for servers speaking the new protocol version. SDKs that support multiple protocol versions retain the session-ID-generating code path for older versions; the change is that it is no longer reachable when the negotiated protocol version is the one this SEP introduces.

## Future Work

This SEP deliberately does not introduce a protocol-level concept of a handle: from the wire's perspective `basket_id` is an ordinary string. A consequence is that nothing marks `basket_id` as a state handle to the client or model — the relationship between `create_basket`'s output and `add_item`'s input is inferred from naming and tool descriptions, not declared.

Cut at 300 lines. The page has the rest.

Feedback