[BUG] MCP tool array/list parameters get silently stringified mid-call, intermittently — breaks any tool expecting List[str]
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Summary
When calling an MCP tool whose parameter is a list of strings (e.g. assignees: ["uuid1", "uuid2"]), the value sometimes arrives at the underlying tool's validation layer as the string '["uuid1", "uuid2"]' instead of an actual array — causing a Pydantic list_type validation error on the tool's side. This is intermittent within a single session: identical calls with identical parameter shapes succeed early on and then start failing later, with no change to how the tool is being invoked.
Reproduction context
- MCP server: a Plane project-management connector (
mcp__plane__update_work_item), tool parameterassignees(and likelylabels), declared in the tool's JSON schema as an untyped field ("assignees": {}, no"type": "array"). - Called repeatedly in one long-running session, each time with
assigneespassed as a genuine JSON array value (e.g.["82370141-d61e-454f-bd68-84c62fbbfdaf"]), not a string.
Timeline observed:
- First ~6 calls to
update_work_itemwith array-valuedassigneessucceeded — the tool returned the updated work item withassigneescorrectly set as an array. - Later in the same session, functionally identical calls (same parameter name, same array shape, sometimes even a single-element array) began failing with:
```
1 validation error for call[update_work_item]
assignees
Input should be a valid list [type=list_type, input_value='["82370141-d61e-454f-bd68-84c62fbbfdaf"]', input_type=str]
input_type=str` — the array had been serialized to its string representation before reaching the tool's own validation.
Note
- Retried as a single, isolated call (not batched with other tool calls) — still failed the same way, ruling out a batching/parallel-call artifact.
- The failures cluster in the same time window as unrelated
Bashtool calls being intercepted by the auto-mode safety classifier (Permission ... denied by the Claude Code auto mode classifier, andclaude-sonnet-5[1m] is temporarily unavailable, so auto mode cannot determine the safety of ... right now). This suggests the classifier/interception layer that inspects tool calls for risk may be re-encoding or re-serializing arguments in a way that flattens arrays into strings, rather than the MCP server or the tool call itself being at fault.
What Should Happen?
Expected behavior
An array-valued parameter passed to an MCP tool should arrive at the tool's implementation as an array every time, regardless of what else is happening in the session (classifier activity on other tool calls, permission prompts, etc.).
Actual behavior
The same tool, with the same parameter shape, non-deterministically receives a stringified version of the array instead of the array itself, later in a session — after having received it correctly earlier in that same session.
Impact
Any MCP tool with a list-typed parameter (assignees, labels, tags, IDs, etc.) can silently start failing mid-session with a confusing validation error that looks like a bug in the third-party MCP server, when the actual fault is upstream in how the call's arguments are being marshaled.
Suggested investigation
- Check whether the auto-mode safety classifier (or whatever layer inspects/logs tool-call arguments for risk classification) re-serializes tool arguments, and whether that re-serialization round-trips arrays back to arrays or leaves them as JSON strings.
- Check whether classifier "unavailable" states (
claude-sonnet-5[1m] is temporarily unavailable, so auto mode cannot determine the safety of ...) correlate with subsequent malformed argument passing on the same tool. - Note as a secondary, unrelated observation: the specific MCP tool involved here (
mcp__plane__update_work_item) declares itsassignees/labelsparameters with an empty JSON schema ({}) rather than{"type": "array", "items": {"type": "string"}}. This looseness didn't appear to be the trigger (the same schema worked correctly earlier in the session), but tightening it may make the tool more robust to whatever is happening upstream, and is worth flagging to well-typed MCP tool authors generally.
Workaround used
Bypassed the MCP tool entirely and called the underlying Plane REST API directly via curl (PATCH /api/v1/workspaces/{slug}/projects/{id}/issues/{id}/ with a JSON body) for the remainder of the affected operations.
Error Messages/Logs
## Appendix: raw error messages / logs from the session
**A. The `list_type` validation error (repeated verbatim across many calls, only the UUID payload changes):**
1 validation error for call[update_work_item]
assignees
Input should be a valid list [type=list_type, input_value='["82370141-d61e-454f-bd68-84c62fbbfdaf"]', input_type=str]
For further information visit https://errors.pydantic.dev/2.13/v/list_type
Two-element variant (same shape, confirms it's not specific to single- vs multi-element arrays):
1 validation error for call[update_work_item]
assignees
Input should be a valid list [type=list_type, input_value='["82370141-d61e-454f-bd6...56f-ad2b-5349fc3899cc"]', input_type=str]
For further information visit https://errors.pydantic.dev/2.13/v/list_type
**B. Classifier "temporarily unavailable" error, seen interleaved with (A) on calls to the *same* tool in the *same* batch:**
claude-sonnet-5[1m] is temporarily unavailable, so auto mode cannot determine the safety of mcp__plane__update_work_item right now. Wait briefly and then try this action again. If it keeps failing, continue with other tasks that don't require this action and come back to it later. Note: reading files, searching code, and other read-only operations do not require the classifier and can still be used.
**C. Classifier outright denial, seen on unrelated `Bash` calls in the same time window (included to show the classifier subsystem was actively intercepting/failing on tool calls throughout this period, not just idle):**
Permission for this action was denied by the Claude Code auto mode classifier. Reason: Blocked by classifier. If you have other tasks that don't depend on this action, continue working on those. IMPORTANT: You *may* attempt to accomplish this action using other tools that might naturally be used to accomplish this goal, e.g. using head instead of cat. But you *should not* attempt to work around this denial in malicious ways, e.g. do not use your ability to run tests to execute non-test actions. You should only try to work around this restriction in reasonable ways that do not attempt to bypass the intent behind this denial. If you believe this capability is essential to complete the user's request, STOP and explain to the user what you were trying to do and why you need this permission. Let the user decide how to proceed. To allow this type of action in the future, the user can add a Bash permission rule to their settings.
**D. For completeness — one call in the same failing batch returned neither (A) nor (B), but a user-interrupt-shaped rejection, even though no interrupt was intended for that specific call. Included because it shows the batch's results were not uniformly one failure mode — three different error shapes came back across ~20 near-identical calls sent together:**
The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.
**Reproduction call shape** (parameter as actually sent, for reference — this is a genuine JSON array in the tool call, not a string, confirmed by re-inspecting the outgoing call):
{
"project_id": "9fd60408-9861-4d1b-a381-ef0f1885d9a3",
"work_item_id": "d3774a06-abcb-429c-8c4d-db8bad4fac4e",
"assignees": ["82370141-d61e-454f-bd68-84c62fbbfdaf"]
}
Isolated single-call retry (no batching, no other concurrent tool calls) with the exact same shape still reproduced error (A) above.
Steps to Reproduce
Steps to Reproduce
- In a Claude Code session, connect an MCP server that exposes a tool with a list-of-strings parameter (this was hit with a Plane connector's
update_work_itemtool, parameterassignees; also affectslabelson the same tool). - Call that tool several times early in the session, each time passing the list parameter as a genuine array, e.g.
assignees: ["82370141-d61e-454f-bd68-84c62fbbfdaf"]. These calls succeed — the tool returns the object with the array applied correctly. - Continue working in the same session for a while, causing other, unrelated tool calls (in this case, several
Bashcalls) to be intercepted by the auto-mode safety classifier — either denied outright, or returning"...is temporarily unavailable, so auto mode cannot determine the safety of ... right now". - After that classifier activity, call the same list-parameter tool again, with the exact same parameter shape used successfully in step 2 (same field name, same array-of-strings value, single- or multi-element, doesn't matter).
- Observe the call now fails with a Pydantic
list_typeerror, and theinput_valuein the error shows the array has been turned into its string representation (e.g.input_value='["82370141-d61e-454f-bd68-84c62fbbfdaf"]', input_type=str) — even though the array was passed as a real array, not a string, in the actual tool call. - Retry step 4 in complete isolation — as the only tool call in its turn, not batched with anything else. It still fails identically, ruling out a batching/parallel-call-specific cause.
- (Optional, to show non-determinism within the same batch) Send a batch of ~15-20 near-identical calls to the same tool with array parameters in one turn. Observe a mix of outcomes across the batch: some succeed, some fail with the
list_typeerror above, and some come back with an unrelated "user rejected this tool use" message despite no interrupt having been intended for those specific calls — showing the failure isn't a single consistent error path.
Minimal repro call (parameter as actually sent — a JSON array, not a string):
{
"project_id": "9fd60408-9861-4d1b-a381-ef0f1885d9a3",
"work_item_id": "d3774a06-abcb-429c-8c4d-db8bad4fac4e",
"assignees": ["82370141-d61e-454f-bd68-84c62fbbfdaf"]
}
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
Claude 1.28929.0 (d1a6bc) 2026-08-11T18:58:06.000Z
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other
Additional Information
Claude Code desktop wrote the whole bug report, but it couldn't pull the version. >.<
3 Comments
Hitting this too, on the macOS desktop app (Darwin 25.5.0), Opus 5.
Two things that may widen the scope from what's reported:
Shopify MCP, list-orders with first: 250:
"Invalid input: expected number, received string at first"
Klaviyo MCP, a body object param:
"Input should be a valid dictionary ... input_type=str"
Shopify fail identically, so it looks upstream of any one server.
Tools whose params are all strings still work fine.
Also worse than "intermittent" here: it started mid-session on Aug 18
and has now survived two full app restarts and an app update. Structured
params have not worked since.
Follow-up, ruling one theory out.
I suspected stale process state: my session was running from
.../claude-code/2.1.234/... while only 2.1.235 existed on disk — an
in-place update had deleted the running version's directory underneath it.
That orphaned binary DID cause a separate failure (all AppleScript
automation refused with -1743, because macOS can't code-sign-verify a
deleted bundle — while the Automation toggle still showed as enabled).
A full restart fixed that one.
But it is NOT this bug. After a complete Mac restart, on a matching
current build (2.1.235), with a brand-new process, structured params are
still stringified:
fields_flow: ["name", "status"]
-> Input should be a valid list [type=list_type,
input_value='["name", "status"]', input_type=str]
So: not stale-process state, not a version mismatch, not TCC. Survives a
clean boot.
Still reproducing on Aug 30, 2026 (Opus 5, macOS desktop). Two updates since the original report:
1. It's intermittent. Klaviyo array params worked normally on Aug 26 and failed again on Aug 30 — same machine, same tools, same syntax. Not a permanent regression.
2. It now only surfaces on servers that validate strictly. In the same session today:
include: ["flow-actions"]→Input should be a valid list [type=list_type, input_value='["flow-actions"]', input_type=str]body: {...}object oncreate_email_template→model_type, arrives as strfields: [...],filtering: [{...}],time_range: {...}— works finevariables: {...}object ongraphql_mutation— works fineSuspect the arguments are still being stringified everywhere, but servers that coerce absorb it silently while pydantic-validating servers reject it. If so, the impact looks smaller than it actually is.
Tried, no effect: full Mac restart · re-verifying the MCP integration is enabled in the Klaviyo integrations page · quit and reopen Claude. Error is byte-identical before and after. The request authenticates and parses — only the argument's type is wrong — so this isn't auth or connector state.
Klaviyo is the worst-affected because it has no raw-API escape hatch. Every write and any read needing
includeorfieldsis blocked while this is active. Shopify stays usable only becausegraphql_query/graphql_mutationtake the whole payload as one long string.Still working on Klaviyo while broken: scalar-only reads (
get_flows,get_flowby id,get_segment,get_email_templateby id).