Initial Checks
Description
Description
When using FastMCP with stateless_http=True (required by Claude.ai remote MCP), returning Image or ImageContent from a @mcp.tool() function results in serialization errors. Text-only tool results work fine in the same configuration.
Environment
mcp version: 1.26.0 (also tested with >=1.8.0 unpinned)
- Python: 3.12
- Transport:
streamable-http
- Deployment: Railway (remote, accessed by Claude.ai)
- Client: Claude.ai (requires
stateless_http=True)
Reproduction
Minimal server:
from mcp.server.fastmcp import FastMCP, Image
mcp = FastMCP(
"test",
host="0.0.0.0",
port=8000,
stateless_http=True,
json_response=True,
)
@mcp.tool()
def text_tool() -> str:
"""Works fine"""
return "hello"
@mcp.tool()
def image_tool() -> Image:
"""Fails with serialization error"""
# 1x1 red PNG
data = bytes.fromhex(
"89504e470d0a1a0a0000000d49484452000000010000000108020000009001"
"2e00000000c4948444154789c6260f8cf00000000020001e221bc330000000049454e44ae426082"
)
return Image(data=data, format="png")
if __name__ == "__main__":
mcp.run(transport="streamable-http")
What happens
Attempt 1: Image class + stateless_http=True + json_response=True
Unable to serialize unknown type: <class 'mcp.server.fastmcp.utilities.types.Image'>
Attempt 2: Image class + stateless_http=True + json_response=False
Same serialization error.
Attempt 3: ImageContent from mcp.types + stateless_http=True
{"error": "Error occurred during tool execution"}
Server returns 200 OK but client receives generic error.
Attempt 4: Image class + stateless_http=False (stateful mode)
POST /mcp HTTP/1.1" 400 Bad Request
Claude.ai rejects stateful mode entirely.
Expected behavior
Image and ImageContent should serialize correctly in stateless_http=True mode, since:
- The MCP spec defines
ImageContent as a valid tool result content type
ToolResultContent.content accepts ContentBlock lists which include image content
- The official SDK docs show
@mcp.tool() returning Image as a supported pattern
- The protocol's Streamable HTTP transport has no text-only restriction — it returns either
application/json or text/event-stream, both capable of carrying base64-encoded image data
Context
This blocks any MCP server deployed for Claude.ai from returning images via tool results. The only workaround is returning image URLs as text, which doesn't work for authenticated/signed URLs (e.g., Notion S3 hosted images that require download proxying).
Related
Example Code
Python & MCP Python SDK
MCP version: 1.26.0
Python: 3.12
Initial Checks
Description
Description
When using
FastMCPwithstateless_http=True(required by Claude.ai remote MCP), returningImageorImageContentfrom a@mcp.tool()function results in serialization errors. Text-only tool results work fine in the same configuration.Environment
mcpversion: 1.26.0 (also tested with>=1.8.0unpinned)streamable-httpstateless_http=True)Reproduction
Minimal server:
What happens
Attempt 1:
Imageclass +stateless_http=True+json_response=TrueAttempt 2:
Imageclass +stateless_http=True+json_response=FalseSame serialization error.
Attempt 3:
ImageContentfrommcp.types+stateless_http=TrueServer returns 200 OK but client receives generic error.
Attempt 4:
Imageclass +stateless_http=False(stateful mode)Claude.ai rejects stateful mode entirely.
Expected behavior
ImageandImageContentshould serialize correctly instateless_http=Truemode, since:ImageContentas a valid tool result content typeToolResultContent.contentacceptsContentBlocklists which include image content@mcp.tool()returningImageas a supported patternapplication/jsonortext/event-stream, both capable of carrying base64-encoded image dataContext
This blocks any MCP server deployed for Claude.ai from returning images via tool results. The only workaround is returning image URLs as text, which doesn't work for authenticated/signed URLs (e.g., Notion S3 hosted images that require download proxying).
Related
Example Code
Python & MCP Python SDK