MCP tool calls from sub-agents serialize single-element string arrays as scalars (server → JSON-RPC -32603)

Open 💬 0 comments Opened Jun 27, 2026 by de-gn

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 deserialize
stringstring[] 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.AspNetCore SDK (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

  1. Define an MCP tool with two array<string> parameters and one array<int> parameter, e.g.

edit(source: string, what: string[], replaceBy: string[], occurrences: int[]).

  1. 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]).

  1. Observe the server receives what / replaceBy as JSON strings ("a", "b") while occurrences

arrives as [1].

  1. A strictly-typed server rejects the scalars; the client shows MCP error -32603: An error occurred.
  2. 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 ["…"].

View original on GitHub ↗