Skip to content

fix(everything): correct the tiny image's iCCP chunk checksums - #4816

Open
BlueX888 wants to merge 1 commit into
modelcontextprotocol:mainfrom
BlueX888:fix/prep-tiny-image-iccp-chunk-crc-corrupt
Open

BlueX888 wants to merge 1 commit into
modelcontextprotocol:mainfrom
BlueX888:fix/prep-tiny-image-iccp-chunk-crc-corrupt

Conversation

@BlueX888

Copy link
Copy Markdown

Description

MCP_TINY_IMAGE (src/everything/tools/get-tiny-image.ts:5) is the hard-coded PNG that the get-tiny-image tool returns as an image/png content block. Its iCCP chunk carries two bad checksums, so the blob is not a valid PNG:

  • the chunk stores CRC-32 0x5321b951, but the bytes it covers hash to 0x9004394b;
  • the zlib stream inside the chunk ends with an Adler-32 trailer of 0x5d040ba2 instead of 0x6f050bad, so it fails to inflate — inflateSync reports Error: incorrect data check.

The PNG specification requires every chunk's CRC-32 to match its contents, so decoders that verify checksums reject the file and the embedded color profile cannot be read.

This PR corrects the two checksums. No other byte of the image changes: the deflate payload is byte-for-byte identical, and only the 4-byte Adler-32 trailer and the 4-byte chunk CRC-32 differ.

Server Details

  • Server: everything
  • Changes to: tools (get-tiny-image)

Motivation and Context

Root cause: the embedded PNG was committed with an incorrect Adler-32 trailer inside its iCCP zlib stream and a consequently incorrect chunk CRC-32 (src/everything/tools/get-tiny-image.ts:6).

The compressed payload is intact, so correcting rather than dropping the chunk preserves the image exactly. Inflating the payload yields a well-formed 3348-byte ICC profile: the declared size field matches the actual length, the tag count is 17, and every tag table lies within the profile (appl, version 2.1, class mntr, color space RGB).

How Has This Been Tested?

New test src/everything/__tests__/get-tiny-image.test.ts walks the PNG chunk stream, recomputes each chunk's CRC-32 over the bytes it covers with node:zlib's crc32, and inflates the iCCP profile.

Against the current main blob, both cases fail:

 ❯ __tests__/get-tiny-image.test.ts (2 tests | 2 failed) 5ms
     × should hold a correct CRC-32 for every chunk 3ms
     × should hold a decompressible iCCP profile 2ms

 FAIL  __tests__/get-tiny-image.test.ts > MCP_TINY_IMAGE > should hold a correct CRC-32 for every chunk
AssertionError: expected [ Array(1) ] to deeply equal []

- []
+ [
+   "iCCP: stored 0x5321b951, computed 0x9004394b",
+ ]

 FAIL  __tests__/get-tiny-image.test.ts > MCP_TINY_IMAGE > should hold a decompressible iCCP profile
AssertionError: expected [Function] to not throw an error but 'Error: incorrect data check' was thrown

 Test Files  1 failed (1)
      Tests  2 failed (2)

With the fix:

$ npx vitest run __tests__/get-tiny-image.test.ts --root src/everything
 Test Files  1 passed (1)
      Tests  2 passed (2)

Existing suite and type check are unaffected:

$ cd src/everything && npm test
 Test Files  6 passed (6)
      Tests  109 passed (109)

$ npm run build
> tsc && shx cp -r docs dist/ && shx chmod +x dist/*.js

Breaking Changes

None. The decoded image is unchanged — only its chunk checksums are corrected — so no client configuration or behavior needs updating.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Protocol Documentation
  • My changes follows MCP security best practices
  • I have updated the server's README accordingly
  • I have tested this with an LLM client
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have documented all environment variables and configuration options

Additional context

The three unchecked boxes above that concern behavior rather than tooling are not applicable here: this change touches no server logic, no README content, no error paths, and no environment variables — it corrects two checksums in a static embedded asset, which is covered by the unit test above rather than by an LLM client run.

Verification of the checksum values was done independently of the test, with a separate PNG chunk parser: every chunk other than iCCP already had a correct CRC-32 (IHDR, eXIf, pHYs, iTXt, IDAT, IEND), and the corrected iCCP trailer equals adler32() of the decompressed profile.

The repo has no prettier config and npm run prettier:check already fails on a clean main checkout (59 files); CI runs only npm test and npm run build. The edited source file is prettier-clean, and the new test follows the existing __tests__ convention.

MCP_TINY_IMAGE is served as image/png by the get-tiny-image tool, but its
iCCP chunk is corrupt: the chunk records CRC-32 0x5321b951 while its
contents hash to 0x9004394b, and the zlib stream inside it ends with an
Adler-32 trailer of 0x5d040ba2 instead of 0x6f050bad. The stream therefore
fails to inflate, with inflateSync reporting "incorrect data check", and a
chunk whose CRC-32 does not match its contents is invalid per the PNG
specification.

The deflate payload itself is intact: once the Adler-32 is corrected it
inflates to a well-formed 3348-byte ICC profile whose declared size
matches and whose 17 tag tables all stay within the profile. Correct the
two checksums rather than dropping the chunk; no other byte of the image
changes.

Adds vitest coverage that walks the chunk stream, checks every chunk's
CRC-32 against the bytes it covers, and inflates the iCCP profile. Both
cases fail against the previous blob and pass now.
Copilot AI balanced review requested due to automatic review settings September 17, 2026 04:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

2 participants