| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
There was a problem hiding this comment.
This LGTM now modulo one inline comment, would be great to get eyes from other SDK maintainers if this is something they'd be OK with supporting as a requirement.
Tagging Tier 1 maintainers of SDKs here as they'll be most affected for comment:
@guglielmo-san & @yarolegovich for Go
@halter73 for C#
@DaleSeo for Rust
@maxisbey + @Kludex for Python
@koic for Ruby
Sorry, something went wrong.
There was a problem hiding this comment.
Thanks for driving this, @sambhav! I agree with the overall direction. I left a few comments from the Rust SDK's perspective, mainly asking how some of the MUSTs apply to Rust.
Sorry, something went wrong.
- Consolidate repeated rules into Conventions, General requirements, and Extension rules - Registering a method fixes its name and types; behaviour changes go through middleware or existing replacement APIs - Replace rollback atomicity with a no-partial-install rule - Require middleware ordering control, leave the mechanism to SDKs - Leave dependency check timing to SDKs, SHOULD check at startup - Make packaging guidance a SHOULD; trim terminology and appendix notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015SKdZofPNU5AUcBGeV31is
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015SKdZofPNU5AUcBGeV31is
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015SKdZofPNU5AUcBGeV31is
- Scope method-name and type rules to the extension registration path - State requirements as outcomes; leave mechanisms to each SDK - Drop the dependency matching rules; SDKs choose how dependencies are expressed - Clarify sending-direction middleware, stream handling, and cleanup - Allow any ordering mechanism; add optional named insertion points - Add -32603 guidance for dependency checks during request handling - Tie the Tier 1 requirement to the next spec release after Final - Move Ruby to Tier 1 in Appendix A - Add non-normative Appendix C with example stacking designs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hwbri51KtC2ugmjkNwKD7D
…verability, and SDK coverage - Split middleware into JSON-RPC middleware (the default) and HTTP transport middleware for behaviour JSON-RPC cannot express, with context passed between layers. Typed per-method middleware is optional. - Add transport hooks: HTTP routes and stdio launch configuration, so authorization extensions and Server Card can ship as packages, with a coverage table mapping their needs to requirements. - Require SDKs to document supported extension points and expose them as a local set of identifiers versioned by defining SEP, with alternatives considered. - Add the authorization extensions and Server Card to Appendix B, and Appendix D rating each requirement against TypeScript, Python, C#, Go, Rust, and Java, with gaps by SDK. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Updated after the Core Maintainers meeting, which asked for three things. Transport-level middleware for auth and Server Card extensions. C# already layers it this way: ASP.NET Core middleware for HTTP and auth (AddMcp), then JSON-RPC message filters and typed request filters, with the HTTP user copied onto each message. The SEP now follows that model: JSON-RPC middleware is the default, HTTP transport middleware is for what it can't do (401/WWW-Authenticate, retry after a challenge), and new transport hooks cover HTTP routes (Server Card, /.well-known/oauth-protected-resource) and the stdio launch environment. Typed middleware is optional. These were added after checking that SDKs already offer the underlying seams:
Every server can sit behind host-framework middleware, and none blocks a <mcp>/server-card route. What's left is mainly passing non-bearer identity to handlers (TypeScript, Python, Go) and letting extensions, not only the app, add stdio settings, which no SDK does yet. Discoverable, versioned extension points. SDKs document the extension points they support and expose them as a local set, e.g. jsonrpc-middleware@sep-3371. Versioning by SEP keeps identifiers stable from first implementation; a spec date would start as @draft and be renamed at release. The Rationale compares this with integer and spec-date versioning. Works across type systems. Appendix D rates every requirement for these six SDKs. None of the gaps comes from the language itself; each is a missing API, such as Rust's single on_custom_request or Java's internal handler map. Still no wire changes. @felixweinberger, could you take another look? SDK maintainers: corrections to Appendix D for your SDK are welcome. |
Sorry, something went wrong.
|
|
||
| Server Card serves a document beneath the MCP endpoint, and authorization extensions serve protected resource metadata at well-known paths, both outside the MCP endpoint's JSON-RPC processing. | ||
|
|
||
| - SDKs **MUST** let applications and extensions serve additional HTTP routes, for any HTTP method including `OPTIONS`, with full control of status, headers, and body. Most SDKs mount the MCP endpoint in a host framework, and documented [host composition](#host-frameworks) that lets an extension package add its routes satisfies this. |
There was a problem hiding this comment.
Is this for the top level route only? or for any route?
Sorry, something went wrong.
There was a problem hiding this comment.
Any route.
Sorry, something went wrong.
| Server Card serves a document beneath the MCP endpoint, and authorization extensions serve protected resource metadata at well-known paths, both outside the MCP endpoint's JSON-RPC processing. | ||
|
|
||
| - SDKs **MUST** let applications and extensions serve additional HTTP routes, for any HTTP method including `OPTIONS`, with full control of status, headers, and body. Most SDKs mount the MCP endpoint in a host framework, and documented [host composition](#host-frameworks) that lets an extension package add its routes satisfies this. | ||
| - Routes **MUST** be possible both beneath the MCP endpoint path, such as `<mcp-endpoint>/server-card`, and at origin-level paths such as `/.well-known/oauth-protected-resource` and `/.well-known/ai-catalog.json`. |
There was a problem hiding this comment.
Does this apply just to .well-known or outside of it?
Sorry, something went wrong.
There was a problem hiding this comment.
Any route as applicable
Sorry, something went wrong.
| | Rust (1) | ? / ✅ | ✅ | ✅ wrappers | | ||
| | Ruby (1) | ? / ✅ | ✅ requests¹ | ? | | ||
| | Java (2) | ? / ❌ | ✅ session API | ✅ handler wrappers | | ||
| | PHP (3) | ✅ / ✅ | ✅ | ? | |
There was a problem hiding this comment.
we currently only have middleware on http transport level, this needs protocol level i understand
| | PHP (3) | ✅ / ✅ | ✅ | ? | | |
| | PHP (3) | ✅ / ✅ | ✅ | ❌ | |
Sorry, something went wrong.
There was a problem hiding this comment.
I still believe we need some form of versioning that is independent from the protocol version. We are describing an API interface of a certain shape and guarantees. If that changes, we have no way to communicate to people which API interface version we support. I understand in general updating it will be tied to MCP release cadence because of conformance testing, however:
I would rather prefer if we have Extension API Interface version 1 that people can introspect at runtime via Extensions.InterfaceVersion. In the release notes of the SDK we can always refer to which Extension API Interface it implements. For example, if V1 and V2 is backwards compatible, an SDK might chose to ship v2 anytime before the next spec release. There is no way to communicate that an SDK supports a next generation interface in the current SEP.
Sorry, something went wrong.
| - **Type**: Standards Track | ||
| - **Created**: 2026-09-18 | ||
| - **Author(s)**: Sambhav Kothari (@sambhav) | ||
| - **Sponsor**: Felix Weinberger (@felixweinberger) |
There was a problem hiding this comment.
I wonder if we need to change that template to ensure this is sponsored by a WG.
Sorry, something went wrong.
|
|
||
| Requirements are stated for SDKs. They apply as written to Tier 1 SDKs; for other SDKs, each **MUST** and **MUST NOT** is a **SHOULD** and **SHOULD NOT**. They apply to protocol version `2026-07-28` and later. SDKs **MAY** offer the same extension points on earlier versions. | ||
|
|
||
| This SEP specifies behaviour, not API shape. Existing APIs, builder options, interfaces, or wrappers can satisfy it; a new plugin framework is not required. Protocol and extension specifications continue to define message formats, capability negotiation, and method contracts. Defining new transports and package loading are out of scope; [transport middleware](#32-transport-middleware) and [transport hooks](#4-transport-hooks) cover the existing Streamable HTTP and stdio transports. |
There was a problem hiding this comment.
| This SEP specifies behaviour, not API shape. Existing APIs, builder options, interfaces, or wrappers can satisfy it; a new plugin framework is not required. Protocol and extension specifications continue to define message formats, capability negotiation, and method contracts. Defining new transports and package loading are out of scope; [transport middleware](#32-transport-middleware) and [transport hooks](#4-transport-hooks) cover the existing Streamable HTTP and stdio transports. | |
| The scope of the SEP is a set of requirements for SDKs to provide an API with functionality that allows the implementation of most protocol extensions. The exact shape of the API are implementation specific and are left to the SDK maintainers. Protocol and extension specifications, new transports, package loading or language specific considerations are out of scope. |
Sorry, something went wrong.
| - External packages **MUST** be able to use the extension points through documented public APIs, without an SDK fork, an SDK-owned allowlist, or an organisation-managed namespace or publishing access. | ||
| - Applications and extension setup code **MUST** be able to tell which extensions are registered before messages are processed. | ||
| - If an extension or any of its contributions cannot be registered, the SDK **MUST** report an error and **MUST NOT** process messages with that extension partially installed. | ||
| - SDKs **MAY** limit registration to configuration time. Runtime installation and removal are **OPTIONAL**. | ||
| - An SDK that offers both synchronous and asynchronous APIs **MAY** provide each extension point once and adapt it to the other style, provided extensions contributed once apply to both. |
There was a problem hiding this comment.
Should we separate these into categories like:
Sorry, something went wrong.
|
|
||
| // Application setup. | ||
| const server = new Server({ | ||
| extensions: [searchExtension(), auditExtension()], |
There was a problem hiding this comment.
We have a section around middleware ordering but not about ordering for extensions. I assume they are quite similar as extension ordering informs middleware ordering. We should be explicit about that.
Sorry, something went wrong.
| Registering a method fixes its name and types: | ||
|
|
||
| - SDKs **MUST** reject an extension's registration that reuses a registered method name, whether as a request or a notification, including core method names. | ||
| - The extension points in this SEP **MUST NOT** let an extension change a registered method's types. The SDK owns the envelope and request correlation. | ||
|
|
There was a problem hiding this comment.
We should have for each of these top level categories such as Middleware, Custom Methods, ... a subsection Requirements that clearly defines the associated semantics for that required functionality.
Sorry, something went wrong.
|
|
||
| Transport middleware runs outside JSON-RPC middleware. An inbound HTTP request passes through transport middleware before its messages are parsed and reach JSON-RPC middleware; outbound messages pass through JSON-RPC middleware before they are serialized and handed to transport middleware. Transport middleware passes information inward as local [context](#context-between-layers). An extension can contribute middleware in either or both categories. | ||
|
|
||
| JSON-RPC middleware is the default. Transport middleware is a lower-level tool for behaviour that JSON-RPC middleware cannot express: |
There was a problem hiding this comment.
I don't think this sentence makes much sense. There is no default for middleware.
Sorry, something went wrong.
| - Behaviour that depends on HTTP status codes or headers rather than messages. | ||
| - Behaviour that must run before a message is parsed or accepted, such as rejecting an unauthenticated HTTP request. | ||
|
|
||
| Extensions **SHOULD** use JSON-RPC middleware wherever it suffices, so that they work the same way over every transport, and **SHOULD** limit transport middleware to the parts that need it. For example, an authorization extension uses transport middleware to verify credentials and answer with `401`, while a policy that inspects tool calls uses JSON-RPC middleware and reads the resulting identity from [context](#context-between-layers). Contributions that do not wrap processing, such as HTTP routes, are [transport hooks](#4-transport-hooks) rather than middleware. |
There was a problem hiding this comment.
I don't think we advice extensions what to do, whatever works for them honestly.
Sorry, something went wrong.
|
|
||
| ```typescript | ||
| // Pseudocode: Handler is an invented message-stream interface. | ||
| function searchMiddleware(next: Handler): Handler { |
There was a problem hiding this comment.
What's a handler here? The distinction between JSON-RPC middleware and a transport middleware is exactly in the type information about the middleware. I would have expected that a JSON-RPC Middleware will return some Request or Response JSON-RPC handler, where as a transport or middleware just has a general type T that represents a transport and has some associated interface that is dependent on the SDK that middleware can manipulate.
Sorry, something went wrong.
|
|
||
| Server Card serves a document beneath the MCP endpoint, and authorization extensions serve protected resource metadata at well-known paths, both outside the MCP endpoint's JSON-RPC processing. | ||
|
|
||
| - SDKs **MUST** let applications and extensions serve additional HTTP routes, for any HTTP method including `OPTIONS`, with full control of status, headers, and body. Most SDKs mount the MCP endpoint in a host framework, and documented [host composition](#host-frameworks) that lets an extension package add its routes satisfies this. |
There was a problem hiding this comment.
Can't this be done via a transport middleware? I am not sure we need to be explicit about this
Sorry, something went wrong.
There was a problem hiding this comment.
Yes, but generic middleware support doesn't necessarily give an extension access to the host router's matching and conflict handling. I'd keep the explicit requirement that extension packages can contribute routes through normal host composition, without requiring an MCP-specific route API.
Sorry, something went wrong.
| ### 4. Transport hooks | ||
|
|
||
| Transport hooks let extensions add to a transport without wrapping message processing. They are not middleware: an HTTP route handles its own requests rather than calling the next layer, and a launch setting configures a process rather than intercepting messages. As with transport middleware, extensions use them only for behaviour that cannot be expressed on JSON-RPC messages. |
There was a problem hiding this comment.
I am not sure I understand the need for transport hooks. I feel a transport hook is strictly a subset of a middleware.
Sorry, something went wrong.
There was a problem hiding this comment.
HTTP routing can be implemented through middleware, so “they are not middleware” is too categorical. Launch arguments and environment variables are configuration before a process starts. I'd describe routing and launch configuration as separate capabilities, without saying that routing cannot be implemented through middleware.
Sorry, something went wrong.
There was a problem hiding this comment.
@dsp-ant, I'm not sure I see the value of cross-SDK interface versioning. Given that extensions already need compatible SDK package versions to access the concrete APIs, what code would use Extensions.InterfaceVersion to make a decision that package compatibility or individual feature detection cannot make?
Sorry, something went wrong.
|
|
||
| Some methods produce more than one message. Middleware **MUST** be able to act on each message as it is produced or consumed, not only on a final result. Adding middleware **MUST NOT** change delivery order, cancellation, or error propagation, or force buffering of the whole stream. This covers protocol messages, not transport frames. | ||
|
|
||
| In the sending direction, middleware acts on an outgoing message before it is sent and on any messages returned by that operation. For a client request, this covers the outgoing request and the peer's response messages, including supported intermediate results. An outgoing notification has no response of its own. A notification emitted on a `subscriptions/listen` stream can be handled as a yielded message in the receiving chain for that request. A separate sending chain is not required when the receiving chain already covers those outbound messages. SDKs choose the API shape; the generator above illustrates receiving middleware, not a required signature for every direction. |
There was a problem hiding this comment.
On stdio, a client cannot reliably associate deprecated logging notifications with a particular operation. Should these messages still be interceptable without request correlation, or can they be excluded from the required client-side middleware coverage?
Sorry, something went wrong.
|
|
||
| #### Host frameworks | ||
|
|
||
| An SDK **MAY** meet the transport middleware and [transport hook](#4-transport-hooks) requirements through the host's HTTP stack, such as ASP.NET Core middleware and endpoints, Express or Hono, ASGI, `net/http` handlers and round trippers, Tower layers and routers, or servlet filters, if it exposes its HTTP handler and HTTP client as composable units and documents how to pass context into message processing. A dedicated MCP API is not required where the host's mechanism suffices, but an extension package **MUST** be able to contribute its transport middleware and hooks through the same registration as its other contributions or through documented host composition. |
There was a problem hiding this comment.
The host-framework section permits contributions through documented host composition. Does an extension still need to declare every contribution in one SDK registration, or can its package configure SDK services/filters and host middleware/routes separately? I'd like normal host configuration and options validation to satisfy this, with setup failures preventing activation, rather than require a combined plugin registration framework.
Sorry, something went wrong.
| ### 4. Transport hooks | ||
|
|
||
| Transport hooks let extensions add to a transport without wrapping message processing. They are not middleware: an HTTP route handles its own requests rather than calling the next layer, and a launch setting configures a process rather than intercepting messages. As with transport middleware, extensions use them only for behaviour that cannot be expressed on JSON-RPC messages. |
There was a problem hiding this comment.
HTTP routing can be implemented through middleware, so “they are not middleware” is too categorical. Launch arguments and environment variables are configuration before a process starts. I'd describe routing and launch configuration as separate capabilities, without saying that routing cannot be implemented through middleware.
Sorry, something went wrong.
|
|
||
| Server Card serves a document beneath the MCP endpoint, and authorization extensions serve protected resource metadata at well-known paths, both outside the MCP endpoint's JSON-RPC processing. | ||
|
|
||
| - SDKs **MUST** let applications and extensions serve additional HTTP routes, for any HTTP method including `OPTIONS`, with full control of status, headers, and body. Most SDKs mount the MCP endpoint in a host framework, and documented [host composition](#host-frameworks) that lets an extension package add its routes satisfies this. |
There was a problem hiding this comment.
Yes, but generic middleware support doesn't necessarily give an extension access to the host router's matching and conflict handling. I'd keep the explicit requirement that extension packages can contribute routes through normal host composition, without requiring an MCP-specific route API.
Sorry, something went wrong.
|
|
||
| - A dependency **MUST NOT** be considered unmet solely because it was registered or enabled after the extension that requires it. | ||
| - An extension's handlers and middleware **MUST NOT** run unless its dependencies are satisfied by the local configuration applicable to that execution. | ||
| - SDKs choose when to check dependencies and **SHOULD** check before serving where possible. A configuration-time check is sufficient when the relevant configuration cannot change. Where it can change or vary by request, the SDK **MUST** ensure the dependencies remain satisfied before running the extension. |
There was a problem hiding this comment.
Can we add a concrete example where dependency validation must happen during execution rather than during configuration? The examples here seem satisfiable with startup validation. In C#, we'd prefer required DI services and options validation where those suffice, rather than introduce a parallel dependency system.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Read the rendered SEP
Summary
Bundling extension implementations into SDKs ties their maintenance and releases together. This SEP defines three public extension points so extension owners can publish independent packages and applications can compose them on one SDK:
Each SDK chooses APIs that fit its language. Static middleware composition can satisfy ordering; runtime inspection is optional. Extensions may expose named insertion points without exposing every internal middleware step. Packaging and API stability follow each SDK's existing public API and versioning policies.
Requirements target protocol version 2026-07-28 and later. Tier 1 enforcement and conformance scenarios take effect with the first specification release after the SEP reaches Final; no separate deadline is introduced.
The SEP adds no wire fields or methods. It states the extension rules under which these hooks are sufficient and leaves extensions needing more responsible for their SDK compatibility. Conformance follows SEP-2484; a complete reference implementation is still needed. Appendices assess existing SDK APIs and extension needs and illustrate optional middleware composition designs.
Validation
AI assistance
Codex assisted with drafting and editing the SEP, reviewing linked sources and comments, validating the changes, and drafting review replies, following my design decisions.