|
| 1 | +--- |
| 2 | +title: MCP (Model Context Protocol) |
| 3 | +description: "Learn about using the Sentry Python SDK for MCP (Model Context Protocol) servers." |
| 4 | +--- |
| 5 | + |
| 6 | +<Alert title="Beta"> |
| 7 | + |
| 8 | +The support for **MCP (Model Context Protocol) Python SDK** is in its beta phase. Please test locally before using in production. |
| 9 | + |
| 10 | +</Alert> |
| 11 | + |
| 12 | +This integration connects Sentry with the [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk), enabling monitoring and error tracking for MCP servers built with Python. |
| 13 | + |
| 14 | +The integration supports both the high-level FastMCP API and the low-level `mcp.server.lowlevel.Server` API, automatically instrumenting tools, prompts, and resources. |
| 15 | + |
| 16 | +Once you've installed this SDK, you can use Sentry to monitor your MCP server's operations, track tool executions, and capture errors that occur during request handling. |
| 17 | + |
| 18 | +Sentry MCP monitoring will automatically collect information about: |
| 19 | + |
| 20 | +- Tool invocations and their arguments |
| 21 | +- Prompt template requests |
| 22 | +- Resource access operations |
| 23 | +- Request and session identifiers |
| 24 | +- Transport types (stdio/HTTP) |
| 25 | +- Execution errors |
| 26 | + |
| 27 | +## Install |
| 28 | + |
| 29 | +Install `sentry-sdk` from PyPI with the `mcp` extra: |
| 30 | + |
| 31 | +```bash {tabTitle:pip} |
| 32 | +pip install "sentry-sdk[mcp]" |
| 33 | +``` |
| 34 | + |
| 35 | +```bash {tabTitle:uv} |
| 36 | +uv add "sentry-sdk[mcp]" |
| 37 | +``` |
| 38 | + |
| 39 | +## Configure |
| 40 | + |
| 41 | +If you have the `mcp` package in your dependencies, the MCP integration will be enabled automatically when you initialize the Sentry SDK. |
| 42 | + |
| 43 | +<PlatformContent includePath="getting-started-config" /> |
| 44 | + |
| 45 | +## Verify |
| 46 | + |
| 47 | +Verify that the integration works by running an MCP server with tool handlers. The resulting data should show up in your Sentry dashboard. |
| 48 | + |
| 49 | +### Using FastMCP (High-Level API) |
| 50 | + |
| 51 | +FastMCP provides a simplified decorator-based API for building MCP servers: |
| 52 | + |
| 53 | +```python |
| 54 | +import sentry_sdk |
| 55 | +from sentry_sdk.integrations.mcp import MCPIntegration |
| 56 | + |
| 57 | +from mcp.server.fastmcp import FastMCP |
| 58 | + |
| 59 | +# Initialize Sentry |
| 60 | +sentry_sdk.init( |
| 61 | + dsn="___PUBLIC_DSN___", |
| 62 | + traces_sample_rate=1.0, |
| 63 | + # Add data like tool inputs/outputs; |
| 64 | + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info |
| 65 | + send_default_pii=True, |
| 66 | +) |
| 67 | + |
| 68 | +# Create the MCP server |
| 69 | +mcp = FastMCP("Example MCP Server") |
| 70 | + |
| 71 | +# Define a tool |
| 72 | +@mcp.tool() |
| 73 | +async def calculate_sum(a: int, b: int) -> int: |
| 74 | + """Add two numbers together.""" |
| 75 | + return a + b |
| 76 | + |
| 77 | +@mcp.tool() |
| 78 | +def greet_user(name: str) -> str: |
| 79 | + """Generate a personalized greeting.""" |
| 80 | + return f"Hello, {name}! Welcome to the MCP server." |
| 81 | + |
| 82 | +# Define a resource |
| 83 | +@mcp.resource("config://settings") |
| 84 | +def get_settings() -> str: |
| 85 | + """Get server configuration settings.""" |
| 86 | + return "Server Configuration: Version 1.0.0" |
| 87 | + |
| 88 | +# Define a prompt |
| 89 | +@mcp.prompt() |
| 90 | +def code_review_prompt(language: str = "python") -> str: |
| 91 | + """Generate a code review prompt for a specific language.""" |
| 92 | + return f"You are an expert {language} code reviewer..." |
| 93 | + |
| 94 | +# Run the server |
| 95 | +mcp.run() |
| 96 | +``` |
| 97 | + |
| 98 | +### Using the Low-Level API |
| 99 | + |
| 100 | +For more control over server behavior, use the low-level API: |
| 101 | + |
| 102 | +```python |
| 103 | +import asyncio |
| 104 | +from typing import Any |
| 105 | + |
| 106 | +import sentry_sdk |
| 107 | +from sentry_sdk.integrations.mcp import MCPIntegration |
| 108 | + |
| 109 | +from mcp.server.lowlevel import Server |
| 110 | +from mcp.server import stdio |
| 111 | +from mcp.types import Tool, TextContent, GetPromptResult, PromptMessage |
| 112 | + |
| 113 | +# Initialize Sentry |
| 114 | +sentry_sdk.init( |
| 115 | + dsn="___PUBLIC_DSN___", |
| 116 | + traces_sample_rate=1.0, |
| 117 | + send_default_pii=True, |
| 118 | +) |
| 119 | + |
| 120 | +# Create the low-level MCP server |
| 121 | +server = Server("example-lowlevel-server") |
| 122 | + |
| 123 | +# List available tools |
| 124 | +@server.list_tools() |
| 125 | +async def list_tools() -> list[Tool]: |
| 126 | + return [ |
| 127 | + Tool( |
| 128 | + name="calculate_sum", |
| 129 | + description="Add two numbers together", |
| 130 | + inputSchema={ |
| 131 | + "type": "object", |
| 132 | + "properties": { |
| 133 | + "a": {"type": "number", "description": "First number"}, |
| 134 | + "b": {"type": "number", "description": "Second number"}, |
| 135 | + }, |
| 136 | + "required": ["a", "b"], |
| 137 | + }, |
| 138 | + ), |
| 139 | + ] |
| 140 | + |
| 141 | +# Handle tool execution |
| 142 | +@server.call_tool() |
| 143 | +async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]: |
| 144 | + if name == "calculate_sum": |
| 145 | + a = arguments.get("a", 0) |
| 146 | + b = arguments.get("b", 0) |
| 147 | + result = a + b |
| 148 | + return [TextContent(type="text", text=f"The sum is {result}")] |
| 149 | + |
| 150 | + return [TextContent(type="text", text=f"Unknown tool: {name}")] |
| 151 | + |
| 152 | +async def main(): |
| 153 | + async with stdio.stdio_server() as (read_stream, write_stream): |
| 154 | + await server.run( |
| 155 | + read_stream, |
| 156 | + write_stream, |
| 157 | + server.create_initialization_options(), |
| 158 | + ) |
| 159 | + |
| 160 | +if __name__ == "__main__": |
| 161 | + asyncio.run(main()) |
| 162 | +``` |
| 163 | + |
| 164 | +It may take a couple of moments for the data to appear in [sentry.io](https://sentry.io). |
| 165 | + |
| 166 | +## Behavior |
| 167 | + |
| 168 | +Data on the following will be collected: |
| 169 | + |
| 170 | +- **Tool executions**: Tool name, arguments, results, and execution errors |
| 171 | +- **Prompt requests**: Prompt name, arguments, message counts, and content (for single-message prompts) |
| 172 | +- **Resource access**: Resource URI, protocol, and access patterns |
| 173 | +- **Request context**: Request IDs, session IDs, and transport types (stdio/HTTP) |
| 174 | +- **Execution spans**: Timing information for all handler invocations |
| 175 | + |
| 176 | +Sentry considers tool inputs/outputs and prompt content as PII and doesn't include PII data by default. If you want to include the data, set `send_default_pii=True` in the `sentry_sdk.init()` call. To explicitly exclude this data despite `send_default_pii=True`, configure the integration with `include_prompts=False` as shown in the [Options section](#options) below. |
| 177 | + |
| 178 | +### Captured Span Data |
| 179 | + |
| 180 | +For each operation, the following span data attributes are captured: |
| 181 | + |
| 182 | +**General (all operations):** |
| 183 | +- `mcp.method.name`: The MCP method name (e.g., `tools/call`, `prompts/get`, `resources/read`) |
| 184 | +- `mcp.transport`: Transport type (`pipe` for stdio, `tcp` for HTTP) |
| 185 | +- `mcp.request_id`: Request identifier (when available) |
| 186 | +- `mcp.session_id`: Session identifier (when available) |
| 187 | + |
| 188 | +**Tools:** |
| 189 | +- `mcp.tool.name`: The name of the tool being executed |
| 190 | +- `mcp.request.argument.*`: Tool input arguments |
| 191 | +- `mcp.tool.result.content`: Tool output (when `send_default_pii=True`) |
| 192 | +- `mcp.tool.result.is_error`: Whether the tool execution resulted in an error |
| 193 | + |
| 194 | +**Prompts:** |
| 195 | +- `mcp.prompt.name`: The name of the prompt being requested |
| 196 | +- `mcp.request.argument.*`: Prompt input arguments |
| 197 | +- `mcp.prompt.result.message.count`: Number of messages in the prompt result |
| 198 | +- `mcp.prompt.result.message.role`: Role of the message (for single-message prompts) |
| 199 | +- `mcp.prompt.result.message.content`: Message content (for single-message prompts, when `send_default_pii=True`) |
| 200 | + |
| 201 | +**Resources:** |
| 202 | +- `mcp.resource.uri`: The URI of the resource being accessed |
| 203 | +- `mcp.resource.protocol`: The URI protocol/scheme (e.g., `config`, `data`, `file`) |
| 204 | + |
| 205 | +## Options |
| 206 | + |
| 207 | +By adding `MCPIntegration` to your `sentry_sdk.init()` call explicitly, you can set options for `MCPIntegration` to change its behavior: |
| 208 | + |
| 209 | +```python |
| 210 | +import sentry_sdk |
| 211 | +from sentry_sdk.integrations.mcp import MCPIntegration |
| 212 | + |
| 213 | +sentry_sdk.init( |
| 214 | + # ... |
| 215 | + # Add data like tool inputs and outputs; |
| 216 | + # see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info |
| 217 | + send_default_pii=True, |
| 218 | + integrations=[ |
| 219 | + MCPIntegration( |
| 220 | + include_prompts=False, # Tool and prompt inputs/outputs will not be sent to Sentry |
| 221 | + ), |
| 222 | + ], |
| 223 | +) |
| 224 | +``` |
| 225 | + |
| 226 | +You can pass the following keyword arguments to `MCPIntegration()`: |
| 227 | + |
| 228 | +- `include_prompts`: |
| 229 | + |
| 230 | + Whether tool inputs/outputs and prompt content should be sent to Sentry. Sentry considers this data personal identifiable data (PII) by default. If you want to include the data, set `send_default_pii=True` in the `sentry_sdk.init()` call. To explicitly exclude prompts and outputs despite `send_default_pii=True`, configure the integration with `include_prompts=False`. |
| 231 | + |
| 232 | + The default is `True`. |
| 233 | + |
| 234 | +## Supported Versions |
| 235 | + |
| 236 | +- MCP SDK: 1.15.0+ |
| 237 | +- Python: 3.9+ |
| 238 | + |
0 commit comments