sse_client blocks indefinitely when server has incorrect base URL
Describe the bug
When using the sse_client function to connect to a remote MCP server, if the MCP server sets an incorrect base URL (like http://localhost:8080), the sse_client will raise an exception in the following code:
| raise ValueError(error_msg) |
The read_stream_writer then sends this exception to the read_stream:
| await read_stream_writer.send(exc) |
However, since the read_stream has not been yielded yet, the exception will never be received.
As a result, the sse_client will be blocked indefinitely.
To Reproduce
- Set up an MCP server with an incorrect base URL on a remote server, for example:
import express, { Request, Response } from 'express'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; import { z } from 'zod'; const server = new McpServer({ name: 'example-server', version: '1.0.0', }); server.tool( "calculate-bmi", { weightKg: z.number(), heightM: z.number() }, async ({ weightKg, heightM }) => ({ content: [{ type: "text", text: String(weightKg / (heightM * heightM)) }] }) ); const app = express(); const transports: { [sessionId: string]: SSEServerTransport } = {}; app.get('/sse', async (_: Request, res: Response) => { // set baseUrl for the transport const baseUrl = 'http://localhost:8080'; const transport = new SSEServerTransport(`${baseUrl}/messages`, res); transports[transport.sessionId] = transport; res.on('close', () => { delete transports[transport.sessionId]; }); await server.connect(transport); }); app.post('/messages', async (req: Request, res: Response) => { const sessionId = req.query.sessionId as string; const transport = transports[sessionId]; if (transport) { await transport.handlePostMessage(req, res); } else { res.status(400).send('No transport found for sessionId'); } }); app.listen(8080);
- Try to connect to the remote MCP server, for example:
import asyncio from mcp.client.sse import sse_client async def run(): try: async with sse_client("http://{your_remote_server}:8080/sse"): print("Connected to SSE endpoint successfully.") except Exception as e: print(f"Error: {e}") if __name__ == "__main__": asyncio.run(run())
Expected behavior
The sse_client should raise an exception and exit gracefully.
Logs
None
Additional context
None