Tool input serialization: adjacent multi-line `<parameter>` blocks merged into a single field
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:
- No
expansionkey ininput. - The closing
</core>and opening<parameter name="expansion">appear as literal text inside thecorestring value, immediately followed by what should have been the separateexpansionparameter's content. - 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)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗