How do you use Sentry?
Sentry Saas (sentry.io)
Version
2.68.0 and 2.68.1 (latest); the code is unchanged on master (692cca25, 2026-09-04)
Steps to Reproduce
Minimal FastMCP (3.4.7, mcp 1.29.x) server with a prompt and sentry_sdk.init active (the MCP integration is auto-enabled):
import sentry_sdk
from fastmcp import FastMCP
sentry_sdk.init(dsn="https://examplePublicKey@o0.ingest.sentry.io/0")
mcp = FastMCP("repro")
@mcp.prompt
def guide() -> str:
return "hello"
mcp.run(transport="http", host="127.0.0.1", port=8765)
Call prompts/get without arguments (spec-legal — the field is optional), e.g. with the SDK client:
async with streamablehttp_client("http://127.0.0.1:8765/mcp") as (r, w, _):
async with ClientSession(r, w) as s:
await s.initialize()
await s.get_prompt("guide") # arguments omitted -> fails
await s.get_prompt("guide", {}) # arguments {} -> renders
or raw JSON-RPC after initialize / notifications/initialized:
{"jsonrpc":"2.0","id":2,"method":"prompts/get","params":{"name":"guide"}}
Expected Result
The prompt renders (GetPromptResult with one message), exactly as it does when sentry_sdk.init is not called, or when arguments: {} is sent.
Actual Result
{"jsonrpc":"2.0","id":2,"error":{"code":0,"message":"'NoneType' object has no attribute 'items'"}}
Cause, sentry_sdk/integrations/mcp.py (2.68.1):
- The mcp v1 low-level server calls the prompt handler positionally as
func(req.params.name, req.params.arguments) (mcp/server/lowlevel/server.py:294), so original_args == (name, None) when the client omitted arguments.
_extract_handler_data_from_args, handler_type == "prompt" branch (:289-298): arguments = {} … if len(original_args) > 1: arguments = original_args[1] — the None is taken as-is. Only the kwargs branch (elif original_kwargs.get("arguments")) is falsy-guarded.
_set_span_input_data then does for k, v in arguments.items() (:206) → AttributeError, which the server returns to the client as a JSON-RPC error.
The tool branch has the same shape at :284-285 (arguments = original_args[1]), though tool calls in practice always carry an arguments dict.
Measured 2026-09-04 (fastmcp 3.4.7, mcp 1.29.1, sentry-sdk 2.68.1, Python 3.12):
sentry=False bare -> OK messages=1
sentry=False empty -> OK messages=1
sentry=False nonempty -> OK messages=1
sentry=True bare -> FAIL mcp.shared.exceptions.McpError: 'NoneType' object has no attribute 'items'
sentry=True empty -> OK messages=1
sentry=True nonempty -> OK messages=1
``` We hit this fleet-wide through an MCP gateway (IBM ContextForge) that forwards `prompts/get` with `arguments` omitted whenever the downstream caller sent none or `{}`; every backend with a `SENTRY_DSN` rejected it.
### Suggested fix
```python
if len(original_args) > 1:
arguments = original_args[1] or {}
(and the same or {} on the tool branch's positional read), or a None guard in _set_span_input_data before .items().
How do you use Sentry?
Sentry Saas (sentry.io)
Version
2.68.0 and 2.68.1 (latest); the code is unchanged on
master(692cca25, 2026-09-04)Steps to Reproduce
Minimal FastMCP (3.4.7, mcp 1.29.x) server with a prompt and
sentry_sdk.initactive (the MCP integration is auto-enabled):Call
prompts/getwithoutarguments(spec-legal — the field is optional), e.g. with the SDK client:or raw JSON-RPC after
initialize/notifications/initialized:Expected Result
The prompt renders (
GetPromptResultwith one message), exactly as it does whensentry_sdk.initis not called, or whenarguments: {}is sent.Actual Result
Cause,
sentry_sdk/integrations/mcp.py(2.68.1):func(req.params.name, req.params.arguments)(mcp/server/lowlevel/server.py:294), sooriginal_args == (name, None)when the client omittedarguments._extract_handler_data_from_args,handler_type == "prompt"branch (:289-298):arguments = {}…if len(original_args) > 1: arguments = original_args[1]— theNoneis taken as-is. Only the kwargs branch (elif original_kwargs.get("arguments")) is falsy-guarded._set_span_input_datathen doesfor k, v in arguments.items()(:206) →AttributeError, which the server returns to the client as a JSON-RPC error.The
toolbranch has the same shape at:284-285(arguments = original_args[1]), though tool calls in practice always carry anargumentsdict.Measured 2026-09-04 (fastmcp 3.4.7, mcp 1.29.1, sentry-sdk 2.68.1, Python 3.12):
(and the same
or {}on the tool branch's positional read), or aNoneguard in_set_span_input_databefore.items().