Skip to content

Commit 30a61fd

Browse files
committed
Handle KeyboardInterrupt in server run
1 parent 19fe9fa commit 30a61fd

2 files changed

Lines changed: 31 additions & 7 deletions

File tree

src/mcp/server/mcpserver/server.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -291,13 +291,16 @@ def run(
291291
if transport not in TRANSPORTS.__args__: # type: ignore # pragma: no cover
292292
raise ValueError(f"Unknown transport: {transport}")
293293

294-
match transport:
295-
case "stdio":
296-
anyio.run(self.run_stdio_async)
297-
case "sse": # pragma: no cover
298-
anyio.run(lambda: self.run_sse_async(**kwargs))
299-
case "streamable-http": # pragma: no cover
300-
anyio.run(lambda: self.run_streamable_http_async(**kwargs))
294+
try:
295+
match transport:
296+
case "stdio":
297+
anyio.run(self.run_stdio_async)
298+
case "sse": # pragma: no cover
299+
anyio.run(lambda: self.run_sse_async(**kwargs))
300+
case "streamable-http": # pragma: no cover
301+
anyio.run(lambda: self.run_streamable_http_async(**kwargs))
302+
except KeyboardInterrupt:
303+
return
301304

302305
async def _handle_list_tools(
303306
self, ctx: ServerRequestContext[LifespanResultT], params: PaginatedRequestParams | None

tests/server/mcpserver/test_server.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,27 @@ def test_dependencies(self):
7373
mcp_no_deps = MCPServer("test")
7474
assert mcp_no_deps.dependencies == []
7575

76+
def test_run_suppresses_keyboard_interrupt(self, monkeypatch: pytest.MonkeyPatch):
77+
mcp = MCPServer("test")
78+
79+
def raise_keyboard_interrupt(*args: Any, **kwargs: Any) -> None:
80+
raise KeyboardInterrupt
81+
82+
monkeypatch.setattr("mcp.server.mcpserver.server.anyio.run", raise_keyboard_interrupt)
83+
84+
assert mcp.run(transport="stdio") is None
85+
86+
def test_run_reraises_other_exceptions(self, monkeypatch: pytest.MonkeyPatch):
87+
mcp = MCPServer("test")
88+
89+
def raise_runtime_error(*args: Any, **kwargs: Any) -> None:
90+
raise RuntimeError("startup failed")
91+
92+
monkeypatch.setattr("mcp.server.mcpserver.server.anyio.run", raise_runtime_error)
93+
94+
with pytest.raises(RuntimeError, match="startup failed"):
95+
mcp.run(transport="stdio")
96+
7697
async def test_sse_app_returns_starlette_app(self):
7798
"""Test that sse_app returns a Starlette application with correct routes."""
7899
mcp = MCPServer("test")

0 commit comments

Comments
 (0)