fix: guard against empty MCP tool input#13
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
request_plan_review/request_code_review/request_execution_partitionwith an empty{}input, hitting MCP-32602in a retry loop they can't recover from (observed: 20 consecutive failed calls before the model self-corrected).-32602(which Claude cannot recover from).plan/code/approved_plan/workspace_rootzod.describe()strings to make the required-vs-empty distinction explicit to the calling model.descriptionwith REQUIRED-vs-optional field lists and a "NEVER call with empty object" instruction..claude/agents/duul-planner.mdwith a minimum valid call example.Background
Session log
~/.claude/projects/-Users-planningo-conductor-workspaces-tesflow-v1-sofia-v2/.../subagents/agent-a71450136bc19f3a1.jsonlshows the failure mode: lines 76–115 are 20 sequentialrequest_plan_reviewtool_use blocks withinput: {}andoutput_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-32602is 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.request_plan_reviewwith{}and confirm tool-level error (not MCP -32602) is returned.request_plan_reviewwith a validplanfield and confirm normal review flow still works.🤖 Generated with Claude Code