Skip to content

[FEATURE] Forward MCP EmbeddedResource blob to Anthropic API content blocks #72271

Description

@carrotRakko

Problem Statement

When an MCP server returns binary content through the standard EmbeddedResource content block ({ "type": "resource", "resource": { "uri": "...", "mimeType": "application/pdf", "blob": "<base64>" } }), Claude Code CLI v2.1.x persists the blob to a file under ~/.claude/projects/<encoded-cwd>/tool-results/mcp-<server>-blob-<id>.<ext> and surfaces only a placeholder text to the model:

[Resource from <server> at <uri>] Binary content (<mimeType>, <size>) saved to <path>

The blob bytes themselves are not forwarded to the Anthropic API as a document / image / audio content block, so the model cannot natively parse the PDF / image / audio that the server tried to deliver.

The built-in Read tool, in contrast, attaches PDFs as Anthropic API document content blocks (delivered via isMeta user messages) so Sonnet+ can read them natively. This means an MCP filesystem server (= e.g. a sandboxed mirror of the built-in Read) cannot match the upstream PDF-reading fidelity: a PDF returned through MCP becomes a disk path placeholder, while the same PDF returned through the built-in Read becomes a multi-modal document block the model reads end-to-end. The same gap applies to images and audio that a server might want to deliver via EmbeddedResource.

Proposed Solution

When an MCP tool result contains an EmbeddedResource content block with resource.blob and resource.mimeType set, forward the bytes to the Anthropic API as the corresponding content block type:

  • mimeType: "application/pdf" → document content block (= { type: "document", source: { type: "base64", media_type: "application/pdf", data: <base64> } })
  • mimeType: "image/png" / "image/jpeg" / "image/gif" / "image/webp" → image content block
  • mimeType: "audio/mp3" / "audio/wav" / etc. → audio content block
  • Other MIME types fall through to the current disk-save behaviour with a placeholder

The MIME-type routing mirrors what the built-in Read tool already does internally for PDFs.

Alternative Solutions

  • An MCP server could implement its own pdftoppm + image-cap pipeline (= mirror the built-in Read's parts-mode) and return image content blocks per page. This works (parts-mode is reproducible at the server side) but loses the upstream pdf-mode fidelity and pushes the complexity onto every server author. Image and audio servers have no equivalent fallback.
  • An MCP server could base64-embed the PDF into a text content block. The model sees the base64 text but cannot natively parse it.
  • The user could open the file separately and drag-drop it into Claude Code. This bypasses the agent's tool-driven workflow.

None of these substitute for the client honouring the standard MCP EmbeddedResource mechanism for binary content.

Priority

Medium — Would be very helpful

Feature Category

MCP server integration

Use Case Example

I am building an MCP server that exposes a filesystem Read tool to a sandboxed agent. For PDFs I want the agent to receive the same multi-modal experience the built-in Read provides: the model parses the PDF natively, fonts and figures intact.

I returned the PDF bytes through the Go SDK as:

&mcp.EmbeddedResource{
    Resource: &mcp.ResourceContents{
        URI:      "file:///path/to/file.pdf",
        MIMEType: "application/pdf",
        Blob:     pdfBytes,
    },
}

Observed against Claude Code CLI 2.1.x:

  • The client persisted the blob to ~/.claude/projects/<encoded-cwd>/tool-results/mcp-<server>-blob-<id>.pdf.
  • The model's tool result content was the placeholder [Resource from <server> at file:///path/to/file.pdf] Binary content (application/pdf, <size>) saved to <path>.
  • The model could only see the path, not the PDF.

If the client had forwarded the blob into an Anthropic document content block, the model would have read the PDF directly, just as it does for built-in Read calls.

Additional Context

  • MCP specification, EmbeddedResource / ResourceContents: https://modelcontextprotocol.io/specification. ResourceContents.blob is the standard MCP mechanism for binary resources.

  • MCP Go SDK type definition (github.com/modelcontextprotocol/[email protected]/mcp/content.go):

    type EmbeddedResource struct {
        Resource    *ResourceContents
        Meta        Meta
        Annotations *Annotations
    }
    
    type ResourceContents struct {
        URI      string `json:"uri"`
        MIMEType string `json:"mimeType,omitempty"`
        Text     string `json:"text,omitempty"`
        Blob     []byte `json:"blob,omitzero"`
        Meta     Meta   `json:"_meta,omitempty"`
    }
  • Built-in Read's PDF transport (= document content block on an isMeta user message) gives the model the native PDF experience. The MCP EmbeddedResource path is the closest standard equivalent for MCP servers, but it currently degrades to a disk-save placeholder.

  • Related but distinct: [DOCS] Custom tools docs do not explain unsupported MCP image MIME fallback #60408 ([DOCS] Custom tools docs do not explain unsupported MCP image MIME fallback) covers the docs side for unsupported image MIME fallbacks. This request is about forwarding supported MIME types (application/pdf, supported image and audio types) into the corresponding Anthropic API content blocks rather than degrading them.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions