Context
#422 added schema-aware argument coercion (coerceInputForSchema) at the MCP dispatch boundary in McpSource.execute, recovering models' string-encoded structured args (e.g. an array param emitted as "[\"a@b.com\"]") before they reach the wire, where the upstream validator would otherwise reject them ("Input should be a valid list on parameter X").
Gap
execute() covers the agent-loop dispatch path (inline + task-augmented). The external /mcp task surface dispatches differently: src/api/mcp-server.ts:888 calls taskAwareSource.startToolAsTask(localName, args, …) directly, bypassing execute() and therefore the coercion. An external MCP client (e.g. another agent driving this platform as a remote MCP server) invoking a task-augmented tool with a stringified-array argument reproduces the original bug.
Why deferred
The production incident behind #422 was on the agent-loop path (now fixed). The /mcp task surface is slated for a broader overhaul, so the fix belongs there rather than bolted onto the current dispatch.
Options when addressed
- Move coerce + scrub into the wire-dispatch primitives (
callToolInline and startToolAsTask), keyed on this.findTool(toolName)?.inputSchema, so every caller — execute and the direct /mcp path — converges on one normalization point; or
- Coerce at the
/mcp call site in mcp-server.ts before startToolAsTask.
The first is the structurally cleaner convergence and should be folded into the /mcp overhaul.
Context
#422 added schema-aware argument coercion (
coerceInputForSchema) at the MCP dispatch boundary inMcpSource.execute, recovering models' string-encoded structured args (e.g. an array param emitted as"[\"a@b.com\"]") before they reach the wire, where the upstream validator would otherwise reject them ("Input should be a valid list on parameter X").Gap
execute()covers the agent-loop dispatch path (inline + task-augmented). The external/mcptask surface dispatches differently:src/api/mcp-server.ts:888callstaskAwareSource.startToolAsTask(localName, args, …)directly, bypassingexecute()and therefore the coercion. An external MCP client (e.g. another agent driving this platform as a remote MCP server) invoking a task-augmented tool with a stringified-array argument reproduces the original bug.Why deferred
The production incident behind #422 was on the agent-loop path (now fixed). The
/mcptask surface is slated for a broader overhaul, so the fix belongs there rather than bolted onto the current dispatch.Options when addressed
callToolInlineandstartToolAsTask), keyed onthis.findTool(toolName)?.inputSchema, so every caller —executeand the direct/mcppath — converges on one normalization point; or/mcpcall site inmcp-server.tsbeforestartToolAsTask.The first is the structurally cleaner convergence and should be folded into the
/mcpoverhaul.