Skip to content

Stop HTML-escaping structured MCP output #9

Description

@justadityaraj

Problem

Ability results are MCP/JSON data, but many callbacks run stored values through HTML display escaping before returning them. Characters such as &, quotes, apostrophes, and angle brackets therefore reach clients as entities such as & and ' instead of the values WordPress stores.

This is observable data corruption, and a client that writes a returned value back can double-encode it.

Evidence

  • includes/Server/Handlers/Tools/ToolsHandler.php:186-187 JSON-encodes each ability result and also returns the same array as structuredContent; there is no HTML rendering boundary here.
  • includes/Abilities/Content/Posts.php:139-147 applies esc_html() to post titles, statuses, dates, and author names.
  • includes/Abilities/Content/Pages.php:149-159 applies it to page titles, slugs, templates, and other fields.
  • includes/Abilities/Content/Taxonomy.php:56-63 applies it to term names and descriptions.
  • includes/Abilities/Media/Media.php:191-204 applies it to attachment titles, alt text, captions, and descriptions.
  • The same pattern is pervasive: there are currently 119 esc_html() calls under includes/Abilities.

For example, a stored title of Rock & Roll is returned as Rock & Roll even though the transport is JSON.

Minimal fix

Return raw, correctly typed WordPress values from ability result arrays. Keep input sanitation and URL normalization such as esc_url_raw(), but move HTML escaping to actual HTML views. Structured messages should use translation without HTML escaping as well.

Done when

  • A representative value such as Rock & Roll <draft> "quoted" O'Brien round-trips through MCP exactly as stored.
  • Both text content and structuredContent contain the same unescaped data.
  • Ability output no longer applies HTML display escaping to structured fields.
  • Existing dashboard/admin HTML continues to escape values at render time.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions