Tool input serialization: adjacent multi-line `<parameter>` blocks merged into a single field

Resolved 💬 3 comments Opened May 11, 2026 by JamesTeague Closed May 15, 2026

Summary

When a tool call has two adjacent <parameter> blocks whose values are multi-line text (e.g. one ~1KB markdown, one ~3KB markdown), the harness's parameter extractor sometimes fails to split them. The second parameter's content gets embedded inside the first parameter's string value, with the literal boundary markup (</param-name>\n<parameter name="next">) preserved as text. The second parameter is then absent from the JSON input object sent to the MCP server, which correctly rejects it with missing field 'X'.

Only the boundary between adjacent multi-line text parameters fails; sibling scalar parameters (memory_type, tags, link_to, etc.) are extracted correctly in the same call.

Smoking gun: harness-recorded JSON

From ~/.claude/projects/<project>/<session>.jsonl, the tool_use.input captured by the harness for a failing call to an MCP tool with required params core (string) and expansion (string):

"input": {
  "core": "Session 97 (2025-09-14): Programming language choices brainstorm → ... Morgan lunch still 2025-09-22.</core>\n<parameter name=\"expansion\">## Session 97 — Programming language choices ... [entire expansion content embedded here] ... not pulled this session",
  "memory_type": "domain",
  "tags": ["session-97", "session-summary", "northstar", "career", "stack-posture", "erp", "language-choice"],
  "project": "career",
  "thread": "career",
  "link_to": "6f5ca3e0",
  "link_type": "next"
}

Observe:

  1. No expansion key in input.
  2. The closing </core> and opening <parameter name="expansion"> appear as literal text inside the core string value, immediately followed by what should have been the separate expansion parameter's content.
  3. Other sibling parameters (memory_type, tags, project, thread, link_to, link_type) extracted cleanly.

Server error returned: MCP error -32602: failed to deserialize parameters: missing field 'expansion' — accurate, given the malformed payload.

Conditions correlated with the failure

Observed across 5+ sessions over ~2 weeks calling the same MCP tool:

  • Two adjacent multi-line text parameters (first ~500–1000 chars, second ~1–4KB)
  • Second parameter contains markdown structure (headers, bullets)
  • Stripping markdown from the second parameter to plain prose flips outcome (success) on some retries
  • Same MCP tool, same session, same harness path can produce fail / succeed / fail in three consecutive calls

Hypothesized mechanism

Parameter-boundary regex/parser in the harness's XML→JSON conversion for tool inputs misses the </parameter>\n<parameter name="..."> boundary when the preceding value is long and multi-line. Likely sensitive to specific content patterns within the value (markdown delimiters, multi-line whitespace, etc.).

Reproduction sketch

Define an MCP tool with two required string params (a, b). Call it with a = ~800 chars, b = multi-section markdown ~3KB with ##/### headers and bullets, plus 3+ scalar siblings. Inspect harness-recorded tool_use.input in the session jsonl. Expect b to be merged into a.

Workaround

Stage data to a pending file and re-import on a later session (when the model emits the call with different formatting). Stripping markdown sometimes works mid-session.

Environment

  • Claude Code CLI (macOS, current as of 2026-05-11)
  • MCP server: Rust, rmcp 1.6, strict schema validation
  • Primarily observed against claude-opus-4-7 (1M context)

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗