claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] MCP resource returning image fills up context with 1 image whereas tool result can go as far as 15 images

Open muvaf opened this issue 1 week ago • 1 comments

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

In our MCP server, we want to provide the screenshot of the current screen of the remote simulator (150-200kb image/jpeg). When we implement this as a tool call that returns image, we see the context getting filled up after about 15 calls. But only the last image is relevant, so we're trying to see if we can get Claude Code to drop the older screenshots from context.

We tested exposing it as an MCP resource and that's the suggested way for screenshots in MCP docs. However, when we expose it as a resource, even a single image can fill up the whole context and /compact doesn't work, saying conversation is too long.

What Should Happen?

Process the image as normal images that are added as result of tool calls or user uploads. Ideally, do not re-add it to context if the uri in the returned result didn't change and just reference the existing one in the context.

Error Messages/Logs


Steps to Reproduce

Here is an example of the returned object when resource is read. The blob is base64 encoded version of 188kb image.

{
  "contents": [
    {
      "uri": "simulator://screenshot/current/c0da716d95d0d1ae",
      "mimeType": "image/jpeg",
      "blob": "<base64 encoded jpg file>"
    },
    {
      "uri": "simulator://screen-dimensions",
      "mimeType": "text/plain",
      "text": "{ width: 402, height: 874 }"
    }
  ]
}

Here is the code that returns it:

        this.mcp.registerResource('screenshot', 'simulator://screenshot/current', {
            description: 'Current screenshot of the iOS simulator screen. The response URI includes the hash of the screenshot. If you already have a screenshot with the same hash in your context, reference that instead of embedding the image data again.',
            mimeType: 'image/jpeg',
        }, async (_: URL, __: RequestHandlerExtra<ServerRequest, ServerNotification>): Promise<ReadResourceResult> => {
            const client = await this.getClient();
            const result = await client.screenshot();
            const binaryData = Buffer.from(result.base64, 'base64');
            const hash = Bun.hash(binaryData).toString(16);
            console.log(`Screenshot hash: ${hash}`);
            return {
                contents: [
                    { 
                        uri: `simulator://screenshot/current/${hash}`,
                        mimeType: 'image/jpeg',
                        blob: result.base64,
                     },
                     {
                        uri: `simulator://screen-dimensions`,
                        mimeType: 'text/plain',
                        text: `{ width: ${result.width}, height: ${result.height} }`,
                     },
                ],
            }
        });

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

2.0.1 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

Here is an example screenshot:

Image

muvaf avatar Dec 21 '25 11:12 muvaf