Skip to content

MCP tool description truncation can exceed the documented 2048-character limit #423

Description

@MicroMilo

MCP tool description truncation can exceed the documented 2048-character limit

Summary

truncateMcpToolDescription() is documented as clamping MCP tool descriptions to MAX_MCP_TOOL_DESCRIPTION_LENGTH characters. For any input longer than the limit, it currently slices the original string to 2048 characters and then appends "… [truncated]", so the returned string is longer than the documented limit.

Affected revision

Observed on main at 9ad10eb0e1ed75f864ca8cbda7f659f7c3b163e9.

Affected code

  • src/mcp/runtime/truncate.ts:2 says tool descriptions are clamped to MAX_MCP_TOOL_DESCRIPTION_LENGTH characters.
  • src/mcp/runtime/truncate.ts:8 sets MAX_MCP_TOOL_DESCRIPTION_LENGTH = 2048.
  • src/mcp/runtime/truncate.ts:10-12 slices to 2048 and then appends the truncation marker.

Reproduction

From the repository root:

cat > repro-truncate.mts <<'EOF'
import {
  MAX_MCP_TOOL_DESCRIPTION_LENGTH,
  truncateMcpToolDescription,
} from "./src/mcp/runtime/truncate.ts";

const input = "x".repeat(MAX_MCP_TOOL_DESCRIPTION_LENGTH + 1);
const output = truncateMcpToolDescription(input);

console.log({
  inputLength: input.length,
  maxLength: MAX_MCP_TOOL_DESCRIPTION_LENGTH,
  outputLength: output.length,
  withinLimit: output.length <= MAX_MCP_TOOL_DESCRIPTION_LENGTH,
  suffix: output.slice(-20),
});
EOF

pnpm exec tsx repro-truncate.mts
rm repro-truncate.mts

Observed output:

{
  inputLength: 2049,
  maxLength: 2048,
  outputLength: 2061,
  withinLimit: false,
  suffix: 'xxxxxxx… [truncated]'
}

Expected behavior

If the contract is “description length is at most MAX_MCP_TOOL_DESCRIPTION_LENGTH”, the returned string should never exceed 2048 characters, including any truncation marker.

Actual behavior

Inputs longer than 2048 characters return a 2061-character string.

Impact

OpenAPI-generated MCP servers can emit very large descriptions. The current behavior contradicts the stated clamp and can still send descriptions larger than the intended provider-facing limit. This also makes boundary tests around the advertised maximum misleading.

Existing coverage

I could not find an existing issue or pull request covering this truncation-boundary behavior.

Suggested fix

Reserve space for the truncation marker before slicing, or change the constant/contract so it clearly means “prefix length before marker”. If the intended contract is a hard output cap, add a regression test for an input of length MAX_MCP_TOOL_DESCRIPTION_LENGTH + 1.

Suggested tests

  • Input length exactly MAX_MCP_TOOL_DESCRIPTION_LENGTH.
  • Input length MAX_MCP_TOOL_DESCRIPTION_LENGTH + 1.
  • A long description where the truncation marker is included in the final length cap.

Submitted with Codex.

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