Skip to content

Detect concealed characters in server metadata #1121

Description

@Adeniyikayodee

Use case

We run MCP clients that reach third party servers alongside our own. On first
connection a person sees an approval prompt listing each tool with its name
and description, and approves the server from that view.

That prompt is the only place a human reads the metadata. Everything after it
goes to the model directly, on every turn. So the approval rests on rendered
text while the model receives the raw bytes, and today those two are free to
differ. A description carrying code points that the prompt leaves unrendered
would be approved on sight and then supplied to the model in full.

Current behaviour

Tool, prompt and resource metadata reaches the caller exactly as the server
sent it. ToolNameValidator already runs on the client listing path and
warns about names that fall outside the spec, so checking server supplied
metadata on arrival has a precedent... the description, title and schema text
remain unchecked.

MCP allows the metadata a host renders for approval and the bytes later
placed in the model context to differ. A code point that lacks a glyph is
therefore absent from an approval dialog while arriving at the model intact.
The Unicode TAG block, U+E0000 to U+E007F, behaves this way in every
mainstream terminal, chat client and IDE.

Proposal

A check on the client listing paths reporting two classes of character:

  • the Unicode TAG block, U+E0000 to U+E007F
  • bidirectional overrides and isolates, U+202A to U+202E and U+2066 to
    U+2069, which reorder how the surrounding text is displayed

Warn by default so current behaviour is preserved, with a system property to
fail the listing instead, following the shape ToolNameValidator already
uses.

Zero width joiners and the remaining format characters would be left alone,
since they carry meaning in Indic, Arabic and Persian text and in emoji
sequences.

Reporting only. A stripped description is still text the server chose, and
editing a name would break the calls that use it.

Open questions

Whether the character set stays fixed or becomes configurable. Fixed seems
safer to me, since a configurable blocklist invites someone to add the whole
Cf category, which would fire on Persian and Indic descriptions.

Whether this belongs in the SDK at all, or sits better in the host above it.
Happy to drop it if you see it as a host concern.

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