Skip to content

feat: return image attachments as native MCP image content#237

Open
vbichkovsky wants to merge 1 commit intokorotovsky:masterfrom
vbichkovsky:feat/native-image-content
Open

feat: return image attachments as native MCP image content#237
vbichkovsky wants to merge 1 commit intokorotovsky:masterfrom
vbichkovsky:feat/native-image-content

Conversation

@vbichkovsky
Copy link
Copy Markdown

Summary

  • Image attachments (any image/* mimetype) are now returned using mcp.NewToolResultImage instead of embedding base64 inside a JSON text response
  • File metadata (file_id, filename, mimetype, size) is included as the text component
  • Non-image binary files retain the existing base64-in-text behavior
  • No new dependencies; uses existing mcp-go SDK capability

Problem

attachment_get_data returns binary files as base64-encoded strings inside a JSON text response. A typical Slack image (100-200KB) expands to 130-270KB of base64 text. This exceeds the token limits of MCP clients (e.g. Claude Code), which then save the overflow to a temp file — requiring the user to manually decode base64, write to disk, and open the image separately.

This turns a single tool call into a multi-step workaround involving bash, python, and manual file management.

Solution

The MCP SDK already provides NewToolResultImage(text, imageData, mimeType) which returns images as native ImageContent. MCP clients that support image rendering (Claude Code, Claude Desktop) can display these directly.

For image/* mimetypes, the handler now returns:

  • Text content: JSON metadata (file_id, filename, mimetype, size)
  • Image content: the base64 image data with proper MIME type

This is a non-breaking change — text files and non-image binary files are unaffected.

Test plan

  • Verified with Claude Code: attachment_get_data on a Slack PNG attachment now returns the image inline in a single tool call, rendered directly by the client
  • Text file attachments still return as plain text (existing behavior)
  • Non-image binary files still return as base64-in-text (existing behavior)

Fixes #88 (partially — improves the image attachment experience specifically)

🤖 Generated with Claude Code

Previously, attachment_get_data returned image files as base64-encoded
strings inside a JSON text response. For typical images (100-200KB),
the base64 expansion produces 130-270KB of text that exceeds MCP client
token limits, forcing clients to save overflow to temp files and manually
decode base64 — defeating the purpose of the tool.

Use the MCP SDK's NewToolResultImage to return images as native image
content, which MCP clients can render directly. File metadata (file_id,
filename, mimetype, size) is returned as the text component. Non-image
binary files retain the existing base64-in-text behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chriscoey chriscoey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, focused change. Returning images as native MCP image content via mcp.NewToolResultImage is a clear improvement over embedding base64 inside a JSON text result.

The isImageMimetype prefix check handles all image subtypes correctly, and the metadata JSON uses the existing escapeJSON helper to handle filenames with special characters. Good that it falls through to the existing text/binary path for non-image files — no behavior change for other file types.

LGTM — this would be useful for multimodal MCP clients.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support reading attachments (e.g., images) in Slack MCP

2 participants