Skip to content

fix: guard against empty MCP tool input#13

Merged
Suprhimp merged 1 commit into
masterfrom
devplanningo/empty-input-guards
May 25, 2026
Merged

fix: guard against empty MCP tool input#13
Suprhimp merged 1 commit into
masterfrom
devplanningo/empty-input-guards

Conversation

@Suprhimp
Copy link
Copy Markdown
Member

Summary

  • Sonnet subagents occasionally emit request_plan_review / request_code_review / request_execution_partition with an empty {} input, hitting MCP -32602 in a retry loop they can't recover from (observed: 20 consecutive failed calls before the model self-corrected).
  • Trap empty/short input at handler entry and return a tool-level error with a concrete retry example, instead of letting zod throw the opaque MCP -32602 (which Claude cannot recover from).
  • Strengthen plan / code / approved_plan / workspace_root zod .describe() strings to make the required-vs-empty distinction explicit to the calling model.
  • Expand each tool's MCP description with REQUIRED-vs-optional field lists and a "NEVER call with empty object" instruction.
  • Add "Tool input rules" section to .claude/agents/duul-planner.md with a minimum valid call example.

Background

Session log ~/.claude/projects/-Users-planningo-conductor-workspaces-tesflow-v1-sofia-v2/.../subagents/agent-a71450136bc19f3a1.jsonl shows the failure mode: lines 76–115 are 20 sequential request_plan_review tool_use blocks with input: {} and output_tokens: 44. The Sonnet subagent emits the tool wrapper but no field content, gets back MCP -32602: plan required, and keeps retrying with the same empty input. Since -32602 is an MCP-protocol error (not a tool_result error), the model has no path to self-correct; only when context shifted at line 117 did it produce a full-input call.

Test plan

  • npm test — 60/60 tests pass.
  • npm run build — clean.
  • Manual: trigger request_plan_review with {} and confirm tool-level error (not MCP -32602) is returned.
  • Manual: trigger request_plan_review with a valid plan field and confirm normal review flow still works.

🤖 Generated with Claude Code

Sonnet subagents sometimes emit `request_plan_review` (and the
sibling tools) with an empty `{}` input, hitting MCP -32602 in a
retry loop they can't escape. Two-part fix:

- Strengthen `plan` / `code` / `approved_plan` zod `.describe()` to
  make the required field unambiguous to the calling model.
- Trap empty/short input at handler entry and return a tool-level
  error with a concrete retry example, instead of letting zod throw
  the opaque MCP -32602.

Also expands tool `description` strings with explicit REQUIRED-vs-
optional field lists, and adds a "Tool input rules" section to the
`duul-planner` agent prompt with a minimum valid call example.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Suprhimp Suprhimp merged commit acb11cb into master May 25, 2026
1 check passed
@Suprhimp Suprhimp deleted the devplanningo/empty-input-guards branch May 25, 2026 11:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant