[BUG] MCP tool array/list parameters get silently stringified mid-call, intermittently — breaks any tool expecting List[str]

Status Open
Maintainer reply None cached
Activity 3 comments · opened Aug 13, 2026

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 parameter assignees (and likely labels), 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 assignees passed as a genuine JSON array value (e.g. ["82370141-d61e-454f-bd68-84c62fbbfdaf"]), not a string.

Timeline observed:

  1. First ~6 calls to update_work_item with array-valued assignees succeeded — the tool returned the updated work item with assignees correctly set as an array.
  2. 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]
`
Note
input_type=str` — the array had been serialized to its string representation before reaching the tool's own validation.

  1. Retried as a single, isolated call (not batched with other tool calls) — still failed the same way, ruling out a batching/parallel-call artifact.
  2. The failures cluster in the same time window as unrelated Bash tool calls being intercepted by the auto-mode safety classifier (Permission ... denied by the Claude Code auto mode classifier, and claude-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 its assignees/labels parameters 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

  1. 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_item tool, parameter assignees; also affects labels on the same tool).
  2. 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.
  3. Continue working in the same session for a while, causing other, unrelated tool calls (in this case, several Bash calls) 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".
  4. 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).
  5. Observe the call now fails with a Pydantic list_type error, and the input_value in 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.
  6. 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.
  7. (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_type error 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. >.<

View original on GitHub ↗

3 Comments

bayorgs · 10 days ago

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:

  1. It's not only arrays. Objects and integers are stringified as well.

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"

  1. It spans unrelated MCP servers in the same session — Klaviyo and

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.

bayorgs · 10 days ago

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.

bayorgs · 18 hours ago

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:

  • Klaviyo rejects include: ["flow-actions"]Input should be a valid list [type=list_type, input_value='["flow-actions"]', input_type=str]
  • Klaviyo rejects a body: {...} object on create_email_templatemodel_type, arrives as str
  • Meta Ads accepts fields: [...], filtering: [{...}], time_range: {...} — works fine
  • Shopify accepts a variables: {...} object on graphql_mutation — works fine

Suspect 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 include or fields is blocked while this is active. Shopify stays usable only because graphql_query / graphql_mutation take the whole payload as one long string.

Still working on Klaviyo while broken: scalar-only reads (get_flows, get_flow by id, get_segment, get_email_template by id).