Summary
Calling bookstack_pages_create (and likely other write tools) through Claude Desktop's custom connector, bridged via mcp-remote over the HTTP transport, fails validation even with a minimal, schema-valid payload. The same exact payload succeeds when sent directly to POST /message via curl. This points to mcp-remote (or Claude Desktop) injecting an extra top-level key into arguments that the server's strictObject Zod schema rejects.
Environment
- Server: self-hosted, Docker (
oven/bun:1.3.14-alpine), MCP_TRANSPORT=http
- Client: Claude Desktop custom connector →
mcp-remote@latest (stdio↔HTTP bridge) → server over HTTPS (nginx reverse proxy in front)
- Tool:
bookstack_pages_create
Reproduction
- Configure Claude Desktop with a
mcpServers entry using mcp-remote@latest pointed at the server's /message endpoint with --header "Authorization: Bearer <token>".
- Ask Claude to create a BookStack page with minimal args:
chapter_id, name, markdown.
- Call fails. Claude Desktop surfaces only a generic
<error>Tool execution failed</error> — no detail.
- Server logs (
LOG_LEVEL=info) show:
[info] Tool called {"tool":"bookstack_pages_create","argument_names":["chapter_id","markdown","name"],"unknown_argument_count":1}
[error] Tool failed {"tool":"bookstack_pages_create","err":{"error_name":"ZodError","error_message":"[redacted: 152 chars]"}}
unknown_argument_count: 1 confirms an extra, unrecognized key was present in arguments beyond the three intentionally sent.
Isolating the cause
The identical logical payload sent directly via curl to /message (bypassing Claude Desktop and mcp-remote entirely) succeeds:
curl -s -X POST https://<host>/message \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"bookstack_pages_create","arguments":{"chapter_id":3,"name":"Test","markdown":"test"}}}'
→ Returns a created page object (200/success). This rules out a server-side schema bug and a BookStack API permissions issue (both were initially suspected) — the server and its validation are correct for this exact argument set. The extra key must be added somewhere in the Claude Desktop → mcp-remote → HTTP path.
Two things this issue is really about
- (Client-side, may belong in
mcp-remote's own tracker instead) — whatever is injecting the extra key into arguments.
- (Server-side, actionable here) — the server's error surfacing makes this very hard to diagnose from the client.
strictObject Zod validation failures return McpError(InvalidParams, 'Validation failed', {type: 'validation_error', validation: [...]}) with a structured validation array naming the offending field(s) — but Claude Desktop shows only a generic banner, and the server's own structured logs redact the validation message text (by design, per the logger's redaction policy) and never log the actual value it saw, only a count. Confirming the real culprit key required a local patch to log unknown key names at debug level.
Ask
- Would a slightly more permissive top-level parse (e.g., explicitly allow-and-ignore a documented MCP reserved key like
_meta if that turns out to be the culprit, rather than blanket strictObject) be acceptable, once the actual injected key is confirmed?
- Separately: any interest in a startup/README note flagging that
mcp-remote bridging is untested against this server's strict validation, so others hit this faster?
I can supply the exact extra key name once I re-run with a local debug patch that logs unknown argument names (not values) — will update this issue.
Summary
Calling
bookstack_pages_create(and likely other write tools) through Claude Desktop's custom connector, bridged viamcp-remoteover the HTTP transport, fails validation even with a minimal, schema-valid payload. The same exact payload succeeds when sent directly toPOST /messageviacurl. This points tomcp-remote(or Claude Desktop) injecting an extra top-level key intoargumentsthat the server'sstrictObjectZod schema rejects.Environment
oven/bun:1.3.14-alpine),MCP_TRANSPORT=httpmcp-remote@latest(stdio↔HTTP bridge) → server over HTTPS (nginx reverse proxy in front)bookstack_pages_createReproduction
mcpServersentry usingmcp-remote@latestpointed at the server's/messageendpoint with--header "Authorization: Bearer <token>".chapter_id,name,markdown.<error>Tool execution failed</error>— no detail.LOG_LEVEL=info) show:unknown_argument_count: 1confirms an extra, unrecognized key was present inargumentsbeyond the three intentionally sent.Isolating the cause
The identical logical payload sent directly via
curlto/message(bypassing Claude Desktop andmcp-remoteentirely) succeeds:→ Returns a created page object (200/success). This rules out a server-side schema bug and a BookStack API permissions issue (both were initially suspected) — the server and its validation are correct for this exact argument set. The extra key must be added somewhere in the Claude Desktop →
mcp-remote→ HTTP path.Two things this issue is really about
mcp-remote's own tracker instead) — whatever is injecting the extra key intoarguments.strictObjectZod validation failures returnMcpError(InvalidParams, 'Validation failed', {type: 'validation_error', validation: [...]})with a structuredvalidationarray naming the offending field(s) — but Claude Desktop shows only a generic banner, and the server's own structured logs redact the validationmessagetext (by design, per the logger's redaction policy) and never log the actual value it saw, only a count. Confirming the real culprit key required a local patch to log unknown key names at debug level.Ask
_metaif that turns out to be the culprit, rather than blanketstrictObject) be acceptable, once the actual injected key is confirmed?mcp-remotebridging is untested against this server's strict validation, so others hit this faster?I can supply the exact extra key name once I re-run with a local debug patch that logs unknown argument names (not values) — will update this issue.