Skip to content

feat(mcp): Add McpServerInterceptor with scoped hooks#1174

Merged
adwsingh merged 1 commit into
smithy-lang:mainfrom
ClayGifford1:mcp-request-interceptor
May 19, 2026
Merged

feat(mcp): Add McpServerInterceptor with scoped hooks#1174
adwsingh merged 1 commit into
smithy-lang:mainfrom
ClayGifford1:mcp-request-interceptor

Conversation

@ClayGifford1
Copy link
Copy Markdown

@ClayGifford1 ClayGifford1 commented May 12, 2026

Summary

Server interceptor hooks:

  • Adds McpServerInterceptor interface with scoped read/modify hooks at specific pipeline stages, following the ClientInterceptor pattern
  • Hooks: readBefore/modifyBefore and readAfter/modifyAfter for both execution-level and tool-call-level stages
  • Hook data via McpExecutionHook and McpToolCallHook (typed context, request, protocol version, tool metadata)
  • McpServerInterceptor.chain() for composing multiple interceptors, with error handling matching ClientInterceptorChain (swapError, last-write-wins for read hooks, immediate propagation for modify hooks)
  • Single interceptor setter on McpService.Builder.interceptor() and McpServerBuilder.interceptor()
  • Zero-cost NOOP fast path when no interceptor is configured

Extensible proxy transport:

  • Makes McpServerProxy.rpc(), start(), shutdown() protected to allow custom proxy transport implementations outside the package

Motivation

There's currently no way to observe, augment, or short-circuit requests at the McpService level. Consumers using McpService directly can wrap it, but that customization is lost when using McpServer, which creates and owns the McpService instance internally. Placing the interceptor on McpService.Builder solves both cases — direct McpService users add interceptors at construction, and McpServerBuilder plumbs them through.

The hook-based approach follows the established ClientInterceptor pattern — scoped hooks with typed context rather than a generic request handler chain. McpService owns when hooks fire, so interceptors never need to understand async dispatch internals.

Separately, custom MCP proxy transports beyond the provided stdio and HTTP implementations are not possible today because McpServerProxy's abstract methods are package-private. Making them protected allows consumers to implement their own proxy transports.

@ClayGifford1 ClayGifford1 force-pushed the mcp-request-interceptor branch from eff5f6a to 33e2eb0 Compare May 18, 2026 18:08
@ClayGifford1 ClayGifford1 changed the title feat(mcp): Add request interceptor chain and extensible proxy transport feat(mcp): Add McpServerInterceptor with scoped hooks May 18, 2026
Add hook-based server interceptor for McpService, following the
established ClientInterceptor pattern. Interceptors observe or modify
requests at specific pipeline stages without exposing async dispatch
internals.

Hooks: readBefore/modifyBefore Execution and ToolCall,
readAfter/modifyAfter Execution and ToolCall.

Also makes McpServerProxy's rpc(), start(), and shutdown() protected
to allow custom proxy transport implementations.
@adwsingh adwsingh force-pushed the mcp-request-interceptor branch from 33e2eb0 to e1dc33d Compare May 18, 2026 22:38
@adwsingh adwsingh enabled auto-merge (rebase) May 18, 2026 23:56
@adwsingh adwsingh merged commit c82469e into smithy-lang:main May 19, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants