From 734aaebe931de611fb46d1ba17e80bdb7cb55a8e Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+he-yufeng@users.noreply.github.com> Date: Sun, 7 Jun 2026 16:50:05 +0800 Subject: [PATCH 1/3] fix: suppress MCPServer KeyboardInterrupt tracebacks --- src/mcp/server/mcpserver/server.py | 17 ++++++++++------- tests/server/mcpserver/test_server.py | 12 +++++++++++- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/mcp/server/mcpserver/server.py b/src/mcp/server/mcpserver/server.py index ec2365810..afa7a06e9 100644 --- a/src/mcp/server/mcpserver/server.py +++ b/src/mcp/server/mcpserver/server.py @@ -291,13 +291,16 @@ def run( if transport not in TRANSPORTS.__args__: # type: ignore # pragma: no cover raise ValueError(f"Unknown transport: {transport}") - match transport: - case "stdio": - anyio.run(self.run_stdio_async) - case "sse": # pragma: no cover - anyio.run(lambda: self.run_sse_async(**kwargs)) - case "streamable-http": # pragma: no cover - anyio.run(lambda: self.run_streamable_http_async(**kwargs)) + try: + match transport: + case "stdio": + anyio.run(self.run_stdio_async) + case "sse": # pragma: no cover + anyio.run(lambda: self.run_sse_async(**kwargs)) + case "streamable-http": # pragma: no cover + anyio.run(lambda: self.run_streamable_http_async(**kwargs)) + except KeyboardInterrupt: + return async def _handle_list_tools( self, ctx: ServerRequestContext[LifespanResultT], params: PaginatedRequestParams | None diff --git a/tests/server/mcpserver/test_server.py b/tests/server/mcpserver/test_server.py index 21352b5f2..418b35fb4 100644 --- a/tests/server/mcpserver/test_server.py +++ b/tests/server/mcpserver/test_server.py @@ -1,6 +1,6 @@ import base64 from pathlib import Path -from typing import Any +from typing import Any, Literal, cast from unittest.mock import AsyncMock, MagicMock, patch import pytest @@ -73,6 +73,16 @@ def test_dependencies(self): mcp_no_deps = MCPServer("test") assert mcp_no_deps.dependencies == [] + @pytest.mark.parametrize("transport", ["stdio", "sse", "streamable-http"]) + def test_run_suppresses_keyboard_interrupt(self, transport: str): + mcp = MCPServer("test") + transport_name = cast(Literal["stdio", "sse", "streamable-http"], transport) + + with patch("mcp.server.mcpserver.server.anyio.run", side_effect=KeyboardInterrupt) as run: + mcp.run(transport=transport_name) + + run.assert_called_once() + async def test_sse_app_returns_starlette_app(self): """Test that sse_app returns a Starlette application with correct routes.""" mcp = MCPServer("test") From 66ca55aa30e07fdd0ecd8d2629dcdd7fd214c8cf Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+he-yufeng@users.noreply.github.com> Date: Sun, 7 Jun 2026 17:37:51 +0800 Subject: [PATCH 2/3] test: update MCPServer run coverage markers --- src/mcp/server/mcpserver/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mcp/server/mcpserver/server.py b/src/mcp/server/mcpserver/server.py index afa7a06e9..131305885 100644 --- a/src/mcp/server/mcpserver/server.py +++ b/src/mcp/server/mcpserver/server.py @@ -295,9 +295,9 @@ def run( match transport: case "stdio": anyio.run(self.run_stdio_async) - case "sse": # pragma: no cover + case "sse": anyio.run(lambda: self.run_sse_async(**kwargs)) - case "streamable-http": # pragma: no cover + case "streamable-http": anyio.run(lambda: self.run_streamable_http_async(**kwargs)) except KeyboardInterrupt: return From a3d4178e5e4663cab00f37e6775b7005dec89f47 Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+he-yufeng@users.noreply.github.com> Date: Sun, 7 Jun 2026 17:47:36 +0800 Subject: [PATCH 3/3] test: preserve MCPServer branch coverage --- src/mcp/server/mcpserver/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mcp/server/mcpserver/server.py b/src/mcp/server/mcpserver/server.py index 131305885..9142552f4 100644 --- a/src/mcp/server/mcpserver/server.py +++ b/src/mcp/server/mcpserver/server.py @@ -297,7 +297,7 @@ def run( anyio.run(self.run_stdio_async) case "sse": anyio.run(lambda: self.run_sse_async(**kwargs)) - case "streamable-http": + case "streamable-http": # pragma: no branch anyio.run(lambda: self.run_streamable_http_async(**kwargs)) except KeyboardInterrupt: return