Skip to content

Conversation

@felixweinberger
Copy link
Contributor

Summary

This PR adds a close_sse_stream callback to the tool context, addressing feedback from findleyr on the TypeScript SDK PR. This is a follow-up to #1654 (SEP-1699 SSE polling).

The key improvements:

  • Reduced coupling: Tools no longer need direct access to session_manager - the callback is injected into the context
  • Event store awareness: Callback is None if no event store is configured (so tools don't need to check this themselves)
  • Per-call retry interval: Each call to close_sse_stream() can specify its own retry interval in milliseconds

API Usage

FastMCP (high-level):

@mcp.tool()
async def long_running_task(ctx: Context) -> str:
    await ctx.info("Starting task...")
    
    # Close SSE stream to trigger polling behavior
    # Callback is None if not on streamable HTTP transport or no event store
    if ctx.close_sse_stream:
        await ctx.close_sse_stream(retry_interval=3000)  # Reconnect after 3s
    
    await asyncio.sleep(1)
    return "Task completed"

Lowlevel Server:

@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.ContentBlock]:
    ctx = app.request_context
    
    if ctx.close_sse_stream:
        await ctx.close_sse_stream(retry_interval=5000)
    
    return [types.TextContent(type="text", text="Done")]

Changes

  • src/mcp/shared/context.py: Added CloseSSEStreamCallback type and close_sse_stream field to RequestContext
  • src/mcp/shared/message.py: Added close_sse_stream field to ServerMessageMetadata
  • src/mcp/server/fastmcp/server.py: Added close_sse_stream property to Context class
  • src/mcp/server/streamable_http.py: Added callback factory and retry_interval parameter
  • src/mcp/server/streamable_http_manager.py: Pass through retry_interval parameter
  • src/mcp/server/lowlevel/server.py: Extract callback from metadata into RequestContext
  • Updated examples to use the new callback API

Test plan

  • All existing tests pass (772 tests)
  • Manual testing with everything-server test_reconnection tool

@felixweinberger felixweinberger marked this pull request as draft November 25, 2025 16:36
@felixweinberger felixweinberger force-pushed the fweinberger/sep-1699-callback-api branch 2 times, most recently from d34ddac to 86d7bd0 Compare November 25, 2025 16:56
Addresses feedback from TypeScript SDK PR #1129 on the SEP-1699 implementation:

1. Reduces coupling between tools and transport by providing a callback
   instead of requiring direct session_manager access
2. Makes event store awareness transparent - callback is None if no
   event store is configured (events would be lost otherwise)
3. Adds per-call retry_interval parameter for tool-specific reconnection
   timing

Changes:
- Add CloseSSEStreamCallback type to mcp/shared/context.py
- Add close_sse_stream field to RequestContext (lowlevel API)
- Add close_sse_stream property to FastMCP Context (high-level API)
- Add retry_interval parameter to close_sse_stream methods
- Create callback factory in StreamableHTTPServerTransport
- Inject callback via ServerMessageMetadata
- Update example servers to use new callback API
@felixweinberger felixweinberger force-pushed the fweinberger/sep-1699-callback-api branch from 86d7bd0 to ef13f29 Compare November 25, 2025 18:41
@felixweinberger felixweinberger marked this pull request as ready for review November 25, 2025 18:44
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