MCP tool results containing only structuredContent are silently dropped

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

When an MCP tools/call result carries data only in structuredContent and its content array is empty, Cursor delivers an empty result to the model: no data, no error, no fallback. The data is silently lost.

Structured-only results are permitted by the spec (the backwards-compatibility text block is a SHOULD, not a MUST), and MCP maintainers have noted such servers exist in the wild (SEP-1624 discussion: SEP-1624: Clarify `structuredContent` vs `content` Usage Guidance · Issue #1624 · modelcontextprotocol/modelcontextprotocol · GitHub ). VS Code hit this same edge case and treated it as a bug: MCP tool returning structuredContent only leads to error in output view · Issue #297669 · microsoft/vscode · GitHub

Context so this isn’t mistaken for a channel-preference complaint: when both channels are populated, only content reaches the model, and we understand that to be intended (post 9 of thread 156072 corrected the earlier post 5 claim: “Looks like my earlier reply was too optimistic… the model doesn’t actually see that data or can’t access it”). This report is only about the structured-only case, where that preference turns into silent data loss.

We verified with a marker-based probe server: it plants a different random nonce in each channel (CONTENT-<nonce> in the text block, STRUCTURED-<nonce> in structuredContent), and neither channel names the other’s value, so the model cannot report a marker it never received. Across five probe runs, two tool variants (with and without outputSchema), three models, and an app restart, the model repeated CONTENT-* markers whenever present, never repeated a STRUCTURED-* marker, and always received an empty result in the structured-only mode. Probe source: MCP channel probe: tests which tool-result channels (content vs structuredContent) a client forwards to its model · GitHub

One correlated pair from a 2026-08-03 run. Cursor’s own Output > MCP log captured the probe’s stderr:

[channel-probe] probe_channels mode=both content=CONTENT-198f494b structured=STRUCTURED-52db8595
[channel-probe] probe_channels mode=structured_only content=CONTENT-5bfffe54 structured=STRUCTURED-73d6b5c0

The model’s verbatim response in that same session reported CONTENT-198f494b only for the first call and nothing for the second. So STRUCTURED-73d6b5c0 existed inside the Cursor-spawned server process and was never repeated or otherwise visible in the model’s result.

Cursor’s own chat UI confirms the result reached the client intact: the expanded tool-call card for the structured_only run renders the full structuredContent JSON, including STRUCTURED-73d6b5c0 (screenshot attached). The UI evidently falls back to rendering structuredContent when content is empty; the model-facing serialization does not. So the data arrives at Cursor and is parsed and displayed — it is lost specifically between the client and the model’s context. This also makes the failure easy to misdiagnose: the transcript looks like the model received the data.

Steps to Reproduce

  1. Save the probe server from MCP channel probe: tests which tool-result channels (content vs structuredContent) a client forwards to its model · GitHub (one Node file, only dependency @modelcontextprotocol/sdk 1.30.0, Node v22.22.2) and install: npm install @modelcontextprotocol/sdk@^1.30.0
  2. Add it to ~/.cursor/mcp.json:
{ "mcpServers": { "channel-probe": {
  "command": "node",
  "args": ["/path/to/channel-probe.mjs"]
} } }
  1. Reload Cursor, then prompt: “Call probe_channels with mode structured_only. Report every marker you can see in the result, exactly as written, and state which marker you canNOT see.”
  2. Observed: the model receives an empty result. No marker, no data, no error. The Output > MCP log for the server shows the STRUCTURED-<nonce> marker that was generated but never delivered.
  3. Optional context check: repeat with mode both; the model repeats only the CONTENT-* marker.

To confirm the server output is well-formed, a raw JSON-RPC capture via curl (no MCP client SDK involved) shows content and structuredContent as sibling fields of result per the spec:

{"result":{"content":[],"structuredContent":{"channel":"structuredContent","marker":"STRUCTURED-3fd25141", ...}},"jsonrpc":"2.0","id":2}

Expected Behavior

Either of these would be fine:

  • Serialize structuredContent into the model context when content is empty, or
  • Surface an explicit error so the failure is visible instead of silent.

For comparison, we ran the same probe against three other clients: Claude Code 2.1.220, the Claude desktop app (tested 2026-08-01), and the ChatGPT desktop app (Codex, version 26.727.51351). All three forward structuredContent to the model, preferring it over content when both are present, and none lose data in the structured-only case. Cursor is the only client we tested where a structured-only result reaches the model as empty.

Screenshots / Screen Recordings

Operating System

MacOS

Version Information

IDE:
(paste from Menu > About Cursor > Copy; known values below)
Version: 3.14.7
Commit: a758f2241ca99fecf380180b6cbdbbce0f1f42c0
OS: Darwin arm64

Probe environment: Node v22.22.2, @modelcontextprotocol/sdk 1.30.0

For AI issues: which model did you use?

Fable 5 High, GPT-5.6 Sol Medium, and Composer 2.5 Fast. Identical results on all three, and again after quitting and restarting Cursor, so it does not look model-specific.

For AI issues: add Request ID with privacy disabled

Not available. Privacy Mode is enforced by our organization and can’t be disabled on this account. The correlated server-log/model-response pair in the description is the substitute we can provide. Your team can also inspect the serialized prompt for any reproduction of step 3 and check whether the STRUCTURED-* marker is present.

Additional Information

Method caveat: repeated marker recall shows which result data was available to the model, not a direct inspection of the serialized prompt. False positives are impossible by design (a repeated marker was necessarily received); the identical pattern across models, sessions, and a restart makes consistent false negatives unlikely.

Related observations, possibly separate issues:

  • Channel preference: if content-over-structuredContent is the intended design, one sentence of official documentation would let server authors build for it. The spec-level clarification attempt (PR #2200: SEP-2200: Clarify tool result content visibility by krubenok · Pull Request #2200 · modelcontextprotocol/modelcontextprotocol · GitHub ) was deferred by the MCP core maintainers in May 2026, so this can only come from Cursor.
  • Hook gap: afterMCPExecution serializes only content and isError, so structuredContent is not reachable programmatically either (acknowledged in thread 156072).
  • outputSchema visibility: the tool definition shown to the model contains inputSchema but not outputSchema. We can’t tell from outside whether Cursor retains it internally.

Related threads: forum 156072 (posts 5 and 9), forum 160503, SEP-1624, PR #2200, microsoft/vscode#297669.

Does this stop you from using Cursor

Sometimes - I can sometimes use Cursor

Hey @Jim_Beno ,

What you’re seeing isn’t intended, and it isn’t caused by your server setup. When a tool result has an empty content array and the payload only in structuredContent, Cursor can show the JSON in the tool card but still deliver an empty result to the model. This is something we’ve seen before, and it’s an issue we’re tracking.

Workaround until it’s fixed: also return the payload as a text item in content (for example a JSON string of the same object), alongside structuredContent. That path does reach the model. Claude Code / Claude desktop / ChatGPT preferring structured when both are present is a real client difference; today Cursor effectively uses the text content channel for the model.

No timeline to share yet - I’ll post here when there’s an update. Happy to dig into anything else your probe surfaces (hooks / outputSchema visibility look like separate gaps).