Repository navigation
MCP tool results delivered only via structuredContent are invisible to the model ("no model-visible content" false timeout)
#8240
Replies: 1 comment
|
Verified against current master (checked 4878cda). render() in packages/mcp/mcp-client/src/tools.ts only ever calls extractText(result.content, rawName), which walks result.content and falls back to the "(toolName returned no model-visible content)" placeholder when nothing in it yields a block. It never looks at result.structuredContent, so your repro is accurate: a structuredContent-only result still hits the placeholder. I implemented this close to your patch's direction but scoped a bit narrower, and pushed it: https://github.com/Mide69/deepseek-harness/tree/fix/mcp-client-structured-content-fallback The condition is content.length === 0 && structuredContent !== undefined, not "content yields nothing after projection". That distinction matters for one case: a content array that has blocks but none of them project to text or image (a refused image, an unsupported block type) already gets a specific per-block diagnostic from the existing projectContent walk. If the fallback triggered on "projects to nothing" instead of "array is empty", a result with both a refused-image diagnostic and a structuredContent payload would silently drop that diagnostic in favor of raw JSON. Checking emptiness up front keeps those two cases separate: genuinely empty content falls back to structuredContent, non-empty content keeps its existing per-block handling untouched, no matter what it projects to. Also skipped the try/catch around JSON.stringify. result.structuredContent is already validated as JsonValue by the CallToolResult schema by the time render() sees it, and JsonValue by construction cannot contain a cycle or a non-JSON member, so JSON.stringify on it cannot throw or return undefined. Added two tests: one for the empty-content/present-structuredContent case (projects the pretty JSON), one confirming a result with both non-empty content and structuredContent still prefers content (so a server's human-readable summary doesn't get replaced by raw JSON when it explicitly provided one). Full packages/mcp/mcp-client suite passes (130 tests), typecheck and lint clean, README/README.zh updated and translation-pairing regenerated. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
Some MCP servers deliver their payload only in
structuredContentand return an emptycontentarray. The dsh MCP client does not fall back in this case, so the model receives a placeholder like(<tool> returned no model-visible content)even though the call succeeded server-side. From the agent's perspective this looks like a timeout / silent failure and triggers blind retries.Environment
dsh-mcp-clienthas the same issue — verified against the npm tarball)mcp-stata3.x,paper-search-mcp(S2/OpenAlex sources)Reproduction
structuredContentonly and an emptycontentarray (e.g.mcp-stata@3executing a Stata regression — the job actually completes).Expected
When
contentcarries no blocks butstructuredContentis present, the serialized structured payload should be projected as one text block so the result stays visible to the model.Related discussions (checked before posting)
structuredContentbeing dropped downstream of the bridge (computer-useelement_tokennever arrives) — the bridge itself preserves it there. Our case is upstream of that: the bridge receives validstructuredContentbut the model never sees anything whencontentis empty.structuredContentis missing). Our case is a successfulstructuredContent-bearing result whose payload is invisible because no fallback projection exists.Suggested fix
We are running this locally as a patch (working well since 2026-09-28); it only touches results that have no content blocks:
Happy to send a PR if the direction is acceptable.
All reactions