Skip to content

mcp: add StreamableHTTPHandler.Close for graceful shutdown#1001

Open
piyushbag wants to merge 1 commit into
modelcontextprotocol:mainfrom
piyushbag:fix-440-streamable-handler-close
Open

mcp: add StreamableHTTPHandler.Close for graceful shutdown#1001
piyushbag wants to merge 1 commit into
modelcontextprotocol:mainfrom
piyushbag:fix-440-streamable-handler-close

Conversation

@piyushbag

@piyushbag piyushbag commented Jun 10, 2026

Copy link
Copy Markdown

Problem

StreamableHTTPHandler holds stateful sessions in an internal map but had no public way to shut them down. Callers embedding the handler in an HTTP server (or running it in tests) could not reliably tear down all MCP sessions or block new ones during shutdown. The issue author proposed a Close() method; the codebase already had a private closeAll() helper with a TODO noting that a public API must also prevent new sessions from being added.

Approach

  • Add Close() error on StreamableHTTPHandler: set a closed flag, snapshot and clear the sessions map under lock, then call session.Close() on each entry outside the lock (avoids deadlocking with session onClose callbacks).
  • Reject new traffic in ServeHTTP with 503 Service Unavailable once closed.
  • Make Close idempotent (second call is a no-op).
  • Keep the existing test-only closeAll() as a thin delegate to Close().
  • Add TestStreamableHTTPHandlerClose covering session teardown, empty map, idempotency, and 503 after close.

Why this is better

  • Matches the API shape requested in the issue (Close() error, closes all sessions, prevents new sessions).
  • Enables idiomatic cleanup: defer handler.Close() in main or test teardown without reaching into unexported fields.
  • Minimal diff: extends existing session lifecycle patterns rather than introducing callbacks or new types.
  • Aligns with graceful-shutdown patterns in other MCP SDKs (explicit handler/session disposal) while staying Go-native.

Fixes #440

Expose public Close() to tear down all sessions and reject new requests
with 503, matching the API proposed in modelcontextprotocol#440.
@piyushbag

Copy link
Copy Markdown
Author

Local verification on fix-440-streamable-handler-close (78d7176):

go test ./... -count=1
ok  github.com/modelcontextprotocol/go-sdk/mcp
ok  github.com/modelcontextprotocol/go-sdk/oauthex

go test -race ./mcp/... -run TestStreamableHTTPHandlerClose -count=1
ok  github.com/modelcontextprotocol/go-sdk/mcp

This matches the shutdown shape discussed in #440. Let me know if you want Close to return the first session error vs. swallowing after best-effort teardown.

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.

Proposal: add StreamableHTTPHandler.Close

1 participant