Skip to content

Reduce MCP token usage: truncate Tools/Resources responses and restrict fields/pagination for page/post searches #96

@igor-adzz

Description

@igor-adzz

Problem

  • tools/call and resources/read currently serialize full results without limits, pulling heavy fields (post HTML content, large plugin/theme lists, etc.) and quickly burning tokens in Claude.
  • Page/post searches via REST aliases (/wp/v2/pages, /wp/v2/posts) do not set _fields/context=embed or enforce small pagination, so large objects are returned.

Affected files: includes/RequestMethodHandlers/ToolsHandler.php, includes/RequestMethodHandlers/ResourcesHandler.php, includes/Tools/McpPostsTools.php, includes/Tools/McpPagesTools.php, optionally includes/Tools/McpCustomPostTypesTools.php.

Proposed solution

  • Truncate tool textual responses to 10k characters in ToolsHandler::call_tool (replace direct wp_json_encode($result) with an intermediate variable, clamp, append [truncated]).
  • Truncate resource text to 10k characters in ResourcesHandler::read_resource (build $json first, clamp, append [truncated]).
  • Add preCallback for wp_posts_search and wp_pages_search in McpPostsTools/McpPagesTools: enforce per_page <= 10 (default 5), set _fields=id,title,excerpt,link,date,slug and context=embed. Optionally, in McpCustomPostTypesTools::search_custom_post_types, map $query->posts to a minimal field set (exclude post_content).

Acceptance criteria

  • tools/call responses with long JSON include [truncated] and length ≤ 10,000 bytes.
  • resources/read responses are also truncated to 10,000 bytes and include [truncated] when applicable.
  • By default, page/post searches return ≤ 10 items and only the listed _fields (no heavy content.rendered).
  • Response sizes drop significantly on typical queries (expected 50–90%).

How to test (commands)

  • Tools (truncation):
export WP_URL="https://<site>/wp-json/wp/v2/wpmcp"; export JWT="<token>"
curl -s -X POST "$WP_URL" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -H "Authorization: Bearer $JWT" \
-d '{"id":1,"jsonrpc":"2.0","method":"tools/call","params":{"name":"wp_posts_search","arguments":{}}}' \
| jq -r '.content[0].text | length, contains("[truncated]")'
  • Resources (truncation):
curl -s -X POST "$WP_URL" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -H "Authorization: Bearer $JWT" \
-d '{"id":2,"jsonrpc":"2.0","method":"resources/read","params":{"uri":"WordPress://site-info"}}' \
| jq -r '.contents[0].text | length, contains("[truncated]")'
  • Page/post search (fields/pagination):
curl -s -X POST "$WP_URL" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -H "Authorization: Bearer $JWT" \
-d '{"id":3,"jsonrpc":"2.0","method":"tools/call","params":{"name":"wp_pages_search","arguments":{}}}' \
| jq -r '.[0]? // . | if type=="array" then length else length end'

curl -s -X POST "$WP_URL" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -H "Authorization: Bearer $JWT" \
-d '{"id":4,"jsonrpc":"2.0","method":"tools/call","params":{"name":"wp_pages_search","arguments":{}}}' \
| jq -r '.[0]? // . | if type=="array" then .[0] | keys|sort else . end'

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