Skip to content

Commit 46a2622

Browse files
author
Olivier Gintrand
committed
fix: use POST ping for StreamableHTTP health check instead of full SDK client
The SDK's streamablehttp_client opens a GET SSE stream after initialize, which returns 405 Method Not Allowed on servers that don't support server-initiated messages (e.g. Microsoft 365, Kubernetes MCP, GitHub). The MCP spec states that GET is optional for StreamableHTTP — only POST is required. Replace the full SDK client health check with a lightweight JSON-RPC POST ping. A successful POST response is sufficient proof that the gateway server is alive and responding.
1 parent c04f65e commit 46a2622

File tree

1 file changed

+26
-8
lines changed

1 file changed

+26
-8
lines changed

mcpgateway/services/gateway_service.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3673,14 +3673,32 @@ def get_httpx_client_factory(
36733673
with anyio.fail_after(settings.health_check_timeout):
36743674
await pooled.session.list_tools()
36753675
else:
3676-
async with streamablehttp_client(url=gateway_url, headers=headers, timeout=settings.health_check_timeout, httpx_client_factory=get_httpx_client_factory) as (
3677-
read_stream,
3678-
write_stream,
3679-
_get_session_id,
3680-
):
3681-
async with ClientSession(read_stream, write_stream) as session:
3682-
# Initialize the session
3683-
response = await session.initialize()
3676+
# Use a lightweight JSON-RPC POST ``initialize`` instead of the
3677+
# full SDK client. The SDK opens a GET SSE stream after
3678+
# initialize, which returns 405 on servers that don't support
3679+
# server-initiated messages (M365, Kubernetes MCP, GitHub).
3680+
# The MCP spec says GET is optional, so a successful POST
3681+
# ``initialize`` is sufficient proof of health.
3682+
# NOTE: ``ping`` would require an existing session, so
3683+
# ``initialize`` is the only stateless RPC we can send.
3684+
init_payload = {
3685+
"jsonrpc": "2.0",
3686+
"id": "health-check",
3687+
"method": "initialize",
3688+
"params": {
3689+
"protocolVersion": "2024-11-05",
3690+
"capabilities": {},
3691+
"clientInfo": {"name": "mcpgateway-health", "version": "1.0.0"},
3692+
},
3693+
}
3694+
init_headers = {
3695+
**headers,
3696+
"Content-Type": "application/json",
3697+
"Accept": "application/json, text/event-stream",
3698+
}
3699+
timeout = httpx.Timeout(settings.health_check_timeout)
3700+
response = await client.post(gateway_url, json=init_payload, headers=init_headers, timeout=timeout)
3701+
response.raise_for_status()
36843702

36853703
# Reactivate gateway if it was previously inactive and health check passed now
36863704
if gateway_enabled and not gateway_reachable:

0 commit comments

Comments
 (0)