diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index e38478cafc..adf4cb97af 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -159,6 +159,14 @@ class GenAICollectionBehaviour(TypedDict): inputs: bool outputs: bool + class MCPCollectionUserOptions(TypedDict, total=False): + inputs: bool + outputs: bool + + class MCPCollectionBehaviour(TypedDict): + inputs: bool + outputs: bool + class GraphQLCollectionUserOptions(TypedDict, total=False): document: bool variables: bool @@ -181,6 +189,7 @@ class DataCollectionUserOptions(TypedDict, total=False): url_query_params: "KeyValueCollectionBehaviour" graphql: "GraphQLCollectionUserOptions" gen_ai: "GenAICollectionUserOptions" + mcp: "MCPCollectionUserOptions" database_query_data: bool queues: bool stack_frame_variables: "Union[bool, KeyValueCollectionBehaviour]" @@ -194,6 +203,7 @@ class DataCollection(TypedDict): url_query_params: "KeyValueCollectionBehaviour" graphql: "GraphQLCollectionBehaviour" gen_ai: "GenAICollectionBehaviour" + mcp: "MCPCollectionBehaviour" database_query_data: bool queues: bool stack_frame_variables: "Union[bool, KeyValueCollectionBehaviour]" diff --git a/sentry_sdk/data_collection.py b/sentry_sdk/data_collection.py index 2baf78dcc2..813165f02e 100644 --- a/sentry_sdk/data_collection.py +++ b/sentry_sdk/data_collection.py @@ -23,6 +23,7 @@ GraphQLCollectionBehaviour, HttpHeadersCollectionBehaviour, KeyValueCollectionBehaviour, + MCPCollectionBehaviour, ) # ``http_bodies`` defaults to this (collect everything the @@ -180,6 +181,7 @@ def _resolve( "url_query_params": _kvcb_from_value(d.get("url_query_params") or {}), "graphql": _graphql_from_value(d.get("graphql") or {}), "gen_ai": _gen_ai_from_value(d.get("gen_ai") or {}), + "mcp": _mcp_from_value(d.get("mcp") or {}), "database_query_data": d.get("database_query_data", True), "queues": d.get("queues", True), "stack_frame_variables": stack_frame_variables, @@ -225,6 +227,13 @@ def _gen_ai_from_value(val: "dict[str, Any]") -> "GenAICollectionBehaviour": } +def _mcp_from_value(val: "dict[str, Any]") -> "MCPCollectionBehaviour": + return { + "inputs": val.get("inputs", True), + "outputs": val.get("outputs", True), + } + + def _graphql_from_value( val: "dict[str, Any]", ) -> "GraphQLCollectionBehaviour": diff --git a/sentry_sdk/integrations/mcp.py b/sentry_sdk/integrations/mcp.py index 351ddda514..9a3f076fec 100644 --- a/sentry_sdk/integrations/mcp.py +++ b/sentry_sdk/integrations/mcp.py @@ -242,7 +242,7 @@ async def _instrument_tool_call( client = sentry_sdk.get_client() handler_name = ctx.params["name"] arguments = ctx.params.get("arguments") - if arguments is None or not client.options["data_collection"]["gen_ai"]["inputs"]: + if arguments is None or not client.options["data_collection"]["mcp"]["inputs"]: arguments = {} # Get request ID, session ID, and transport from context @@ -290,7 +290,7 @@ async def _instrument_tool_call( if ( result_content is None - or not client.options["data_collection"]["gen_ai"]["outputs"] + or not client.options["data_collection"]["mcp"]["outputs"] ): return result @@ -324,7 +324,7 @@ async def _instrument_prompt_get( arguments = ctx.params.get("arguments") - if arguments is None or not client.options["data_collection"]["gen_ai"]["inputs"]: + if arguments is None or not client.options["data_collection"]["mcp"]["inputs"]: arguments = {} # Get request ID, session ID, and transport from context @@ -381,7 +381,7 @@ async def _instrument_prompt_get( if ( message_count != 1 - or not client.options["data_collection"]["gen_ai"]["inputs"] + or not client.options["data_collection"]["mcp"]["outputs"] or not messages ): return result diff --git a/tests/integrations/fastmcp/test_fastmcp.py b/tests/integrations/fastmcp/test_fastmcp.py index edf101a330..7df8af9c48 100644 --- a/tests/integrations/fastmcp/test_fastmcp.py +++ b/tests/integrations/fastmcp/test_fastmcp.py @@ -276,7 +276,7 @@ async def test_fastmcp_tool_sync( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -333,7 +333,7 @@ async def test_fastmcp_tool_sync_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -385,7 +385,7 @@ async def test_fastmcp_tool_async(sentry_init, capture_items, FastMCP, json_rpc) integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -460,7 +460,7 @@ async def test_fastmcp_tool_async_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -589,7 +589,7 @@ async def test_fastmcp_tool_with_complex_return( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -647,7 +647,7 @@ async def test_fastmcp_prompt_sync( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -714,7 +714,7 @@ async def test_fastmcp_prompt_sync_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } diff --git a/tests/integrations/mcp/test_mcp.py b/tests/integrations/mcp/test_mcp.py index 038227a6d3..7cac486de4 100644 --- a/tests/integrations/mcp/test_mcp.py +++ b/tests/integrations/mcp/test_mcp.py @@ -258,7 +258,7 @@ async def test_tool_handler_stdio( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -334,7 +334,7 @@ async def test_tool_handler_stdio_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -399,7 +399,7 @@ async def test_tool_handler_streamable_http(sentry_init, capture_items, json_rpc integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -476,7 +476,7 @@ async def test_tool_handler_streamable_http_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -654,7 +654,7 @@ async def test_prompt_handler_stdio( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -727,7 +727,7 @@ async def test_prompt_handler_stdio_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -795,7 +795,7 @@ async def test_prompt_handler_streamable_http(sentry_init, capture_items, json_r integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -868,7 +868,7 @@ async def test_prompt_handler_streamable_http_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -1144,7 +1144,7 @@ async def test_tool_result_extraction_tuple( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -1197,7 +1197,7 @@ async def test_tool_result_extraction_tuple_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -1245,7 +1245,7 @@ async def test_tool_result_extraction_unstructured( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -1296,7 +1296,7 @@ async def test_tool_result_extraction_unstructured_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -1430,7 +1430,7 @@ async def test_prompt_with_dict_result( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, } @@ -1485,7 +1485,7 @@ async def test_prompt_with_dict_result_no_sensitive_data( integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": False, "outputs": False, } @@ -1536,7 +1536,7 @@ async def test_tool_with_complex_arguments(sentry_init, capture_items, stdio): integrations=[MCPIntegration()], traces_sample_rate=1.0, data_collection={ - "gen_ai": { + "mcp": { "inputs": True, "outputs": True, },