[BUG] Valid MCP tool silently dropped: API schema validation rejects property names containing `[]`
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
A tool from a spec-compliant MCP server is silently discarded at session start because its
input schema contains a property named uids[]. Tool schemas are validated against^[a-zA-Z0-9_.-]{1,64}$ for property keys, and the square brackets fail that pattern.
uids[] is a legal property name in JSON Schema — the spec places no constraints on the keys
of properties — and the MCP specification defines inputSchema as a JSON Schema object.
So the server is valid on both counts; the rejection comes from a stricter constraint layered
on top by the API. The result is that a working MCP server loses functionality with no
actionable error surfaced to the user.
Environment
- Claude Code: 2.1.263 (VS Code extension)
- Platform: Linux 7.0.12-linuxkit (devcontainer), Node v24.19.0
- MCP server:
pushpad-mcp@0.1.1(stdio,npx -y pushpad-mcp) - Affected tool:
subscriptions_list
Reproduction
- Configure the MCP server in
.mcp.json:
``json``
{
"mcpServers": {
"pushpad": {
"type": "stdio",
"command": "npx",
"args": ["-y", "pushpad-mcp"],
"env": { "PUSHPAD_TOKEN": "<token>" }
}
}
}
- Start a session and ask the model to list subscriptions for a project.
Expected
subscriptions_list is available, like the server's other 18 tools.
Actual
The tool is excluded before the model ever sees it. The only trace is an internal note:
- "subscriptions_list" (MCP server "pushpad"): "property key uids[] does not match /^[a-zA-Z0-9_.-]{1,64}$/"
Root cause
pushpad-mcp is a generic OpenAPI-to-MCP bridge; it fetches https://pushpad.xyz/openapi.yaml
at startup and derives tools from it. The spec declares:
uids:
in: query
name: uids[]
style: form
explode: true
schema:
type: array
items:
type: string
This is valid OpenAPI 3 and the standard way to express a repeated bracketed query parameter
(?uids[]=a&uids[]=b), the convention used by Rails, PHP, and many other backends. The bridge
maps the query-parameter name directly to a JSON Schema property name, yielding uids[].
subscriptions_list is the only one of the spec's 19 operations that references a bracketed
parameter, which is exactly why it is the only tool dropped — the failure is entirely attributable
to the character class, not to anything else about the server.
Impact
- Any OpenAPI-derived MCP server exposing bracket-style array query params loses those tools.
This is a widespread convention, so the blast radius is larger than one server.
- The failure is silent from the user's perspective. Nothing appears in the UI: the tool simply
does not exist, and the model can only report it as missing after the fact.
- There is no user-side remedy. Fixing it requires changing the upstream API's parameter naming
or patching the bridge — neither is available to someone who just installed the server.
Suggested resolutions
Any one of these would resolve it:
- Relax the property-key pattern to accept the characters JSON Schema permits, or at minimum
[ and ]. (recommended)
- Sanitize on the client side. Rewrite non-conforming keys to a safe alias when registering
the tool, and map them back when invoking it. This keeps the constraint intact while preserving
compatibility with compliant servers.
What Should Happen?
API schema validation should allow property names containing []
Error Messages/Logs
Steps to Reproduce
- Configure the MCP server in
.mcp.json:
``json``
{
"mcpServers": {
"pushpad": {
"type": "stdio",
"command": "npx",
"args": ["-y", "pushpad-mcp"],
"env": { "PUSHPAD_TOKEN": "<token>" }
}
}
}
- Start a session and ask the model to list subscriptions for a project.
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.263 (VS Code extension)
Platform
Anthropic API
Operating System
Other Linux
Terminal/Shell
VS Code integrated terminal
Additional Information
_No response_
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Hitting the same class of failure on OpenAPI→MCP bridges: the server is fine, the host applies a stricter key charset than JSON Schema, and the only observable outcome is a missing tool.
A few host-ops notes that have helped when debugging similar silent drops:
1. Distinguish three failure modes
| Class | When | What the model sees | What ops needs |
|---|---|---|---|
| schema_reject | register / list_tools | tool absent | key + regex + server name |
| invoke_reject | call_tool | explicit error | mapped alias vs wire name |
| transport_fail | stdio/http | timeout/crash | not a schema problem |
Right now this is pure
schema_reject, but it presents like "the server never implementedsubscriptions_list." That is the worst of the three for triage.2. Prefer sanitize-on-register over silent drop
If the upstream API key charset cannot accept
[], the client can still preserve the tool:uids[]→uids_arrayoruids).tools/call, reverse-map args before forwarding to the MCP server.tool=subscriptions_list server=pushpad key="uids[]" alias="uids_array" reason=property_key_charset.That keeps OpenAPI-form
explodearray params (uids[]=a&uids[]=b) working without requiring every bridge author to rename query params.3. Surface, don't swallow
A dropped tool should show up in the same place operators already look for MCP health (server status / tool count / session init log). A single internal line that never reaches the UI guarantees the model will invent a story about a missing capability.
Minimum signal:
If N≠M, fail loud at session start (or at least badge the server), not mid-conversation when the user asks for the one dropped operation.
4. OpenAPI bridges will keep producing this
Bracketed array query names are normal in Rails/PHP/OpenAPI
style: form, explode: true. Any generic OpenAPI→MCP generator that copies parameternameinto JSON Schemapropertieswill hit[], and occasionally other legal-but-strict-charset characters. Treating that as "invalid server" is backwards; the bridge is following OpenAPI, the host is applying an API-side constraint.Acceptance checks (if fixing)
uids[]still lists the tool to the modeltools/callwith the model-facing alias round-trips to the wire name the server expects_,.,-still pass as todayHappy to retest against
pushpad-mcp/ any OpenAPI-derived fixture once a sanitize or relaxed-pattern path lands.Withdrawn (2026-09-27). This earlier commercial note from Exactlane Operations, including the price quoted here, is withdrawn and no longer valid. It should not have been posted on this issue — apologies for the noise.
— Exactlane Operations
Follow-up on
pushpad-mcp@0.1.1with the Claude Code 2.1.282 CLI (local server, no Pushpad API call).19 tools listed;
subscriptions_listis still the only one dropped. The log namesuids[], but the same input schema also hastags[], which fails the same/^[a-zA-Z0-9_.-]{1,64}$/check. A constructed variant withuids[]removed andtags[]kept was still dropped:So renaming only
uids[]would leave the tool dropped.Proposed bridge fix (not invocation-tested): alias both schema keys to legal names (
uids,tags) while keeping the bracketed namesuids[]/tags[]on the wire for the query string.