Problem
Real-world MCP clients (forge agent runtimes among them) sometimes send sub-ops inside codedb_bundle with empty arguments and the actual args sitting inline at the op level — e.g.:
{"ops":[{"tool":"codedb_outline","arguments":{},"path":"src/main.zig"}]}
The current dispatcher sees "arguments" is present, treats it as authoritative even though it's empty, and reports missing 'path' argument with received keys: [] — even though path is right there in the op.
The diagnostic is also unhelpful in this state: received keys: [] tells the user "you sent nothing" but doesn't suggest the inline-args fallback that would route around their broken client wrapper.
Steps to reproduce
$ (printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}'; \
sleep 1; \
printf '%s\n' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"codedb_bundle","arguments":{"ops":[{"tool":"codedb_outline","arguments":{},"path":"src/main.zig"}]}}}'; \
sleep 1) | codedb mcp 2>/dev/null
Bundle reports:
error: all 1 bundle op(s) failed
--- [0] codedb_outline ---
error: missing 'path' argument
received keys: []
Failing tests (3)
test "issue-424-B: bundle falls through to inline args when arguments is empty object" { ... }
test "issue-424-D: received-keys diagnostic hints at inline-args workaround when empty" { ... }
test "issue-424-A: bundle envelope errors carry the 'error:' prefix consistently" { ... }
All three fail on main at e7f177be (v0.2.5805).
Expected
- B (medium): when
arguments is present but is an empty object, the dispatcher should fall through to inline-args mode rather than treating the empty object as authoritative. Sending {tool, arguments:{}, path} should be equivalent to {tool, path}.
- D (medium): when
received keys: is empty, append a hint pointing at the inline-args shape so a user with a broken client wrapper can self-recover.
- A (low): the bundle dispatcher's
"op must be an object" and "missing 'tool' field" errors should be prefixed with error: for consistency with per-tool handlers and the TTY summary parser at mcp.zig:3373.
Fix
In handleBundle (src/mcp.zig ~1843):
- When
op_obj.get("arguments") returns an empty object, treat it the same as when arguments is absent — use op_obj as the inline source.
- In
appendBundleArgKeysDiagnostic (src/mcp.zig ~1710), when the args map is empty, append a one-line hint like (empty — try inline shape: {"tool":"...","path":"..."}).
- Add
error: prefix to the two malformed-envelope branches.
Related
This is a follow-on to #423 (which deduped the diagnostic) and #422 (which made the descriptor explicit about arguments vs args). #422/#423 made the output less misleading for human readers; this issue makes the behaviour tolerant of one common client serialization bug, plus actionable when it can't be fixed server-side.
Problem
Real-world MCP clients (forge agent runtimes among them) sometimes send sub-ops inside
codedb_bundlewith emptyargumentsand the actual args sitting inline at the op level — e.g.:{"ops":[{"tool":"codedb_outline","arguments":{},"path":"src/main.zig"}]}The current dispatcher sees
"arguments"is present, treats it as authoritative even though it's empty, and reportsmissing 'path' argumentwithreceived keys: []— even thoughpathis right there in the op.The diagnostic is also unhelpful in this state:
received keys: []tells the user "you sent nothing" but doesn't suggest the inline-args fallback that would route around their broken client wrapper.Steps to reproduce
Bundle reports:
Failing tests (3)
All three fail on
mainate7f177be(v0.2.5805).Expected
argumentsis present but is an empty object, the dispatcher should fall through to inline-args mode rather than treating the empty object as authoritative. Sending{tool, arguments:{}, path}should be equivalent to{tool, path}.received keys:is empty, append a hint pointing at the inline-args shape so a user with a broken client wrapper can self-recover."op must be an object"and"missing 'tool' field"errors should be prefixed witherror:for consistency with per-tool handlers and the TTY summary parser atmcp.zig:3373.Fix
In
handleBundle(src/mcp.zig~1843):op_obj.get("arguments")returns an empty object, treat it the same as whenargumentsis absent — useop_objas the inline source.appendBundleArgKeysDiagnostic(src/mcp.zig~1710), when the args map is empty, append a one-line hint like(empty — try inline shape: {"tool":"...","path":"..."}).error:prefix to the two malformed-envelope branches.Related
This is a follow-on to #423 (which deduped the diagnostic) and #422 (which made the descriptor explicit about
argumentsvsargs). #422/#423 made the output less misleading for human readers; this issue makes the behaviour tolerant of one common client serialization bug, plus actionable when it can't be fixed server-side.