Description
Question
I'm building a camera monitoring MCP server using FastMCP and encountering inconsistent behavior between @mcp.resource()
and @mcp.tool()
decorators when returning Image
objects. I want to expose the current camera frame as a resource (similar to a REST API endpoint) rather than a tool, since it represents static data that can be accessed on-demand.
Code snippets showing what I've tried:
Working approach with @mcp.tool()
:
from mcp.server.fastmcp import FastMCP, Image
@mcp.tool()
async def get_camera_snapshot() -> Image:
"""Get the current camera frame as Image."""
ctx = mcp.get_context()
camera = ctx.request_context.lifespan_context.camera
frame = await camera.get_current_frame()
if frame is None:
raise ValueError("No camera frame available")
# Encode frame as JPEG
success, buffer = cv2.imencode('.jpg', frame)
if not success:
raise ValueError("Failed to encode camera frame")
return Image(data=buffer.tobytes(), format="jpeg")
This gives the JSON:
{
"content": [
{
"type": "image",
"data": "/9j/4AAQSk...",
"mimeType": "image/jpeg"
}
],
"isError": false
}
Non-working approach with @mcp.resource()
:
@mcp.resource("camera://current_frame.jpg")
async def get_current_frame() -> Image:
"""Get the current camera frame as an Image."""
# Same implementation as above
return Image(data=buffer.tobytes(), format="jpeg")
When I do the resource I get:
{
"contents": [
{
"uri": "camera://current_frame.jpg",
"mimeType": "text/plain",
"text": "\"<mcp.server.fastmcp.utilities.types.Image object at 0x7f8818782f30>\""
}
]
}
Expected vs actual behavior:
- Expected: Both decorators should handle Image return types identically
- Actual: Only
@mcp.tool()
works withImage
return types, while@mcp.resource()
does not
Looking at the FastMCP source code at src/mcp/server/fastmcp/server.py
, the comments indicate that resources support various return types including Image
objects via the _convert_to_content()
method. However, in practice, only @mcp.tool()
seems to handle Image returns correctly.
Is this a known limitation, bug, or is this by design and I misunderstand the role of resource vs tool?
Additional Context
- MCP Python SDK version: 1.9.4
- Python version: 3.12.11
- Environment: Linux with OpenCV for camera capture and PyTorch for ML inference