diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 715fb6082..a36d9bffc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 cache: npm - run: npm ci diff --git a/.github/workflows/markdown-format.yml b/.github/workflows/markdown-format.yml index e566e2506..ed26e0b4e 100644 --- a/.github/workflows/markdown-format.yml +++ b/.github/workflows/markdown-format.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '24' - name: Install dependencies run: npm ci diff --git a/.github/workflows/render-seps.yml b/.github/workflows/render-seps.yml new file mode 100644 index 000000000..fa0bb6278 --- /dev/null +++ b/.github/workflows/render-seps.yml @@ -0,0 +1,61 @@ +name: Render SEPs + +on: + push: + branches: + - main + paths: + - "seps/**/*.md" + - "scripts/render-seps.ts" + + pull_request: + paths: + - "seps/**/*.md" + - "scripts/render-seps.ts" + + # Allow manual trigger + workflow_dispatch: + +permissions: + contents: write + +jobs: + render-seps: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: npm + + - run: npm ci + + - name: Render SEPs + run: npm run generate:seps + + - name: Check for changes + id: changes + run: | + if [[ -n "$(git status --porcelain docs/community/seps/ docs/snippets/badge.mdx docs/docs.json)" ]]; then + echo "has_changes=true" >> $GITHUB_OUTPUT + else + echo "has_changes=false" >> $GITHUB_OUTPUT + fi + + # On push to main, commit any changes + - name: Commit changes + if: github.event_name == 'push' && github.ref == 'refs/heads/main' && steps.changes.outputs.has_changes == 'true' + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add docs/community/seps/ docs/snippets/badge.mdx docs/docs.json + git commit -m "docs: auto-render SEPs documentation" + git push + + # On PR, verify docs are up to date + - name: Verify SEPs are up to date + if: github.event_name == 'pull_request' + run: npm run check:seps diff --git a/.nvmrc b/.nvmrc index e8aa64417..dc864a052 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.18.1 +v24.2.0 diff --git a/docs/community/seps/1046-support-oauth-client-credentials-flow-in-authoriza.mdx b/docs/community/seps/1046-support-oauth-client-credentials-flow-in-authoriza.mdx new file mode 100644 index 000000000..3158b1ecb --- /dev/null +++ b/docs/community/seps/1046-support-oauth-client-credentials-flow-in-authoriza.mdx @@ -0,0 +1,58 @@ +--- +title: "SEP-1046: Support OAuth client credentials flow in authorization" +sidebarTitle: "SEP-1046: Support OAuth client credentials flow i…" +description: "Support OAuth client credentials flow in authorization" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Standards Track +
+ +| Field | Value | +| ------------- | ------------------------------------------------------------------------ | +| **SEP** | 1046 | +| **Title** | Support OAuth client credentials flow in authorization | +| **Status** | Final | +| **Type** | Standards Track | +| **Created** | 2025-07-23 | +| **Author(s)** | Darin McAdams ([@D-McAdams](https://github.com/D-McAdams) ) | +| **Sponsor** | None | +| **PR** | [#1046](https://github.com/modelcontextprotocol/specification/pull/1046) | + +--- + +## Abstract + +Recommends adding the OAuth client credentials flow to the authorization spec to enable machine-to-machine scenarios. + +### Motivation + +The original authorization spec mentioned the client credentials flow, but it was dropped in subsequent revisions. Therefore, the spec is currently silent on how to solve machine-to-machine scenarios where an end-user is unavailable for interactive authorization. + +### Specification + +The authorization spec would be amended to list the OAuth client credentials flow as being allowed. Adhering to the patterns established by OAuth 2.1, the specification would RECOMMEND the use of asymmetric methods defined in RFC 753 (JWT Assertions), but also allow client secrets. + +As guidance to implementors, the spec overview would also be updated to describe the different flows and when each is applicable. In addition, to address a common question, the spec would be updated to indicate that implementors may implement other authorization scenarios beyond what's defined; emphasizing that the specification defines the baseline requirements. + +### Rationale + +To maximize interoperability (and minimize SDK complexity), this change would intentionally constrain the client credentials flow to two options: + +1. JWT Assertions as per RFC 7523 (RECOMMENDED) +2. Client Secrets via HTTP Basic authentication (Allowed for maximum compatibility with existing systems) + +Other options, such as mTLS, are not included. + +While the spec encourages the use of RFC 7523 (JWT Assertions), it does not yet specify how to populate the JWT contents nor how to discover the client's JWKS URI to validate the JWT. In future iterations of the spec, it will be beneficial to do so. However, this was currently left unspecified pending maturity of other RFCs that can define these profiles. The other RFCs include [WIMSE Headless JWT Authentication](https://www.ietf.org/archive/id/draft-levy-wimse-headless-jwt-authentication-01.html) (for specifying JWT contents) and [Client ID Metadata](https://datatracker.ietf.org/doc/draft-parecki-oauth-client-id-metadata-document/) (for specifying the JWKS URI). This revision intentionally leaves extensibility for these future profiles. As a practical matter, this means implementers needing to ship solutions ASAP will most likely use client secrets which are widely supported today, whereas the JWT Assertion pattern represents the longer-term direction. + +### Backward Compatibility + +This change is fully backward compatible. It introduces a new authorization flow, but does not alter the existing flows. + +### Security Implications + +The specification refers to the existing OAuth security guidance. diff --git a/docs/community/seps/1302-formalize-working-groups-and-interest-groups-in-mc.mdx b/docs/community/seps/1302-formalize-working-groups-and-interest-groups-in-mc.mdx new file mode 100644 index 000000000..bc9eca384 --- /dev/null +++ b/docs/community/seps/1302-formalize-working-groups-and-interest-groups-in-mc.mdx @@ -0,0 +1,242 @@ +--- +title: "SEP-1302: Formalize Working Groups and Interest Groups in MCP Governance" +sidebarTitle: "SEP-1302: Formalize Working Groups and Interest G…" +description: "Formalize Working Groups and Interest Groups in MCP Governance" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Standards Track +
+ +| 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/specification/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 + +## 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) diff --git a/docs/community/seps/1319-decouple-request-payload-from-rpc-methods-definiti.mdx b/docs/community/seps/1319-decouple-request-payload-from-rpc-methods-definiti.mdx new file mode 100644 index 000000000..4ac06e14e --- /dev/null +++ b/docs/community/seps/1319-decouple-request-payload-from-rpc-methods-definiti.mdx @@ -0,0 +1,101 @@ +--- +title: "SEP-1319: Decouple Request Payload from RPC Methods Definition" +sidebarTitle: "SEP-1319: Decouple Request Payload from RPC Metho…" +description: "Decouple Request Payload from RPC Methods Definition" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Standards Track +
+ +| 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/specification/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 +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 +/** + * 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 +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. diff --git a/docs/community/seps/1330-elicitation-enum-schema-improvements-and-standards.mdx b/docs/community/seps/1330-elicitation-enum-schema-improvements-and-standards.mdx new file mode 100644 index 000000000..ccad434cc --- /dev/null +++ b/docs/community/seps/1330-elicitation-enum-schema-improvements-and-standards.mdx @@ -0,0 +1,440 @@ +--- +title: "SEP-1330: Elicitation Enum Schema Improvements and Standards Compliance" +sidebarTitle: "SEP-1330: Elicitation Enum Schema Improvements an…" +description: "Elicitation Enum Schema Improvements and Standards Compliance" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Standards Track +
+ +| 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/specification/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 +Typescript SDK Changes: https://github.com/modelcontextprotocol/typescript-sdk/pull/1077 +Python SDK Changes: https://github.com/modelcontextprotocol/python-sdk/pull/1246 +**Client Implementation:** https://github.com/evalstate/fast-agent/pull/324/files +**Working Demo:** 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 +// 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 +// 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 +// 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 +// 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 +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 +{ + "type": "string", + "title": "Color Selection", + "description": "Choose your favorite color", + "enum": ["Red", "Green", "Blue"], + "default": "Green" +} +``` + +### Legacy Single Select With Titles + +```json +{ + "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 +{ + "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 +{ + "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 +{ + "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 + +## 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 +Typescript SDK Changes: https://github.com/modelcontextprotocol/typescript-sdk/pull/1077 +Python SDK Changes: https://github.com/modelcontextprotocol/python-sdk/pull/1246 +**Client Implementation:** https://github.com/evalstate/fast-agent/pull/324/files +**Working Demo:** 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/ 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) + +#### Multiple Selection + +- `EnumSchema` validating the [multi-select instance schema without titles](https://www.jsonschemavalidator.net/s/4uc3Ndsq) +- `EnumSchema` validating the [multi-select instance schema with titles](https://www.jsonschemavalidator.net/s/TmkIqqXI) +- The untitled multi-select instance schema validating [a correct multiple selection](https://www.jsonschemavalidator.net/s/IE8Bkvtg) + The untitled multi-select instance schema validating invalidating[ an incorrect multiple selection](https://www.jsonschemavalidator.net/s/8tlqjUgW) + The titled multi-select instance schema validating [a correct multiple selection](https://www.jsonschemavalidator.net/s/Nb1Rw1qa) + The titled multi-select instance schema validating invalidating [an incorrect multiple selection](https://www.jsonschemavalidator.net/s/MRfyqrVC) + +### JSON meta-schema + +This is our proposal for the replacement of the current `EnumSchema` in the specification’s `schema.json`. + +```json +{ + "$schema": "https://json-schema.org/draft-07/schema", + "definitions": { + // New Definitions Follow + "UntitledSingleSelectEnumSchema": { + "type": "object", + "properties": { + "type": { "const": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "enum": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + } + }, + "required": ["type", "enum"], + "additionalProperties": false + }, + + "UntitledMultiSelectEnumSchema": { + "type": "object", + "properties": { + "type": { "const": "array" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "minItems": { + "type": "number", + "minimum": 0 + }, + "maxItems": { + "type": "number", + "minimum": 0 + }, + "items": { + "type": "object", + "properties": { + "type": { "const": "string" }, + "enum": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + } + }, + "required": ["type", "enum"], + "additionalProperties": false + } + }, + "required": ["type", "items"], + "additionalProperties": false + }, + + "TitledSingleSelectEnumSchema": { + "type": "object", + "required": ["type", "anyOf"], + "properties": { + "type": { "const": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "anyOf": { + "type": "array", + "items": { + "type": "object", + "required": ["const", "title"], + "properties": { + "const": { "type": "string" }, + "title": { "type": "string" } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + + "TitledMultiSelectEnumSchema": { + "type": "object", + "required": ["type", "anyOf"], + "properties": { + "type": { "const": "array" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "anyOf": { + "type": "array", + "items": { + "type": "object", + "required": ["const", "title"], + "properties": { + "const": { "type": "string" }, + "title": { "type": "string" } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + + "LegacyEnumSchema": { + "properties": { + "type": { + "type": "string", + "const": "string" + }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "enum": { + "type": "array", + "items": { "type": "string" } + }, + "enumNames": { + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["enum", "type"], + "type": "object" + }, + + "EnumSchema": { + "oneOf": [ + { "$ref": "#/definitions/UntitledSingleSelectEnumSchema" }, + { "$ref": "#/definitions/UntitledMultiSelectEnumSchema" }, + { "$ref": "#/definitions/TitledSingleSelectEnumSchema" }, + { "$ref": "#/definitions/TitledMultiSelectEnumSchema" }, + { "$ref": "#/definitions/LegacyEnumSchema" } + ] + } + } +} +``` diff --git a/docs/community/seps/1850-pr-based-sep-workflow.mdx b/docs/community/seps/1850-pr-based-sep-workflow.mdx new file mode 100644 index 000000000..415660b1e --- /dev/null +++ b/docs/community/seps/1850-pr-based-sep-workflow.mdx @@ -0,0 +1,201 @@ +--- +title: "SEP-1850: PR-Based SEP Workflow" +sidebarTitle: "SEP-1850: PR-Based SEP Workflow" +description: "PR-Based SEP Workflow" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Process +
+ +| 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/specification/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 +# 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 (@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. diff --git a/docs/community/seps/932-model-context-protocol-governance.mdx b/docs/community/seps/932-model-context-protocol-governance.mdx new file mode 100644 index 000000000..c2ab5d7fa --- /dev/null +++ b/docs/community/seps/932-model-context-protocol-governance.mdx @@ -0,0 +1,117 @@ +--- +title: "SEP-932: Model Context Protocol Governance" +sidebarTitle: "SEP-932: Model Context Protocol Governance" +description: "Model Context Protocol Governance" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Process +
+ +| Field | Value | +| ------------- | --------------------------------- | +| **SEP** | 932 | +| **Title** | Model Context Protocol Governance | +| **Status** | Final | +| **Type** | Process | +| **Created** | 2025-07-08 | +| **Author(s)** | David Soria Parra | +| **Sponsor** | None | +| **PR** | [#932](#931) | + +--- + +## Abstract + +This SEP establishes the formal governance model for the Model Context Protocol (MCP) project. It defines the organizational structure, decision-making processes, and contribution guidelines necessary for transparent and effective project stewardship. The proposal introduces a hierarchical governance structure with clear roles and responsibilities, along with the Specification Enhancement Proposal (SEP) process for managing protocol changes. + +## Motivation + +As the Model Context Protocol grows in adoption and complexity, the need for formal governance becomes critical. The current informal decision-making process lacks: + +1. **Transparency**: Community members have no clear visibility into how decisions are made +2. **Participation Pathways**: Contributors lack defined ways to influence project direction +3. **Accountability**: No formal structure exists for resolving disputes or contentious issues +4. **Scalability**: Ad-hoc processes cannot scale with growing community and technical complexity + +Without formal governance, the project risks: + +- Fragmentation of the ecosystem +- Unclear or inconsistent technical decisions +- Reduced community trust and participation +- Inability to effectively manage contributions at scale + +## Rationale + +The proposed governance model draws inspiration from successful open source projects like Python, PyTorch, and Rust. Key design decisions include: + +### Hierarchical Structure + +We chose a hierarchical model (Contributors → Maintainers → Core Maintainers → Lead Maintainers) that is effectively how the project decisions are made today. From there we will continue to evolve governance in the best interest of the project. + +### Individual vs Corporate Membership + +Membership is explicitly tied to individuals rather than companies to: + +- Ensure decisions prioritize protocol integrity over corporate interests +- Prevent capture by any single organization +- Maintain continuity when individuals change employers + +### SEP Process + +The Specification Enhancement Proposal process ensures: + +- All protocol changes undergo thorough review +- Community input is systematically collected +- Design decisions are documented for posterity +- Implementation precedes finalization + +## Specification + +### Governance Structure + +#### Contributors + +- Any individual who files issues, submits pull requests, or participates in discussions +- No formal membership or approval required + +#### Maintainers + +- Responsible for specific components (SDKs, documentation, etc.) +- Appointed by Core Maintainers +- Have write/admin access to their repositories +- May establish component-specific processes + +#### Core Maintainers + +- Deep understanding of MCP specification required +- Responsible for protocol evolution and project direction +- Meet bi-weekly for decisions +- Can veto maintainer decisions by majority vote +- Current members listed in governance documentation + +#### Lead Maintainers + +- Justin Spahr-Summers and David Soria Parra +- Can veto any decision +- Appoint/remove Core Maintainers +- Admin access to all infrastructure + +## Backwards Compatibility + +N/A + +## Reference Implementation + +See #931 + +1. **Documentation Files**: + - `/docs/community/governance.mdx` - Full governance documentation + - `/docs/community/sep-guidelines.mdx` - SEP process guidelines + +## Security Implications + +N/A diff --git a/docs/community/seps/973-expose-additional-metadata-for-implementations-res.mdx b/docs/community/seps/973-expose-additional-metadata-for-implementations-res.mdx new file mode 100644 index 000000000..638f7186c --- /dev/null +++ b/docs/community/seps/973-expose-additional-metadata-for-implementations-res.mdx @@ -0,0 +1,150 @@ +--- +title: "SEP-973: Expose additional metadata for Implementations, Resources, Tools and Prompts" +sidebarTitle: "SEP-973: Expose additional metadata for Implemen…" +description: "Expose additional metadata for Implementations, Resources, Tools and Prompts" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Standards Track +
+ +| Field | Value | +| ------------- | ---------------------------------------------------------------------------- | +| **SEP** | 973 | +| **Title** | Expose additional metadata for Implementations, Resources, Tools and Prompts | +| **Status** | Final | +| **Type** | Standards Track | +| **Created** | 2025-07-15 | +| **Author(s)** | [@jesselumarie](https://github.com/jesselumarie) | +| **Sponsor** | None | +| **PR** | [#973](https://github.com/modelcontextprotocol/specification/pull/973) | + +--- + +## Abstract + +This SEP proposes adding two optional fields—`icons` and `websiteUrl`. The `icons` and `websiteUrl` would be added to the `Implementation` schema so that clients can visually identify third-party implementations and link directly to their documentation. The `icons` parameter will also be added to the `Tool`, `Resource` and `Prompt` schemas. While this can be used by both servers and clients for all implementations, we expect it to be used initially for server-provided implementations. + +## Motivation + +### Current State + +Current implementations only expose namespaced metadata, forcing clients to display generic labels with no visual cues. + +Image + +### Proposed State + +The proposed implementation would allow us to add visual affordances and links to documentation, making it easier to visually identify which servers/clients are providing an implementation e.g. a tool in a slash command interface: + +Image + +- **Visual Affordance:** Icons make it immediately clear to users which tool or resource source is in use. +- **Discoverability:** A link to documentation (`websiteUrl`) allows clients to direct users to more information with a single click. + +## Rationale + +This design builds on prior work in web manifests (MDN) and consolidates community feedback: + +- **Consolidation of PRs:** Merges the changes from PR #417 and PR #862 into a single, cohesive enhancement. +- **Flexible Icon Sizes:** Supports multiple icon sizes (e.g., `48x48`, `96x96`, or `any` for vector formats) to accommodate different client UI needs. +- **Optional Fields:** By making both fields optional, existing implementations remain fully compatible. + +## Specification + +Extend the `Implementation` object as follows: + +```typescript +/** + * A url pointing to an icon URL or a base64-encoded data URI + * + * Clients that support rendering icons MUST support at least the following MIME types: + * - image/png - PNG images (safe, universal compatibility) + * - image/jpeg (and image/jpg) - JPEG images (safe, universal compatibility) + * + * Clients that support rendering icons SHOULD also support: + * - image/svg+xml - SVG images (scalable but requires security precautions) + * - image/webp - WebP images (modern, efficient format) + */ +export interface Icon { + /** + * A standard URI pointing to an icon resource. + * + * Consumers MUST takes steps to ensure URLs serving icons are from the + * same domain as the client/server or a trusted domain. + * + * Consumers MUST take appropriate precautions when consuming SVGs as they can contain + * executable JavaScript + * + * @format uri + */ + src: string; + /** Optional override if the server’s MIME type is missing or generic. */ + mimeType?: string; + /** e.g. "48x48", "any" (for SVG), or "48x48 96x96" */ + sizes?: string; +} + +/** + * Describes the MCP implementation + */ +export interface Implementation extends BaseMetadata { + version: string; + /** + * An optional list of icons for this implementation. + * This can be used by clients to display the implementation in a user interface. + * Each icon should have a `kind` property that specifies whether it is a data representation or a URL source, a `src` property that points to the icon file or data representation, and may also include a `mimeType` and `sizes` property. + * The `mimeType` property should be a valid MIME type for the icon file, such as "image/png" or "image/svg+xml". + * The `sizes` property should be a string that specifies one or more sizes at which the icon file can be used, such as "48x48" or "any" for scalable formats like SVG. + * The `sizes` property is optional, and if not provided, the client should assume that the icon can be used at any size. + */ + icons?: Icon[]; + /** + * An optional URL of the website for this implementation. + * + * Consumers MUST takes steps to ensure URLs serving icons are from the + * same domain as the client/server or a trusted domain. + * + * Consumers MUST take appropriate precautions when consuming SVGs as they can contain + * executable JavaScript + * + * @format: uri + */ + websiteUrl?: string; +} +``` + +Extend the `Tool`, `Resource` and `Prompt` interfaces with the following type: + +```typescript + /** + * An optional list of icons for a resource. + * This can be used by clients to display the resource's icon in a user interface. + * Each icon should have a `kind` property that specifies whether it is a data representation or a URL source, a `src` property that points to the icon file or data representation, and may also include a `mimeType` and `sizes` property. + * The `mimeType` property should be a valid MIME type for the icon file, such as "image/png" or "image/svg+xml". + * The `sizes` property should be a string that specifies one or more sizes at which the icon file can be used, such as "48x48" or "any" for scalable formats like SVG. + * The `sizes` property is optional, and if not provided, the client should assume that the icon can be used at any size. + */ + icons?: Icon[]; +``` + +## Backwards Compatibility + +Both icons and websiteUrl are optional fields; clients that ignore them will fall back to existing behavior. + +## Security Implications + +This shouldn't introduce any new security implications. diff --git a/docs/community/seps/985-align-oauth-20-protected-resource-metadata-with-rf.mdx b/docs/community/seps/985-align-oauth-20-protected-resource-metadata-with-rf.mdx new file mode 100644 index 000000000..8cb859238 --- /dev/null +++ b/docs/community/seps/985-align-oauth-20-protected-resource-metadata-with-rf.mdx @@ -0,0 +1,114 @@ +--- +title: "SEP-985: Align OAuth 2.0 Protected Resource Metadata with RFC 9728" +sidebarTitle: "SEP-985: Align OAuth 2.0 Protected Resource Meta…" +description: "Align OAuth 2.0 Protected Resource Metadata with RFC 9728" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Standards Track +
+ +| Field | Value | +| ------------- | ---------------------------------------------------------------------- | +| **SEP** | 985 | +| **Title** | Align OAuth 2.0 Protected Resource Metadata with RFC 9728 | +| **Status** | Final | +| **Type** | Standards Track | +| **Created** | 2025-07-16 | +| **Author(s)** | sunishsheth2009 | +| **Sponsor** | None | +| **PR** | [#985](https://github.com/modelcontextprotocol/specification/pull/985) | + +--- + +## Abstract + +This proposal brings the MCP spec's handling of OAuth 2.0 Protected Resource Metadata in line with [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728#name-obtaining-protected-resourc). + +Currently, the MCP spec requires the use of the HTTP WWW-Authenticate header when returning a 401 Unauthorized to indicate the location of the protected resource metadata. However, [RFC 9728, Section 5](https://datatracker.ietf.org/doc/html/rfc9728#section-5) states: + +“A protected resource MAY use the WWW-Authenticate HTTP response header field, as discussed in RFC 9110, to return a URL to its protected resource metadata to the client.” + +This suggests that the MCP spec could be made more flexible while still maintaining RFC compliance. + +## Rationale + +Many large-scale, dynamic, multi-tenant environments rely on a centralized authentication service separate from the backend resource servers. In such deployments, injecting WWW-Authenticate headers from backend services is non-trivial due to separation of concerns and infrastructure complexity. + +In these scenarios, having the option to discover metadata via a well-known URL provides a practical path forward for easier MCP adoption. Requiring only the header would impose significant communication overhead between components, especially when hundreds or thousands of MCP instances are created and destroyed dynamically. Also if there are specific managed MCP servers, adopting headers across centralized system would add significant overhead. + +While this increases complexity for clients—who must now implement logic to probe metadata endpoints—it reduces friction for server deployments and may encourage broader adoption. There are tradeoffs: + +Pros for Server Developers: Avoid complex header injection; simplifies integration in distributed environments. + +Cons for Client Developers: Clients must fall back to metadata discovery logic when the header is absent, increasing client complexity. + +## Proposed State + +Update the MCP spec to: + +``` +Clients MUST interpret the WWW-Authenticate header, and fallback to probing for metadata if not present. +Servers SHOULD return the WWW-Authenticate header +``` + +**The reason for deviating a bit on the RFC:** +Go with SHOULD over MAY for WWW-Authenticate is that it makes supporting other features, such as incremental authorization easier (e.g. you make a request for a tool, but need additional scopes, and receive a WWW-Authenticate challenge indicating the scopes). + +Based on the above, following the updated flow: + +- Attempt the MCP request without a token. +- If a 401 Unauthorized response is received: Check for a WWW-Authenticate header. If present and includes the resource_metadata parameter, use it to locate the resource metadata. +- If the header is absent or does not include resource_metadata, fallback to requesting /.well-known/oauth-protected-resource. + +This change allows more flexible deployment models without removing existing capabilities. + +```mermaid +sequenceDiagram + participant C as Client + participant M as MCP Server (Resource Server) + participant A as Authorization Server + + Note over C: Attempt unauthenticated MCP request + C->>M: MCP request without token + M-->>C: HTTP 401 Unauthorized (may include WWW-Authenticate header) + + alt Header includes resource_metadata + Note over C: Extract resource_metadata URL from header + C->>M: GET resource_metadata URI + M-->>C: Resource metadata with authorization server URL + else No resource_metadata in header + Note over C: Fallback to metadata probing + C->>M: GET /.well-known/oauth-protected-resource + alt Metadata found + M-->>C: Resource metadata with authorization server URL + else Metadata not found + Note over C: Abort or use pre-configured values + end + end + + Note over C: Validate RS metadata,
build AS metadata URL + + C->>A: GET /.well-known/oauth-authorization-server + A-->>C: Authorization server metadata + + Note over C,A: OAuth 2.1 authorization flow happens here + + C->>A: Token request + A-->>C: Access token + + C->>M: MCP request with access token + M-->>C: MCP response + Note over C,M: MCP communication continues with valid token +``` + +## Backward Compatibility + +This proposal is fully backward-compatible. + +It retains support for the WWW-Authenticate header (already in the spec) and introduces a fallback mechanism using the .well-known metadata path, which is already defined in MCP as a MUST-support location. + +Clients that already support metadata probing benefit from improved interoperability. Servers are not required to emit the WWW-Authenticate header if it is infeasible, but doing so is still encouraged to reduce client complexity and enable future extensibility. diff --git a/docs/community/seps/986-specify-format-for-tool-names.mdx b/docs/community/seps/986-specify-format-for-tool-names.mdx new file mode 100644 index 000000000..b404855a6 --- /dev/null +++ b/docs/community/seps/986-specify-format-for-tool-names.mdx @@ -0,0 +1,72 @@ +--- +title: "SEP-986: Specify Format for Tool Names" +sidebarTitle: "SEP-986: Specify Format for Tool Names" +description: "Specify Format for Tool Names" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Standards Track +
+ +| Field | Value | +| ------------- | ---------------------------------------------------------------------- | +| **SEP** | 986 | +| **Title** | Specify Format for Tool Names | +| **Status** | Final | +| **Type** | Standards Track | +| **Created** | 2025-07-16 | +| **Author(s)** | kentcdodds | +| **Sponsor** | None | +| **PR** | [#986](https://github.com/modelcontextprotocol/specification/pull/986) | + +--- + +## Abstract + +The Model Context Protocol (MCP) currently lacks a standardized format for tool names, resulting in inconsistencies and confusion for both implementers and users. This SEP proposes a clear, flexible standard for tool names: tool names should be 1–64 characters, case-sensitive, and may include alphanumeric characters, underscores (\_), dashes (-), dots (.), and forward slashes (/). This aims to maximize compatibility, clarity, and interoperability across MCP implementations while accommodating a wide range of naming conventions. + +## Motivation + +Without a prescribed format for tool names, MCP implementations have adopted a variety of naming conventions, including different separators, casing, and character sets. This inconsistency can lead to confusion, errors in tool invocation, and difficulties in documentation and automation. Standardizing the allowed characters and length will: + +- Make tool names predictable and interoperable across clients. +- Allow for hierarchical and namespaced tool names (e.g., using / and .). +- Support both human-readable and machine-generated names. +- Avoid unnecessary restrictions that could block valid use cases. + +## Rationale + +Community discussion highlighted the need for flexibility in tool naming. While some conventions (like lower-kebab-case) are common, many tools and clients use uppercase, underscores, dots, and slashes for namespacing or clarity. The proposed pattern—allowing a-z, A-Z, 0-9, \_, -, ., and /—is based on patterns used in major clients (e.g., VS Code, Claude) and aligns with common conventions in programming and APIs. Restricting spaces and commas avoids parsing issues and ambiguity. The length limit (1–64) is generous enough for most use cases but prevents abuse. + +## Specification + +- Tool names SHOULD be between 1 and 64 characters in length (inclusive). +- Tool names are case-sensitive. +- Allowed characters: uppercase and lowercase ASCII letters (A-Z, a-z), digits + (0-9), underscore (\_), dash (-), dot (.), and forward slash (/). +- Tool names SHOULD NOT contain spaces, commas, or other special characters. +- Tool names SHOULD be unique within their namespace. +- Example valid tool names: + - getUser + - user-profile/update + - DATA_EXPORT_v2 + - admin.tools.list + +## Backwards Compatibility + +This change is not backwards compatible for existing tools that use disallowed characters or exceed the new length limits. To minimize disruption: + +- Existing non-conforming tool names SHOULD be supported as aliases for at least one major version, with a deprecation warning. +- Tool authors SHOULD update their documentation and code to use the new format. +- A migration guide SHOULD be provided to assist implementers in updating their tool names. + +## Reference Implementation + +A reference implementation can be provided by updating the MCP core library to enforce the new tool name validation rules at registration time. Existing tools can be updated to provide aliases for their new conforming names, with warnings for deprecated formats. Example code and migration scripts can be included in the MCP repository. + +## Security Implications + +None. Standardizing tool name format does not introduce new security risks. diff --git a/docs/community/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o.mdx b/docs/community/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o.mdx new file mode 100644 index 000000000..b088acc23 --- /dev/null +++ b/docs/community/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o.mdx @@ -0,0 +1,86 @@ +--- +title: "SEP-990: Enable enterprise IdP policy controls during MCP OAuth flows" +sidebarTitle: "SEP-990: Enable enterprise IdP policy controls d…" +description: "Enable enterprise IdP policy controls during MCP OAuth flows" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Standards Track +
+ +| Field | Value | +| ------------- | ------------------------------------------------------------ | +| **SEP** | 990 | +| **Title** | Enable enterprise IdP policy controls during MCP OAuth flows | +| **Status** | Final | +| **Type** | Standards Track | +| **Created** | 2025-06-04 | +| **Author(s)** | Aaron Parecki ([@aaronpk](https://github.com/aaronpk)) | +| **Sponsor** | None | +| **PR** | [#990](#646) | + +--- + +## Abstract + +This extension is designed to facilitate secure and interoperable authorization of MCP clients within corporate environments, leveraging existing enterprise identity infrastructure. + +- For end users, this removes the need to manually connect and authorize the MCP Client to individual services within the organization. +- For enterprise admins, this enables visibility and control over which MCP Servers are able to be used within the organization. + +## How Has This Been Tested? + +We have an end to end implementation of this [here](https://github.com/oktadev/okta-cross-app-access-mcp), and in-progress MCP implementations with some partners. + +## Breaking Changes + +This is designed to augment the existing OAuth profile by providing an alternative when used under an enterprise IdP. MCP clients can opt in to this profile when necessary. + +## Additional Context + +For more background on this problem, you can refer to my blog post about this here: + +[Enterprise-Ready MCP](https://aaronparecki.com/2025/05/12/27/enterprise-ready-mcp) + +I also presented this at the MCP Dev Summit in May. + +A high level overview of the flow is below: + +```mermaid +sequenceDiagram + participant UA as Browser + participant C as MCP Client + participant MAS as MCP Authorization Server + participant MRS as MCP Resource Server + participant IdP as Identity Provider + + rect rgb(255,255,225) + C-->>UA: Redirect to IdP + UA->>+IdP: Redirect to IdP + Note over IdP: User Logs In + IdP-->>-UA: IdP Authorization Code + UA->>C: IdP Authorization Code + C->>+IdP: Token Request with IdP Authorization Code + IdP-->-C: ID Token + end + + note over C: User is logged
in to MCP Client.
Client stores ID Token. + + C->+IdP: Exchange ID Token for ID-JAG + note over IdP: Evaluate Policy + IdP-->-C: Responds with ID-JAG + C->+MAS: Token Request with ID-JAG + note over MAS: Validate ID-JAG + MAS-->-C: MCP Access Token + + loop + C->>+MRS: Call MCP API with Access Token + MRS-->>-C: MCP Response with Data + end +``` + +> [!IMPORTANT] +> **State:** Ready to Review diff --git a/docs/community/seps/994-shared-communication-practicesguidelines.mdx b/docs/community/seps/994-shared-communication-practicesguidelines.mdx new file mode 100644 index 000000000..ef14e27fe --- /dev/null +++ b/docs/community/seps/994-shared-communication-practicesguidelines.mdx @@ -0,0 +1,124 @@ +--- +title: "SEP-994: Shared Communication Practices/Guidelines" +sidebarTitle: "SEP-994: Shared Communication Practices/Guidelin…" +description: "Shared Communication Practices/Guidelines" +--- + +import { Badge } from "/snippets/badge.mdx"; + +
+ Final + Process +
+ +| Field | Value | +| ------------- | ----------------------------------------- | +| **SEP** | 994 | +| **Title** | Shared Communication Practices/Guidelines | +| **Status** | Final | +| **Type** | Process | +| **Created** | 2025-07-17 | +| **Author(s)** | [@localden](https://github.com/localden) | +| **Sponsor** | None | +| **PR** | [#994](#1002) | + +--- + +## Abstract + +This SEP establishes the communication strategy and framework for the Model Context Protocol community. It defines the official channels for contributor communication, guidelines for their use, and processes for decision documentation. + +## Motivation + +As the MCP community grows, clear communication guidelines are essential for: + +- **Consistency**: Ensuring all contributors know where and how to communicate +- **Transparency**: Making project decisions visible and accessible +- **Efficiency**: Directing discussions to the most appropriate channels +- **Security**: Establishing proper processes for handling sensitive issues + +## Specification + +### Communication Channels + +The MCP project uses three primary communication channels: + +1. **Discord**: For real-time or ad-hoc discussions among contributors +2. **GitHub Discussions**: For structured, longer-form discussions +3. **GitHub Issues**: For actionable tasks, bug reports, and feature requests + +Security-sensitive issues follow a separate process defined in SECURITY.md. + +### Discord Guidelines + +The Discord server is designed for **MCP contributors** and is not intended for general MCP support. + +#### Public Channels (Default) + +- Open community engagement and collaborative development +- SDK and tooling development discussions +- Working and Interest Group discussions +- Community onboarding and contribution guidance +- Office hours and maintainer availability + +#### Private Channels (Exceptions) + +Private channels are reserved for: + +- Security incidents (CVEs, protocol vulnerabilities) +- People matters (maintainer discussions, code of conduct) +- Coordination requiring immediate focused response + +All technical and governance decisions must be documented publicly in GitHub. + +### GitHub Discussions + +Used for structured, long-form discussion: + +- Project roadmap planning +- Announcements and release communications +- Community polls and consensus-building +- Feature requests with context and rationale + +### GitHub Issues + +Used for actionable items: + +- Bug reports with reproducible steps +- Documentation improvements +- CI/CD and infrastructure issues +- Release tasks and milestone tracking + +### Decision Records + +All MCP decisions are documented publicly: + +- **Technical decisions**: GitHub Issues and SEPs +- **Specification changes**: Changelog on the MCP website +- **Process changes**: Community documentation +- **Governance decisions**: GitHub Issues and SEPs + +Decision documentation includes: + +- Decision makers +- Background context and motivation +- Options considered +- Rationale for chosen approach +- Implementation steps + +## Rationale + +This framework balances openness with practicality: + +- **Public by default**: Maximizes transparency and community participation +- **Private when necessary**: Protects security and personal matters +- **Channel separation**: Keeps discussions organized and searchable +- **Documentation requirements**: Ensures decisions are preserved and discoverable + +## Backward Compatibility + +This SEP establishes new processes and does not affect existing protocol functionality. + +## Reference Implementation + +The communication guidelines are published at: https://modelcontextprotocol.io/community/communication diff --git a/docs/community/seps/index.mdx b/docs/community/seps/index.mdx new file mode 100644 index 000000000..7da24285c --- /dev/null +++ b/docs/community/seps/index.mdx @@ -0,0 +1,49 @@ +--- +title: Specification Enhancement Proposals (SEPs) +sidebarTitle: SEP Index +description: Index of all MCP Specification Enhancement Proposals +--- + +import { Badge } from "/snippets/badge.mdx"; + +Specification Enhancement Proposals (SEPs) are the primary mechanism for proposing major changes to the Model Context Protocol. Each SEP provides a concise technical specification and rationale for proposed features. + + + Learn how to submit your own Specification Enhancement Proposal + + +## Summary + +- **Final**: 11 + +## All SEPs + +| SEP | Title | Status | Type | Created | +| ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------- | --------------- | ---------- | +| [SEP-1850](/community/seps/1850-pr-based-sep-workflow) | PR-Based SEP Workflow | Final | Process | 2025-11-20 | +| [SEP-1330](/community/seps/1330-elicitation-enum-schema-improvements-and-standards) | Elicitation Enum Schema Improvements and Standards Compliance | Final | Standards Track | 2025-08-11 | +| [SEP-1319](/community/seps/1319-decouple-request-payload-from-rpc-methods-definiti) | Decouple Request Payload from RPC Methods Definition | Final | Standards Track | 2025-08-08 | +| [SEP-1302](/community/seps/1302-formalize-working-groups-and-interest-groups-in-mc) | Formalize Working Groups and Interest Groups in MCP Governance | Final | Standards Track | 2025-08-05 | +| [SEP-1046](/community/seps/1046-support-oauth-client-credentials-flow-in-authoriza) | Support OAuth client credentials flow in authorization | Final | Standards Track | 2025-07-23 | +| [SEP-994](/community/seps/994-shared-communication-practicesguidelines) | Shared Communication Practices/Guidelines | Final | Process | 2025-07-17 | +| [SEP-990](/community/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o) | Enable enterprise IdP policy controls during MCP OAuth flows | Final | Standards Track | 2025-06-04 | +| [SEP-986](/community/seps/986-specify-format-for-tool-names) | Specify Format for Tool Names | Final | Standards Track | 2025-07-16 | +| [SEP-985](/community/seps/985-align-oauth-20-protected-resource-metadata-with-rf) | Align OAuth 2.0 Protected Resource Metadata with RFC 9728 | Final | Standards Track | 2025-07-16 | +| [SEP-973](/community/seps/973-expose-additional-metadata-for-implementations-res) | Expose additional metadata for Implementations, Resources, Tools and Prompts | Final | Standards Track | 2025-07-15 | +| [SEP-932](/community/seps/932-model-context-protocol-governance) | Model Context Protocol Governance | Final | Process | 2025-07-08 | + +## SEP Status Definitions + +- Draft - SEP proposal with a sponsor, undergoing + informal review +- In-Review - SEP proposal ready for formal review + by Core Maintainers +- Accepted - SEP accepted, awaiting reference + implementation +- Final - SEP finalized with reference + implementation complete +- Rejected - SEP rejected by Core Maintainers +- Withdrawn - SEP withdrawn by the author +- Superseded - SEP replaced by a newer SEP +- Dormant - SEP without a sponsor, closed after 6 + months diff --git a/docs/docs.json b/docs/docs.json index 130637a51..8a07b756f 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -27,7 +27,9 @@ "pages": [ { "group": "Get started", - "pages": ["docs/getting-started/intro"] + "pages": [ + "docs/getting-started/intro" + ] }, { "group": "About MCP", @@ -56,7 +58,9 @@ }, { "group": "Developer tools", - "pages": ["docs/tools/inspector"] + "pages": [ + "docs/tools/inspector" + ] } ] }, @@ -333,6 +337,28 @@ "community/antitrust" ] }, + { + "group": "SEPs", + "pages": [ + "community/seps/index", + { + "group": "Final", + "pages": [ + "community/seps/932-model-context-protocol-governance", + "community/seps/973-expose-additional-metadata-for-implementations-res", + "community/seps/985-align-oauth-20-protected-resource-metadata-with-rf", + "community/seps/986-specify-format-for-tool-names", + "community/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o", + "community/seps/994-shared-communication-practicesguidelines", + "community/seps/1046-support-oauth-client-credentials-flow-in-authoriza", + "community/seps/1302-formalize-working-groups-and-interest-groups-in-mc", + "community/seps/1319-decouple-request-payload-from-rpc-methods-definiti", + "community/seps/1330-elicitation-enum-schema-improvements-and-standards", + "community/seps/1850-pr-based-sep-workflow" + ] + } + ] + }, { "group": "Roadmap", "pages": [ diff --git a/docs/snippets/badge.mdx b/docs/snippets/badge.mdx new file mode 100644 index 000000000..54203bb61 --- /dev/null +++ b/docs/snippets/badge.mdx @@ -0,0 +1,49 @@ +export const Badge = ({ children, color = "gray" }) => { + const styles = { + green: { + light: { bg: "#dcfce7", text: "#166534" }, + dark: { bg: "#14532d", text: "#86efac" }, + }, + blue: { + light: { bg: "#dbeafe", text: "#1e40af" }, + dark: { bg: "#1e3a5f", text: "#93c5fd" }, + }, + yellow: { + light: { bg: "#fef9c3", text: "#854d0e" }, + dark: { bg: "#713f12", text: "#fde047" }, + }, + red: { + light: { bg: "#fee2e2", text: "#991b1b" }, + dark: { bg: "#7f1d1d", text: "#fca5a5" }, + }, + orange: { + light: { bg: "#ffedd5", text: "#9a3412" }, + dark: { bg: "#7c2d12", text: "#fdba74" }, + }, + purple: { + light: { bg: "#f3e8ff", text: "#6b21a8" }, + dark: { bg: "#581c87", text: "#d8b4fe" }, + }, + gray: { + light: { bg: "#f3f4f6", text: "#1f2937" }, + dark: { bg: "#374151", text: "#d1d5db" }, + }, + }; + const s = styles[color] || styles.gray; + return ( + <> + + + {children} + + + ); +}; diff --git a/migrate_seps.js b/migrate_seps.js new file mode 100644 index 000000000..ea14886d7 --- /dev/null +++ b/migrate_seps.js @@ -0,0 +1,243 @@ +#!/usr/bin/env node + +/** + * Migration script to convert SEP GitHub issues to the new seps/ markdown format. + * + * This script: + * 1. Fetches all SEP issues with accepted, accepted-with-changes, or final status + * 2. Converts them to the new SEP markdown format + * 3. Saves them as files in the seps/ directory with the format SEP-{number}-{title}.md + */ + +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +// Status mappings from issue labels to SEP statuses +const STATUS_MAPPING = { + 'accepted': 'Accepted', + 'accepted-with-changes': 'Accepted', + 'final': 'Final', + 'draft': 'Draft', + 'in-review': 'In-Review' +}; + +// Fetch all SEP issues from GitHub +function fetchSEPIssues() { + console.log('Fetching SEP issues from GitHub...'); + + const result = execSync( + 'gh issue list --label SEP --state all --limit 500 --json number,title,state,labels,body,createdAt,closedAt,author', + { encoding: 'utf-8' } + ); + + return JSON.parse(result); +} + +// Determine SEP status from labels +function getStatusFromLabels(labels) { + const labelNames = labels.map(l => l.name.toLowerCase()); + + // Check for status labels in priority order + if (labelNames.includes('final')) return 'Final'; + if (labelNames.includes('accepted-with-changes')) return 'Accepted'; + if (labelNames.includes('accepted')) return 'Accepted'; + if (labelNames.includes('in-review')) return 'In-Review'; + if (labelNames.includes('draft')) return 'Draft'; + if (labelNames.includes('proposal')) return 'Draft'; + + return null; +} + +// Check if issue should be migrated (has accepted, accepted-with-changes, or final status) +function shouldMigrate(issue) { + const status = getStatusFromLabels(issue.labels); + return status && ['Accepted', 'Final'].includes(status); +} + +// Extract metadata from issue body +function parseIssueBody(body, issue) { + if (!body) return null; + + const metadata = { + title: issue.title.replace(/^\[?SEP-\d+\]?:?\s*/i, ''), + status: getStatusFromLabels(issue.labels), + type: 'Standards Track', + created: issue.createdAt ? issue.createdAt.split('T')[0] : new Date().toISOString().split('T')[0], + author: issue.author ? issue.author.login : 'Unknown', + sponsor: null, + pr: null + }; + + // Try to extract metadata from the body + const lines = body.split('\n'); + + for (const line of lines) { + const trimmed = line.trim(); + + // Extract type + if (trimmed.match(/\*?\*?Type\*?\*?:/i)) { + const match = trimmed.match(/Type\*?\*?:\s*(.+)/i); + if (match) metadata.type = match[1].trim(); + } + + // Extract author(s) + if (trimmed.match(/\*?\*?Authors?\*?\*?:/i)) { + const match = trimmed.match(/Authors?\*?\*?:\s*(.+)/i); + if (match) metadata.author = match[1].trim(); + } + + // Extract sponsor + if (trimmed.match(/\*?\*?Sponsor\*?\*?:/i)) { + const match = trimmed.match(/Sponsor\*?\*?:\s*(.+)/i); + if (match) metadata.sponsor = match[1].trim(); + } + + // Extract PR number + if (trimmed.match(/\*?\*?PR\*?\*?:/i)) { + const match = trimmed.match(/PR\*?\*?:\s*#?(\d+)/i); + if (match) metadata.pr = match[1]; + } + + // Extract created date + if (trimmed.match(/\*?\*?Created\*?\*?:/i)) { + const match = trimmed.match(/Created\*?\*?:\s*(\d{4}-\d{2}-\d{2})/i); + if (match) metadata.created = match[1]; + } + } + + return metadata; +} + +// Clean up the body content (remove preamble/metadata section) +function cleanBodyContent(body) { + if (!body) return ''; + + // Remove the preamble/metadata section at the start + const lines = body.split('\n'); + let inPreamble = false; + let preambleEnded = false; + const contentLines = []; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const trimmed = line.trim(); + + // Detect preamble start + if (!preambleEnded && (trimmed.match(/^##?\s*Preamble/i) || trimmed.match(/^#\s*SEP-/))) { + inPreamble = true; + continue; + } + + // Detect preamble end (next major section) + if (inPreamble && trimmed.match(/^##\s*(Abstract|Motivation|Specification|Overview)/i)) { + inPreamble = false; + preambleEnded = true; + } + + // Skip preamble lines and metadata lines + if (inPreamble) continue; + if (!preambleEnded && trimmed.match(/^[-*]\s*\*?\*?(SEP Number|Title|Authors?|Status|Type|Created|Sponsor|PR)\*?\*?:/i)) { + continue; + } + + // Add content lines + if (preambleEnded || trimmed.length > 0 || contentLines.length > 0) { + contentLines.push(line); + } + } + + return contentLines.join('\n').trim(); +} + +// Generate SEP markdown content +function generateSEPMarkdown(issue, metadata, body) { + const sepNumber = issue.number; + const title = metadata.title; + + let content = `# SEP-${sepNumber}: ${title}\n\n`; + content += `- **Status**: ${metadata.status}\n`; + content += `- **Type**: ${metadata.type}\n`; + content += `- **Created**: ${metadata.created}\n`; + content += `- **Author(s)**: ${metadata.author}\n`; + + if (metadata.sponsor) { + content += `- **Sponsor**: ${metadata.sponsor}\n`; + } + + if (metadata.pr) { + content += `- **PR**: #${metadata.pr}\n`; + } + + content += `- **Issue**: #${sepNumber}\n`; + content += '\n'; + content += body; + + return content; +} + +// Convert title to filename +function titleToFilename(title) { + return title + .toLowerCase() + .replace(/[^\w\s-]/g, '') + .replace(/\s+/g, '-') + .replace(/-+/g, '-') + .substring(0, 50); // Limit length +} + +// Main migration function +function migrateSEPs() { + const issues = fetchSEPIssues(); + console.log(`Found ${issues.length} total SEP issues`); + + const sepsDir = path.join(__dirname, 'seps'); + + // Ensure seps directory exists + if (!fs.existsSync(sepsDir)) { + fs.mkdirSync(sepsDir, { recursive: true }); + } + + let migratedCount = 0; + let skippedCount = 0; + + for (const issue of issues) { + if (!shouldMigrate(issue)) { + console.log(`Skipping #${issue.number}: ${issue.title} (status: ${getStatusFromLabels(issue.labels) || 'none'})`); + skippedCount++; + continue; + } + + console.log(`\nMigrating #${issue.number}: ${issue.title}`); + + const metadata = parseIssueBody(issue.body, issue); + if (!metadata) { + console.log(` ⚠️ Could not parse metadata, skipping`); + skippedCount++; + continue; + } + + const cleanBody = cleanBodyContent(issue.body); + const sepContent = generateSEPMarkdown(issue, metadata, cleanBody); + + const filename = `${issue.number}-${titleToFilename(metadata.title)}.md`; + const filepath = path.join(sepsDir, filename); + + fs.writeFileSync(filepath, sepContent, 'utf-8'); + console.log(` ✓ Created ${filename}`); + migratedCount++; + } + + console.log(`\n=== Migration Complete ===`); + console.log(`Migrated: ${migratedCount}`); + console.log(`Skipped: ${skippedCount}`); + console.log(`Total: ${issues.length}`); +} + +// Run migration +try { + migrateSEPs(); +} catch (error) { + console.error('Error during migration:', error.message); + process.exit(1); +} diff --git a/package-lock.json b/package-lock.json index a19274249..2620a6907 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "": { "name": "@modelcontextprotocol/specification", "version": "0.1.0", - "license": "MIT", + "license": "SEE LICENSE IN LICENSE", "devDependencies": { "@eslint/js": "^9.8.0", "ajv": "^8.17.1", @@ -27,7 +27,7 @@ "unified": "^11.0.5" }, "engines": { - "node": ">=20" + "node": ">=20,<25" } }, "node_modules/@cspotcode/source-map-support": { @@ -43,21 +43,282 @@ "node": ">=12" } }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", - "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -71,10 +332,163 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -128,19 +542,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/config-helpers": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", @@ -168,9 +569,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -180,7 +581,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -215,23 +616,10 @@ "dev": true, "license": "MIT" }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { @@ -266,16 +654,16 @@ } }, "node_modules/@gerrit0/mini-shiki": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.14.0.tgz", - "integrity": "sha512-c5X8fwPLOtUS8TVdqhynz9iV0GlOtFUT1ppXYzUUlEXe4kbZ/mvMT8wXoT8kCwUka+zsiloq7sD3pZ3+QVTuNQ==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.21.0.tgz", + "integrity": "sha512-9PrsT5DjZA+w3lur/aOIx3FlDeHdyCEFlv9U+fmsVyjPZh61G5SYURQ/1ebe2U63KbDmI2V8IhIUegWb8hjOyg==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/engine-oniguruma": "^3.14.0", - "@shikijs/langs": "^3.14.0", - "@shikijs/themes": "^3.14.0", - "@shikijs/types": "^3.14.0", + "@shikijs/engine-oniguruma": "^3.21.0", + "@shikijs/langs": "^3.21.0", + "@shikijs/themes": "^3.21.0", + "@shikijs/types": "^3.21.0", "@shikijs/vscode-textmate": "^10.0.2" } }, @@ -389,79 +777,52 @@ "dev": true, "license": "MIT" }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.14.0.tgz", - "integrity": "sha512-TNcYTYMbJyy+ZjzWtt0bG5y4YyMIWC2nyePz+CFMWqm+HnZZyy9SWMgo8Z6KBJVIZnx8XUXS8U2afO6Y0g1Oug==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.21.0.tgz", + "integrity": "sha512-OYknTCct6qiwpQDqDdf3iedRdzj6hFlOPv5hMvI+hkWfCKs5mlJ4TXziBG9nyabLwGulrUjHiCq3xCspSzErYQ==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.14.0", + "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/langs": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.14.0.tgz", - "integrity": "sha512-DIB2EQY7yPX1/ZH7lMcwrK5pl+ZkP/xoSpUzg9YC8R+evRCCiSQ7yyrvEyBsMnfZq4eBzLzBlugMyTAf13+pzg==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.21.0.tgz", + "integrity": "sha512-g6mn5m+Y6GBJ4wxmBYqalK9Sp0CFkUqfNzUy2pJglUginz6ZpWbaWjDB4fbQ/8SHzFjYbtU6Ddlp1pc+PPNDVA==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.14.0" + "@shikijs/types": "3.21.0" } }, "node_modules/@shikijs/themes": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.14.0.tgz", - "integrity": "sha512-fAo/OnfWckNmv4uBoUu6dSlkcBc+SA1xzj5oUSaz5z3KqHtEbUypg/9xxgJARtM6+7RVm0Q6Xnty41xA1ma1IA==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.21.0.tgz", + "integrity": "sha512-BAE4cr9EDiZyYzwIHEk7JTBJ9CzlPuM4PchfcA5ao1dWXb25nv6hYsoDiBq2aZK9E3dlt3WB78uI96UESD+8Mw==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/types": "3.14.0" + "@shikijs/types": "3.21.0" } }, "node_modules/@shikijs/types": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.14.0.tgz", - "integrity": "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.21.0.tgz", + "integrity": "sha512-zGrWOxZ0/+0ovPY7PvBU2gIS9tmhSUUt30jAcNV0Bq0gb2S98gwfjIs1vxlmH5zM7/4YxLamT6ChlqqAJmPPjA==", "dev": true, "license": "MIT", "dependencies": { @@ -477,9 +838,9 @@ "license": "MIT" }, "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "dev": true, "license": "MIT" }, @@ -566,14 +927,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.2.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz", - "integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==", + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "undici-types": "~7.10.0" + "undici-types": "~5.26.4" } }, "node_modules/@types/unist": { @@ -584,21 +944,20 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.3.tgz", - "integrity": "sha512-sbaQ27XBUopBkRiuY/P9sWGOWUW4rl8fDoHIUmLpZd8uldsTyB4/Zg6bWTegPoTLnKj9Hqgn3QD6cjPNB32Odw==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.1.tgz", + "integrity": "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.46.3", - "@typescript-eslint/type-utils": "8.46.3", - "@typescript-eslint/utils": "8.46.3", - "@typescript-eslint/visitor-keys": "8.46.3", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/type-utils": "8.53.1", + "@typescript-eslint/utils": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -608,7 +967,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.46.3", + "@typescript-eslint/parser": "^8.53.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -624,17 +983,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.3.tgz", - "integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.1.tgz", + "integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.46.3", - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/typescript-estree": "8.46.3", - "@typescript-eslint/visitor-keys": "8.46.3", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -649,15 +1008,15 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.3.tgz", - "integrity": "sha512-Fz8yFXsp2wDFeUElO88S9n4w1I4CWDTXDqDr9gYvZgUpwXQqmZBr9+NTTql5R3J7+hrJZPdpiWaB9VNhAKYLuQ==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.1.tgz", + "integrity": "sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.46.3", - "@typescript-eslint/types": "^8.46.3", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.53.1", + "@typescript-eslint/types": "^8.53.1", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -671,14 +1030,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.3.tgz", - "integrity": "sha512-FCi7Y1zgrmxp3DfWfr+3m9ansUUFoy8dkEdeQSgA9gbm8DaHYvZCdkFRQrtKiedFf3Ha6VmoqoAaP68+i+22kg==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.1.tgz", + "integrity": "sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/visitor-keys": "8.46.3" + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -689,9 +1048,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.3.tgz", - "integrity": "sha512-GLupljMniHNIROP0zE7nCcybptolcH8QZfXOpCfhQDAdwJ/ZTlcaBOYebSOZotpti/3HrHSw7D3PZm75gYFsOA==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.1.tgz", + "integrity": "sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==", "dev": true, "license": "MIT", "engines": { @@ -706,17 +1065,17 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.3.tgz", - "integrity": "sha512-ZPCADbr+qfz3aiTTYNNkCbUt+cjNwI/5McyANNrFBpVxPt7GqpEYz5ZfdwuFyGUnJ9FdDXbGODUu6iRCI6XRXw==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.1.tgz", + "integrity": "sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/typescript-estree": "8.46.3", - "@typescript-eslint/utils": "8.46.3", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1", + "@typescript-eslint/utils": "8.53.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -731,9 +1090,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.3.tgz", - "integrity": "sha512-G7Ok9WN/ggW7e/tOf8TQYMaxgID3Iujn231hfi0Pc7ZheztIJVpO44ekY00b7akqc6nZcvregk0Jpah3kep6hA==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz", + "integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==", "dev": true, "license": "MIT", "engines": { @@ -745,22 +1104,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.3.tgz", - "integrity": "sha512-f/NvtRjOm80BtNM5OQtlaBdM5BRFUv7gf381j9wygDNL+qOYSNOgtQ/DCndiYi80iIOv76QqaTmp4fa9hwI0OA==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.1.tgz", + "integrity": "sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.46.3", - "@typescript-eslint/tsconfig-utils": "8.46.3", - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/visitor-keys": "8.46.3", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/project-service": "8.53.1", + "@typescript-eslint/tsconfig-utils": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/visitor-keys": "8.53.1", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -800,16 +1158,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.3.tgz", - "integrity": "sha512-VXw7qmdkucEx9WkmR3ld/u6VhRyKeiF1uxWwCy/iuNfokjJ7VhsgLSOTjsol8BunSw190zABzpwdNsze2Kpo4g==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.1.tgz", + "integrity": "sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.46.3", - "@typescript-eslint/types": "8.46.3", - "@typescript-eslint/typescript-estree": "8.46.3" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.53.1", + "@typescript-eslint/types": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -824,13 +1182,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.3.tgz", - "integrity": "sha512-uk574k8IU0rOF/AjniX8qbLSGURJVUCeM5e4MIMKBFFi8weeiLrG1fyQejyLXQpRZbU/1BuQasleV/RfHC3hHg==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.1.tgz", + "integrity": "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.46.3", + "@typescript-eslint/types": "8.53.1", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -913,9 +1271,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", "engines": { @@ -926,18 +1284,28 @@ } }, "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -981,19 +1349,6 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1032,22 +1387,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -1161,22 +1500,6 @@ "node": ">=8" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1184,16 +1507,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -1338,9 +1651,9 @@ } }, "node_modules/decode-named-character-reference": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", - "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1383,9 +1696,9 @@ } }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -1493,9 +1806,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", - "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1506,32 +1819,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.8", - "@esbuild/android-arm": "0.25.8", - "@esbuild/android-arm64": "0.25.8", - "@esbuild/android-x64": "0.25.8", - "@esbuild/darwin-arm64": "0.25.8", - "@esbuild/darwin-x64": "0.25.8", - "@esbuild/freebsd-arm64": "0.25.8", - "@esbuild/freebsd-x64": "0.25.8", - "@esbuild/linux-arm": "0.25.8", - "@esbuild/linux-arm64": "0.25.8", - "@esbuild/linux-ia32": "0.25.8", - "@esbuild/linux-loong64": "0.25.8", - "@esbuild/linux-mips64el": "0.25.8", - "@esbuild/linux-ppc64": "0.25.8", - "@esbuild/linux-riscv64": "0.25.8", - "@esbuild/linux-s390x": "0.25.8", - "@esbuild/linux-x64": "0.25.8", - "@esbuild/netbsd-arm64": "0.25.8", - "@esbuild/netbsd-x64": "0.25.8", - "@esbuild/openbsd-arm64": "0.25.8", - "@esbuild/openbsd-x64": "0.25.8", - "@esbuild/openharmony-arm64": "0.25.8", - "@esbuild/sunos-x64": "0.25.8", - "@esbuild/win32-arm64": "0.25.8", - "@esbuild/win32-ia32": "0.25.8", - "@esbuild/win32-x64": "0.25.8" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escalade": { @@ -1558,9 +1871,9 @@ } }, "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "dependencies": { @@ -1570,7 +1883,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -1687,19 +2000,6 @@ "dev": true, "license": "MIT" }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", @@ -1719,9 +2019,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -1787,53 +2087,23 @@ "dev": true, "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1849,9 +2119,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "dev": true, "funding": [ { @@ -1865,14 +2135,22 @@ ], "license": "BSD-3-Clause" }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, "node_modules/file-entry-cache": { @@ -1888,19 +2166,6 @@ "node": ">=16.0.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1963,6 +2228,21 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1974,9 +2254,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", - "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2023,6 +2303,22 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -2036,13 +2332,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2054,9 +2343,9 @@ } }, "node_modules/htmlparser2": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", - "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -2069,14 +2358,14 @@ "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", - "domutils": "^3.2.1", - "entities": "^6.0.0" + "domutils": "^3.2.2", + "entities": "^7.0.1" } }, "node_modules/htmlparser2/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -2202,6 +2491,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2226,16 +2525,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -2375,11 +2664,11 @@ } }, "node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } @@ -2580,16 +2869,6 @@ "dev": true, "license": "MIT" }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/micromark": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", @@ -3214,34 +3493,17 @@ ], "license": "MIT" }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "ISC", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/minipass": { @@ -3479,9 +3741,9 @@ } }, "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -3496,13 +3758,13 @@ } }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -3519,9 +3781,9 @@ } }, "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -3554,27 +3816,6 @@ "node": ">=6" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/remark-mdx": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", @@ -3647,39 +3888,14 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", "dev": true, "license": "MIT", "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" + "node": ">=10" } }, "node_modules/safer-buffer": { @@ -3789,16 +4005,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3828,9 +4034,9 @@ } }, "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, "license": "MIT", "dependencies": { @@ -3864,7 +4070,7 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/strip-json-comments": { @@ -3893,17 +4099,21 @@ "node": ">=8" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">=8.0" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, "node_modules/trough": { @@ -3918,9 +4128,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { @@ -3974,21 +4184,14 @@ } } }, - "node_modules/ts-node/node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, "node_modules/tsx": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz", - "integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "~0.25.0", + "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "bin": { @@ -4015,13 +4218,13 @@ } }, "node_modules/typedoc": { - "version": "0.28.14", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.14.tgz", - "integrity": "sha512-ftJYPvpVfQvFzpkoSfHLkJybdA/geDJ8BGQt/ZnkkhnBYoYW6lBgPQXu6vqLxO4X75dA55hX8Af847H5KXlEFA==", + "version": "0.28.16", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.16.tgz", + "integrity": "sha512-x4xW77QC3i5DUFMBp0qjukOTnr/sSg+oEs86nB3LjDslvAmwe/PUGDWbe3GrIqt59oTqoXK5GRK9tAa0sYMiog==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@gerrit0/mini-shiki": "^3.12.0", + "@gerrit0/mini-shiki": "^3.17.0", "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", @@ -4065,9 +4268,9 @@ } }, "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4079,16 +4282,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.46.3", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.3.tgz", - "integrity": "sha512-bAfgMavTuGo+8n6/QQDVQz4tZ4f7Soqg53RbrlZQEoAltYop/XR4RAts/I0BrO3TTClTSTFJ0wYbla+P8cEWJA==", + "version": "8.53.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.53.1.tgz", + "integrity": "sha512-gB+EVQfP5RDElh9ittfXlhZJdjSU4jUSTyE2+ia8CYyNvet4ElfaLlAIqDvQV9JPknKx0jQH1racTYe/4LaLSg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.46.3", - "@typescript-eslint/parser": "8.46.3", - "@typescript-eslint/typescript-estree": "8.46.3", - "@typescript-eslint/utils": "8.46.3" + "@typescript-eslint/eslint-plugin": "8.53.1", + "@typescript-eslint/parser": "8.53.1", + "@typescript-eslint/typescript-estree": "8.53.1", + "@typescript-eslint/utils": "8.53.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4122,16 +4325,6 @@ "typescript-json-schema": "bin/typescript-json-schema" } }, - "node_modules/typescript-json-schema/node_modules/@types/node": { - "version": "18.19.122", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.122.tgz", - "integrity": "sha512-yzegtT82dwTNEe/9y+CM8cgb42WrUfMMCg2QqSddzO1J6uPmBD7qKCZ7dOHZP2Yrpm/kb0eqdNMn2MUyEiqBmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/typescript-json-schema/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -4154,29 +4347,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/typescript-json-schema/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/typescript-json-schema/node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/typescript-json-schema/node_modules/typescript": { "version": "5.5.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", @@ -4191,13 +4361,6 @@ "node": ">=14.17" } }, - "node_modules/typescript-json-schema/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true, - "license": "MIT" - }, "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", @@ -4206,9 +4369,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", - "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.19.0.tgz", + "integrity": "sha512-Heho1hJD81YChi+uS2RkSjcVO+EQLmLSyUlHyp7Y/wFbxQaGb4WXVKD073JytrjXJVkSZVzoE2MCSOKugFGtOQ==", "dev": true, "license": "MIT", "engines": { @@ -4216,12 +4379,11 @@ } }, "node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/unified": { "version": "11.0.5", @@ -4367,6 +4529,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", "dev": true, "license": "MIT", "dependencies": { @@ -4459,22 +4622,6 @@ "node": ">=8" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -4482,16 +4629,6 @@ "dev": true, "license": "MIT" }, - "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4520,6 +4657,19 @@ "node": ">=8" } }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -4538,9 +4688,9 @@ } }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", "bin": { @@ -4548,6 +4698,9 @@ }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { @@ -4596,16 +4749,6 @@ "dev": true, "license": "MIT" }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", diff --git a/package.json b/package.json index b1cb28226..e63ee22c4 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "homepage": "https://modelcontextprotocol.io", "bugs": "https://github.com/modelcontextprotocol/specification/issues", "engines": { - "node": ">=20" + "node": ">=20,<25" }, "prettier": { "overrides": [ @@ -21,7 +21,8 @@ ] }, "scripts": { - "check": "npm run check:schema && npm run check:docs", + "check": "npm run check:schema && npm run check:docs && npm run check:seps", + "check:seps": "tsx scripts/render-seps.ts --check", "check:docs": "npm run check:docs:format && npm run check:docs:js-comments && npm run check:docs:links", "check:docs:format": "prettier --check \"**/*.{md,mdx}\"", "check:docs:js-comments": "tsx scripts/check-mdx-comments.ts", @@ -33,6 +34,7 @@ "check:schema:md": "for f in schema/*/schema.mdx; do typedoc --entryPoints \"${f%.mdx}.ts\" --schemaPageTemplate \"$f\" | cmp docs/specification/$(basename -- $(dirname -- \"$f\"))/schema.mdx - || exit 1; done", "format": "prettier --write \"**/*.{md,mdx}\" --ignore \"docs/specification/*/schema.mdx\" ", "generate:schema": "npm run generate:schema:json & npm run generate:schema:md & wait", + "generate:seps": "tsx scripts/render-seps.ts", "generate:schema:json": "tsx scripts/generate-schemas.ts", "generate:schema:md": "find schema/*/schema.mdx -print0 | xargs -0 -P 0 -I {} sh -c 'f=\"{}\"; typedoc --entryPoints \"${f%.mdx}.ts\" --schemaPageTemplate \"$f\" > docs/specification/$(basename -- $(dirname -- \"$f\"))/schema.mdx'", "prep:changes": "npm run check:schema:ts && npm run generate:schema && npm run check:docs && npm run format", diff --git a/schema/2025-11-25/schema.ts b/schema/2025-11-25/schema.ts index bfb56c474..ca580e5b8 100644 --- a/schema/2025-11-25/schema.ts +++ b/schema/2025-11-25/schema.ts @@ -185,8 +185,10 @@ export const URL_ELICITATION_REQUIRED = -32042; * * @internal */ -export interface URLElicitationRequiredError - extends Omit { +export interface URLElicitationRequiredError extends Omit< + JSONRPCErrorResponse, + "error" +> { error: Error & { code: typeof URL_ELICITATION_REQUIRED; data: { diff --git a/schema/draft/schema.ts b/schema/draft/schema.ts index 9dc41a2a8..25acc62d5 100644 --- a/schema/draft/schema.ts +++ b/schema/draft/schema.ts @@ -306,8 +306,10 @@ export const URL_ELICITATION_REQUIRED = -32042; * * @internal */ -export interface URLElicitationRequiredError - extends Omit { +export interface URLElicitationRequiredError extends Omit< + JSONRPCErrorResponse, + "error" +> { error: Error & { code: typeof URL_ELICITATION_REQUIRED; data: { @@ -939,8 +941,7 @@ export interface ListResourceTemplatesResult extends PaginatedResult { * * @category `resources/templates/list` */ -export interface ListResourceTemplatesResultResponse - extends JSONRPCResultResponse { +export interface ListResourceTemplatesResultResponse extends JSONRPCResultResponse { result: ListResourceTemplatesResult; } diff --git a/scripts/render-seps.ts b/scripts/render-seps.ts new file mode 100644 index 000000000..59cb1c889 --- /dev/null +++ b/scripts/render-seps.ts @@ -0,0 +1,480 @@ +#!/usr/bin/env tsx +/** + * Script to render SEPs (Specification Enhancement Proposals) into Mintlify docs format. + * + * This script: + * 1. Reads all SEP markdown files from the seps/ directory + * 2. Parses their metadata (title, status, type, authors, etc.) + * 3. Generates an index page with a tabular overview + * 4. Generates individual MDX files for each SEP in docs/community/seps/ + * + * Usage: npx tsx scripts/render-seps.ts [--check] + * --check: Verify generated files are up to date (exit 1 if not) + */ + +import * as fs from "fs"; +import * as path from "path"; +import { execSync } from "child_process"; + +const SEPS_DIR = path.join(__dirname, "..", "seps"); +const DOCS_SEPS_DIR = path.join(__dirname, "..", "docs", "community", "seps"); +const DOCS_JSON_PATH = path.join(__dirname, "..", "docs", "docs.json"); + +interface SEPMetadata { + number: string; + title: string; + status: string; + type: string; + created: string; + accepted?: string; + authors: string; + sponsor: string; + prUrl: string; + slug: string; + filename: string; +} + +/** + * Parse SEP metadata from markdown content + */ +function parseSEPMetadata(content: string, filename: string): SEPMetadata | null { + // Skip template and README files + if (filename === "TEMPLATE.md" || filename === "README.md") { + return null; + } + + // Extract SEP number and slug from filename (e.g., "1850-pr-based-sep-workflow.md") + const filenameMatch = filename.match(/^(\d+)-(.+)\.md$/); + if (!filenameMatch) { + // Skip files that don't match SEP naming convention (like 0000-*.md drafts) + if (filename.match(/^0000-/)) { + return null; + } + console.warn(`Warning: Skipping ${filename} - doesn't match SEP naming convention`); + return null; + } + + const [, number, slug] = filenameMatch; + + // Parse title from first heading + const titleMatch = content.match(/^#\s+SEP-\d+:\s+(.+)$/m); + const title = titleMatch ? titleMatch[1].trim() : "Untitled"; + + // Parse metadata fields using regex + const statusMatch = content.match(/^\s*-\s*\*\*Status\*\*:\s*(.+)$/m); + const typeMatch = content.match(/^\s*-\s*\*\*Type\*\*:\s*(.+)$/m); + const createdMatch = content.match(/^\s*-\s*\*\*Created\*\*:\s*(.+)$/m); + const acceptedMatch = content.match(/^\s*-\s*\*\*Accepted\*\*:\s*(.+)$/m); + const authorsMatch = content.match(/^\s*-\s*\*\*Author\(s\)\*\*:\s*(.+)$/m); + const sponsorMatch = content.match(/^\s*-\s*\*\*Sponsor\*\*:\s*(.+)$/m); + const prMatch = content.match(/^\s*-\s*\*\*PR\*\*:\s*(.+)$/m); + + return { + number, + title, + status: statusMatch ? statusMatch[1].trim() : "Unknown", + type: typeMatch ? typeMatch[1].trim() : "Unknown", + created: createdMatch ? createdMatch[1].trim() : "Unknown", + accepted: acceptedMatch ? acceptedMatch[1].trim() : undefined, + authors: authorsMatch ? authorsMatch[1].trim() : "Unknown", + sponsor: sponsorMatch ? sponsorMatch[1].trim() : "None", + prUrl: prMatch ? prMatch[1].trim() : `https://github.com/modelcontextprotocol/specification/pull/${number}`, + slug, + filename, + }; +} + +/** + * Convert GitHub usernames to links + */ +function formatAuthors(authors: string): string { + return authors.replace(/@([\w-]+)/g, "[@$1](https://github.com/$1)"); +} + +/** + * Truncate title to max length, adding ellipsis if needed + */ +function truncateTitle(title: string, maxLength: number): string { + if (title.length <= maxLength) return title; + return title.slice(0, maxLength - 1).trim() + "…"; +} + +/** + * Get status badge color for Mintlify + */ +function getStatusBadgeColor(status: string): string { + const statusLower = status.toLowerCase(); + if (statusLower === "final") return "green"; + if (statusLower === "accepted") return "blue"; + if (statusLower === "in-review") return "yellow"; + if (statusLower === "draft") return "gray"; + if (statusLower === "rejected" || statusLower === "withdrawn") return "red"; + if (statusLower === "dormant") return "orange"; + if (statusLower === "superseded") return "purple"; + return "gray"; +} + +/** + * Generate MDX content for a single SEP page + */ +function generateSEPPage(sep: SEPMetadata, originalContent: string): string { + // Remove the header metadata section and title from original content for the body + // Find where the Abstract section starts + const abstractIndex = originalContent.indexOf("## Abstract"); + const body = abstractIndex !== -1 ? originalContent.slice(abstractIndex) : originalContent; + + return `--- +title: "SEP-${sep.number}: ${sep.title}" +sidebarTitle: "SEP-${sep.number}: ${truncateTitle(sep.title, 40)}" +description: "${sep.title}" +--- + +import { Badge } from '/snippets/badge.mdx' + +
+ ${sep.status} + ${sep.type} +
+ +| Field | Value | +|-------|-------| +| **SEP** | ${sep.number} | +| **Title** | ${sep.title} | +| **Status** | ${sep.status} | +| **Type** | ${sep.type} | +| **Created** | ${sep.created} | +${sep.accepted ? `| **Accepted** | ${sep.accepted} |\n` : ""}| **Author(s)** | ${formatAuthors(sep.authors)} | +| **Sponsor** | ${formatAuthors(sep.sponsor)} | +| **PR** | [#${sep.number}](${sep.prUrl}) | + +--- + +${body} +`; +} + +/** + * Generate the SEP index page with tabular overview + */ +function generateIndexPage(seps: SEPMetadata[]): string { + // Sort SEPs by number (descending - newest first) + const sortedSeps = [...seps].sort((a, b) => parseInt(b.number) - parseInt(a.number)); + + // Group by status for summary + const byStatus = sortedSeps.reduce( + (acc, sep) => { + const status = sep.status.toLowerCase(); + acc[status] = (acc[status] || 0) + 1; + return acc; + }, + {} as Record + ); + + // Generate table rows + const tableRows = sortedSeps + .map((sep) => { + const statusBadge = `${sep.status}`; + return `| [SEP-${sep.number}](/community/seps/${sep.number}-${sep.slug}) | ${sep.title} | ${statusBadge} | ${sep.type} | ${sep.created} |`; + }) + .join("\n"); + + // Generate status summary + const statusSummary = Object.entries(byStatus) + .map(([status, count]) => `- **${status.charAt(0).toUpperCase() + status.slice(1)}**: ${count}`) + .join("\n"); + + return `--- +title: Specification Enhancement Proposals (SEPs) +sidebarTitle: SEP Index +description: Index of all MCP Specification Enhancement Proposals +--- + +import { Badge } from '/snippets/badge.mdx' + +Specification Enhancement Proposals (SEPs) are the primary mechanism for proposing major changes to the Model Context Protocol. Each SEP provides a concise technical specification and rationale for proposed features. + + + Learn how to submit your own Specification Enhancement Proposal + + +## Summary + +${statusSummary} + +## All SEPs + +| SEP | Title | Status | Type | Created | +|-----|-------|--------|------|---------| +${tableRows} + +## SEP Status Definitions + +- Draft - SEP proposal with a sponsor, undergoing informal review +- In-Review - SEP proposal ready for formal review by Core Maintainers +- Accepted - SEP accepted, awaiting reference implementation +- Final - SEP finalized with reference implementation complete +- Rejected - SEP rejected by Core Maintainers +- Withdrawn - SEP withdrawn by the author +- Superseded - SEP replaced by a newer SEP +- Dormant - SEP without a sponsor, closed after 6 months +`; +} + +/** + * Generate the badge snippet MDX file + */ +function generateBadgeSnippet(): string { + // Use inline styles for dark mode since Mintlify may not support all Tailwind dark: classes + return `export const Badge = ({ children, color = "gray" }) => { + const styles = { + green: { light: { bg: "#dcfce7", text: "#166534" }, dark: { bg: "#14532d", text: "#86efac" } }, + blue: { light: { bg: "#dbeafe", text: "#1e40af" }, dark: { bg: "#1e3a5f", text: "#93c5fd" } }, + yellow: { light: { bg: "#fef9c3", text: "#854d0e" }, dark: { bg: "#713f12", text: "#fde047" } }, + red: { light: { bg: "#fee2e2", text: "#991b1b" }, dark: { bg: "#7f1d1d", text: "#fca5a5" } }, + orange: { light: { bg: "#ffedd5", text: "#9a3412" }, dark: { bg: "#7c2d12", text: "#fdba74" } }, + purple: { light: { bg: "#f3e8ff", text: "#6b21a8" }, dark: { bg: "#581c87", text: "#d8b4fe" } }, + gray: { light: { bg: "#f3f4f6", text: "#1f2937" }, dark: { bg: "#374151", text: "#d1d5db" } }, + }; + const s = styles[color] || styles.gray; + return ( + <> + + + {children} + + + ); +}; +`; +} + +/** + * Read all SEP files and parse their metadata + */ +function readAllSEPs(): { metadata: SEPMetadata; content: string }[] { + const files = fs.readdirSync(SEPS_DIR).filter((f) => f.endsWith(".md")); + const seps: { metadata: SEPMetadata; content: string }[] = []; + + for (const file of files) { + const content = fs.readFileSync(path.join(SEPS_DIR, file), "utf-8"); + const metadata = parseSEPMetadata(content, file); + if (metadata) { + seps.push({ metadata, content }); + } + } + + return seps; +} + +/** + * Group SEPs by status for navigation + */ +function groupSepsByStatus(seps: SEPMetadata[]): Record { + const groups: Record = {}; + + // Define status order for navigation + const statusOrder = ["Final", "Accepted", "In-Review", "Draft", "Withdrawn", "Rejected", "Superseded", "Dormant"]; + + for (const sep of seps) { + // Normalize status to title case + const status = sep.status.charAt(0).toUpperCase() + sep.status.slice(1).toLowerCase(); + if (!groups[status]) { + groups[status] = []; + } + groups[status].push(sep); + } + + // Sort each group by SEP number + for (const status of Object.keys(groups)) { + groups[status].sort((a, b) => parseInt(a.number) - parseInt(b.number)); + } + + // Return in preferred order + const orderedGroups: Record = {}; + for (const status of statusOrder) { + if (groups[status]) { + orderedGroups[status] = groups[status]; + } + } + // Add any remaining statuses not in the predefined order + for (const status of Object.keys(groups)) { + if (!orderedGroups[status]) { + orderedGroups[status] = groups[status]; + } + } + + return orderedGroups; +} + +/** + * Update docs.json to include SEPs in navigation, grouped by status + */ +function updateDocsJson(seps: SEPMetadata[]): string { + const docsJson = JSON.parse(fs.readFileSync(DOCS_JSON_PATH, "utf-8")); + + // Group SEPs by status + const groupedSeps = groupSepsByStatus(seps); + + // Build nested navigation structure + const sepSubgroups: Array = []; + + for (const [status, statusSeps] of Object.entries(groupedSeps)) { + if (statusSeps.length === 0) continue; + + const pages = statusSeps.map((sep) => `community/seps/${sep.number}-${sep.slug}`); + + sepSubgroups.push({ + group: status, + pages, + }); + } + + // Find the Community tab and add/update SEPs group + const communityTab = docsJson.navigation.tabs.find((tab: { tab: string }) => tab.tab === "Community"); + if (communityTab) { + // Check if SEPs group already exists + const sepsGroupIndex = communityTab.pages.findIndex( + (item: { group?: string } | string) => typeof item === "object" && item.group === "SEPs" + ); + + const sepsGroup = { + group: "SEPs", + pages: ["community/seps/index", ...sepSubgroups], + }; + + if (sepsGroupIndex >= 0) { + communityTab.pages[sepsGroupIndex] = sepsGroup; + } else { + // Insert after Governance group (index 1) + communityTab.pages.splice(2, 0, sepsGroup); + } + } + + return JSON.stringify(docsJson, null, 2) + "\n"; +} + +/** + * Main function + */ +async function main() { + const checkMode = process.argv.includes("--check"); + + console.log("Reading SEP files..."); + const seps = readAllSEPs(); + console.log(`Found ${seps.length} SEP(s)`); + + if (seps.length === 0) { + console.log("No SEPs found to render."); + return; + } + + // Ensure output directory exists + if (!fs.existsSync(DOCS_SEPS_DIR)) { + fs.mkdirSync(DOCS_SEPS_DIR, { recursive: true }); + } + + // Ensure snippets directory exists + const snippetsDir = path.join(__dirname, "..", "docs", "snippets"); + if (!fs.existsSync(snippetsDir)) { + fs.mkdirSync(snippetsDir, { recursive: true }); + } + + // Track all expected files for check mode + const expectedFiles: { path: string; content: string }[] = []; + + // Generate badge snippet + const badgeSnippetPath = path.join(snippetsDir, "badge.mdx"); + const badgeContent = generateBadgeSnippet(); + expectedFiles.push({ path: badgeSnippetPath, content: badgeContent }); + + // Generate index page + const indexPath = path.join(DOCS_SEPS_DIR, "index.mdx"); + const indexContent = generateIndexPage(seps.map((s) => s.metadata)); + expectedFiles.push({ path: indexPath, content: indexContent }); + + // Generate individual SEP pages + for (const { metadata, content } of seps) { + const sepPath = path.join(DOCS_SEPS_DIR, `${metadata.number}-${metadata.slug}.mdx`); + const sepContent = generateSEPPage(metadata, content); + expectedFiles.push({ path: sepPath, content: sepContent }); + } + + // Generate updated docs.json + const docsJsonContent = updateDocsJson(seps.map((s) => s.metadata)); + expectedFiles.push({ path: DOCS_JSON_PATH, content: docsJsonContent }); + + if (checkMode) { + // Check mode: verify all files match expected content (after formatting) + // Write to temp files, format with Prettier, then compare + const tempDir = fs.mkdtempSync(path.join(require("os").tmpdir(), "seps-check-")); + let hasChanges = false; + + try { + // Write expected content to temp files + const tempFiles: { original: string; temp: string }[] = []; + for (const { path: filePath, content } of expectedFiles) { + const tempPath = path.join(tempDir, path.basename(filePath)); + fs.writeFileSync(tempPath, content, "utf-8"); + tempFiles.push({ original: filePath, temp: tempPath }); + } + + // Format MDX files with Prettier + const mdxTempFiles = tempFiles.filter(({ temp }) => temp.endsWith(".mdx")).map(({ temp }) => temp); + if (mdxTempFiles.length > 0) { + execSync(`npx prettier --write ${mdxTempFiles.join(" ")}`, { stdio: "pipe" }); + } + + // Compare formatted temp files with existing files + for (const { original, temp } of tempFiles) { + if (!fs.existsSync(original)) { + console.error(`Missing file: ${original}`); + hasChanges = true; + continue; + } + const existing = fs.readFileSync(original, "utf-8"); + const formatted = fs.readFileSync(temp, "utf-8"); + if (existing !== formatted) { + console.error(`File out of date: ${original}`); + hasChanges = true; + } + } + } finally { + // Clean up temp directory + fs.rmSync(tempDir, { recursive: true, force: true }); + } + + if (hasChanges) { + console.error("\nSEP documentation is out of date. Run 'npm run generate:seps' to update."); + process.exit(1); + } + console.log("All SEP documentation is up to date."); + } else { + // Write mode: generate all files + for (const { path: filePath, content } of expectedFiles) { + fs.writeFileSync(filePath, content, "utf-8"); + console.log(`Generated: ${path.relative(process.cwd(), filePath)}`); + } + + // Format generated files with Prettier + const filesToFormat = expectedFiles + .filter(({ path: p }) => p.endsWith(".mdx")) + .map(({ path: p }) => path.relative(process.cwd(), p)); + if (filesToFormat.length > 0) { + console.log("\nFormatting generated files with Prettier..."); + execSync(`npx prettier --write ${filesToFormat.join(" ")}`, { stdio: "inherit" }); + } + + console.log("\nSEP documentation generated successfully!"); + } +} + +main().catch((err) => { + console.error("Error:", err); + process.exit(1); +}); diff --git a/seps/1024-mcp-client-security-requirements-for-local-server-.md b/seps/1024-mcp-client-security-requirements-for-local-server-.md new file mode 100644 index 000000000..2a3b2b1d2 --- /dev/null +++ b/seps/1024-mcp-client-security-requirements-for-local-server-.md @@ -0,0 +1,104 @@ +# SEP-1024: MCP Client Security Requirements for Local Server Installation + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-07-22 +- **Author(s)**: Den Delimarsky +- **Issue**: #1024 + +## Abstract + +This SEP addresses critical security vulnerabilities in MCP client implementations that support one-click installation of local MCP servers. The current MCP specification lacks explicit security requirements for client-side installation flows, allowing malicious actors to execute arbitrary commands on user systems through crafted MCP server configurations distributed via links or social engineering. + +This proposal establishes a best practice for MCP clients, requiring explicit user consent before executing any local server installation commands and complete command transparency. + +## Motivation + +The existing MCP specification does not address client-side security concerns related to streamlined ("one-click") local server configuration. Current MCP clients that implement these configuration experiences create significant attack vectors: + +1. **Silent Command Execution**: MCP clients can automatically execute embedded commands without user review or consent when installing local servers via one-click flows. + +2. **Lack of Visibility**: Users have no insight into what commands are being executed on their systems, creating opportunities for data exfiltration, system compromise, and privilege escalation. + +3. **Social Engineering Vulnerabilities**: Users become comfortable executing commands labeled as "MCP servers" without proper scrutiny, making them susceptible to malicious configurations. + +4. **Arbitrary Code Execution**: Attackers can embed harmful commands in MCP server configurations and distribute them through legitimate channels (repositories, documentation, social media). + +Visual Studio Code [addressed this](https://den.dev/blog/vs-code-mcp-install-consent/) by implementing consent dialogs. Similarly, Cursor also supports a consent dialog for one-click local MCP server installation. + +Without explicit security requirements in the specification, MCP client implementers may unknowingly create vulnerable installation flows, putting end users at risk of system compromise. + +## Specification + +### Client Security Requirements + +MCP clients that support one-click local MCP server configuration **MUST** implement the following security controls: + +#### Pre-Configuration Consent + +Before executing any command to install or configure a local MCP server, the MCP client **MUST**: + +1. Display a clear consent dialog that shows: + - The exact command that will be executed, without truncation + - All arguments and parameters + - A clear warning that this operation may be potentially dangerous +2. Require explicit user approval through an affirmative action (button click, checkbox, etc.) + +3. Provide an option for users to cancel the installation + +4. Not proceed with installation if consent is denied or not provided + +## Rationale + +### Design Decisions + +**Mandatory Consent Dialogs**: The requirement for explicit consent dialogs balances security with usability. While this adds friction to the MCP server configuration process, it prevents potential breaches from silent command execution. + +## Backward Compatibility + +This SEP introduces new **requirements** for MCP client implementations but does not change the core MCP protocol or wire format. + +**Impact Assessment:** + +- **Low Impact**: Existing MCP servers and the core protocol remain unchanged +- **Client Implementation Required**: MCP clients must update their local server installation flows to comply with new security requirements +- **User Experience Changes**: Users will see consent dialogs where none existed before + +**Migration Path:** + +1. MCP clients can implement these changes in new versions without breaking existing functionality +2. Existing installed MCP servers continue to work normally +3. Only new installation flows require the consent mechanisms + +No protocol-level backward compatibility issues exist, as this SEP addresses client behavior rather than the MCP wire protocol. + +## Reference Implementation + +N/A + +## Security Implications + +### Security Benefits + +This SEP directly addresses: + +- **Arbitrary Code Execution**: Prevents silent execution of malicious commands +- **Social Engineering**: Forces users to consciously review commands before execution +- **Supply Chain Attacks**: Creates visibility into MCP server installation commands +- **Privilege Escalation**: Users can identify and reject commands requesting elevated privileges + +### Residual Risks + +Even with these controls, risks remain: + +- **User Override**: Users may approve malicious commands despite warnings +- **Sophisticated Obfuscation**: Advanced attackers may craft commands that appear legitimate +- **Implementation Gaps**: Clients may implement controls incorrectly + +### Risk Mitigation + +These residual risks are addressed through: + +- Clear warning language in consent dialogs +- Recommendation for additional security layers (sandboxing, signatures) +- Ongoing security research and community awareness diff --git a/seps/1034--support-default-values-for-all-primitive-types-in.md b/seps/1034--support-default-values-for-all-primitive-types-in.md new file mode 100644 index 000000000..a0a3c9492 --- /dev/null +++ b/seps/1034--support-default-values-for-all-primitive-types-in.md @@ -0,0 +1,143 @@ +# SEP-1034: Support default values for all primitive types in elicitation schemas + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-07-22 +- **Author(s)**: Tapan Chugh (chugh.tapan@gmail.com) +- **Issue**: #1034 + +## Abstract + +This SEP recommends adding support for default values to all primitive types in the MCP elicitation schema (StringSchema, NumberSchema, and EnumSchema), extending the existing support that only covers BooleanSchema. + +## Motivation + +Elicitations in MCP offer a way to mitigate complex API designs: tools can request information on-demand rather than resorting to convoluted parameter handling. The challenge however is that users must manually enter obvious information that could be pre-populated for more natural interactions. Currently, only `BooleanSchema` supports default values in elicitation requests. This limitation prevents servers from providing sensible defaults for text inputs, numbers, and enum selections leading to more user overhead. + +### Real-World Example + +Consider implementing an email reply function. Without elicitation, the tool becomes unwieldy: + +```python +def reply_to_email_thread( + thread_id: str, + content: str, + recipient_list: List[str] = [], + cc_list: List[str] = [] +) -> None: + # Ambiguity: Does empty list mean "no recipients" or "use defaults"? + # Complex logic needed to handle different combinations +``` + +With elicitation, the tool signature itself can be much simpler + +```python +def reply_to_email_thread( + thread_id: str, + content: Optional[str] = "" +) -> None: + # Code can lookup the participants from the original thread + # and prepare an elicitation request with the defaults setup +``` + +```typescript +const response = await client.request("elicitation/create", { + message: "Configure email reply", + requestedSchema: { + type: "object", + properties: { + recipients: { + type: "string", + title: "Recipients", + default: "alice@company.com, bob@company.com" // Pre-filled + }, + cc: { + type: "string", + title: "CC", + default: "john@company.com" // Pre-filled + }, + content: { + type: "string", + title: "Message" + default: "" // If provided in the tool above + } + } + } +}); +``` + +### Implementation + +A working implementation demonstrating clients require minimal changes to display defaults (~10 lines of code): + +- Implementation PR: https://github.com/chughtapan/fast-agent/pull/2 +- A demo with the above email reply workflow: https://asciinema.org/a/X7aQZjT2B5jVwn9dJ9sqQVkOM + +## Specification + +### Schema Changes + +Extend the elicitation primitive schemas to include optional default values: + +```typescript +export interface StringSchema { + type: "string"; + title?: string; + description?: string; + minLength?: number; + maxLength?: number; + format?: "email" | "uri" | "date" | "date-time"; + default?: string; // NEW +} + +export interface NumberSchema { + type: "number" | "integer"; + title?: string; + description?: string; + minimum?: number; + maximum?: number; + default?: number; // NEW +} + +export interface EnumSchema { + type: "string"; + title?: string; + description?: string; + enum: string[]; + enumNames?: string[]; + default?: string; // NEW - must be one of enum values +} + +// BooleanSchema already has default?: boolean +``` + +### Behavior + +1. The `default` field is optional, maintaining full backward compatibility +2. Default values must match the schema type +3. For EnumSchema, the default must be one of the valid enum values +4. Clients that support defaults SHOULD pre-populate form fields. Clients that don't support defaults MAY ignore the field entirely. + +## Rationale + +1. The high-level rationale is to follow the precedent set by BooleanSchema rather than creating new mechanisms. +2. Making defaults optional ensures backward compatibility. +3. This maintains the high-level intuition of keeping the client implementation simple. + +### Alternatives Considered + +1. **Server-side Templates**: Servers could maintain templates separately, but this adds complexity +2. **New Request Type**: A separate request type for forms with defaults would fragment the API +3. **Required Defaults**: Making defaults required would break existing implementations + +## Backwards Compatibility + +This change is fully backward compatible with no breaking changes. Clients that don't understand defaults will ignore them, and existing elicitation requests continue to work unchanged. Clients can adopt default support at their own pace + +## Security Implications + +No new security concerns: + +1. **No Sensitive Data**: The existing guidance against requesting sensitive information still applies +2. **Client Control**: Clients retain full control over what data is sent to servers +3. **User Visibility**: Default values are visible to users who can modify them before submission diff --git a/seps/1036-url-mode-elicitation-for-secure-out-of-band-intera.md b/seps/1036-url-mode-elicitation-for-secure-out-of-band-intera.md new file mode 100644 index 000000000..9eb50ceb6 --- /dev/null +++ b/seps/1036-url-mode-elicitation-for-secure-out-of-band-intera.md @@ -0,0 +1,304 @@ +# SEP-1036: URL Mode Elicitation for secure out-of-band interactions + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-07-22 +- **Author(s)**: Nate Barbettini (@nbarbettini) and Wils Dawson (@wdawson) +- **Issue**: #1036 + +## Abstract + +This SEP introduces a new `url` mode for the existing elicitation client capability, enabling secure out-of-band interactions that bypass the MCP client. URL mode elicitation addresses sensitive use cases that form mode elicitation cannot, such as gathering sensitive credentials, performing OAuth flows for external (3rd-party) authorization, and handling payments, _without_ exposing sensitive data to the MCP client. By directing users to trusted URLs in their browser, this mode maintains security boundaries while enabling rich integrations with third-party services. + +## Motivation + +The current MCP specification (2025-06-18) provides an elicitation mechanism for gathering non-sensitive information from users through structured, in-band requests (most commonly imagined as the MCP client rendering a form to collect data from the end-user). However, several critical use cases require interactions that must not pass through the MCP client: + +1. Sensitive data collection: API keys, passwords, and other credentials must never transit through intermediary systems. +2. External authorization: MCP servers often need to access third-party APIs on behalf of users. The MCP authorization specification only covers client-to-server authorization, not server-to-third-party authorization. The [Security Best Practices](https://modelcontextprotocol.io/specification/2025-06-18/basic/security_best_practices) document explicitly forbids token passthrough, requiring a secure mechanism for external (3rd-party) OAuth flows. This was a particularly important motivating factor emerging from discussions in #234 and #284. +3. Payment and Subscription Flows: Financial transactions require PCI compliance and secure payment processing that cannot be achieved through in-band data collection. + +Without a standardized mechanism for these interactions, MCP servers must resort to non-standard workarounds or insecure practices like requesting API keys through in-band, form-style elicitation. This SEP addresses these gaps by introducing a URL elicitation mode that leverages established web security patterns to handle sensitive interactions securely. + +URL elicitation is fundamentally different from [MCP authorization](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization). URL elicitation is not for authorizing the MCP client's access to the MCP server (that's handled directly by MCP authorization). Instead, it's used when the MCP server needs to obtain sensitive information or third-party authorization on behalf of the user. The MCP client's bearer token remains unchanged, and the client's only responsibility is to provide the user with context about the elicitation URL the server wants them to open. + +## Specification + +### Overview + +Elicitation is updated to support two modes: + +- **Form mode** (in-band): Servers can request structured data from users with optional JSON schemas to validate responses (no change here, other than adding a name to the existing capability) +- **URL mode** (out-of-band): Servers can direct users to external URLs for sensitive interactions that must not pass through the MCP client + +### Capabilities + +Clients that support elicitation **MUST** declare the `elicitation` capability during initialization: + +```json +{ + "capabilities": { + "elicitation": { + "form": {}, + "url": {} + } + } +} +``` + +For backwards compatibility, an empty capabilities object is equivalent to declaring support for `form` mode only: + +```jsonc +{ + "capabilities": { + "elicitation": {}, + }, +} +``` + +Clients declaring the `elicitation` capability **MUST** support at least one mode (`form` or `url`). + +### Form Elicitation Requests + +The only change from the existing specification is the addition of a `mode` field in the `elicitation/create` request: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "elicitation/create", + "params": { + "mode": "form", // New field + "message": "Please provide your GitHub username", + "requestedSchema": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "required": ["name"] + } + } +} +``` + +### URL Elicitation Requests + +URL elicitation requests **MUST** specify `mode: "url"` and include these parameters: + +| Name | Type | Description | +| --------------- | ------ | ------------------------------------------------------------------ | +| `url` | string | The URL that the user should navigate to. | +| `elicitationId` | string | A unique identifier for the elicitation. | +| `message` | string | A human-readable message explaining why the interaction is needed. | + +#### Example: OAuth Authorization Flow + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "method": "elicitation/create", + "params": { + "mode": "url", + "elicitationId": "550e8400-e29b-41d4-a716-446655440000", + "url": "https://github.com/login/oauth/authorize?client_id=abc123&state=xyz789&scope=repo", + "message": "Please authorize access to your GitHub repositories to continue." + } +} +``` + +#### Response Actions + +URL elicitation responses use the same three-action model as form elicitation: + +```json +{ + "jsonrpc": "2.0", + "id": 3, + "result": { + "action": "accept" // or "decline" or "cancel" + } +} +``` + +The response with `action: "accept"` indicates that the user has consented to the interaction. The interaction occurs out of band and the client is not aware of the outcome unless the server sends a completion notification. + +#### Completion Notifications + +Servers **SHOULD** send a `notifications/elicitation/complete` notification when an +out-of-band interaction started by URL mode elicitation is completed. This allows clients to react programmatically if appropriate. + +- The notification **MUST** only be sent to the client that initiated the elicitation request. +- The notification **MUST** include the `elicitationId` established in the original `elicitation/create` request. +- Clients **MUST** ignore notifications referencing unknown or already-completed IDs. +- If a completion notification never arrives, clients **SHOULD** provide a manual way for the user to continue the interaction. + +Clients **MAY** use the notification to automatically retry requests that received a URL elicitation required error, update the user interface, or otherwise continue an interaction. However, because delivery of the notification is not guaranteed, clients must not wait indefinitely for a notification from the server. + +```json +{ + "jsonrpc": "2.0", + "method": "notifications/elicitation/complete", + "params": { + "elicitationId": "550e8400-e29b-41d4-a716-446655440000" + } +} +``` + +#### URL Elicitation Required Error + +When a request cannot be processed until an elicitation is completed, the server **MAY** return a `URLElicitationRequiredError` (code `-32042`) to indicate that a URL mode elicitation is required. The server **MUST NOT** return this error except when URL mode elicitation is required by the user interaction. + +```json +{ + "jsonrpc": "2.0", + "id": 2, + "error": { + "code": -32042, + "message": "This request requires more information.", + "data": { + "elicitations": [ + { + "mode": "url", + "elicitationId": "550e8400-e29b-41d4-a716-446655440000", + "url": "https://oauth.example.com/authorize?client_id=abc123&response_type=code&...", + "message": "Authorization is required to access your Example Co files." + } + ] + } + } +} +``` + +Any elicitations returned in the error **MUST** be URL mode elicitations and include an `elicitationId`. + +Returning a `URLElicitationRequiredError` is equivalent to sending an `elicitation/create` request. The server may return an error (instead of sending a separate `elicitation/create` request) as an affordance to the client to make it clear that a particular elicitation is directly related to a failed client request. + +The client must treat `URLElicitationRequiredError` responses as equivalent to `elicitation/create` requests. Clients may automatically retry the failed request after the elicitation is completed successfully, for example after receiving a completion notification. + +## Rationale + +### Design Decisions + +**Why extend elicitation instead of creating a new mechanism?** + +Initially, we considered creating a separate mechanism for out-of-band interactions (discussed in #475). However, after discussions with the MCP maintainers, we decided to extend the existing elicitation specification because: + +1. Both mechanisms serve the same fundamental purpose: gathering information from users +2. Having two similar-but-separate mechanisms for the same purpose is confusing and error-prone +3. The `mode` parameter cleanly separates the two interaction patterns + +**Why can't the client perform the interaction itself?** + +It is tempting to suggest that the MCP client should perform the interaction itself, e.g. act as an OAuth client to a third-party authorization server. However, there are several reasons why this is not a good idea: + +- If the MCP client obtains user tokens from a third-party authorization server, the MCP server becomes a [token passthrough](https://modelcontextprotocol.io/specification/2025-06-18/basic/security_best_practices#token-passthrough) server, which is explicitly forbidden. +- Similarly, for payment-type flows, the MCP client would need to perform PCI-compliant payment processing, which is not a desired requirement for MCP clients. + +**Why doesn't the server block (wait) on the elicitation to complete?** + +URL mode elicitation requests are asynchronous or "disconnected" flows by design, because the kinds of interactions they enable are inherently asynchronous. Payment flows, external authorization, etc. can take minutes or more to complete, and in some cases never complete at all (if abandoned by the end-user). + +**Why disallow URLs in form mode?** + +Being very explicit about when URLs can (and cannot) be sent in an elicitation request improves the client's security posture. By clearly stating in the spec that URLs are _only_ allowed in the `url` field of a URL mode elicitation request, client implementers can implement UX patterns that are consistent with the security model. For example, a client could refuse to render a URL as a clickable hyperlink in a form mode elicitation request, reducing the likelihood of a user clicking on a malicious URL sent by a malicious server. + +### Alternative Approaches Considered + +1. **Token Passthrough**: Simply passing the MCP client's token to external services was rejected due to security concerns documented in the Security Best Practices. Having the MCP client obtain additional tokens and passing those to the MCP server was rejected for the same reason. + +2. **OAuth-specific Capability**: Creating a capability specific to external (3rd-party) authorization with OAuth was considered, but rejected in favor of the more general URL mode elicitation approach that supports multiple use cases. + +### Community Feedback + +This proposal incorporates extensive community feedback from discussions in #475, #234, and #284, as well as the #auth-wg working group on Discord. The community identified the need for: + +- Secure credential collection without client exposure +- External authorization patterns separate from MCP authorization +- Payment and subscription flow support +- Clear security boundaries and trust models + +## Backward Compatibility + +This SEP introduces the following breaking changes: + +1. **Capability Declaration**: Clients must now specify which elicitation modes they support: + + ```json + { + "capabilities": { + "elicitation": { + "form": {}, + "url": {} + } + } + } + ``` + + Previously, clients only declared `"elicitation": {}` without mode specification. + +2. **Mode Parameter**: All `elicitation/create` requests must now include a `mode` parameter (`"form"` or `"url"`). + +### Migration Path + +To ease migration: + +- Servers SHOULD check client capabilities before sending mode-specific requests +- Clients MAY initially support only form mode to maintain compatibility +- Existing form elicitation implementations continue to work with the addition of the mode parameter + +# Reference Implementation + +Client/server implementation in TypeScript: [feat/url-elicitation](https://github.com/modelcontextprotocol/typescript-sdk/compare/main...ArcadeAI:mcp-typescript-sdk:feat/url-elicitation) + +Explainer video: https://drive.google.com/file/d/1llCFS9wmkK_RUgi5B-zHfUUgy-CNb0n0/view?usp=sharing + +## Security Implications + +This SEP introduces several security considerations: + +### URL Security Requirements + +1. **SSRF Prevention**: Clients must validate URLs to prevent Server-Side Request Forgery attacks +2. **Protocol Restrictions**: Only HTTPS URLs are allowed for URL elicitation +3. **Domain Validation**: Clients must clearly display target domains to users + +### Trust Boundaries + +URL elicitation explicitly creates clear trust boundaries: + +- The MCP client never sees sensitive data obtained by the MCP server via URL elicitation +- The MCP server must independently verify user identity +- Third-party services interact directly with users through secure browser contexts + +### Identity Verification + +Servers must verify that the user completing a URL elicitation is the same user who initiated the request. Verifying the identity of the user must not rely on untrusted input (e.g. user input) from the client. + +### Implementation Requirements + +1. **Clients must**: + - Use secure browser contexts that prevent inspection of user inputs + - Validate URLs for SSRF protection + - Obtain explicit user consent before opening URLs + - Clearly display target domains + +2. **Servers must**: + - Bind elicitation state to authenticated user sessions + - Verify user identity at the beginning and end of a URL elicitation flow + - Implement appropriate rate limiting + +3. **Both parties should**: + - Log security events for audit purposes + - Implement timeout mechanisms for elicitation requests + - Provide clear error messages for security failures + +### Relationship to Existing Security Measures + +This proposal builds upon and complements existing MCP security measures: + +- Works within the existing MCP authorization framework (MCP authorization is not affected by this proposal) +- Follows Security Best Practices regarding token handling +- Maintains separation of concerns between client-server and server-third-party authorization diff --git a/seps/1046-support-oauth-client-credentials-flow-in-authoriza.md b/seps/1046-support-oauth-client-credentials-flow-in-authoriza.md new file mode 100644 index 000000000..4738ed1f1 --- /dev/null +++ b/seps/1046-support-oauth-client-credentials-flow-in-authoriza.md @@ -0,0 +1,48 @@ +# SEP-1046: Support OAuth client credentials flow in authorization + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-07-23 +- **Author(s)**: Darin McAdams (@D-McAdams ) +- **Issue**: #1046 + +### Preamble + +Title: Support OAuth client credentials flow in authorization +Author: Darin McAdams (@D-McAdams ) +Status: Proposal +Type: Standards Track +Created: 2025-07-23 + +### Abstract + +Recommends adding the OAuth client credentials flow to the authorization spec to enable machine-to-machine scenarios. + +### Motivation + +The original authorization spec mentioned the client credentials flow, but it was dropped in subsequent revisions. Therefore, the spec is currently silent on how to solve machine-to-machine scenarios where an end-user is unavailable for interactive authorization. + +### Specification + +The authorization spec would be amended to list the OAuth client credentials flow as being allowed. Adhering to the patterns established by OAuth 2.1, the specification would RECOMMEND the use of asymmetric methods defined in RFC 753 (JWT Assertions), but also allow client secrets. + +As guidance to implementors, the spec overview would also be updated to describe the different flows and when each is applicable. In addition, to address a common question, the spec would be updated to indicate that implementors may implement other authorization scenarios beyond what's defined; emphasizing that the specification defines the baseline requirements. + +### Rationale + +To maximize interoperability (and minimize SDK complexity), this change would intentionally constrain the client credentials flow to two options: + +1. JWT Assertions as per RFC 7523 (RECOMMENDED) +2. Client Secrets via HTTP Basic authentication (Allowed for maximum compatibility with existing systems) + +Other options, such as mTLS, are not included. + +While the spec encourages the use of RFC 7523 (JWT Assertions), it does not yet specify how to populate the JWT contents nor how to discover the client's JWKS URI to validate the JWT. In future iterations of the spec, it will be beneficial to do so. However, this was currently left unspecified pending maturity of other RFCs that can define these profiles. The other RFCs include [WIMSE Headless JWT Authentication](https://www.ietf.org/archive/id/draft-levy-wimse-headless-jwt-authentication-01.html) (for specifying JWT contents) and [Client ID Metadata](https://datatracker.ietf.org/doc/draft-parecki-oauth-client-id-metadata-document/) (for specifying the JWKS URI). This revision intentionally leaves extensibility for these future profiles. As a practical matter, this means implementers needing to ship solutions ASAP will most likely use client secrets which are widely supported today, whereas the JWT Assertion pattern represents the longer-term direction. + +### Backward Compatibility + +This change is fully backward compatible. It introduces a new authorization flow, but does not alter the existing flows. + +### Security Implications + +The specification refers to the existing OAuth security guidance. diff --git a/seps/1302-formalize-working-groups-and-interest-groups-in-mc.md b/seps/1302-formalize-working-groups-and-interest-groups-in-mc.md new file mode 100644 index 000000000..29ae4578d --- /dev/null +++ b/seps/1302-formalize-working-groups-and-interest-groups-in-mc.md @@ -0,0 +1,226 @@ +# SEP-1302: Formalize Working Groups and Interest Groups in MCP Governance + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-08-05 +- **Author(s)**: tadasant +- **Issue**: #1302 + +PR: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1350 + +## 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 + +## 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) diff --git a/seps/1303-input-validation-errors-as-tool-execution-errors.md b/seps/1303-input-validation-errors-as-tool-execution-errors.md new file mode 100644 index 000000000..93f9c0200 --- /dev/null +++ b/seps/1303-input-validation-errors-as-tool-execution-errors.md @@ -0,0 +1,178 @@ +# SEP-1303: Input Validation Errors as Tool Execution Errors + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-08-05 +- **Author(s)**: @fredericbarthelet +- **Issue**: #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 +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 +// 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 +// 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 diff --git a/seps/1319-decouple-request-payload-from-rpc-methods-definiti.md b/seps/1319-decouple-request-payload-from-rpc-methods-definiti.md new file mode 100644 index 000000000..83e8259a1 --- /dev/null +++ b/seps/1319-decouple-request-payload-from-rpc-methods-definiti.md @@ -0,0 +1,83 @@ +# SEP-1319: Decouple Request Payload from RPC Methods Definition + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-08-08 +- **Author(s)**: @kurtisvg +- **Issue**: #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 +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 +/** + * 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 +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. diff --git a/seps/1330-elicitation-enum-schema-improvements-and-standards.md b/seps/1330-elicitation-enum-schema-improvements-and-standards.md new file mode 100644 index 000000000..da7000c19 --- /dev/null +++ b/seps/1330-elicitation-enum-schema-improvements-and-standards.md @@ -0,0 +1,422 @@ +# SEP-1330: Elicitation Enum Schema Improvements and Standards Compliance + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-08-11 +- **Author(s)**: chughtapan +- **Issue**: #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 +Typescript SDK Changes: https://github.com/modelcontextprotocol/typescript-sdk/pull/1077 +Python SDK Changes: https://github.com/modelcontextprotocol/python-sdk/pull/1246 +**Client Implementation:** https://github.com/evalstate/fast-agent/pull/324/files +**Working Demo:** 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 +// 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 +// 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 +// 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 +// 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 +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 +{ + "type": "string", + "title": "Color Selection", + "description": "Choose your favorite color", + "enum": ["Red", "Green", "Blue"], + "default": "Green" +} +``` + +### Legacy Single Select With Titles + +```json +{ + "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 +{ + "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 +{ + "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 +{ + "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 + +## 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 +Typescript SDK Changes: https://github.com/modelcontextprotocol/typescript-sdk/pull/1077 +Python SDK Changes: https://github.com/modelcontextprotocol/python-sdk/pull/1246 +**Client Implementation:** https://github.com/evalstate/fast-agent/pull/324/files +**Working Demo:** 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/ 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) + +#### Multiple Selection + +- `EnumSchema` validating the [multi-select instance schema without titles](https://www.jsonschemavalidator.net/s/4uc3Ndsq) +- `EnumSchema` validating the [multi-select instance schema with titles](https://www.jsonschemavalidator.net/s/TmkIqqXI) +- The untitled multi-select instance schema validating [a correct multiple selection](https://www.jsonschemavalidator.net/s/IE8Bkvtg) + The untitled multi-select instance schema validating invalidating[ an incorrect multiple selection](https://www.jsonschemavalidator.net/s/8tlqjUgW) + The titled multi-select instance schema validating [a correct multiple selection](https://www.jsonschemavalidator.net/s/Nb1Rw1qa) + The titled multi-select instance schema validating invalidating [an incorrect multiple selection](https://www.jsonschemavalidator.net/s/MRfyqrVC) + +### JSON meta-schema + +This is our proposal for the replacement of the current `EnumSchema` in the specification’s `schema.json`. + +```json +{ + "$schema": "https://json-schema.org/draft-07/schema", + "definitions": { + // New Definitions Follow + "UntitledSingleSelectEnumSchema": { + "type": "object", + "properties": { + "type": { "const": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "enum": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + } + }, + "required": ["type", "enum"], + "additionalProperties": false + }, + + "UntitledMultiSelectEnumSchema": { + "type": "object", + "properties": { + "type": { "const": "array" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "minItems": { + "type": "number", + "minimum": 0 + }, + "maxItems": { + "type": "number", + "minimum": 0 + }, + "items": { + "type": "object", + "properties": { + "type": { "const": "string" }, + "enum": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + } + }, + "required": ["type", "enum"], + "additionalProperties": false + } + }, + "required": ["type", "items"], + "additionalProperties": false + }, + + "TitledSingleSelectEnumSchema": { + "type": "object", + "required": ["type", "anyOf"], + "properties": { + "type": { "const": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "anyOf": { + "type": "array", + "items": { + "type": "object", + "required": ["const", "title"], + "properties": { + "const": { "type": "string" }, + "title": { "type": "string" } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + + "TitledMultiSelectEnumSchema": { + "type": "object", + "required": ["type", "anyOf"], + "properties": { + "type": { "const": "array" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "anyOf": { + "type": "array", + "items": { + "type": "object", + "required": ["const", "title"], + "properties": { + "const": { "type": "string" }, + "title": { "type": "string" } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + + "LegacyEnumSchema": { + "properties": { + "type": { + "type": "string", + "const": "string" + }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "enum": { + "type": "array", + "items": { "type": "string" } + }, + "enumNames": { + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["enum", "type"], + "type": "object" + }, + + "EnumSchema": { + "oneOf": [ + { "$ref": "#/definitions/UntitledSingleSelectEnumSchema" }, + { "$ref": "#/definitions/UntitledMultiSelectEnumSchema" }, + { "$ref": "#/definitions/TitledSingleSelectEnumSchema" }, + { "$ref": "#/definitions/TitledMultiSelectEnumSchema" }, + { "$ref": "#/definitions/LegacyEnumSchema" } + ] + } + } +} +``` diff --git a/seps/1577--sampling-with-tools.md b/seps/1577--sampling-with-tools.md new file mode 100644 index 000000000..6390a7eba --- /dev/null +++ b/seps/1577--sampling-with-tools.md @@ -0,0 +1,400 @@ +# SEP-1577: Sampling With Tools + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-09-30 +- **Author(s)**: Olivier Chafik (@ochafik) +- **Issue**: #1577 + +| SEP Number | #1577 | +| ----------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| **Title** | Sampling With Tools | +| **Author** | Olivier Chafik | +| **Sponsor** | @bhosmer-ant | +| **Status** | Draft | +| **Created** | 2025-09-29 | +| **Specification** | MCP 2025-06-18 | +| **Prototype** | https://github.com/modelcontextprotocol/typescript-sdk/pull/991 | +| **PR** | https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1796 | +| **SDKs** | https://github.com/modelcontextprotocol/python-sdk/pull/1594 https://github.com/modelcontextprotocol/typescript-sdk/pull/1101 | + +**Updates**: + +- _Oct 1_: renamed `tool_choice` -> `toolChoice` (+ `"none"` value); removed exotic `stopReason`s `"refusal" & "other"`; allowed `{CreateMessageResult,SamplingMessage}.content` to be single contents or arrays of contents; +- _Oct 6_: aligned `ToolResultContent` on `CallToolResult` (support image / audio); added "Possible Follow Ups" section. +- _Oct 10_: updated reference impl example w/ simple tool registry (unify mcp tools w/ tool loop tools, see [comment below](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1577#issuecomment-3389273471)) and a "choose your own adventure" game that uses sampling w/ tools + elicitation. +- _Oct 27_: aligned `ToolResultContent.content` on `CallToolResult.content` (using [ContentBlock](https://modelcontextprotocol.io/specification/2025-06-18/schema#contentblock)); added `ToolResultContent._meta` +- _Nov 5_: + - kept `stopReason` as open string but w/ redundant explicit enums for visibility + - removed requirement to throw when `includeContext` not matching advertised `ClientCapabilities.sampling.context` + - mitigates backwards compatibility issue of `CreateMessageResult.content` being an array of contents OR a single content by saying sampling _MUST NOT_ return an array in earlier spec versions (+ ackowledging SDK updates of code w/ sampling will need small code changes) +- _Nov 7_: renamed type `ToolCallContent` to `ToolUseContent` (to match its `tool_use` type & the `toolUse` `stopReason`). SEP was approved! +- _Nov 10_: removing `disable_parallel_tool_use` / keeping for a later update as the Gemini API has no way to implement this for now. +- _Nov 11_: added extra notes about Gemini API's function calling modes & roles; requiring SamplingMessage w/ tool result contents not be mixed w/ other content types + +## 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 + 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 + 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 + /* + 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 + [ + { 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 + [ + { + "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 + /* + 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 + +Theses 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 + +Two bits needed here: + +- Introduce cache awareness + - Implicit caching guidelines phrased as SHOULDs + - Explicit cache points and TTL semantics [as in the Claude API](https://docs.claude.com/en/docs/build-with-claude/prompt-caching)? (incl. beta behaviour for longer caching) + - Pros: easy to implement _for at least 1 implementor (Anthropic)_ + - Cons: if hard to implement for others, unlikely to get approval. + - “Whole prompt” / prompt-prefix cache w/ an explicit key [as in the OpenAI API](https://platform.openai.com/docs/api-reference/responses/create#responses-create-prompt_cache_key)? + - Pros: + - simpler for users (no need to think about where the shared prefix stops) + - implicitly supports updating the cache (maybe even as subtree) + - Cons: possibly harder to implement / more storage inefficient +- Introduce allowed_tools feature to enable / disable tools w/o breaking context caching + - Relevant to this SEP as we may want to merge this feature [under the tool_choice field, similar to what OpenAI did](https://platform.openai.com/docs/guides/function-calling). + + ```typescript + interface ToolChoice { // NEW + mode?: “auto” | "required"; + allowed_tools?: string[] + } + ``` + +### Allow client to call the server’s tools by itself in an agentic loop + +From the server’s perspective, that would remove the need to call tools by itself / inject tool results in follow up sampling calls. + +The MCP server would just allowlist its own tools in the sampling request, w/t a dedicated tool definition such as: + +```typescript +{ + type: "server-tool"; // MCP tool from same server. + name: string; +} +``` + +Pros: + +- Safe, limited to that server’s tools. +- If we propagate the mcp-session-id, can leverage keep any server-side session context / caching + +### Allow client to call any other MCP servers’ tools by itself in an agentic loop + +Although this sounds similar to the previous one (allow only same server’s tools), this option wouldn’t need a protocol change / could be entirely done by the client as an implementation detail of their sampling support. + +The end user would allowlist tools from any other MCP server for use in a sampling request, without the server having to ask for anything. The client UI would e.g. display a tool selection UI as part of the sampling approval flow, auto enabling tools from same server by default. + +Pros: + +- Technically no spec change needed (if anything, mention this as a freedom clients have) +- Possibly similar to what [CreateMessageRequest.params.includeContext](https://modelcontextprotocol.io/specification/2025-06-18/schema#createmessagerequest) = thisServer / allServers intended semantics may have meant + - `CreateMessageRequest.params.allowImplicitToolCalls = “none” | “thisServer” | “allServers”` + (assuming we wanted to give the server any control over this) + +Cons: + +- Classifier might be needed to avoid High potential for privacy leaks / abuse + - If user approves Gmail MCP tool usage / delegation by mistake, server gets access to their private emails through sampling + +### Allow server to list & call clients’ tools (client/server → p2p) + +If we say the client can now expose tools that the server can call, it opens a set of possibilities: + +- The client can “forward” other servers’ tools (maybe w/ some namespacing for seamless aggregation) + - The server can then call these tools as part of its tool loop. +- Client & Server semantics start to lose weight, we enter a more peer-to-peer, symmetrical relationship + - Client could also ask a server for sampling, while we’re at it + - Symmetry at the protocol layer, but still directionality at the transport layer (e.g. for HTTP transport, direction of POST requests still matters) + +### Simplify structured outputs use case + +A major use case of sampling is to get outputs that conform to a given schema. + +This is possible in [OpenAI’s API](https://platform.openai.com/docs/guides/structured-outputs) for instance. + +The most common workaround is to give a single tool and set `tool_choice: "required"`, which guarantees the output is a ToolCall containing inputs that conform to the tool’s input schema. + +While this SEP proposes we enable this `"required"`-based workaround, as a follow up it would be great to provide more explicit / simpler JSON schema support, which would also allow schema types not allowed in tool inputs (which require an object w/ properties, so one has to pick at least a name for their outputs, which requires thinking / interplay w/ the prompting strategy): + +```typescript +interface CreateMessageRequest { +  method: “sampling/createMessage”; +  params: { +    messages: SamplingMessage[]; + ... + format: { + type: "json_schema", + "schema": { + "type": "array", + "minItems": 5, + "maxItems": 100 + } + } + } +``` diff --git a/seps/1613-establish-json-schema-2020-12-as-default-dialect-f.md b/seps/1613-establish-json-schema-2020-12-as-default-dialect-f.md new file mode 100644 index 000000000..cc96b7e72 --- /dev/null +++ b/seps/1613-establish-json-schema-2020-12-as-default-dialect-f.md @@ -0,0 +1,171 @@ +# SEP-1613: Establish JSON Schema 2020-12 as Default Dialect for MCP + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-10-06 +- **Author(s)**: Ola Hungerford +- **Issue**: #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 +{ + "$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 +{ + "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. diff --git a/seps/1686-tasks.md b/seps/1686-tasks.md new file mode 100644 index 000000000..62bd93283 --- /dev/null +++ b/seps/1686-tasks.md @@ -0,0 +1,1083 @@ +# SEP-1686: Tasks + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-10-20 +- **Author(s)**: Surbhi Bansal, Luca Chang +- **Issue**: #1686 + +## Abstract + +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 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 +{ + "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 +{ + "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 +{ + "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 +{ + "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 +{ + "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 +{ + "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 +{ + "jsonrpc": "2.0", + "id": 5, + "method": "tasks/list", + "params": { + "cursor": "optional-cursor-value" + } +} +``` + +**Response:** + +```json +{ + "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" + } +} +``` + +#### 3.6 Deleting Tasks + +To explicitly delete a task and its associated results, requestors send a `tasks/delete` request. + +**Request:** + +```json +{ + "jsonrpc": "2.0", + "id": 6, + "method": "tasks/delete", + "params": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", + "_meta": { + "modelcontextprotocol.io/related-task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840" + } + } + } +} +``` + +**Response:** + +```json +{ + "jsonrpc": "2.0", + "id": 6, + "result": { + "_meta": { + "modelcontextprotocol.io/related-task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840" + } + } + } +} +``` + +### 4. Behavior Requirements + +These requirements apply to all parties that support receiving task-augmented requests. + +#### 4.1. Task Support and Handling + +1. Receivers that do not support task augmentation on a request **MUST** process the request normally, ignoring any task metadata in `_meta`. +2. Receivers that support task augmentation **MAY** choose which request types support tasks. + +#### 4.2. Task ID Requirements + +1. Task IDs **MUST** be a string value. +2. Task IDs **SHOULD** be unique across all tasks controlled by the receiver. +3. The receiver of a request with a task ID in its `_meta` **MAY** validate that the provided task ID has not already been associated with a task controlled by that receiver. + +#### 4.3. Task Status Lifecycle + +1. Tasks **MUST** begin in the `submitted` status when created. +2. Receivers **MUST** only transition tasks through the following valid paths: + 1. From `submitted`: may move to `working`, `input_required`, `completed`, `failed`, `cancelled`, or `unknown` + 2. From `working`: may move to `input_required`, `completed`, `failed`, `cancelled`, or `unknown` + 3. From `input_required`: may move to `working`, `completed`, `failed`, `cancelled`, or `unknown` + 4. Tasks in `completed`, `failed`, `cancelled`, or `unknown` status **MUST NOT** transition to any other status (terminal states) +3. Receivers **MAY** move directly from `submitted` to `completed` if execution completes immediately. +4. The `unknown` status is a terminal fallback state for unexpected error conditions. Receivers **SHOULD** use `failed` with an error message instead when possible. + +**Task Status State Diagram:** + +```mermaid +stateDiagram-v2 + [*] --> submitted + + submitted --> working + submitted --> terminal + + working --> input_required + working --> terminal + + input_required --> working + input_required --> terminal + + terminal --> [*] + + note right of terminal + Terminal states: + • completed + • failed + • cancelled + • unknown + end note +``` + +#### 4.4. Input Required Status + +1. When a receiver sends a request associated with a task (e.g., elicitation, sampling), the receiver **MUST** move the task to the `input_required` status. +2. The receiver **MUST** include the `modelcontextprotocol.io/related-task` metadata in the request to associate it with the task. +3. When the receiver receives all required responses, the task **MAY** transition out of `input_required` status (typically back to `working`). +4. If multiple related requests are pending, the task **SHOULD** remain in `input_required` status until all are resolved. + +#### 4.5. Keep-Alive and Resource Management + +1. Receivers **MAY** override the requested `keepAlive` duration. +2. Receivers **MUST** include the actual `keepAlive` duration (or `null` for unlimited) in `tasks/get` responses. +3. After a task reaches a terminal status (`completed`, `failed`, or `cancelled`) and its `keepAlive` duration has elapsed, receivers **MAY** delete the task and its results. +4. Receivers **MAY** include a `pollFrequency` value (in milliseconds) in `tasks/get` responses to suggest polling intervals. Requestors **SHOULD** respect this value when provided. + +#### 4.6. Result Retrieval + +1. Receivers **MUST** only return results from `tasks/result` when the task status is `completed`. +2. Receivers **MUST** return an error if `tasks/result` is called for a task in any other status. +3. Requestors **MAY** call `tasks/result` multiple times for the same task while it remains available. + +#### 4.7. Associating Task-Related Messages + +1. All requests, notifications, and responses related to a task **MUST** include the `modelcontextprotocol.io/related-task` key in their `_meta`, with the value set to an object with a `taskId` matching the associated task ID. +2. For example, an elicitation that a task-augmented tool call depends on **MUST** share the same related task ID with that tool call's task. + +#### 4.8. Task Cancellation + +1. When a receiver receives a `notifications/cancelled` notification for the JSON-RPC request ID of a task-augmented request, the receiver **SHOULD** immediately move the task to the `cancelled` status and cease all processing associated with that task. +2. Due to the asynchronous nature of notifications, receivers **MAY** not cancel task processing instantaneously. Receivers **SHOULD** make a best-effort attempt to halt execution as quickly as possible. +3. If a `notifications/cancelled` notification arrives after a task has already reached a terminal status (`completed`, `failed`, `cancelled`, or `unknown`), receivers **SHOULD** ignore the notification. +4. After a task reaches `cancelled` status and its `keepAlive` duration has elapsed, receivers **MAY** delete the task and its metadata. +5. Requestors **MAY** send `notifications/cancelled` at any time during task execution, including when the task is in `input_required` status. If a task is cancelled while in `input_required` status, receivers **SHOULD** also disregard any pending responses to associated requests. +6. Because notifications do not provide confirmation of receipt, requestors **SHOULD** continue to poll with `tasks/get` after sending a cancellation notification to confirm the task has transitioned to `cancelled` status. If the task does not transition to `cancelled` within a reasonable timeframe, requestors **MAY** assume the cancellation was not processed. + +#### 4.9. Task Listing + +1. Receivers **SHOULD** use cursor-based pagination to limit the number of tasks returned in a single response. +2. Receivers **MUST** include a `nextCursor` in the response if more tasks are available. +3. Requestors **MUST** treat cursors as opaque tokens and not attempt to parse or modify them. +4. If a task is retrievable via `tasks/get` for a requestor, it **MUST** be retrievable via `tasks/list` for that requestor. + +#### 4.10 Task Deletion + +1. Receivers **MAY** accept or reject delete requests for any task at their discretion. +1. If a receiver accepts a delete request, it **SHOULD** delete the task and all associated results and metadata. +1. Receivers **MAY** choose not to support deletion at all, or only support deletion for tasks in certain statuses (e.g., only terminal statuses). +1. Requestors **SHOULD** delete tasks containing sensitive data promptly rather than relying solely on `keepAlive` expiration for cleanup. + +### 5. Message Flow + +https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1686#issuecomment-3452378176 + +### 6. Data Types + +#### Task + +A task represents the execution state of a request. The task metadata includes: + +- `taskId`: Unique identifier for the task +- `keepAlive`: Time in milliseconds that results will be kept available after completion +- `pollFrequency`: Suggested time in milliseconds between status checks +- `status`: Current state of the task execution + +#### Task Status + +Tasks can be in one of the following states: + +- `submitted`: The request has been received and queued for execution +- `working`: The request is currently being processed +- `input_required`: The request is waiting on additional input from the requestor +- `completed`: The request completed successfully and results are available +- `failed`: The task lifecycle itself encountered an error, unrelated to the associated request logic +- `cancelled`: The request was cancelled before completion +- `unknown`: A terminal fallback state for unexpected error conditions when the receiver cannot determine the actual task state + +#### Task Metadata + +When augmenting a request with task execution, the `modelcontextprotocol.io/task` key is included in `_meta`: + +```json +{ + "modelcontextprotocol.io/task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", + "keepAlive": 60000 + } +} +``` + +Fields: + +- `taskId` (string, required): Client-generated unique identifier for the task +- `keepAlive` (number, optional): Requested duration in milliseconds to retain results after completion + +#### Task Creation Notification + +When a receiver creates a task, it sends a `notifications/tasks/created` notification to signal that the task is ready for polling. The notification has empty params, with the task ID conveyed through the `modelcontextprotocol.io/related-task` metadata key: + +```json +{ + "jsonrpc": "2.0", + "method": "notifications/tasks/created", + "params": { + "_meta": { + "modelcontextprotocol.io/related-task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840" + } + } + } +} +``` + +This notification enables requestors to begin polling without encountering race conditions where the task might not yet exist on the receiver. + +#### Task Get Request + +The `tasks/get` request retrieves the current state of a task: + +```typescript +{ + taskId: string; // The task identifier to query +} +``` + +#### Task Get Response + +The `tasks/get` response includes: + +```typescript +{ + taskId: string; // The task identifier + status: TaskStatus; // Current task state + keepAlive: number | null; // Actual retention duration in milliseconds, null for unlimited + pollFrequency?: number; // Suggested polling interval in milliseconds + error?: string; // Error message if status is "failed" +} +``` + +#### Task Result Request + +The `tasks/result` request retrieves the result of a completed task: + +```typescript +{ + taskId: string; // The task identifier to retrieve results for +} +``` + +#### Task Result Response + +The `tasks/result` response returns the original result that would have been returned by the request: + +```typescript +{ + // The structure matches the result type of the original request + // For example, a tools/call task would return CallToolResult structure + [key: string]: unknown; +} +``` + +The result structure depends on the original request type. The receiver returns the same result structure that would have been returned if the request had been executed without task augmentation. + +#### Task List Request + +The `tasks/list` request retrieves a list of tasks: + +```typescript +{ + cursor?: string; // Optional cursor for pagination +} +``` + +#### Task List Response + +The `tasks/list` response includes: + +```typescript +{ + tasks: Array<{ + taskId: string; // The task identifier + status: TaskStatus; // Current task state + keepAlive: number | null; // Retention duration in milliseconds, null for unlimited + pollFrequency?: number; // Suggested polling interval in milliseconds + error?: string; // Error message if status is "failed" + }>; + nextCursor?: string; // Cursor for next page, absent if no more results +} +``` + +#### Related Task Metadata + +All requests, responses, and notifications associated with a task **MUST** include the `modelcontextprotocol.io/related-task` key in `_meta`: + +```json +{ + "modelcontextprotocol.io/related-task": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840" + } +} +``` + +This associates messages with their originating task across the entire request lifecycle. + +### 7. Error Handling + +Tasks use two error reporting mechanisms: + +1. **Protocol Errors**: Standard JSON-RPC errors for protocol-level issues +2. **Task Execution Errors**: Errors in the underlying request execution, reported through task status + +#### 7.1. Protocol Errors + +Receivers **MUST** return standard JSON-RPC errors for the following protocol error cases: + +- Invalid or nonexistent `taskId` in `tasks/get`, `tasks/list`, or `tasks/result`: `-32602` (Invalid params) +- Invalid or nonexistent cursor in `tasks/list`: `-32602` (Invalid params) +- Request with a `taskId` that was already used for a different task (if the receiver validates task ID uniqueness): `-32602` (Invalid params) +- Attempting to retrieve result when task is not in `completed` status: `-32602` (Invalid params) +- Internal errors: `-32603` (Internal error) + +Receivers **SHOULD** provide informative error messages to describe the cause of errors. + +**Example: Task not found** + +```json +{ + "jsonrpc": "2.0", + "id": 70, + "error": { + "code": -32602, + "message": "Failed to retrieve task: Task not found" + } +} +``` + +**Example: Task expired** + +```json +{ + "jsonrpc": "2.0", + "id": 71, + "error": { + "code": -32602, + "message": "Failed to retrieve task: Task has expired" + } +} +``` + +> NOTE: Receivers are not obligated to retain task metadata indefinitely. It is compliant behavior for a receiver to return a "not-found" error if it has purged an expired task. + +**Example: Result requested for incomplete task** + +```json +{ + "jsonrpc": "2.0", + "id": 72, + "error": { + "code": -32602, + "message": "Cannot retrieve result: Task status is 'working', not 'completed'" + } +} +``` + +**Example: Duplicate task ID (if receiver validates uniqueness)** + +```json +{ + "jsonrpc": "2.0", + "id": 73, + "error": { + "code": -32602, + "message": "Task ID already exists: 786512e2-9e0d-44bd-8f29-789f320fe840" + } +} +``` + +#### 7.2. Task Execution Errors + +When the underlying request fails during execution, the task moves to the `failed` status. The `tasks/get` response **SHOULD** include an `error` field with details about the failure: + +```typescript +{ + taskId: string; + status: "failed"; + keepAlive: number | null; + pollFrequency?: number; + error?: string; // Description of what went wrong +} +``` + +**Example: Task with execution error** + +```json +{ + "jsonrpc": "2.0", + "id": 4, + "result": { + "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840", + "status": "failed", + "keepAlive": 30000, + "error": "Tool execution failed: API rate limit exceeded" + } +} +``` + +For tasks that wrap requests with their own error semantics (like `tools/call` with `isError: true`), the task should still reach `completed` status, and the error information is conveyed through the result structure of the original request type. + +### 8. Security Considerations + +#### 8.1. Task Isolation and Access Control + +1. Receivers **SHOULD** scope task IDs to prevent unauthorized access: + 1. Bind tasks to the session that created them (if sessions are supported) + 2. Bind tasks to the authentication context (if authentication is used) + 3. Reject `tasks/get`, `tasks/list`, or `tasks/result` requests for tasks from different sessions or auth contexts +2. Receivers that do not implement session or authentication binding **SHOULD** document this limitation clearly, as task results may be accessible to any requestor that can guess the task ID. +3. Receivers **SHOULD** implement rate limiting on: + 1. Task creation to prevent resource exhaustion + 2. Task status polling to prevent denial of service + 3. Task result retrieval attempts + 4. Task listing requests to prevent denial of service + +#### 8.2. Resource Management + +> WARNING: Task results may persist longer than the original request execution time. For sensitive operations, requestors should carefully consider the security implications of extended result retention and may want to retrieve results promptly and request shorter `keepAlive` durations. + +1. Receivers **SHOULD**: + 1. Enforce limits on concurrent tasks per requestor + 2. Enforce maximum `keepAlive` durations to prevent indefinite resource retention + 3. Clean up expired tasks promptly to free resources +2. Receivers **SHOULD**: + 1. Document maximum supported `keepAlive` duration + 2. Document maximum concurrent tasks per requestor + 3. Implement monitoring and alerting for resource usage + +#### 8.3. Audit and Logging + +1. Receivers **SHOULD**: + 1. Log task creation, completion, and retrieval events for audit purposes + 2. Include session/auth context in logs when available + 3. Monitor for suspicious patterns (e.g., many failed task lookups, excessive polling) +2. Requestors **SHOULD**: + 1. Log task lifecycle events for debugging and audit purposes + 2. Track task IDs and their associated operations + +## Rationale + +### Design Decision: Generic Task Primitive + +The decision to implement tasks as a generic request augmentation mechanism (rather than tool-specific or method-specific) was made to maximize protocol simplicity and flexibility. + +Tasks are designed to work with any request type in the MCP protocol, not just tool calls. This means that `resources/read`, `prompts/get`, `sampling/createMessage`, and any future request types can all be augmented with task metadata. This approach provides significant benefits over a tool-specific design. + +From a protocol perspective, this design eliminates the need for separate task implementations per request type. Instead of defining different async patterns for tools versus resources versus prompts, a single set of task management methods (`tasks/get` and `tasks/result`) works uniformly across all request types. This uniformity reduces cognitive load for implementers and creates a consistent experience for applications using the protocol. + +The generic design also provides implementation flexibility. Servers can choose which requests support task augmentation without requiring protocol changes or version negotiation. If a server doesn't support tasks for a particular request type, it simply ignores the task metadata and processes the request normally. This allows servers to add task support to requests incrementally, starting with high-value operations and expanding over time based on actual usage patterns. + +Architecturally, tasks are treated as metadata rather than a separate execution model. They augment existing requests rather than replacing them. The original request/response flow remains intact—the request still gets a response eventually. Tasks simply provide an additional polling-based mechanism for result retrieval. This design ensures that related messages (such as elicitations during task execution) can be associated consistently via the `modelcontextprotocol.io/related-task` metadata key, regardless of the underlying request type. + +### Design Decision: Metadata-Based Augmentation + +Using `_meta` for task information rather than dedicated request parameters was chosen to maintain a clear separation of concerns between request semantics and execution tracking. + +Task information is fundamentally orthogonal to request semantics. The task ID and keepAlive duration don't affect what the request does—they only affect how the result is retrieved and retained. A `tools/call` request performs the same operation whether or not it includes task metadata. The task metadata simply provides an alternative mechanism for accessing the result. + +By placing task information in `_meta`, we create a clear architectural boundary between "what to execute" (request parameters) and "how to track execution" (task metadata). This boundary makes it easier for implementers to reason about the protocol. Request parameters define the operation being performed, while metadata provides orthogonal concerns like progress tracking, task management, and other execution-related information. + +This approach also provides natural backward compatibility. Servers that don't support tasks can ignore the `_meta` content without breaking request processing. The request parameters remain valid and complete, so the operation can proceed normally. This means no protocol version negotiation is required—the new functionality is purely additive and non-disruptive. + +SDKs can provide ergonomic abstractions over the task primitive while maintaining the separation of concerns, for example: + +```typescript +// === MCP SDK (Pseudocode based loosely on modelcontextprotocol/typescript-sdk) === + +/** + * NEW: A request that resolves to a result, either directly or by polling a task. + */ +class PendingRequest { + constructor(readonly protocol: Protocol, readonly result: Promise, readonly taskId?: string) {} + + /** + * Waits for a result, calling onTaskStatus if provided and a task was created. + */ + async result({ onTaskStatus }): Promise => { + if (!onTaskStatus || !this.taskId) { + // No task listener or task ID provided, just block for the result + return await result; + } + + // Whichever is successful first (or a failure if all fail) is returned. + return Promise.any([ + result, // Blocks for result + (async () => { + // Blocks for a notifications/tasks/created with the provided task ID + await this.protocol.waitForTask(this.taskId); + return await taskHandler(this.taskId); + })(), + ]); + } + + /** + * Encapsulates polling for a result, calling onTaskStatus after querying the task. + */ + private async taskHandler({ onTaskStatus }): Promise => { + // Poll for completion + let task: Task; + do { + task = await this.protocol.getTask(this.taskId); + await onTaskStatus(task); + await sleep(task.pollFrequency ?? DEFAULT_POLLING_INTERNAL); + } while (!task.isTerminal()); + + // Process result + return await this.protocol.getTaskResult(this.taskId); + } +} + +/** + * Simplified/partial client session implementation for illustration purposes. + * Extends a base class it shares with the server. + */ +class Client extends Protocol { + /** + * Existing request method, but with most implementation refactored to beginCallTool + */ + async callTool( + params: CallToolRequest['params'], + resultSchema: Schema, + ) { + // Existing request methods can be changed to reuse new methods exposed for + // separating request/response flows. + const request = await this.beginCallTool(params, resultSchema); + return request.result(); + } + + /** + * NEW: Low-level method that starts a tool call and returns a PendingRequest + * object for more granular control. + */ + async beginCallTool( + params: CallToolRequest['params'], + resultSchema: Schema, + ) { + const request = await this.beginRequest({ method: 'tools/call', params }, resultSchema, options); + return request; + } +} + +// === HOST APPLICATION === + +// Begin a tool call with task support +const pending: PendingRequest = await client.beginCallTool( + { + name: "analyze_dataset", + arguments: { dataset: "large_file.csv" }, + }, + CallToolResultSchema, + { + keepAlive: 3600000, + }, +); + +// Client code can assume tasks are supported, and the fallback case can be handled internally +const result = await pending.result({ + onTaskStatus: async (task) => { + await sendLatestStateSomewhere(task); + }, +}); +``` + +As the design does not alter the basic request semantics, the existing form would continue to work as well: + +```typescript +const result = await client.callTool( + { + name: "analyze_dataset", + arguments: { dataset: "large_file.csv" }, + }, + CallToolResultSchema, +); +``` + +### Design Decision: Client-Generated Task IDs + +The choice to have clients generate task IDs rather than having servers assign them provides several critical benefits: + +**Idempotency and Fault Tolerance:** +The primary benefit is enabling idempotent task creation. When a client generates the task ID, it can safely retry a task-augmented request if it doesn't receive a response, knowing that the server will recognize the duplicate task ID and return an error. This is essential for reliable operation over unreliable networks: + +- If a request times out, the client can safely retry without creating duplicate tasks +- If a connection drops before the response arrives, the client can reconnect and retry +- The server validates task ID uniqueness and returns an error for duplicates, confirming whether the task was created + +With server-generated task IDs, a timeout or connection failure creates uncertainty—the client doesn't know whether the task was created, and has no safe way to retry without potentially creating duplicate tasks. + +**Simplicity for Clients:** +Client-generated task IDs simplify the client's implementation by eliminating the need to correlate the initial response with a task identifier. The client can immediately begin polling for task status using the task ID it generated, without needing to parse the response to extract a server-assigned identifier. This is particularly valuable for asynchronous programming models where the client may want to store the task ID before the response arrives. + +**Trade-offs for Servers:** +The main trade-off is that servers wrapping existing workflow systems with their own task identifiers will generally handle this by maintaining a mapping between the client-provided task IDs and the underlying system's identifiers. For example, an MCP server wrapping AWS Step Functions might receive a client-generated task ID like `"client-abc-123"` and need to track that it corresponds to Step Functions execution ARN `"arn:aws:states:...:exec-xyz"`. + +This requires: + +- Persistent storage for the task ID mapping (typically a simple key-value store) +- Maintaining the mapping for the task's keepAlive duration +- Handling mapping lookups for task status and result retrieval + +However, this complexity is typically minor compared to the overall work of integrating an existing workflow system into MCP. Most workflow systems already require state management for tracking execution, and maintaining a task ID mapping is a straightforward addition. The mapping structure is simple (client task ID maps to an internal identifier), and can be implemented using existing databases or key-value stores such a server likely already uses for other state management. + +### Design Decision: Task Creation Notification + +The decision to use a `notifications/tasks/created` notification rather than altering the response semantics (as #1391 proposed) acknowledges the asynchronous nature of task creation and enables efficient race patterns between task-based polling and traditional request/response flows. + +When a server creates a task, it must signal to the client that the task is ready for polling. There are at least two possible approaches: (1) the initial request could return synchronously with task metadata, or (2) the server could send a notification. This proposal uses notifications for several key reasons: + +1. Notifications enable fire-and-forget request processing. The server can accept the request, begin processing it, and send the notification once the task is created, without needing to block the initial request/response cycle. This is particularly important for servers that dispatch work to background systems or queues—they can acknowledge the request immediately and send the notification once the background system confirms task creation. +2. Notifications support the race pattern that enables graceful degradation. Clients can race between waiting for the original request's response and waiting for the `notifications/tasks/created` notification. If the server doesn't support tasks, no notification arrives and the original response wins. If the server does support tasks, the notification typically arrives first (or approximately simultaneously), enabling polling to begin. A synchronous response would force clients to wait for the response before knowing whether to poll or not. +3. Notifications avoid ambiguity with existing protocol semantics. If the initial request response included task metadata and the client then polled for results, it would change the implied meaning of existing notification types: + 1. **Progress notifications**: The current MCP specification requires that progress notifications reference tokens that "are associated with an in-progress operation." While "operation" is not formally defined, the implied understanding is that an operation is bounded by a request/response pair—progress notifications stop when the response is sent. With a synchronous response containing task metadata, progress notifications would need to continue while the task executes, expanding the implied meaning of "operation" to include asynchronous tasks that outlive the original request/response cycle. The notification-based approach avoids this semantic expansion by keeping progress notifications tied to the initial request's lifecycle, while future task-based progress can be cleanly associated via `modelcontextprotocol.io/related-task` metadata. We recommend that a future SEP clarify the definition of "operation" in the progress specification. + 2. **Cancellation semantics**: With the notification-based approach, `notifications/cancelled` clearly targets the original request ID and causes the associated task to move to `cancelled` status, maintaining a clean separation between request cancellation and task lifecycle management. + +While the notification is required by the specification for servers that create tasks, there are edge cases where it may be unavailable: + +- **sHTTP without stream support**: In environments where either the client or the server does not support SSE streams, notifications cannot be delivered. In such cases, clients may choose to proactively poll with `tasks/get` using exponential backoff, though this is nonstandard and may result in unnecessary polling attempts if the server doesn't support tasks. +- **Degraded connection scenarios**: If the notification is lost in transit, clients should implement reasonable timeout behavior and fall back to the original response. + +The standard and recommended approach is to wait for the `notifications/tasks/created` notification before beginning polling. Proactive polling without waiting for the notification should be considered a fallback mechanism for constrained environments only. + +### Design Decision: No Capabilities Declaration + +Unlike other protocol features such as tools, resources, and prompts, tasks do not require capability negotiation. This decision was made to enable graceful degradation and per-request flexibility. + +Task support can be determined implicitly through usage rather than explicitly through capability declarations. When a client sends a task-augmented request, the server will process it according to its capabilities. If the server doesn't support tasks for that request type, it simply ignores the task metadata and returns the result normally through the original request/response flow. The client can then detect the lack of task support by attempting to call `tasks/get` and handling any errors that result. + +This approach eliminates the need for complex handshakes or feature detection protocols. Clients can optimistically try task augmentation and gracefully fall back to direct response handling if needed. This makes the protocol more resilient and easier to implement. + +Additionally, this design provides per-request flexibility that would be difficult to express through capabilities. A server might support tasks on some request types but not others, or support might vary based on runtime conditions such as resource availability or load. Requiring granular capability declarations per request type would significantly complicate the protocol without providing substantial benefits. The implicit detection model is simpler and more flexible. + +### Alternative Designs Considered + +**Tool-Specific Async Execution:** +An earlier version of this proposal (#1391) focused specifically on tool calls, introducing an `invocationMode` field on tool definitions to mark tools as supporting synchronous, asynchronous, or both execution modes. This approach would have added dedicated fields to the tool call request and response structures, with server-side capability declarations to indicate support for async tool execution. + +While this design would have addressed the immediate need for long-running tool calls, it was rejected in favor of the more general task primitive for several reasons. First, it artificially limited the async execution pattern to tools when other request types have similar needs. Resources can be expensive to read, prompts can require complex processing, and sampling requests may involve lengthy user interactions. Creating separate async patterns for each request type would lead to protocol fragmentation and inconsistent implementation patterns. + +Second, the tool-specific approach required more complex capability negotiation and version handling. Servers would need to filter tool lists based on client capabilities, and SDKs would need to manage different invocation patterns for sync versus async tools. This complexity would ripple through every layer of the implementation stack. + +Finally, the tool-specific design didn't address the broader architectural need for deferred result retrieval across all MCP request types. By generalizing to a task primitive that augments any request, this proposal provides a consistent pattern that can be applied uniformly across the protocol. More importantly, this foundation is extensible to future protocol messages and features such as subtasks, making it a more appropriate building block for the protocol's evolution. + +**Transport-Layer Solutions:** +An alternative approach would be to solve for this purely at the transport layer, without introducing a new data-layer primitive. Several proposals (#1335, #1442, #1597) address transport-specific concerns such as connection resilience, request retry semantics, and stream management for sHTTP. These are valuable improvements that can mitigate many scaling and reliability challenges associated with requests that may take extended time to complete. + +However, transport-layer solutions alone are insufficient for the use cases this SEP addresses. Even with perfect transport-layer reliability, several data-layer concerns remain: + +First, servers and clients need a way to communicate expectations about execution patterns. Without this, host applications cannot make informed decisions about UX patterns—should they block, show a spinner, or allow the user to continue working? An annotation alone could signal that a request might take extended time, but provides no mechanism to actively check status or retrieve results later. + +Second, transport-layer solutions cannot provide visibility into the execution state of a request that is still in progress. If a request stops sending progress notifications, the client cannot distinguish between "the server is doing expensive work" and "the request was lost." Transport-level retries can confirm the connection is alive, but cannot answer "is this specific request still executing?" This visibility is critical for operations where users need confidence their work is progressing. + +Third, different transports would require different mechanisms for these concerns. The sHTTP proposals adjust stream management and retry semantics to fulfill these requirements, but stdio has no equivalent extension points. This creates transport-specific fragmentation where implementers must solve the same problems differently depending on their choice of transport. Data-layer operations provides consistent semantics across all transports. + +Finally, deferred result retrieval and active status checks are data-layer concerns that cannot be addressed by transport improvements alone. The ability to retrieve a result multiple times, specify retention duration, and handle cleanup is orthogonal to how the underlying messages are delivered. + +**Resource-Based Approaches:** +Another possible approach would be to leverage existing MCP resources for tracking long-running operations. For example, a tool could return a linked resource that communicates operation status, and clients could subscribe to that resource to receive updates when the operation completes. This would allow servers to represent task state using the resource primitive, potentially with annotations for suggested polling frequency. + +While this approach is technically feasible and servers remain free to adopt such conventions, it suffers from similar limitations as the tool-splitting pattern described in the Motivation section. Like the `start_tool` and `get_tool` convention, a resource-based tracking system would be convention-based rather than standardized, creating several challenges: + +The most fundamental issue is the lack of a consistent way for clients to distinguish between ordinary resources (meant to be exposed to models) and status-tracking resources (meant to be polled by the application). Should a status resource be presented to the model? How should the client correlate a returned resource with the original tool call? Without standardization, different servers would implement different conventions, forcing clients/hosts/models to handle each server's particular approach. Extending resources with task-like semantics (such as polling frequency, keepalive durations, and explicit status states) would create a new and distinct purpose for resources that would be difficult to distinguish from their existing purpose as model-accessible content. + +The resource subscription model has one additional issue: as it is push-based, it requires clients to wait for notifications of resource changes rather than actively polling for status. While this works for some use cases, it doesn't address scenarios where clients need to actively check status—for example, proactively and deterministically checking if work is still progressing, which is the original intent of this proposal. + +The task primitive addresses these concerns by providing a standardized, protocol-level mechanism specifically designed for this use case, with consistent semantics that any client can leverage without host applications needing to understand server-specific conventions. While resource-based tracking remains possible for servers that prefer it and/or are already using it, this SEP provides a first-class alternative that solves the broader set of requirements identified previously. + +### Backward Compatibility + +This SEP introduces **no backward incompatibilities**. All existing MCP functionality remains unchanged: + +**Compatibility Guarantees:** + +- Existing requests work identically with or without task metadata +- Servers that don't understand tasks process requests normally +- No protocol version negotiation required +- No capability declarations needed + +**Graceful Degradation:** + +- Clients race between waiting for the original request's response and waiting for the `notifications/tasks/created` notification followed by polling +- Whichever completes first (original response or task-based retrieval) is used by the client +- If a server doesn't support tasks, no `notifications/tasks/created` is sent, and the original request's response is used +- If a server supports tasks, the `notifications/tasks/created` notification is sent, enabling the client to begin polling for results +- This race pattern ensures graceful degradation without requiring capability negotiation or version detection +- Partial support is possible—servers can support tasks on some requests but not others + +**Adoption Path:** + +- Servers can implement task support incrementally, starting with high-value request types +- Clients can opportunistically use tasks where supported +- No coordination required between client and server updates + +## Future Work + +The task primitive introduced in this SEP provides a foundation for several important extensions that will enhance MCP's workflow capabilities. + +### Push Notifications + +While this SEP focuses on client-driven polling, future work could introduce server-initiated notifications for task state changes. This would be particularly valuable for operations that take hours or longer, where continuous polling becomes impractical. + +A notification-based approach would allow servers to proactively inform clients when: + +- A task completes or fails +- A task reaches a milestone or significant state transition +- A task requires input (complementing the `input_required` status) + +This could be implemented through webhook-style mechanisms or persistent notification channels, depending on the transport capabilities. The proposed task ID and status model provides the necessary infrastructure for servers to identify which tasks warrant notifications and for clients to correlate notifications with their outstanding tasks. + +### Intermediate Results + +The current task model returns results only upon completion. Future extensions could enable tasks to report intermediate results or progress artifacts during execution. This would support use cases where servers can produce partial outputs before final completion, such as: + +- Streaming analysis results as they become available +- Reporting completed phases of multi-step operations +- Providing preview data while full processing continues + +Intermediate results would build on the proposed task ID association mechanism, allowing servers to send multiple result notifications or response messages tied to the same task ID throughout its lifecycle. + +### Nested Task Execution + +A significant future enhancement is support for hierarchical task relationships, where a task can spawn subtasks as part of its execution. This would enable complex, multi-step workflows orchestrated by the server. + +In a nested task model, a server could: + +- Create subtasks in response to a parent task reaching a state that requires additional operations +- Communicate subtask requirements to the client, potentially including required tool calls or sampling requests +- Track subtask completion and use subtask results to advance the parent task +- Maintain provenance through task ID hierarchies, showing the relationship between parent and child tasks + +For example, a complex analysis task might spawn several subtasks for data gathering, each represented by its own task ID but associated with the parent task. The parent task would remain in a pending state (potentially in a new `tool_required` status) until all required subtasks complete. + +This hierarchical model would support sophisticated server-controlled workflows while maintaining the client's ability to monitor and retrieve results at any level of the task tree. + +
+ +Example nested task flow + +```mermaid +sequenceDiagram + participant C as Client + participant S as Server + + Note over C,S: Client Creates Parent Task + C->>S: tools/call "deploy_application"
_meta: {taskId: "deploy-123"} + S--)C: notifications/tasks/created + + C->>S: tasks/get (taskId: "deploy-123") + S->>C: status: working + + Note over S: Server determines subtasks needed + + Note over C,S: Server Responds with Subtask Requirements + C->>S: tasks/get (taskId: "deploy-123") + S->>C: status: working
childTasks: [{
taskId: "build-456",
toolName: "run_build",
arguments: {...}
}, {
taskId: "test-789",
toolName: "run_tests",
arguments: {...}
}] + + Note over C: Client initiates subtasks + + C->>S: tools/call "run_build"
_meta: {taskId: "build-456", parentTaskId: "deploy-123"} + S--)C: notifications/tasks/created + + C->>S: tools/call "run_tests"
_meta: {taskId: "test-789", parentTaskId: "deploy-123"} + S--)C: notifications/tasks/created + + Note over C: Client polls subtasks + + C->>S: tasks/get (taskId: "build-456") + S->>C: status: completed + + C->>S: tasks/get (taskId: "test-789") + S->>C: status: completed + + Note over S: All subtasks complete, parent continues + + C->>S: tasks/get (taskId: "deploy-123") + S->>C: status: completed + + C->>S: tasks/result (taskId: "deploy-123") + S->>C: Deployment complete +``` + +**Potential Data Model Extensions:** +The task status response could be extended to include parent and child task relationships: + +```typescript +{ + taskId: string; + status: TaskStatus; + keepAlive: number | null; + pollFrequency?: number; + error?: string; + + // Extensions for nested tasks + parentTaskId?: string; // ID of parent task, if this is a subtask + childTasks?: Array<{ // Subtasks required by this task + taskId: string; // Pre-generated task ID for the subtask + toolName: string; // Tool to call for this subtask + arguments?: object; // Arguments for the tool call + }>; +} +``` + +This would allow clients to: + +- Discover subtasks required by a parent task through the `childTasks` array +- Initiate the required subtask tool calls using the pre-generated task IDs and provided arguments +- Navigate the task hierarchy by following parent/child relationships via `parentTaskId` +- Monitor all subtasks by polling each child task ID +- Wait for all subtasks to complete before checking parent task completion + +The existing task metadata and status lifecycle are designed to be forward-compatible with these extensions. + +
diff --git a/seps/1699-support-sse-polling-via-server-side-disconnect.md b/seps/1699-support-sse-polling-via-server-side-disconnect.md new file mode 100644 index 000000000..80eb23060 --- /dev/null +++ b/seps/1699-support-sse-polling-via-server-side-disconnect.md @@ -0,0 +1,44 @@ +# SEP-1699: Support SSE polling via server-side disconnect + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-10-22 +- **Author(s)**: Jonathan Hefner (@jonathanhefner) +- **Issue**: #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). diff --git a/seps/1730-sdks-tiering-system.md b/seps/1730-sdks-tiering-system.md new file mode 100644 index 000000000..fe3112567 --- /dev/null +++ b/seps/1730-sdks-tiering-system.md @@ -0,0 +1,247 @@ +# SEP-1730: SDKs Tiering System + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-10-29 +- **Author(s)**: Inna Harper, Felix Weinberger +- **Issue**: #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 +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 \ 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. diff --git a/seps/2085-governance-succession-and-amendment.md b/seps/2085-governance-succession-and-amendment.md new file mode 100644 index 000000000..2ffd6edf3 --- /dev/null +++ b/seps/2085-governance-succession-and-amendment.md @@ -0,0 +1,87 @@ +# SEP-2085: Governance Succession and Amendment Procedures + +- **Status**: Draft +- **Type**: Process +- **Created**: 2025-12-05 +- **Author(s)**: David Soria Parra (@dsp-ant) +- **Sponsor**: David Soria Parra (@dsp-ant) +- **PR**: 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. diff --git a/seps/2127-mcp-server-cards.md b/seps/2127-mcp-server-cards.md new file mode 100644 index 000000000..48ddd7bcc --- /dev/null +++ b/seps/2127-mcp-server-cards.md @@ -0,0 +1,542 @@ +# SEP-2127: MCP Server Cards - HTTP Server Discovery via .well-known + +- **Status**: Draft +- **Type**: Standards Track +- **Created**: 2026-01-21 +- **Author(s)**: David Soria Parra (@dsp-ant), Nick Cooper (@nickcoai), Tadas Antanavicius (@tadasant), Raluca Gruber (@maiargu) +- **Sponsor**: None +- **PR**: https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2127 + +## Abstract + +This SEP proposes adding a standardized, self-contained format to describe MCP servers, e.g. for discovery using a `.well-known` endpoint. This enables clients to automatically discover server capabilities, available transports, authentication requirements, protocol versions and descriptions of primitives before establishing a connection. + +## Motivation + +MCP clients currently lack efficient mechanisms to discover information about MCP servers before establishing a full connection. To obtain even basic metadata like server name and version, clients must complete an entire initialization handshake. This creates friction for discovery, integration, and optimization scenarios. + +### Current Pain Points + +- **Manual Endpoint Configuration**: Users must manually configure transport URLs for each server, with no standardized discovery mechanism. +- **No Domain-Level Discovery**: Clients cannot automatically discover available MCP servers on a domain. This prevents automated integration scenarios, such as registry crawling or service auto-detection. +- **Expensive Initialization**: Every capability query requires a full initialization sequence. This round-trip is costly, difficult to cache efficiently, and creates unnecessary latency for simple metadata retrieval. + +### Proposed Solution + +This SEP introduces **MCP Server Cards** – structured metadata documents that servers expose through standardized mechanisms. The primary mechanism is a `.well-known` endpoint and similar mechanism appropriate for the transport. These provide static server information without requiring connection establishment. In addition the same information is served via a well known MCP resource. + +### Enabled Use Cases + +- **Autoconfiguration**: IDE extensions can automatically configure themselves when pointed at a domain, eliminating manual setup. +- **Automated Discovery**: Clients and registries can crawl domains to discover available MCP servers, enabling ecosystem-wide server indexes. +- **Static Verification**: Clients can validate tool descriptions against security classifiers and cache these validations, improving safety without repeated checks. +- **Reduced Latency:** Display server information, capabilities, and metadata without waiting for full initialization sequences. + +### Design Philosophy + +The discovery mechanism complements rather than replaces initialization. Discovery answers where to connect and what is available, while initialization handles how to communicate. + +### Discovery + +#### Relationship to AI Card + +The [AI Card](https://github.com/Agent-Card/ai-card) standard is paving a path to providing decentralized, protocol-agnostic mechanisms for identifying agent entrypoints. For example, a `.well-known` path and file format for discovering services (`.well-known/ai-catalog.json`). + +#### MCP Connection Details + +MCP Server Cards will provide a richer, MCP-specific definition that can be used by MCP clients to actually connect and start performing MCP operations. We will store these values at `.well-known/mcp/server-card`. + +Example: + +- "Restaurant A" works with platform "Restaurant Reservations SaaS" to provide MCP-powered bookings for their restaurant +- Restaurant A also works with platform "Jobs SaaS" to provide MCP-powered job listings to prospective job seekers +- Restaurant A would advertise the two relevant AI Cards at `restaurant-a.com/.well-known/ai-catalog.json` +- Restaurant Reservations SaaS would have many Server Cards at `restaurant-reservations-saas.com/.well-known/mcp/server-card/*`, including entries for each of Restaurant A (`restaurant-reservations-saas.com/.well-known/mcp/server-card/restaurant-a`), Restaurant B (`restaurant-reservations-saas.com/.well-known/mcp/server-card/restaurant-b`), etc. +- Jobs Saas would have many Server Cards at `jobs-saas.com/.well-known/mcp/server-card/*`, including entries for each of Restaurant A (`jobs-saas.com/.well-known/mcp/server-card/restaurant-a`), Coffee Shop B (`jobs-saas.com/.well-known/mcp/server-card/coffee-shop-b`), etc. + +We can develop and iterate on MCP Server Cards largely independently from the broader effort to integrate with AI Cards, as long as we maintain some integration point so it is possible to understand when an entry in an AI Card references an MCP Server Card that is hosted and maintained elsewhere. + +### Relationship to `server.json` + +The focus of MCP Server Cards is on expressing _remote_ MCP servers; however the card is designed to be compatible with the previously established `server.json` standard that includes consideration for locally-run MCP servers (e.g. where to download executable packages, how to run them). + +This alignment is useful for the following reasons: + +1. **Cross-cutting concerns**. The two use cases share many cross-cutting concerns, such as static primitive definitions, identity, documentation, and more. By keeping one as a strict subset of the other, we ensure that efforts to improve the shape move in concert and avoid re-inventing the wheel. + +2. **Shared tooling**. Only one set of tooling or frameworks needs to exist to parse and generate/modify Server Card files. + +3. **Sprawl and adoption friction**. Server maintainers don't have _yet another_ shape to maintain. For example, a single server may already have a `package.json`, `Dockerfile`, `manifest.json`, and more. By consolidating to a single `server-card.json` shape, we limit further maintenance sprawl and adoption friction. + +We chose not to include these local considerations in the core MCP Server Card specification because: + +1. **Compliance with .well-known guidance**. Given our intent to use MCP Server Cards in concert with `.well-known` standardization, [RFC 5785](https://www.ietf.org/rfc/rfc5785.txt) says, _"in keeping with the Architecture of the World-Wide Web, well-known URIs are not intended for general information retrieval or establishment of large URI namespaces on the Web. Rather, they are designed to facilitate discovery of information on a site when it isn't practical to use other mechanisms; for example, when discovering policy that needs to be evaluated before a resource is accessed, or when using multiple round-trips is judged detrimental to performance."_. Local servers cannot, by definition, be hosted on a website, and so do not belong in file hosted at a `.well-known` URI. + +2. **Exposure of additional security vectors**. If we include local servers (and how to run them) in this shape, we would effectively be saying that clients that receive that metadata must absolutely do proper input sanitization as you just gave a one-click shortcut for someone to install something/trigger execution on a local machine. The threat model went from "We can point to resources to connect to" to "Here is an executable blob that might run on a target machine right away if the client didn't check it." You could also argue that this is something we do with the registry today, and the discovery mechanism might just be a variation of it - however, the registry has some degree of moderation. This would be a wide-open mechanism for anyone to advertise their server, however good or bad it is. + +## Specification + +This section provides the technical specification for MCP Server Cards. + +### MCP Server Card Schema + +```json +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json", + "name": "io.modelcontextprotocol.anonymous/brave-search", + "version": "1.0.2", + "description": "MCP server for Brave Search API integration", + "title": "Brave Search", + "websiteUrl": "https://anonymous.modelcontextprotocol.io/examples", + "repository": { ... }, + "icons": [ ... ], + "remotes": [ ... ], + "capabilities": { ... }, + "requires": { ... }, + "resources": [ ... ], + "tools": [ ... ], + "prompts": [ ... ], + "_meta": { ... } +} +``` + +Fleshed out (contrived values) example: + +```json +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json", + "name": "io.modelcontextprotocol.anonymous/brave-search", + "version": "1.0.2", + "description": "MCP server for Brave Search API integration", + "title": "Brave Search", + "websiteUrl": "https://anonymous.modelcontextprotocol.io/examples", + "repository": { + "url": "https://github.com/modelcontextprotocol/servers", + "source": "github", + "subfolder": "src/everything", + "id": "b94b5f7e-c7c6-d760-2c78-a5e9b8a5b8c9" + }, + "icons": [ + { + "src": "https://example.com/icons/weather-icon-48.png", + "sizes": ["48x48"], + "mimeType": "image/png", + "theme": "light" + } + ], + "remotes": [ + { + "type": "streamable-http", + "url": "https://mcp.anonymous.modelcontextprotocol.io/http", + "supportedProtocolVersions": [ "2025-03-12", "2025-06-15" ], + "headers": [ + { + "name": "X-API-Key", + "description": "API key for authentication", + "isRequired": true, + "isSecret": true + }, + { + "name": "X-Region", + "description": "Service region", + "default": "us-east-1", + "choices": [ + "us-east-1", + "eu-west-1", + "ap-southeast-1" + ] + } + ], + "authentication": { + "required": true, + "schemes": ["bearer", "oauth2"] + }, + }, + { + "type": "sse", + "url": "https://mcp.anonymous.modelcontextprotocol.io/sse", + "supportedProtocolVersions": [ "2025-03-12", "2025-06-15" ], + "authentication": { + "required": true, + "schemes": ["bearer", "oauth2"] + }, + } + ], + "capabilities": { + "tools": { + "listChanged": true + }, + "prompts": { + "listChanged": true + }, + "resources": { + "subscribe": true, + "listChanged": true + } + }, + "requires": { + "sampling": {}, + "roots": {} + }, + "resources": [ + { + "uri": "file:///project/src/main.rs", + "name": "main.rs", + "title": "Rust Software Application Main File", + "description": "Primary application entry point", + "mimeType": "text/x-rust", + "icons": [ + { + "src": "https://example.com/rust-file-icon.png", + "mimeType": "image/png", + "sizes": ["48x48"] + } + ] + } + ], + "tools": [ + { + "name": "get_weather", + "title": "Weather Information Provider", + "description": "Get current weather information for a location", + "inputSchema": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "City name or zip code" + } + }, + "required": ["location"] + }, + "icons": [ + { + "src": "https://example.com/weather-icon.png", + "mimeType": "image/png", + "sizes": ["48x48"] + } + ] + } + ], + "prompts": [ + { + "name": "code_review", + "title": "Request Code Review", + "description": "Asks the LLM to analyze code quality and suggest improvements", + "arguments": [ + { + "name": "code", + "description": "The code to review", + "required": true + } + ], + "icons": [ + { + "src": "https://example.com/review-icon.svg", + "mimeType": "image/svg+xml", + "sizes": ["any"] + } + ] + } + ], + "_meta": { ... } +} + +``` + +#### Field Descriptions + +Most fields follow the current MCP Registry `server.json` standard: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/generic-server-json.md + +0. **$schema** (string, required): The Server Card JSON schema URI that evolves in-place per major version iteration +1. **name** (string, required): Server name in reverse-DNS format. Must contain exactly one forward slash separating namespace from server name. +2. **version** (string, required): Version string for this server. SHOULD follow semantic versioning (e.g., '1.0.2', '2.1.0-alpha'). Equivalent of Implementation.version in MCP specification. Non-semantic versions are allowed but may not sort predictably. Version ranges are rejected (e.g., '^1.2.3', '~1.2.3', '\u003e=1.2.3', '1.x', '1.\*'). +3. **description** (string, optional): Clear human-readable explanation of server functionality. Should focus on capabilities, not implementation details. +4. **title** (string, optional): Optional human-readable title or display name for the MCP server. +5. **websiteUrl** (string, optional): Optional URL to the server's homepage, documentation, or project website. This provides a central link for users to learn more about the server. Particularly useful when the server has custom installation instructions or setup requirements. +6. **repository** (object, optional): Repository metadata for the MCP server source code. [See details](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/draft/server.schema.json#L371). +7. **icons** (array of object, optional): Optional set of sized icons that the client can display in a user interface. Clients that support rendering icons MUST support at least the following MIME types: image/png and image/jpeg (safe, universal compatibility). Clients SHOULD also support: image/svg+xml (scalable but requires security precautions) and image/webp (modern, efficient format). [See details](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/draft/server.schema.json#L18). +8. **remotes** (array of object, optional): Metadata helpful for making HTTP-based connections to this MCP server. + 1. **supportedProtocolVersions** (array of string, optional): list of MCP protocol versions actively supported by this Remote. + 2. **authentication** (object, optional): Authentication requirements + 1. **required** (boolean, required): Whether authentication is mandatory + 2. **schemes** (array, required): Supported schemes (e.g., ["bearer", "oauth2"]) + 3. [See details](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/draft/server.schema.json#L344) for other fields. +9. **capabilities** (object, required): Server capabilities following `ServerCapabilities` + 1. **experimental** (object, optional): Experimental capabilities + 2. **logging** (object, optional): Log message support + 3. **completions** (object, optional): Argument autocompletion support + 4. **prompts** (object, optional): Prompt template support + 1. **listChanged** (boolean, optional): Server runtime change notification support for the client when its prompts list has changed + 5. **resources** (object, optional): Resource support + 1. **subscribe** (boolean, optional): Subscription support + 2. **listChanged** (boolean, optional): Server runtime change notification support for the client when its resources list has changed + 6. **tools** (object, optional): Tool support + 1. **listChanged** (boolean, optional): Server runtime change notification support for the client when its tools list has changed +10. **requires** (object, optional): Required client capabilities following `ClientCapabilities` + 1. **experimental** (object, optional): Required experimental capabilities + 2. **roots** (object, optional): Root access requirement + 3. **sampling** (object, optional): LLM sampling requirement + 4. **elicitation** (object, optional): User elicitation requirement +11. **resources** (array, optional): array of static Resource definitions exposed by the server, array items following the [`Resource`](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.json#L2947) JSON Schema +12. **tools** (array, optional): array of static Tool definitions exposed by the server, array items following the [`Tool`](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.json#L3993) JSON Schema +13. **prompts** (array, optional): array of static Prompt definitions exposed by the server, array items following the [`Prompt`](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.json#L2682) JSON Schema +14. **\_meta** (object, optional): Additional metadata following [\_meta definition](https://modelcontextprotocol.io/specification/2025-06-18/basic/index#meta) + +### Primitives + +MCP primitives (tools, resources and prompts) are the most important concepts within MCP. +With the help of the `.well-known` URI a client can discover what primitive capabilities a server can offer. + +1. Static Primitives + + The server's available primitives, which would normally be listed in the MCP protocol lifecycle initialization phase (`*/list`), will be listed under the root document `$.tools`, `$.resources`, and `$.prompts` properties. + +2. Dynamic Primitives + + To indicate that a list of primitives is dynamic in nature and can change at runtime, authors can set the `$.capabilities.tools.listChanged`, `$.capabilities.resources.listChanged`, or `$.capabilities.prompts.listChanged` boolean to `true`. + This indicates that the server will inform the client at runtime when some of its list of primitives has changed. + +### `server.json` Schema + +Building on the previously established [`server.json` shape](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/generic-server-json.md), we move it to be defined in terms of the new Server Card shape: + +```json +{ + // ... all the fields above except $schema + "$schema": "https://static.modelcontextprotocol.io/schemas/v1/server.schema.json", + "packages": [ ... ] +} +``` + +With example values: + +```json +{ + // ... all the fields above except $schema + "$schema": "https://static.modelcontextprotocol.io/schemas/v1/server.schema.json", + "packages": [ + { + "registryType": "npm", + "registryBaseUrl": "https://registry.npmjs.org", + "identifier": "@modelcontextprotocol/server-brave-search", + "version": "1.0.2", + "supportedProtocolVersions": ["2025-03-12", "2025-06-15"], + "transport": { + "type": "stdio" + }, + "runtimeArguments": [ + { + "type": "named", + "description": "Mount a volume into the container", + "name": "--mount", + "value": "type=bind,src={source_path},dst={target_path}", + "isRequired": true, + "isRepeated": true, + "variables": { + "source_path": { + "description": "Source path on host", + "format": "filepath", + "isRequired": true + }, + "target_path": { + "description": "Path to mount in the container. It should be rooted in `/project` directory.", + "isRequired": true, + "default": "/project" + } + } + } + ], + "packageArguments": [ + { + "type": "positional", + "value": "mcp" + }, + { + "type": "positional", + "value": "start" + } + ], + "environmentVariables": [ + { + "name": "BRAVE_API_KEY", + "description": "Brave Search API Key", + "isRequired": true, + "isSecret": true + } + ] + } + ] +} +``` + +#### Field Descriptions + +1. **packages** (array of object, optional): Metadata helpful for running and connecting to local instances of this MCP server. + 1. **supportedProtocolVersions** (array of string, optional): list of MCP protocol versions actively supported by this Package. + 2. [See details](https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/draft/server.schema.json#L207) for other fields. + +See above for the rest. + +### Endpoints + +MCP Server Cards can be provided through multiple endpoints. All endpoints are optional, but at least one endpoint is recommended for servers that wish to support discovery. + +- All MCP Servers _SHOULD_ provide server cards via an MCP resource. +- MCP servers supporting HTTP-based transports (including Streamable HTTP and SSE) _SHOULD_ provide a server card via a .well-known URI. + +#### MCP Resource + +Servers SHOULD provide their server card as an MCP resource with: + +- **URI**: `mcp://server-card.json` +- **MIME type**: `application/json` +- **Resource type**: Static resource containing the server card JSON + +This enables clients to discover server metadata after establishing an MCP connection, without requiring HTTP access. + +#### .well-known URI + +Servers using HTTP-based transports SHOULD provide their server card at: + +``` +/.well-known/mcp/server-card +``` + +This endpoint: + +- MUST be accessible via HTTPS (HTTP MAY be supported for local/development use) +- MUST return `Content-Type: application/json` +- MUST include appropriate CORS headers (see below) +- SHOULD include appropriate caching headers (see below) + +See [RFC 8615](https://datatracker.ietf.org/doc/html/rfc8615) for details on constructing .well-known URIs. + +##### CORS Requirements + +Discovery endpoints MUST include appropriate CORS headers to allow browser-based clients: + +``` +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET +Access-Control-Allow-Headers: Content-Type +``` + +##### Caching + +Servers MAY include cache headers for the discovery document: + +``` +Cache-Control: public, max-age=3600 +``` + +#### Registry + +The registry should expose the MCP Server Card for a given registry entry. + +### Other Considered Endpoints + +**DNS-based discovery**: We considered using DNS TXT records for discovery, similar to DKIM or SPF. However, this approach would be limited to domain-level discovery and wouldn't work for path-based or port-based MCP servers, making it too restrictive. + +**Header-based discovery**: We considered using HTTP headers (similar to Link headers) to advertise server card locations. While this could work, it requires an HTTP request to the main endpoint first, eliminating many of the benefits of pre-connection discovery. + +## Rationale + +### Why .well-known? + +The `.well-known` URI pattern is an established IETF standard (RFC 8615) used by many protocols for service discovery, including OAuth 2.0 Authorization Server Metadata (RFC 8414). This approach: + +- Provides a predictable, standardized location for discovery +- Requires no prior knowledge of server configuration +- Works with standard HTTP infrastructure (caches, CDNs, load balancers) +- Is already familiar to developers working with web services + +### Why Adopt `server.json`'s shape? + +MCP Server Cards aim to provide a static representation of server metadata and capabilities so that clients can discover and connect to them without prior knowledge of their existence. + +The MCP Registry and its corresponding `server.json` share the same goal but for different consumers. Consequently, keeping both as closely aligned as possible ensures that we don't have to re-invent and diverge, and that developers have to only rely on one parser. + +### Why Support Both Static and Dynamic Primitives? + +Some servers have fixed tool sets that never change, while others generate tools dynamically based on user context or external data. Supporting both patterns: + +- Allows static servers to fully describe themselves in the server card +- Enables security scanning of static tool sets before connection +- Preserves flexibility for dynamic use cases +- Makes the "dynamic" marker explicit rather than implicit + +## Backward Compatibility + +This SEP is fully backward compatible with existing MCP implementations: + +- Server cards are **optional**. Servers that don't implement them continue to work normally through standard initialization. +- Clients that don't support server cards can ignore them and use the initialization handshake as before. +- The server card schema is designed to mirror the initialization response structure, minimizing implementation complexity for servers that want to support both. +- No changes to the core MCP protocol messages or initialization flow are required. + +### Migration Path + +1. **Phase 1** (Optional): Servers can begin exposing server cards without requiring client support +2. **Phase 2** (Recommended): Clients can implement server card fetching for enhanced discovery and pre-connection validation +3. **Phase 3** (Future): The ecosystem can develop tooling around server cards for registries, security scanning, and automated discovery + +## Security Implications + +### Information Disclosure + +Server cards are publicly accessible by design. Servers MUST NOT include sensitive information in server cards, including: + +- Authentication credentials or tokens +- Internal network topology or private endpoints +- Proprietary business logic or algorithms +- User-specific or session-specific data + +### Primitive Description Security + +Exposing primitive descriptions in server cards before connection establishment creates an opportunity for clients to perform security analysis. This is a security _improvement_ as it enables: + +- Offline security scanning of server primitives (tools, resources, prompts) +- Automated classification before user exposure +- Cached security validations reducing runtime overhead + +However, clients MUST still validate that the actual primitives provided during initialization lifecycle phase match the advertised primitives in the server card. +Servers MAY omit sensitive primitives descriptions from the server card and mark primitives as "dynamic" by boolean flag `$.capabilities.tools.listChanged`, `$.capabilities.resources.listChanged`, or `$.capabilities.prompts.listChanged` set to `true`, if pre-connection disclosure is undesirable. + +### CORS Requirements + +Server cards MUST be served with appropriate CORS headers to enable browser-based client discovery. The recommended configuration (`Access-Control-Allow-Origin: *`) is safe for server cards because: + +1. Server cards contain only public metadata (no credentials or secrets) +2. They are read-only (no state-changing operations) +3. Wide accessibility benefits the discovery use case + +### Denial of Service + +Servers SHOULD implement rate limiting on `.well-known/mcp/server-card` endpoints to prevent abuse. Clients SHOULD respect cache headers and avoid excessive polling. + +### Man-in-the-Middle Attacks + +Server cards SHOULD be served over HTTPS. Clients SHOULD validate TLS certificates when fetching server cards. However, because server cards are advisory (the actual connection still requires initialization and authentication), compromised server cards primarily affect discoverability rather than security. + +## Reference Implementation + +_To be added. A reference implementation is required before this SEP can be given "Final" status._ + +## IETF Registration + +`.well-known/` URIs must be registered with the IETF per RFC 8615. The SEP authors are responsible for submitting a registration request to IANA for the `.well-known/mcp/` URI suffix once this SEP is approved. + +The registration will include: + +- URI suffix: `mcp` +- Change controller: Model Context Protocol Steering Committee +- Specification document: This SEP +- Related information: Link to MCP specification + +## References + +- [RFC 8414: OAuth 2.0 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) +- [RFC 8615: Well-Known URIs](https://datatracker.ietf.org/doc/html/rfc8615) +- [MCP Protocol Specification](https://modelcontextprotocol.io/specification) +- [Original GitHub Issue #1649](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1649) \ No newline at end of file diff --git a/seps/932-model-context-protocol-governance.md b/seps/932-model-context-protocol-governance.md new file mode 100644 index 000000000..2ce633ace --- /dev/null +++ b/seps/932-model-context-protocol-governance.md @@ -0,0 +1,100 @@ +# SEP-932: Model Context Protocol Governance + +- **Status**: Final +- **Type**: Process +- **Created**: 2025-07-08 +- **Author(s)**: David Soria Parra +- **PR**: #931 +- **Issue**: #932 + +## Abstract + +This SEP establishes the formal governance model for the Model Context Protocol (MCP) project. It defines the organizational structure, decision-making processes, and contribution guidelines necessary for transparent and effective project stewardship. The proposal introduces a hierarchical governance structure with clear roles and responsibilities, along with the Specification Enhancement Proposal (SEP) process for managing protocol changes. + +## Motivation + +As the Model Context Protocol grows in adoption and complexity, the need for formal governance becomes critical. The current informal decision-making process lacks: + +1. **Transparency**: Community members have no clear visibility into how decisions are made +2. **Participation Pathways**: Contributors lack defined ways to influence project direction +3. **Accountability**: No formal structure exists for resolving disputes or contentious issues +4. **Scalability**: Ad-hoc processes cannot scale with growing community and technical complexity + +Without formal governance, the project risks: + +- Fragmentation of the ecosystem +- Unclear or inconsistent technical decisions +- Reduced community trust and participation +- Inability to effectively manage contributions at scale + +## Rationale + +The proposed governance model draws inspiration from successful open source projects like Python, PyTorch, and Rust. Key design decisions include: + +### Hierarchical Structure + +We chose a hierarchical model (Contributors → Maintainers → Core Maintainers → Lead Maintainers) that is effectively how the project decisions are made today. From there we will continue to evolve governance in the best interest of the project. + +### Individual vs Corporate Membership + +Membership is explicitly tied to individuals rather than companies to: + +- Ensure decisions prioritize protocol integrity over corporate interests +- Prevent capture by any single organization +- Maintain continuity when individuals change employers + +### SEP Process + +The Specification Enhancement Proposal process ensures: + +- All protocol changes undergo thorough review +- Community input is systematically collected +- Design decisions are documented for posterity +- Implementation precedes finalization + +## Specification + +### Governance Structure + +#### Contributors + +- Any individual who files issues, submits pull requests, or participates in discussions +- No formal membership or approval required + +#### Maintainers + +- Responsible for specific components (SDKs, documentation, etc.) +- Appointed by Core Maintainers +- Have write/admin access to their repositories +- May establish component-specific processes + +#### Core Maintainers + +- Deep understanding of MCP specification required +- Responsible for protocol evolution and project direction +- Meet bi-weekly for decisions +- Can veto maintainer decisions by majority vote +- Current members listed in governance documentation + +#### Lead Maintainers + +- Justin Spahr-Summers and David Soria Parra +- Can veto any decision +- Appoint/remove Core Maintainers +- Admin access to all infrastructure + +## Backwards Compatibility + +N/A + +## Reference Implementation + +See #931 + +1. **Documentation Files**: + - `/docs/community/governance.mdx` - Full governance documentation + - `/docs/community/sep-guidelines.mdx` - SEP process guidelines + +## Security Implications + +N/A diff --git a/seps/973-expose-additional-metadata-for-implementations-res.md b/seps/973-expose-additional-metadata-for-implementations-res.md new file mode 100644 index 000000000..1925b8fe3 --- /dev/null +++ b/seps/973-expose-additional-metadata-for-implementations-res.md @@ -0,0 +1,122 @@ +# SEP-973: Expose additional metadata for Implementations, Resources, Tools and Prompts + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-07-15 +- **Author(s)**: @jesselumarie +- **Issue**: #973 + +## Abstract + +This SEP proposes adding two optional fields—`icons` and `websiteUrl`. The `icons` and `websiteUrl` would be added to the `Implementation` schema so that clients can visually identify third-party implementations and link directly to their documentation. The `icons` parameter will also be added to the `Tool`, `Resource` and `Prompt` schemas. While this can be used by both servers and clients for all implementations, we expect it to be used initially for server-provided implementations. + +## Motivation + +### Current State + +Current implementations only expose namespaced metadata, forcing clients to display generic labels with no visual cues. + +Image + +### Proposed State + +The proposed implementation would allow us to add visual affordances and links to documentation, making it easier to visually identify which servers/clients are providing an implementation e.g. a tool in a slash command interface: + +Image + +- **Visual Affordance:** Icons make it immediately clear to users which tool or resource source is in use. +- **Discoverability:** A link to documentation (`websiteUrl`) allows clients to direct users to more information with a single click. + +## Rationale + +This design builds on prior work in web manifests (MDN) and consolidates community feedback: + +- **Consolidation of PRs:** Merges the changes from PR #417 and PR #862 into a single, cohesive enhancement. +- **Flexible Icon Sizes:** Supports multiple icon sizes (e.g., `48x48`, `96x96`, or `any` for vector formats) to accommodate different client UI needs. +- **Optional Fields:** By making both fields optional, existing implementations remain fully compatible. + +## Specification + +Extend the `Implementation` object as follows: + +```typescript +/** + * A url pointing to an icon URL or a base64-encoded data URI + * + * Clients that support rendering icons MUST support at least the following MIME types: + * - image/png - PNG images (safe, universal compatibility) + * - image/jpeg (and image/jpg) - JPEG images (safe, universal compatibility) + * + * Clients that support rendering icons SHOULD also support: + * - image/svg+xml - SVG images (scalable but requires security precautions) + * - image/webp - WebP images (modern, efficient format) + */ +export interface Icon { + /** + * A standard URI pointing to an icon resource. + * + * Consumers MUST takes steps to ensure URLs serving icons are from the + * same domain as the client/server or a trusted domain. + * + * Consumers MUST take appropriate precautions when consuming SVGs as they can contain + * executable JavaScript + * + * @format uri + */ + src: string; + /** Optional override if the server’s MIME type is missing or generic. */ + mimeType?: string; + /** e.g. "48x48", "any" (for SVG), or "48x48 96x96" */ + sizes?: string; +} + +/** + * Describes the MCP implementation + */ +export interface Implementation extends BaseMetadata { + version: string; + /** + * An optional list of icons for this implementation. + * This can be used by clients to display the implementation in a user interface. + * Each icon should have a `kind` property that specifies whether it is a data representation or a URL source, a `src` property that points to the icon file or data representation, and may also include a `mimeType` and `sizes` property. + * The `mimeType` property should be a valid MIME type for the icon file, such as "image/png" or "image/svg+xml". + * The `sizes` property should be a string that specifies one or more sizes at which the icon file can be used, such as "48x48" or "any" for scalable formats like SVG. + * The `sizes` property is optional, and if not provided, the client should assume that the icon can be used at any size. + */ + icons?: Icon[]; + /** + * An optional URL of the website for this implementation. + * + * Consumers MUST takes steps to ensure URLs serving icons are from the + * same domain as the client/server or a trusted domain. + * + * Consumers MUST take appropriate precautions when consuming SVGs as they can contain + * executable JavaScript + * + * @format: uri + */ + websiteUrl?: string; +} +``` + +Extend the `Tool`, `Resource` and `Prompt` interfaces with the following type: + +```typescript + /** + * An optional list of icons for a resource. + * This can be used by clients to display the resource's icon in a user interface. + * Each icon should have a `kind` property that specifies whether it is a data representation or a URL source, a `src` property that points to the icon file or data representation, and may also include a `mimeType` and `sizes` property. + * The `mimeType` property should be a valid MIME type for the icon file, such as "image/png" or "image/svg+xml". + * The `sizes` property should be a string that specifies one or more sizes at which the icon file can be used, such as "48x48" or "any" for scalable formats like SVG. + * The `sizes` property is optional, and if not provided, the client should assume that the icon can be used at any size. + */ + icons?: Icon[]; +``` + +## Backwards Compatibility + +Both icons and websiteUrl are optional fields; clients that ignore them will fall back to existing behavior. + +## Security Implications + +This shouldn't introduce any new security implications. diff --git a/seps/985-align-oauth-20-protected-resource-metadata-with-rf.md b/seps/985-align-oauth-20-protected-resource-metadata-with-rf.md new file mode 100644 index 000000000..cbcb73dcf --- /dev/null +++ b/seps/985-align-oauth-20-protected-resource-metadata-with-rf.md @@ -0,0 +1,96 @@ +# SEP-985: Align OAuth 2.0 Protected Resource Metadata with RFC 9728 + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-07-16 +- **Author(s)**: sunishsheth2009 +- **Issue**: #985 + +## Abstract + +This proposal brings the MCP spec's handling of OAuth 2.0 Protected Resource Metadata in line with [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728#name-obtaining-protected-resourc). + +Currently, the MCP spec requires the use of the HTTP WWW-Authenticate header when returning a 401 Unauthorized to indicate the location of the protected resource metadata. However, [RFC 9728, Section 5](https://datatracker.ietf.org/doc/html/rfc9728#section-5) states: + +“A protected resource MAY use the WWW-Authenticate HTTP response header field, as discussed in RFC 9110, to return a URL to its protected resource metadata to the client.” + +This suggests that the MCP spec could be made more flexible while still maintaining RFC compliance. + +## Rationale + +Many large-scale, dynamic, multi-tenant environments rely on a centralized authentication service separate from the backend resource servers. In such deployments, injecting WWW-Authenticate headers from backend services is non-trivial due to separation of concerns and infrastructure complexity. + +In these scenarios, having the option to discover metadata via a well-known URL provides a practical path forward for easier MCP adoption. Requiring only the header would impose significant communication overhead between components, especially when hundreds or thousands of MCP instances are created and destroyed dynamically. Also if there are specific managed MCP servers, adopting headers across centralized system would add significant overhead. + +While this increases complexity for clients—who must now implement logic to probe metadata endpoints—it reduces friction for server deployments and may encourage broader adoption. There are tradeoffs: + +Pros for Server Developers: Avoid complex header injection; simplifies integration in distributed environments. + +Cons for Client Developers: Clients must fall back to metadata discovery logic when the header is absent, increasing client complexity. + +## Proposed State + +Update the MCP spec to: + +``` +Clients MUST interpret the WWW-Authenticate header, and fallback to probing for metadata if not present. +Servers SHOULD return the WWW-Authenticate header +``` + +**The reason for deviating a bit on the RFC:** +Go with SHOULD over MAY for WWW-Authenticate is that it makes supporting other features, such as incremental authorization easier (e.g. you make a request for a tool, but need additional scopes, and receive a WWW-Authenticate challenge indicating the scopes). + +Based on the above, following the updated flow: + +- Attempt the MCP request without a token. +- If a 401 Unauthorized response is received: Check for a WWW-Authenticate header. If present and includes the resource_metadata parameter, use it to locate the resource metadata. +- If the header is absent or does not include resource_metadata, fallback to requesting /.well-known/oauth-protected-resource. + +This change allows more flexible deployment models without removing existing capabilities. + +```mermaid +sequenceDiagram + participant C as Client + participant M as MCP Server (Resource Server) + participant A as Authorization Server + + Note over C: Attempt unauthenticated MCP request + C->>M: MCP request without token + M-->>C: HTTP 401 Unauthorized (may include WWW-Authenticate header) + + alt Header includes resource_metadata + Note over C: Extract resource_metadata URL from header + C->>M: GET resource_metadata URI + M-->>C: Resource metadata with authorization server URL + else No resource_metadata in header + Note over C: Fallback to metadata probing + C->>M: GET /.well-known/oauth-protected-resource + alt Metadata found + M-->>C: Resource metadata with authorization server URL + else Metadata not found + Note over C: Abort or use pre-configured values + end + end + + Note over C: Validate RS metadata,
build AS metadata URL + + C->>A: GET /.well-known/oauth-authorization-server + A-->>C: Authorization server metadata + + Note over C,A: OAuth 2.1 authorization flow happens here + + C->>A: Token request + A-->>C: Access token + + C->>M: MCP request with access token + M-->>C: MCP response + Note over C,M: MCP communication continues with valid token +``` + +## Backward Compatibility + +This proposal is fully backward-compatible. + +It retains support for the WWW-Authenticate header (already in the spec) and introduces a fallback mechanism using the .well-known metadata path, which is already defined in MCP as a MUST-support location. + +Clients that already support metadata probing benefit from improved interoperability. Servers are not required to emit the WWW-Authenticate header if it is infeasible, but doing so is still encouraged to reduce client complexity and enable future extensibility. diff --git a/seps/986-specify-format-for-tool-names.md b/seps/986-specify-format-for-tool-names.md new file mode 100644 index 000000000..aa07f9917 --- /dev/null +++ b/seps/986-specify-format-for-tool-names.md @@ -0,0 +1,54 @@ +# SEP-986: Specify Format for Tool Names + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-07-16 +- **Author(s)**: kentcdodds +- **Issue**: #986 + +## Abstract + +The Model Context Protocol (MCP) currently lacks a standardized format for tool names, resulting in inconsistencies and confusion for both implementers and users. This SEP proposes a clear, flexible standard for tool names: tool names should be 1–64 characters, case-sensitive, and may include alphanumeric characters, underscores (\_), dashes (-), dots (.), and forward slashes (/). This aims to maximize compatibility, clarity, and interoperability across MCP implementations while accommodating a wide range of naming conventions. + +## Motivation + +Without a prescribed format for tool names, MCP implementations have adopted a variety of naming conventions, including different separators, casing, and character sets. This inconsistency can lead to confusion, errors in tool invocation, and difficulties in documentation and automation. Standardizing the allowed characters and length will: + +- Make tool names predictable and interoperable across clients. +- Allow for hierarchical and namespaced tool names (e.g., using / and .). +- Support both human-readable and machine-generated names. +- Avoid unnecessary restrictions that could block valid use cases. + +## Rationale + +Community discussion highlighted the need for flexibility in tool naming. While some conventions (like lower-kebab-case) are common, many tools and clients use uppercase, underscores, dots, and slashes for namespacing or clarity. The proposed pattern—allowing a-z, A-Z, 0-9, \_, -, ., and /—is based on patterns used in major clients (e.g., VS Code, Claude) and aligns with common conventions in programming and APIs. Restricting spaces and commas avoids parsing issues and ambiguity. The length limit (1–64) is generous enough for most use cases but prevents abuse. + +## Specification + +- Tool names SHOULD be between 1 and 64 characters in length (inclusive). +- Tool names are case-sensitive. +- Allowed characters: uppercase and lowercase ASCII letters (A-Z, a-z), digits + (0-9), underscore (\_), dash (-), dot (.), and forward slash (/). +- Tool names SHOULD NOT contain spaces, commas, or other special characters. +- Tool names SHOULD be unique within their namespace. +- Example valid tool names: + - getUser + - user-profile/update + - DATA_EXPORT_v2 + - admin.tools.list + +## Backwards Compatibility + +This change is not backwards compatible for existing tools that use disallowed characters or exceed the new length limits. To minimize disruption: + +- Existing non-conforming tool names SHOULD be supported as aliases for at least one major version, with a deprecation warning. +- Tool authors SHOULD update their documentation and code to use the new format. +- A migration guide SHOULD be provided to assist implementers in updating their tool names. + +## Reference Implementation + +A reference implementation can be provided by updating the MCP core library to enforce the new tool name validation rules at registration time. Existing tools can be updated to provide aliases for their new conforming names, with warnings for deprecated formats. Example code and migration scripts can be included in the MCP repository. + +## Security Implications + +None. Standardizing tool name format does not introduce new security risks. diff --git a/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o.md b/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o.md new file mode 100644 index 000000000..4e5f64858 --- /dev/null +++ b/seps/990-enable-enterprise-idp-policy-controls-during-mcp-o.md @@ -0,0 +1,69 @@ +# SEP-990: Enable enterprise IdP policy controls during MCP OAuth flows + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-06-04 +- **Author(s)**: Aaron Parecki (@aaronpk) +- **PR**: #646 +- **Issue**: #990 + +## Abstract + +This extension is designed to facilitate secure and interoperable authorization of MCP clients within corporate environments, leveraging existing enterprise identity infrastructure. + +- For end users, this removes the need to manually connect and authorize the MCP Client to individual services within the organization. +- For enterprise admins, this enables visibility and control over which MCP Servers are able to be used within the organization. + +## How Has This Been Tested? + +We have an end to end implementation of this [here](https://github.com/oktadev/okta-cross-app-access-mcp), and in-progress MCP implementations with some partners. + +## Breaking Changes + +This is designed to augment the existing OAuth profile by providing an alternative when used under an enterprise IdP. MCP clients can opt in to this profile when necessary. + +## Additional Context + +For more background on this problem, you can refer to my blog post about this here: + +[Enterprise-Ready MCP](https://aaronparecki.com/2025/05/12/27/enterprise-ready-mcp) + +I also presented this at the MCP Dev Summit in May. + +A high level overview of the flow is below: + +```mermaid +sequenceDiagram + participant UA as Browser + participant C as MCP Client + participant MAS as MCP Authorization Server + participant MRS as MCP Resource Server + participant IdP as Identity Provider + + rect rgb(255,255,225) + C-->>UA: Redirect to IdP + UA->>+IdP: Redirect to IdP + Note over IdP: User Logs In + IdP-->>-UA: IdP Authorization Code + UA->>C: IdP Authorization Code + C->>+IdP: Token Request with IdP Authorization Code + IdP-->-C: ID Token + end + + note over C: User is logged
in to MCP Client.
Client stores ID Token. + + C->+IdP: Exchange ID Token for ID-JAG + note over IdP: Evaluate Policy + IdP-->-C: Responds with ID-JAG + C->+MAS: Token Request with ID-JAG + note over MAS: Validate ID-JAG + MAS-->-C: MCP Access Token + + loop + C->>+MRS: Call MCP API with Access Token + MRS-->>-C: MCP Response with Data + end +``` + +> [!IMPORTANT] +> **State:** Ready to Review diff --git a/seps/991-enable-url-based-client-registration-using-oauth-c.md b/seps/991-enable-url-based-client-registration-using-oauth-c.md new file mode 100644 index 000000000..7c8ea2912 --- /dev/null +++ b/seps/991-enable-url-based-client-registration-using-oauth-c.md @@ -0,0 +1,278 @@ +# SEP-991: Enable URL-based Client Registration using OAuth Client ID Metadata Documents + +- **Status**: Final +- **Type**: Standards Track +- **Created**: 2025-07-07 +- **Author(s)**: Paul Carleton (@pcarleton) Aaron Parecki (@aaronpk) +- **Issue**: #991 + +# SEP: OAuth Client ID Metadata Documents for MCP + +## Abstract + +This SEP proposes adopting OAuth Client ID Metadata Documents as specified in [draft-parecki-oauth-client-id-metadata-document-03](https://datatracker.ietf.org/doc/draft-parecki-oauth-client-id-metadata-document/) as an additional client registration mechanism for the Model Context Protocol (MCP). This approach allows OAuth clients to use HTTPS URLs as client identifiers, where the URL points to a JSON document containing client metadata. This specifically addresses the common MCP scenario where servers and clients have no pre-existing relationship, enabling servers to trust clients without pre-coordination while maintaining full control over access policies. + +## Motivation + +The Model Context Protocol currently supports two client registration approaches: + +1. **Pre-registration**: Requires either client developers or users to manually register clients with each server +2. **Dynamic Client Registration (DCR)**: Allows just-in-time registration by sending client metadata to a register endpoint on the Authorization server. + +Both approaches have significant limitations for MCP's use case where clients frequently need to connect to servers they've never encountered before: + +- Pre-registration by developers is impractical as servers may not exist when clients ship +- Pre-registration by users creates poor UX requiring manual credential management +- DCR requires servers to manage unbounded databases, handle expiration, and trust self-asserted metadata + +### The Target Use Case: No Pre-existing Relationship + +This proposal specifically targets the common MCP scenario where: + +- A user wants to connect a client to a server they've discovered +- The client developer has never heard of this server +- The server operator has never heard of this client +- Both parties need to establish trust without prior coordination + +For scenarios with pre-existing relationships, pre-registration remains the optimal solution. However, MCP's value comes from its ability to connect arbitrary clients and servers, making the "no pre-existing relationship" case critical to address. + +Relatedly, there are many more MCP servers than there are clients (similar to how there are many more web browsers than API's). A common scenario is an MCP server developer wanting to restrict usage to a set of clients they trust. + +### Key Innovation: Server-Controlled Trust Without Pre-Coordination + +Client ID Metadata Documents enable a unique trust model where: + +1. **Servers can trust clients they've never seen before** based on: + - The HTTPS domain hosting the metadata + - The metadata content itself + - Domain reputation and security policies + +2. **Servers maintain full control** through flexible policies: + - **Open Servers**: Can accept any HTTPS client_id, enabling maximum interoperability + - **Protected Servers**: Can restrict to trusted domains or specific clients + +3. **No client pre-coordination required**: + - Clients don't need to know about servers in advance + - Clients just need to host their metadata document + - Trust flows from the client's domain, not prior registration + +## Specification Changes + +The change to the specification will be adding Client ID Metadata documents as a SHOULD, and changing DCR to a MAY, as we think that Client ID Metadata documents are a better default option for this scenario. + +We will primarily rely on the text in the linked RFC, aiming not to repeat most of it. Below is a short version of what we'll need to specify. + +```mermaid + sequenceDiagram + participant User + participant Client as MCP Client + participant Server as Authorization Server + participant Metadata as Metadata Endpoint
(Client's HTTPS URL) + participant Resource as MCP Server + + Note over Client,Metadata: Client hosts metadata at
https://app.example.com/oauth/metadata.json + + User->>Client: Initiates connection to MCP Server + Client->>Server: Authorization Request
client_id=https://app.example.com/oauth/metadata.json
redirect_uri=http://localhost:3000/callback + + Note over Server: Authenticates user + + + Note over Server: Detects URL-formatted client_id + + Server->>Metadata: GET https://app.example.com/oauth/metadata.json + Metadata-->>Server: JSON Metadata Document
{client_id, client_name, redirect_uris, ...} + + Note over Server: Validates:
1. client_id matches URL
2. redirect_uri in allowed list
3. Document structure valid
4. Domain allowed via trust policy + + alt Validation Success + Server->>User: Display consent page with client_name + User->>Server: Approves access + Server->>Client: Authorization code via redirect_uri + Client->>Server: Exchange code for token
client_id=https://app.example.com/oauth/metadata.json + Server-->>Client: Access token + Client->>Resource: MCP requests with access token + Resource-->>Client: MCP responses + else Validation Failure + Server->>User: Error response
error=invalid_client or invalid_request + end + + Note over Server: Cache metadata for future requests
(respecting HTTP cache headers) +``` + +### Client Requirements + +- Clients MUST host their metadata document at an HTTPS URL following RFC requirements +- The client_id URL MUST use "https" scheme and contain a path component +- Metadata documents MUST be valid JSON and include at minimum: + - `client_id`: matching the document URL exactly + - `client_name`: human-readable name for authorization prompts + - `redirect_uris`: array of allowed redirect URIs + - `token_endpoint_auth_method`: "none" for public clients + +Note a client can use `private_key_jwt` for a `token_endpoint_auth_method` given the client metadata can provide public key information. + +### Server Requirements + +- Servers SHOULD fetch metadata documents when encountering URL-formatted client_ids +- Servers MUST validate the fetched document contains matching client_id +- Servers SHOULD cache metadata respecting HTTP headers (max 24 hours recommended) +- Servers MUST validate redirect URIs match those in metadata document + +### Discovery + +- Servers advertise support via OAuth metadata: `client_id_metadata_document_supported: true` +- Clients detect support and can fallback to DCR or pre-registration if unavailable + +Example metadata document: + +```json +{ + "client_id": "https://app.example.com/oauth/client-metadata.json", + "client_name": "Example MCP Client", + "client_uri": "https://app.example.com", + "logo_uri": "https://app.example.com/logo.png", + "redirect_uris": [ + "http://127.0.0.1:3000/callback", + "http://localhost:3000/callback" + ], + "grant_types": ["authorization_code"], + "response_types": ["code"], + "token_endpoint_auth_method": "none" +} +``` + +### Integration with Existing MCP Auth + +This proposal adds Client ID Metadata Documents as a third registration option alongside pre-registration and DCR. Servers MAY support any combination of these approaches: + +- Pre-registration remains unchanged +- DCR remains unchanged +- Client ID Metadata Documents are detected by URL-formatted client_ids, and server support is advertised in OAuth metadata. + +## Rationale + +### Why This Solves the "No Pre-existing Relationship" Problem + +Unlike pre-registration which requires coordination, or DCR which requires servers to manage a registration database, Client ID Metadata Documents provide: + +1. **Verifiable Identity**: The HTTPS URL serves as both identifier and trust anchor +2. **No Coordination Needed**: Clients publish metadata, servers consume it +3. **Flexible Trust Policies**: Servers decide their own trust criteria without requiring client changes +4. **Stable Identifiers**: Unlike DCR's ephemeral IDs, URLs are stable and auditable + +### Redirect URI Attestation + +A key benefit of Client ID Metadata Documents is attestation of redirect URIs: + +1. **The metadata document cryptographically binds redirect URIs to the client identity** via HTTPS +2. **Servers can trust that redirect URIs in the metadata are controlled by the client** - not attacker-supplied +3. **This prevents redirect URI manipulation attacks** common with self-asserted registration + +### Risks of this approach + +#### Risk: Localhost URL Impersonation + +A limitation of Client ID Metadata Documents is that they cannot prevent localhost URL impersonation by itself. An attacker can claim to be any client by: + +1. Providing the legitimate client's metadata URL as their client_id +2. Binding to the same localhost port the legitimate client uses +3. Intercepting the authorization code when the user approves + +This attack is concerning because the server sees the correct metadata +document and the user sees the correct client name, making detection +difficult. + +Platform-specific attestations (iOS DeviceCheck, Android +Play Integrity) could address this, but they're not universally available. This +would work by a developer running a backend service that consumes the DeviceCheck / Play Integrity +signatures and returns a JWT usable as the `private_key_jwt` authentication for the `token_endpoint_auth_method`. + +A similar approach without requiring platform-specific attestations that still raises the cost of the attack +is possible using JWKS and short-lived JWTs signed by a server-side component hosted by the client developer. This component could use attestation mechanisms other than platform-specific ones to attest to the clients identity, such as the client's standard login flow. Using short lived JWTs reduces the risk of credential compromise and replay, but does not eliminate it +entirely - an attacker could still proxy requests to the legitimate +client's signing endpoint. + +Fully mitigating this risk is outside the scope of this proposal. This +proposal has the same risks as DCR does in a localhost redirect scenario. + +Servers SHOULD display additional warnings for localhost-only clients. + +#### Risk: Server Side Request Forgery (SSRF) + +The authorization server takes a URL as input from an unknown client, and then fetches that URL. A malicious client could use this to send non-metadata requests on behalf of the authorization server. An example would be sending a URL corresponding to a private administration endpoint that the authorization server has access to. + +This can be prevented by validating the URL's and the IP's those URL's resolve to prior to initiating a fetch request. + +#### Risk: Distributed Denial of Service (DDoS) + +Similarly, an attacker could try to leverage a pool of authorization servers to perform a denial of service attack on a non-MCP server. + +There is not any additional amplification for the fetch request (i.e. the bandwidth from the client to make the request roughly equals the bandwidth of the request sent to the target server), and each authorization server can aggressively cache the result of these metadata fetches, so it is unlikely to be an attractive DDoS vector. + +#### Risk: Maturity of referenced specification + +The RFC for Client ID Metadata documents is still a draft. It has been implemented by the platform Bluesky, but has not been ratified or very widely adopted outside of that, and may evolve over time. Our intention is to evolve and align with subsequent drafts and any final standard, while minimizing disruption and breakage with existing implementations. + +This approach has the risk that there are implementation challenges or flaws in the protocol that have not surfaced yet. However, even though DCR has been ratified, and it also has a number of implementation challenges that developers are facing when trying to use it in an open ecosystem context like MCP. Those challenges are the motiviation behind this proposal. + +#### Risk: Client implementation burden, espcially local clients + +This specification requires an additional piece of infrastructure for clients, since they need to host a metadata file behind an HTTPS url. Without this specification, a client could be strictly a desktop application for example. + +The burden of hosting this endpoint is expected to be low as hosting a static JSON file is fairly straightforward and most known clients have a webpage advertising their client or providing download links. + +#### Risk: Fragmentation of authorization approaches + +Authorization for MCP is already challenging to fully implement for clients and servers. Questions about how to do it correctly and best practices are some of the most common in the community. Adding another branch to the authorization flow means this could be even more complicated and fractured, meaning fewer developers succeed in following the specification, and the promise of compatibility and an open ecosystem suffers as a result. + +This proposal intends to simplify the story for authorization server and resource server developers by providing a clearer mechanism to trust redirect URIs and less operational overhead. This proposal depends on that simplicity being clearly the better option for most folks, which will drive more adoption and end up being the most supported option. If we do not believe that it is clearly the better option, then we should not adopt this proposal. + +This proposal also provides a unified mechanism for both open servers and servers that want to restrict which clients can be used. Alternatives to this proposal require that clients and servers implement different mechanisms for the open and protected use cases. + +## Alternatives Considered + +1. **Enhanced DCR with Software Statements**: More complex, requires JWKS hosting and JWT signing +2. **Mandatory Pre-registration**: Poor developer and user experience for MCP's distributed ecosystem +3. **Mutual TLS**: Requires trusting a client certificate authority, impractical in an open ecosystem +4. **Status Quo**: Continues current pain points for server implementers + +Client ID Metadata document is a strict improvement over DCR for the most common open-ecosystem use case. It can be further extended in the future to better support things like OS-level attestations and jwks_uri's. + +## Backward Compatibility + +This proposal is fully backward compatible: + +- Existing pre-registered clients continue working unchanged +- Existing DCR implementations continue working unchanged +- Servers can adopt Client ID Metadata Documents incrementally +- Clients can detect support and fall back to other methods + +## Prototype Implementation + +A prototype implementation is available [here](https://github.com/modelcontextprotocol/typescript-sdk/pull/839) demonstrating: + +1. Client-side metadata document hosting +2. Server-side metadata fetching and validation +3. Integration with existing MCP OAuth flows +4. Proper error handling and fallback behavior + +## Security Implications + +1. **Phishing Prevention**: Display client hostname prominently +2. **SSRF Protection**: Validate URLs, limit response size, timeout requests, rate limit outbound requests + +### Best Practices + +- Only fetch client metadata after authenticating the user +- Implement rate limiting on outbound metadata fetches +- Consider additional warnings for new/unknown/localhost domains +- Log metadata fetch failures for monitoring + +## References + +- [draft-parecki-oauth-client-id-metadata-document-03](https://www.ietf.org/archive/id/draft-parecki-oauth-client-id-metadata-document-03.txt) +- [OAuth 2.1](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1/) +- [RFC 7591 - OAuth 2.0 Dynamic Client Registration](https://www.rfc-editor.org/rfc/rfc7591.html) +- [MCP Specification - Authorization](https://modelcontextprotocol.org/docs/spec/authorization) +- [Evolving OAuth Client Registration in the Model Context Protocol](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/1027/) diff --git a/seps/994-shared-communication-practicesguidelines.md b/seps/994-shared-communication-practicesguidelines.md new file mode 100644 index 000000000..91ce744de --- /dev/null +++ b/seps/994-shared-communication-practicesguidelines.md @@ -0,0 +1,107 @@ +# SEP-994: Shared Communication Practices/Guidelines + +- **Status**: Final +- **Type**: Process +- **Created**: 2025-07-17 +- **Author(s)**: @localden +- **Issue**: #994 +- **PR**: #1002 + +## Abstract + +This SEP establishes the communication strategy and framework for the Model Context Protocol community. It defines the official channels for contributor communication, guidelines for their use, and processes for decision documentation. + +## Motivation + +As the MCP community grows, clear communication guidelines are essential for: + +- **Consistency**: Ensuring all contributors know where and how to communicate +- **Transparency**: Making project decisions visible and accessible +- **Efficiency**: Directing discussions to the most appropriate channels +- **Security**: Establishing proper processes for handling sensitive issues + +## Specification + +### Communication Channels + +The MCP project uses three primary communication channels: + +1. **Discord**: For real-time or ad-hoc discussions among contributors +2. **GitHub Discussions**: For structured, longer-form discussions +3. **GitHub Issues**: For actionable tasks, bug reports, and feature requests + +Security-sensitive issues follow a separate process defined in SECURITY.md. + +### Discord Guidelines + +The Discord server is designed for **MCP contributors** and is not intended for general MCP support. + +#### Public Channels (Default) + +- Open community engagement and collaborative development +- SDK and tooling development discussions +- Working and Interest Group discussions +- Community onboarding and contribution guidance +- Office hours and maintainer availability + +#### Private Channels (Exceptions) + +Private channels are reserved for: + +- Security incidents (CVEs, protocol vulnerabilities) +- People matters (maintainer discussions, code of conduct) +- Coordination requiring immediate focused response + +All technical and governance decisions must be documented publicly in GitHub. + +### GitHub Discussions + +Used for structured, long-form discussion: + +- Project roadmap planning +- Announcements and release communications +- Community polls and consensus-building +- Feature requests with context and rationale + +### GitHub Issues + +Used for actionable items: + +- Bug reports with reproducible steps +- Documentation improvements +- CI/CD and infrastructure issues +- Release tasks and milestone tracking + +### Decision Records + +All MCP decisions are documented publicly: + +- **Technical decisions**: GitHub Issues and SEPs +- **Specification changes**: Changelog on the MCP website +- **Process changes**: Community documentation +- **Governance decisions**: GitHub Issues and SEPs + +Decision documentation includes: + +- Decision makers +- Background context and motivation +- Options considered +- Rationale for chosen approach +- Implementation steps + +## Rationale + +This framework balances openness with practicality: + +- **Public by default**: Maximizes transparency and community participation +- **Private when necessary**: Protects security and personal matters +- **Channel separation**: Keeps discussions organized and searchable +- **Documentation requirements**: Ensures decisions are preserved and discoverable + +## Backward Compatibility + +This SEP establishes new processes and does not affect existing protocol functionality. + +## Reference Implementation + +The communication guidelines are published at: https://modelcontextprotocol.io/community/communication