MCP tool calls from sub-agents serialize single-element string arrays as scalars (server → JSON-RPC -32603)
Bug: single-element string arrays in MCP tool calls from sub-agents are serialized as scalars (server rejects → JSON-RPC -32603)
Summary
When a sub-agent (spawned via the Agent/Task tool) invokes an MCP tool that has a parameter typed
as an array of strings, and the model supplies a single-element array (e.g. ["foo"]), the
harness serializes the argument over the wire as a bare JSON string ("foo") instead of a
one-element JSON array (["foo"]). A strictly-typed MCP server then fails to deserializestring → string[] and the call fails with JSON-RPC error -32603 ("An error occurred"). The
error surfaces before the tool body runs, so there is no application-level error message — only the
opaque -32603.
Scope (important)
The defect is specific to sub-agent invocations. The identical MCP tool call made by the main
agent serializes single-element string arrays correctly (as ["foo"]) and succeeds. Only tool
calls originating from sub-agents (Agent/Task tool) exhibit the scalar collapse. This was confirmed
by running the same edit call from both contexts against the same server: main-agent → success and
logged normally; sub-agent → -32603 with the server-side string[] deserialization error below.
Environment
- Claude Code: 2.1.195 (reported as client by the server during the failing
tools/call) - Invocation path: sub-agent (Agent/Task tool) — main-agent invocations are unaffected
- MCP transport: Streamable HTTP (
POST /mcp) - Server: .NET 8 host using the
ModelContextProtocol/ModelContextProtocol.AspNetCoreSDK (1.4.0) - OS: Windows 11
Expected behavior
A model-supplied single-element array ["foo"] for an array<string> parameter is serialized as a
JSON array ["foo"], matching the tool's input schema ({"type":"array","items":{"type":"string"}}).
Actual behavior
The single-element string array is serialized as the scalar "foo". The server SDK's parameter
marshaller throws and the call returns -32603.
Notable asymmetry
In the same tool call, a single-element integer array parameter (occurrences: [1]) is sent as
a proper array, while single-element string array parameters (what, replaceBy) are collapsed to
scalars. So the collapse appears specific to string-typed array parameters.
Reproduction
- Define an MCP tool with two
array<string>parameters and onearray<int>parameter, e.g.
edit(source: string, what: string[], replaceBy: string[], occurrences: int[]).
- From a sub-agent (spawn one via the Agent/Task tool), call it with single-element arrays for the
string params: edit(source: "s", what: ["a"], replaceBy: ["b"], occurrences: [1]).
- Observe the server receives
what/replaceByas JSON strings ("a","b") whileoccurrences
arrives as [1].
- A strictly-typed server rejects the scalars; the client shows
MCP error -32603: An error occurred. - Make the same call from the main agent → it serializes as arrays and succeeds. The only
difference is the invocation context (sub-agent vs. main agent).
Server-side evidence (captured stack trace)
ModelContextProtocol.Server.McpServer [Error]: "<tool>" threw an unhandled exception.
System.Text.Json.JsonException: The JSON value could not be converted to System.String[].
Path: $ | LineNumber: 0 | BytePositionInLine: 20
at System.Text.Json...JsonCollectionConverter`2.OnTryRead(...)
at Microsoft.Extensions.AI.AIFunctionFactory.ReflectionAIFunctionDescriptor...GetParameterMarshaller...
at ModelContextProtocol.Server.AIFunctionMcpServerTool.InvokeAsync(...)
Impact
- Affects any MCP tool with
array<string>(and likely other array-of-scalar) parameters when the
model provides a single-element array — a common, natural case.
- The failure is opaque: -32603 with no actionable message; nothing reaches the tool implementation, so
server-side logging/telemetry shows no application error and no operation record. Hard to diagnose
without instrumenting the SDK's own logger.
Workaround (user-side)
Coerce the value so a genuine array survives serialization, or have the server accept scalar-or-array
for string[] params (a JsonConverter<string[]>). Both are mitigations for a client serialization bug.
Suggested fix
Serialize model-supplied array arguments according to the tool's JSON input schema
(type: array) regardless of element count, so single-element string arrays are emitted as ["…"].