Skip to content

fix(github-mcp): vendor bash-mcp-sdk v5.2.0 and drop cancelled partials - #9

Merged
Martin Bens (SpiGAndromeda) merged 2 commits into
mainfrom
chore/bash-mcp-sdk-v5.2.0
Oct 1, 2026
Merged

Martin Bens (SpiGAndromeda) merged 2 commits into
mainfrom
chore/bash-mcp-sdk-v5.2.0

Conversation

@SpiGAndromeda

@SpiGAndromeda Martin Bens (SpiGAndromeda) commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Moves the vendored protocol layer from bash-mcp-sdk v5.0.0 to v5.2.0, removes the plugin code the SDK now makes redundant, and fixes two download defects.

SDK v5.2.0

v5.2.0 dispatches a tools/call only when the running server's tools list declares the tool, and answers -32601 otherwise. That is the guarantee _gh_unset_undeclared_tools added in 4.2.0, so the helper is removed. The SDK also closes two routes the helper left open: an executable named tool_<name> on PATH, and a tool_<name>_cancel hook called as a tool. tool_dispatch_declaration.bats is unchanged and still passes, so the read server and the disabled write server refuse every tool they do not declare.

v5.1.0 chains an EXIT trap set before run_mcp_server into teardown. Neither server sets one. The comment in server-write.sh that said such a trap never runs now gives only the reasons for shipping tools-empty.json that still hold.

Startup check for the tools list

The removed helper also read the tools list at startup, which made a missing or corrupt list stop the server. The SDK reads that list only on tools/list and tools/call, so without the helper the server would start and then fail every such call. _gh_require_tools_list restores the startup refusal in both servers. It applies the SDK's own rule that the file holds exactly one JSON object.

Cancelled downloads

repo_file and search_code with download_to write to a <dest>.partial.* sibling and rename it when the body is complete. A cancel sends SIGTERM to the call's process group, and nothing removed the sibling, so it stayed next to the user's file.

Both sites now use _gh_partial_create in lib/common.sh:

  • It installs a fixed EXIT trap before the file exists, and creates the file with noclobber in the tool's own shell. mktemp created the file inside a $() subshell before the caller could name it in a trap.
  • The name is recorded only after the file is created, so the trap never deletes a file left by another process under a colliding name. What remains: a SIGTERM on that single assignment, or a SIGKILL, still leaves the sibling.
  • No earlier EXIT handler is captured or chained. In a subshell with no trap of its own, trap -p reports the parent's handler. Here that is the server's _server_teardown, and running it inside a tool shell would tear the server down. As a consequence, a future mcp_before_tool_call hook that sets an EXIT trap would have it replaced by the download trap.
  • The partial file now takes its mode from the umask instead of mktemp's 0600, so a downloaded file ends up with an ordinary mode.

gh stderr in downloaded files

_gh_download_file sent gh's stderr into the downloaded file with 2>&1, so a warning on an otherwise successful search_code download became part of the file. stderr is now captured separately. A warning on success goes to the log, and on failure the captured text is part of the error message.

shared/mcpserver_core.sh is vendored from shopwareLabs/bash-mcp-sdk v5.2.0, up from v5.0.0. v5.2.0 dispatches a tools/call only when the running server's tools list declares the tool and answers -32601 otherwise, which is the guarantee _gh_unset_undeclared_tools added in 4.2.0. The protocol layer also covers two routes the helper did not: an executable named tool_<name> on PATH, and a tool_<name>_cancel hook called as a tool. The helper is removed. tool_dispatch_declaration.bats passes unchanged against the SDK's enforcement, so the read server and the disabled write server still answer "Tool not found" for every tool they do not declare. v5.1.0 chains an EXIT trap set before run_mcp_server into teardown. Neither server sets one, and the comment in server-write.sh that said such a trap never runs now gives only the reasons that still hold.

Removing the helper also removed the jq read it did over the tools list at startup. The SDK reads that list only per tools/list or tools/call request, so a missing or corrupt tools-read.json let the server start and then fail every such call. _gh_require_tools_list restores the refusal at startup in both servers and applies the SDK's own rule that the file holds exactly one JSON object.

A cancelled repo_file or search_code download with download_to left its <dest>.partial.XXXXXX sibling next to the user's file. Cancellation sends SIGTERM to the call's process group and nothing removed the file. Both sites now go through _gh_partial_create, which installs a fixed EXIT trap before the file exists and creates it with noclobber in the tool's own shell. mktemp created the file inside a $() subshell before the caller could name it in a trap. The name is recorded only after creation, so the trap never removes a file another process left under a colliding name. No earlier EXIT handler is captured or chained. In a subshell with no trap of its own, trap -p reports the parent's handler, which here is the server's _server_teardown, and running that inside a tool shell would tear the server down. A SIGTERM on the single assignment after creation, or a SIGKILL, still leaves the sibling behind. The partial file now takes its mode from umask instead of mktemp's 0600.

_gh_download_file redirected gh's stderr into the downloaded file with 2>&1, so a warning on an otherwise successful search_code download became part of the file. stderr is now captured apart from the body. A warning on success is logged, and a failure's text is returned in the error message.

Released as 4.2.1. Every tool a server declares behaves as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Version bumps land in a separate release commit, so the entry goes under Unreleased and both plugin manifests stay at 4.2.0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@SpiGAndromeda
Martin Bens (SpiGAndromeda) merged commit e44bc7d into main Oct 1, 2026
1 check passed
@SpiGAndromeda
Martin Bens (SpiGAndromeda) deleted the chore/bash-mcp-sdk-v5.2.0 branch October 2, 2026 14:18
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