Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions sentry_sdk/integrations/mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,6 @@ class MCPIntegration(Integration):
identifier = "mcp"
origin = "auto.ai.mcp"

def __init__(self, include_prompts: bool = True) -> None:
"""
Initialize the MCP integration.

Args:
include_prompts: Whether to include prompts (tool results and prompt content)
in span data. Requires send_default_pii=True. Default is True.
"""
self.include_prompts = include_prompts

@staticmethod
def setup_once() -> None:
"""
Expand Down Expand Up @@ -307,7 +297,7 @@ async def _instrument_tool_call(
if has_data_collection_enabled(client.options):
if client.options["data_collection"]["gen_ai"]["outputs"]:
should_include_result_data = True
elif should_send_default_pii() and integration.include_prompts:
elif should_send_default_pii():
should_include_result_data = True

result_content = result
Expand Down Expand Up @@ -399,7 +389,7 @@ async def _instrument_prompt_get(
if has_data_collection_enabled(client.options):
if client.options["data_collection"]["gen_ai"]["inputs"]:
should_include_result_data = True
elif should_send_default_pii() and integration.include_prompts:
elif should_send_default_pii():
should_include_result_data = True

# For prompts, count messages and set role/content only for single-message prompts
Expand Down
33 changes: 15 additions & 18 deletions tests/integrations/fastmcp/test_fastmcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- Span creation when tools/prompts/resources are called through MCP protocol
- Span data accuracy (operation, name, origin, etc.)
- Error capture and instrumentation
- PII and include_prompts flag behavior
- PII flag behavior
- Request context data extraction
- Transport detection (stdio, http, sse)

Expand Down Expand Up @@ -267,20 +267,19 @@ def reset_request_ctx():
@pytest.mark.asyncio
@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids)
@pytest.mark.parametrize(
"send_default_pii, include_prompts",
[(True, True), (True, False), (False, True), (False, False)],
"send_default_pii",
[True, False],
)
async def test_fastmcp_tool_sync(
sentry_init,
capture_items,
FastMCP,
send_default_pii,
include_prompts,
stdio,
):
"""Test that FastMCP synchronous tool handlers create proper spans"""
sentry_init(
integrations=[MCPIntegration(include_prompts=include_prompts)],
integrations=[MCPIntegration()],
traces_sample_rate=1.0,
send_default_pii=send_default_pii,
)
Expand Down Expand Up @@ -320,7 +319,7 @@ def add_numbers(a: int, b: int) -> dict:
assert span["attributes"][SPANDATA.MCP_REQUEST_ID] == "req-123"

# Check PII-sensitive data
if send_default_pii and include_prompts:
if send_default_pii:
assert SPANDATA.MCP_TOOL_RESULT_CONTENT in span["attributes"]
else:
assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in span["attributes"]
Expand All @@ -329,15 +328,15 @@ def add_numbers(a: int, b: int) -> dict:
@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids)
@pytest.mark.asyncio
@pytest.mark.parametrize(
"send_default_pii, include_prompts",
[(True, True), (True, False), (False, True), (False, False)],
"send_default_pii",
[True, False],
)
async def test_fastmcp_tool_async(
sentry_init, capture_items, FastMCP, send_default_pii, include_prompts, json_rpc
sentry_init, capture_items, FastMCP, send_default_pii, json_rpc
):
"""Test that FastMCP async tool handlers create proper spans"""
sentry_init(
integrations=[MCPIntegration(include_prompts=include_prompts)],
integrations=[MCPIntegration()],
traces_sample_rate=1.0,
send_default_pii=send_default_pii,
)
Expand Down Expand Up @@ -398,7 +397,7 @@ async def multiply_numbers(x: int, y: int) -> dict:
assert span["attributes"][SPANDATA.MCP_SESSION_ID] == session_id

# Check PII-sensitive data
if send_default_pii and include_prompts:
if send_default_pii:
assert SPANDATA.MCP_TOOL_RESULT_CONTENT in span["attributes"]
else:
assert SPANDATA.MCP_TOOL_RESULT_CONTENT not in span["attributes"]
Expand Down Expand Up @@ -464,7 +463,7 @@ async def test_fastmcp_tool_with_complex_return(
):
"""Test FastMCP tool with complex nested return value"""
sentry_init(
integrations=[MCPIntegration(include_prompts=True)],
integrations=[MCPIntegration()],
traces_sample_rate=1.0,
send_default_pii=True,
)
Expand Down Expand Up @@ -499,7 +498,6 @@ def get_user_data(user_id: int) -> dict:
assert len(tool_spans) == 1
assert tool_spans[0]["attributes"]["sentry.op"] == OP.MCP_SERVER
assert tool_spans[0]["attributes"][SPANDATA.MCP_TOOL_NAME] == "get_user_data"
# Complex return value should be captured since include_prompts=True and send_default_pii=True
assert SPANDATA.MCP_TOOL_RESULT_CONTENT in tool_spans[0]["attributes"]


Expand All @@ -511,20 +509,19 @@ def get_user_data(user_id: int) -> dict:
@pytest.mark.asyncio
@pytest.mark.parametrize("FastMCP", fastmcp_implementations, ids=fastmcp_ids)
@pytest.mark.parametrize(
"send_default_pii, include_prompts",
[(True, True), (False, False)],
"send_default_pii",
[True, False],
)
async def test_fastmcp_prompt_sync(
sentry_init,
capture_items,
FastMCP,
send_default_pii,
include_prompts,
stdio,
):
"""Test that FastMCP synchronous prompt handlers create proper spans"""
sentry_init(
integrations=[MCPIntegration(include_prompts=include_prompts)],
integrations=[MCPIntegration()],
traces_sample_rate=1.0,
send_default_pii=send_default_pii,
)
Expand Down Expand Up @@ -574,7 +571,7 @@ def code_help_prompt(language: str):
assert span["attributes"][SPANDATA.MCP_PROMPT_NAME] == "code_help_prompt"

# Check PII-sensitive data
if send_default_pii and include_prompts:
if send_default_pii:
assert SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT in span["attributes"]
else:
assert SPANDATA.MCP_PROMPT_RESULT_MESSAGE_CONTENT not in span["attributes"]
Expand Down
Loading
Loading