Skip to content

Commit 247f5d4

Browse files
ref(mcp): Use middleware when available
1 parent 41eece3 commit 247f5d4

1 file changed

Lines changed: 17 additions & 103 deletions

File tree

sentry_sdk/integrations/mcp.py

Lines changed: 17 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
if TYPE_CHECKING:
5656
from typing import Any, Awaitable, Callable, ContextManager, Optional, Tuple, Union
5757

58+
from mcp.server.context import CallNext, HandlerResult
5859
from mcp_types import (
5960
CallToolResult,
6061
GetPromptResult,
@@ -943,6 +944,21 @@ async def wrapper(*args: "Any") -> "Any":
943944
Server.read_resource = patched_read_resource # type: ignore[attr-defined]
944945

945946

947+
async def _sentry_middleware(
948+
ctx: "ServerRequestContext[Any, Any]", call_next: "CallNext"
949+
) -> "HandlerResult":
950+
if ctx.method == "tools/call":
951+
return await _tool_handler_wrapper(call_next, ctx)
952+
953+
if ctx.method == "prompts/get":
954+
return await _prompt_handler_wrapper(call_next, ctx)
955+
956+
if ctx.method == "resources/read":
957+
return await _resource_handler_wrapper(call_next, ctx)
958+
959+
return await call_next(ctx)
960+
961+
946962
def _patch_lowlevel_server_v2() -> None:
947963
"""Patches the v2 Server to wrap tool/prompt/resource handlers.
948964
@@ -955,113 +971,11 @@ def _patch_lowlevel_server_v2() -> None:
955971

956972
@wraps(original_init)
957973
def patched_init(self: "Server", *args: "Any", **kwargs: "Any") -> None:
958-
on_tool_call = kwargs.get("on_call_tool")
959-
if on_tool_call is not None and not getattr(
960-
on_tool_call, "__sentry_mcp_wrapped__", False
961-
):
962-
963-
@wraps(on_tool_call)
964-
async def wrapper(*args: "Any", **kwargs: "Any") -> "Any":
965-
return await _tool_handler_wrapper(
966-
on_tool_call, args, kwargs, force_await=False
967-
)
968-
969-
wrapper.__sentry_mcp_wrapped__ = True # type: ignore[attr-defined]
970-
kwargs["on_call_tool"] = wrapper
971-
972-
on_get_prompt = kwargs.get("on_get_prompt")
973-
if on_get_prompt is not None and not getattr(
974-
on_get_prompt, "__sentry_mcp_wrapped__", False
975-
):
976-
977-
@wraps(on_get_prompt)
978-
async def wrapper(*args: "Any", **kwargs: "Any") -> "Any":
979-
return await _prompt_handler_wrapper(
980-
on_get_prompt, args, kwargs, force_await=False
981-
)
982-
983-
wrapper.__sentry_mcp_wrapped__ = True # type: ignore[attr-defined]
984-
kwargs["on_get_prompt"] = wrapper
985-
986-
on_read_resource = kwargs.get("on_read_resource")
987-
if on_read_resource is not None and not getattr(
988-
on_read_resource, "__sentry_mcp_wrapped__", False
989-
):
990-
991-
@wraps(on_read_resource)
992-
async def wrapper(*args: "Any", **kwargs: "Any") -> "Any":
993-
return await _resource_handler_wrapper(
994-
on_read_resource, args, kwargs, force_await=False
995-
)
996-
997-
wrapper.__sentry_mcp_wrapped__ = True # type: ignore[attr-defined]
998-
kwargs["on_read_resource"] = wrapper
999-
1000974
original_init(self, *args, **kwargs)
975+
self.middleware.append(_sentry_middleware)
1001976

1002977
Server.__init__ = patched_init # type: ignore[method-assign]
1003978

1004-
original_add_request_handler = Server.add_request_handler
1005-
1006-
def patched_add_request_handler(
1007-
self: "Server",
1008-
method: str,
1009-
params_type: "Any",
1010-
handler: "Callable[..., Any]",
1011-
*args: "Any",
1012-
**kwargs: "Any",
1013-
) -> None:
1014-
if getattr(handler, "__sentry_mcp_wrapped__", False):
1015-
return original_add_request_handler(
1016-
self, method, params_type, handler, *args, **kwargs
1017-
)
1018-
1019-
if method == "tools/call":
1020-
1021-
@wraps(handler)
1022-
async def wrapper(*args: "Any", **kwargs: "Any") -> "Any":
1023-
return await _tool_handler_wrapper(
1024-
handler, args, kwargs, force_await=False
1025-
)
1026-
1027-
wrapper.__sentry_mcp_wrapped__ = True # type: ignore[attr-defined]
1028-
1029-
return original_add_request_handler(
1030-
self, method, params_type, wrapper, *args, **kwargs
1031-
)
1032-
if method == "prompts/get":
1033-
1034-
@wraps(handler)
1035-
async def wrapper(*args: "Any", **kwargs: "Any") -> "Any":
1036-
return await _prompt_handler_wrapper(
1037-
handler, args, kwargs, force_await=False
1038-
)
1039-
1040-
wrapper.__sentry_mcp_wrapped__ = True # type: ignore[attr-defined]
1041-
1042-
return original_add_request_handler(
1043-
self, method, params_type, wrapper, *args, **kwargs
1044-
)
1045-
if method == "resources/read":
1046-
1047-
@wraps(handler)
1048-
async def wrapper(*args: "Any", **kwargs: "Any") -> "Any":
1049-
return await _resource_handler_wrapper(
1050-
handler, args, kwargs, force_await=False
1051-
)
1052-
1053-
wrapper.__sentry_mcp_wrapped__ = True # type: ignore[attr-defined]
1054-
1055-
return original_add_request_handler(
1056-
self, method, params_type, wrapper, *args, **kwargs
1057-
)
1058-
1059-
original_add_request_handler(
1060-
self, method, params_type, handler, *args, **kwargs
1061-
)
1062-
1063-
Server.add_request_handler = patched_add_request_handler # type: ignore[method-assign]
1064-
1065979

1066980
def _patch_handle_request() -> None:
1067981
original_handle_request = StreamableHTTPServerTransport.handle_request

0 commit comments

Comments
 (0)