Skip to content

headFile/tailFile in filesystem server corrupts multi-byte UTF-8 characters at 1024-byte chunk boundaries #4666

Description

@cloud-id-2012

Description

headFile() and tailFile() in src/filesystem/lib.js read the file in
fixed 1024-byte chunks and call .toString('utf-8') on each chunk
independently:

const chunk = Buffer.alloc(1024);
...
buffer += chunk.slice(0, result.bytesRead).toString('utf-8');

When a multi-byte UTF-8 character (e.g. CJK characters, which are 3 bytes
each) straddles a 1024-byte chunk boundary, the trailing incomplete bytes
in one chunk are decoded independently from the leading bytes in the next
chunk, producing mojibake (typically U+FFFD replacement characters) at
that position.

Reproduction

  1. Create a UTF-8 text file containing Japanese (or other CJK) text long
    enough that some character boundary falls exactly on a multiple of
    1024 bytes.
  2. Call head (or tail) with a line count that requires reading past
    that 1024-byte boundary.
  3. Observe corrupted character(s) near the boundary in the returned text.
  4. A full read of the same file (no head/tail) does not show the
    corruption, confirming the bug is specific to the chunked head/tail
    path.

Suggested fix

Decode the accumulated byte buffer incrementally using a streaming
decoder (e.g. Node's StringDecoder, which correctly buffers incomplete
trailing multi-byte sequences across chunk boundaries) instead of calling
.toString('utf-8') on each raw chunk independently.

Environment

  • @modelcontextprotocol/server-filesystem (installed via npm, dist
    build dated 2026-07-22)
  • macOS, Claude Desktop

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions