anthropics / anthropics/claude-code

Hosted connector drops `blob` from embedded resources: -32602 invalid_union for any binary document (same payload accepted by the engine client)

Open
#94,746 1 comment 0 reactions 0 assignees View on GitHub
area:mcp bug platform:macos
Dominant language
Python
Stars
145k
Forks
23.1k
PR merge metrics
PR metrics pending

Description

## Summary

A tool result that carries a binary document as a standard MCP embedded resource (`{"type":"resource","resource":{"uri":…,"mimeType":"application/pdf","blob":""}}`) is rejected by the hosted-connector MCP client with `MCP error -32602: Invalid tools/call result` (`invalid_union` on `content[N]`). The same response, byte for byte, is accepted when the same server is reached by the Claude Code engine client.

This is the same failure signature as #72621 (Slack connector, `slack_read_file`, PDF). Filing again because that one was closed as not planned while the failure is still reproducible, and because this report carries a same-wire control that isolates it to the connector.

## Environment

- Claude Desktop 2.110.0 (macOS), connector added against a self-hosted remote MCP server (Streamable HTTP, OAuth).
- Server: a Python MCP server on `mcp` 2.x that returns, for a PDF document:
`[EmbeddedResource(type="resource", resource=BlobResourceContents(uri="…", mimeType="application/pdf", blob=)), TextContent(type="text", text='{"filename":…,"mimetype":…,"size":…}')]`

## Reproduction

1. In a Claude Desktop conversation backed by the **connector**, call the tool that returns a PDF.
2. Observe:

```
MCP error -32602: Invalid tools/call result: [
{ "code": "invalid_union",
"errors": [
[ {"path":["content",0,"type"],"message":"Invalid input: expected \"text\""},
{"path":["content",0,"text"],"message":"Invalid input: expected string, received undefined"} ],
[ {"path":["content",0,"type"],"message":"Invalid input: expected \"image\""}, … ],
[ {"path":["content",0,"type"],"message":"Invalid input: expected \"audio\""}, … ],
[ {"path":["content",0,"type"],"message":"Invalid input: expected \"resource_link\""}, … ],
[ {"path":["content",0,"resource","text"],"message":"Invalid input: expected string"},
{"path":["content",0,"resource","blob"],"message":"Invalid input: expected string"} ]
],
"path": ["content", 0], "message": "Invalid input" } ]
```

Note the last branch: `content[0].resource` parsed as an object, and neither `text` nor `blob` survived to validation — i.e. the `blob` field does not reach the validator through the connector, while `uri` / `mimeType` do.

## Control: same wire, engine client

Reaching the same server from a Claude Code session (engine client) returns the identical payload and succeeds: the client reports `Binary content (application/pdf, …) saved to …/tool-results/…pdf`, and the bytes are intact. Nothing differs between the two runs except which client carried the call.

The server records the calling client's self-reported `initialize` name. Same host, same tool, minutes apart:

- connector: `client=Anthropic/ClaudeAI/1.0.0 proto=2026-07-28` → `-32602 invalid_union` (client-side; the server answered 200)
- engine: `client=claude-code/2.1.273 proto=2026-07-28` → payload accepted, file written

## Server-side validation

The payload matches `CallToolResultSchema` in the MCP TypeScript SDK (the same schema the desktop client bundles): `EmbeddedResource` → `resource` union of `TextResourceContents{text}` / `BlobResourceContents{blob}` over a base `{uri, mimeType?, _meta?}`. The blob is base64 with no line breaks. So it is not a server-side shape error.

## Related

- #72621 — same `invalid_union` for binary files through a hosted connector; closed as not planned, no maintainer reply.
- anthropics/claude-ai-mcp#287 — Claude Desktop does not render `EmbeddedResource` blocks at all (open).
- #53453 — `resource_link` results silently ignored (open).

## Ask

Fix or document the connector's handling of binary content blocks. The engine client handles the exact same payload, so the gap is connector-specific, and today the only workarounds available to a server author are to stop using `blob` (inline base64 text, which overflows for real documents) or to hand the caller an out-of-band download URL.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reproducing the PDF tool call through the hosted connector and compare it with the same-wire Claude Code engine-client result. Read the MCP CallToolResultSchema and trace the connector path where EmbeddedResource fields are passed to validation, focusing on why blob is dropped while uri and mimeType survive. Done means binary resources validate and reach the user intact, or the connector documents a supported workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, typescript
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.