Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion csharp/sdk/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dotnet test # 66 tests across the interceptor test project

**Why message filter, not handlers**: `McpServerHandlers` and `McpServerImpl` are `internal` in the SDK. We can't register handlers for new JSON-RPC methods from outside. Instead we use `McpServerOptions.Filters.Message.IncomingFilters` to intercept `interceptors/list` and `interceptor/invoke`, handle them, send `JsonRpcResponse` via `context.Server.SendMessageAsync()`, and skip calling `next`. See `InterceptorMessageFilter.cs`. Chain execution is no longer a wire method — it's SDK orchestration in `Client/InterceptorChainOrchestrator.cs`.

**Why `ServerCapabilities.Extensions`**: The SDK's intended mechanism for protocol extensions. Requires `#pragma warning disable MCPEXP001`. We advertise `InterceptorsCapability { SupportedEvents }` under `Extensions["interceptors"]`.
**Why `ServerCapabilities.Extensions`**: The SDK's intended mechanism for protocol extensions. Requires `#pragma warning disable MCPEXP001`. We advertise `InterceptorsCapability { SupportedEvents }` under `Extensions["io.modelcontextprotocol/interceptors"]`.

**Client `SendRequestAsync`**: The public overload (`McpSession.Methods.cs:24`) takes `JsonSerializerOptions`. We pass `InterceptorJsonUtilities.DefaultOptions` which chains `McpJsonUtilities.DefaultOptions` + our `InterceptorJsonContext`. The internal overload takes `JsonTypeInfo<T>` — we can't use it.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ namespace ModelContextProtocol.Interceptors;

internal static class InterceptorProtocolConstants
{
internal const string ExtensionCapabilityKey = "interceptors";
internal const string ExtensionCapabilityKey = "io.modelcontextprotocol/interceptors";
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace ModelContextProtocol.Interceptors.Protocol;

/// <summary>
/// Represents the interceptors capability advertised by a server during initialization.
/// This is placed in <c>ServerCapabilities.Extensions["interceptors"]</c>.
/// This is placed in <c>ServerCapabilities.Extensions["io.modelcontextprotocol/interceptors"]</c>.
/// </summary>
public sealed class InterceptorsCapability
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ public async Task ConfigureServerOptions_MirrorsBackendExtensionsInTransparentMo
var caps = fixture.ProxyClient.ServerCapabilities;
Assert.NotNull(caps.Extensions);
Assert.True(caps.Extensions!.ContainsKey("com.example/backend"));
Assert.False(caps.Extensions.ContainsKey("interceptors"));
Assert.False(caps.Extensions.ContainsKey("io.modelcontextprotocol/interceptors"));
#pragma warning restore MCPEXP001
}

Expand All @@ -292,7 +292,7 @@ public async Task ConfigureServerOptions_DoesNotAdvertiseInterceptorsCapabilityB

#pragma warning disable MCPEXP001
var caps = fixture.ProxyClient.ServerCapabilities;
Assert.False(caps?.Extensions?.ContainsKey("interceptors") ?? false);
Assert.False(caps?.Extensions?.ContainsKey("io.modelcontextprotocol/interceptors") ?? false);
#pragma warning restore MCPEXP001
}

Expand All @@ -318,7 +318,7 @@ public async Task ConfigureServerOptions_AdvertisesInterceptorsCapabilityWhenEna
#pragma warning disable MCPEXP001
var caps = fixture.ProxyClient.ServerCapabilities;
Assert.NotNull(caps?.Extensions);
Assert.True(caps!.Extensions!.ContainsKey("interceptors"));
Assert.True(caps!.Extensions!.ContainsKey("io.modelcontextprotocol/interceptors"));
Assert.True(caps.Extensions.ContainsKey("com.example/backend"));
#pragma warning restore MCPEXP001
}
Expand Down
12 changes: 7 additions & 5 deletions docs/sep.md
Original file line number Diff line number Diff line change
Expand Up @@ -1346,13 +1346,15 @@ During initialization, servers declare interceptor support:
jsonrpc: "2.0",
id: 1,
result: {
protocolVersion: "2024-11-05",
protocolVersion: "2025-06-18",
capabilities: {
interceptor?: {
// Events this server's interceptor can handle
supportedEvents: InterceptionEvent[];
},
// ...existing capabilities
extensions: {
"io.modelcontextprotocol/interceptors": {
// Events this server's interceptors can handle
supportedEvents: InterceptionEvent[];
}
}
},
serverInfo: {
name: "example-server",
Expand Down
11 changes: 5 additions & 6 deletions go/sdk/interceptors/extension/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/modelcontextprotocol/ext-interceptors/go/sdk/interceptors/chain"
)

// extensionID is the capability key used in Capabilities.Experimental
// extensionID is the capability key used in Capabilities.Extensions
const extensionID = "io.modelcontextprotocol/interceptors"

// Option configures an Extension.
Expand Down Expand Up @@ -163,8 +163,7 @@ func (e *Extension) initMiddleware() mcp.Middleware {

// enrichInitResult injects interceptor capability metadata into the
// InitializeResult, following the same pattern as the variants extension.
// The capability is declared under Capabilities.Experimental so it works
// without upstream go-sdk changes.
// The capability is declared under Capabilities.Extensions per SEP-2133.
func (e *Extension) enrichInitResult(result mcp.Result) (mcp.Result, error) {
initResult, ok := result.(*mcp.InitializeResult)
if !ok {
Expand All @@ -174,8 +173,8 @@ func (e *Extension) enrichInitResult(result mcp.Result) (mcp.Result, error) {
if initResult.Capabilities == nil {
initResult.Capabilities = &mcp.ServerCapabilities{}
}
if initResult.Capabilities.Experimental == nil {
initResult.Capabilities.Experimental = make(map[string]any)
if initResult.Capabilities.Extensions == nil {
initResult.Capabilities.Extensions = make(map[string]any)
}

all := e.getInterceptors()
Expand All @@ -193,7 +192,7 @@ func (e *Extension) enrichInitResult(result mcp.Result) (mcp.Result, error) {
events = append(events, ev)
}

initResult.Capabilities.Experimental[extensionID] = map[string]any{
initResult.Capabilities.Extensions[extensionID] = map[string]any{
"supportedEvents": events,
}

Expand Down
Loading