You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Write tools report a failed write as a success when fallback is set, and return gh's stderr in successful results #22
25 of the 26 tools in tools-write.json take a fallback parameter. On a write tool it turns a failed write into a successful result that carries the caller's text, so an agent cannot tell a failed write from one that went through. pr_merge with fallback: "merged" on a PR that cannot be merged returns isError: false with the text merged.
The same tools also return gh's stderr inside a successful result. When --head is not passed and the working tree has uncommitted changes, gh pr create prints Warning: N uncommitted changes on stderr (pkg/cmd/pr/create/create.go in cli/cli), and pr_create returns that line together with the PR URL.
Cause
fallback: each write tool copies the same execution block, whose failure branch prints fallback and returns 0: [[ -n "${fallback}" ]] && { echo "${fallback}"; return 0; }, or the same with printf '%s\n'. Examples: lib/pr_write.sh:73, lib/issue_write.sh:63, lib/review_write.sh:129, lib/label.sh:115 (shared by the label and assignee tools), lib/issue_schema_write.sh:295, lib/sub_issue_write.sh:95, lib/api.sh:88, and lib/project.sh:238, :311 and :331. Because the tool exits 0, shared/mcpserver_core.sh:939 answers "isError": false. Without fallback, a non-zero exit becomes "isError": true (mcpserver_core.sh:932-933).
stderr: PR fix(github-mcp): stop hiding gh failures and validate tool input earlier #13 moved the values it lists (sub-issue node IDs, the head SHA pr_review_submit fetches, the project and status listings, among others) onto _gh_capture_split. The success path of the copied block was left as it was: 22 copies in the write tools run __raw=$("${cmd[@]}" 2>&1), and 20 of them return __raw unchanged (for example lib/pr_write.sh:70). Two write paths parse the merged stream: _gh_issue_schema_write runs jq over it and returns the raw text when jq fails (lib/issue_schema_write.sh:302), and project_status_set pipes gh project item-list ... 2>&1 into jq (lib/project.sh:307).
comment_edit (PR #21) already does what this issue asks for: it declares neither fallback nor suppress_errors, and it reads stdout and stderr apart (lib/review_write.sh:256).
Fix
Remove fallback from the schema of the 25 write tools in tools-write.json, and remove the fallback branch from each tool_*() function and from _gh_edit_list_param and _gh_issue_schema_write. Cost: every write tool sets additionalProperties: false, so a call that still passes fallback fails with Unknown parameter(s): fallback. REFERENCE.md:583, which describes fallback for write tools, changes with it.
In every write tool, capture gh's output with _gh_capture_split. On success, return stdout. On failure, return stderr, or stdout when stderr is empty, because gh api prints an HTTP error's JSON body on stdout (lib/issue_schema_write.sh:296-297). Apply the same split to the item-list lookup at lib/project.sh:307.
Tests: per tool, a call that passes fallback is rejected by schema validation, and a gh stub that writes a warning to stderr and exits 0 returns only stdout.
Activity