Skip to content

Write tools report a failed write as a success when fallback is set, and return gh's stderr in successful results #22

Open

Description

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions