Skip to content

fix(mcp): add SSE keepalive ping task#21343

Open
airudotsh wants to merge 1 commit into
NousResearch:mainfrom
airudotsh:fix/mcp-sse-keepalive
Open

fix(mcp): add SSE keepalive ping task#21343
airudotsh wants to merge 1 commit into
NousResearch:mainfrom
airudotsh:fix/mcp-sse-keepalive

Conversation

@airudotsh

Copy link
Copy Markdown

Summary

  • adds a focused SSE keepalive task that sends lightweight MCP send_ping() calls while an SSE transport session is open
  • requests reconnect if a ping fails, leaving transport teardown in the existing _wait_for_lifecycle_event() / SSE session lifecycle path
  • starts and cancels the keepalive task inside the SSE-only branch so Streamable HTTP and stdio behavior are unchanged

Context

Follow-up to #5981 after #21323 landed the timeout and OAuth-forwarding pieces. This keeps the remaining keepalive work as a small single-commit PR on current main and avoids resurrecting the stale branch.

Related: #3976 proposed SSE/HTTP keepalive work more broadly; this PR intentionally limits scope to the unmerged SSE keepalive coroutine.

Test plan

  • RED: python -m pytest tests/tools/test_mcp_sse_transport.py::TestSSEKeepalive::test_sse_keepalive_sends_ping_until_ping_fails -q -o 'addopts=' failed on current main because _sse_keepalive did not exist
  • GREEN: python -m pytest tests/tools/test_mcp_sse_transport.py::TestSSEKeepalive -q -o 'addopts='
  • Regression: python -m pytest tests/tools/test_mcp_tool.py tests/tools/test_mcp_sse_transport.py -q -o 'addopts='

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an SSE-specific keepalive coroutine to MCPServerTask that periodically issues lightweight MCP send_ping() calls while an SSE session is open, triggering a reconnect signal on ping failure without changing teardown semantics for other transports.

Changes:

  • Add _sse_keepalive() coroutine to ping SSE sessions and request reconnect on failure.
  • Start/cancel the SSE keepalive task within the SSE branch of _run_http().
  • Add tests ensuring the keepalive task is started for SSE and that it uses send_ping() until failure.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
tools/mcp_tool.py Adds SSE keepalive coroutine and wires it into the SSE session lifecycle in _run_http().
tests/tools/test_mcp_sse_transport.py Adds unit tests for SSE keepalive task startup and ping loop behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tools/mcp_tool.py Outdated
Comment on lines +1362 to +1365
try:
await keepalive_task
except (asyncio.CancelledError, Exception):
pass
@airudotsh

Copy link
Copy Markdown
Author

Small clarification on scope: this intentionally does not replace the existing lifecycle keepalive in _wait_for_lifecycle_event(). That path still owns shutdown/reconnect coordination for all transports.

This PR only adds an SSE-scoped send_ping() loop while the SSE session is open, so idle SSE servers see lightweight client activity before the broader lifecycle keepalive interval. Ping failure only sets _reconnect_event; teardown still happens through the existing lifecycle/session path.

@airudotsh airudotsh force-pushed the fix/mcp-sse-keepalive branch from a909863 to 7fc9e90 Compare May 7, 2026 14:41
@airudotsh

Copy link
Copy Markdown
Author

Adjusted the keepalive cleanup per Copilot's cancellation note.

The SSE branch now cancels the keepalive task and awaits it with:

await asyncio.gather(keepalive_task, return_exceptions=True)

That still drains exceptions from the child keepalive task, but avoids explicitly catching asyncio.CancelledError around the await site so parent-task cancellation can propagate through _run_http() normally.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists tool/mcp MCP client and OAuth comp/tools Tool registry, model_tools, toolsets labels May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets P2 Medium — degraded but workaround exists tool/mcp MCP client and OAuth type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants