Local linting and CI expect a few command-line tools to be present:
shellcheck– static analysis for all shell scripts.shfmt– enforces consistent formatting (used bytest/lint.sh). Install viago install mvdan.cc/sh/v3/cmd/shfmt@latest(official upstream method) or your OS package manager.jqorgojq– deterministic JSON tooling. mcp-bash auto-detects both; for Windows Git Bash/MSYS,jqis often more reliable due to observed exec/argument-size limits withgojqon some CI runners. CI installsgojqfor reproducibility, but you can override detection withMCPBASH_JSON_TOOL/MCPBASH_JSON_TOOL_BINif needed.bats– unit tests use bats-core (v1.5.0+). Runnpm installto install bats and helper libraries (bats-support, bats-assert, bats-file). Alternatively, install bats-core viabrew install bats-core(macOS) orapt install bats(Debian/Ubuntu).
Without shfmt, the lint step fails immediately with "Required command "shfmt" not found in PATH".
Install pre-commit and run pre-commit install to mirror CI formatting/linting locally. Hooks cover whitespace, shfmt, and shellcheck so commits fail fast when style drifts.
See TESTING.md for detailed instructions on running the test suite.
For CI parity (GitHub Actions uses these defaults), set MCPBASH_CI_MODE=1 when reproducing failures locally so log paths, staging tar, and failure summaries match what the runners see.
- Shell scripts must pass
./test/lint.sh(shellcheck + shfmt). Keep functions small and preferset -euo pipefail. - Guard against unset variables/arrays when using
set -u; avoidBASH_REMATCHunderset -u(use parameter expansion or only read captures when a match succeeds). README.mdis generated fromREADME.md.in. After modifyingREADME.md.in, runbash scripts/render-readme.shand include both files in your PR (CI enforcesbash scripts/render-readme.sh --check).- Branches should be short-lived and opened as PRs against
mainwith a concise summary of scope and test evidence. - Contributions are governed by the Code of Conduct; escalate concerns via the security contact in
docs/SECURITY.md.
Follow this checklist to cut a release:
- Bump version & changelog – run
bash scripts/bump-version.sh X.Y.Z, updateCHANGELOG.md, and re-render the README withbash scripts/render-readme.sh. - Merge to
main– ensure all changes (code, tests, docs, version bump) are onmainand CI is green. - Create and push the tag –
git tag vX.Y.Z && git push origin vX.Y.Z. The CI release workflow triggers on version tags. - Let CI create the release – the GitHub Actions workflow creates the GitHub Release, uploads
mcp-bash-vX.Y.Z.tar.gzandSHA256SUMSassets, and populates the release body. Do not create the release manually before the workflow runs, or the CI step will fail withalready_exists. - Verify – confirm the release page has both assets and correct release notes:
gh release view vX.Y.Z --json assets,body,url. - Bump the Homebrew formula – the
bump-homebrew.ymlworkflow fires onrelease: types: [released], but GitHub'sGITHUB_TOKENsecurity restriction prevents it from triggering when the release is created by another CI workflow. After step 4, manually trigger it:Or, if the workflow doesn't accept inputs, update the formula ingh workflow run bump-homebrew.yml --repo yaniv-golan/mcp-bash-framework \ -f tag_name=vX.Y.Z
yaniv-golan/homebrew-mcp-bashmanually:Verify with# Get the new sha256 gh release download vX.Y.Z --pattern SHA256SUMS --output - | grep '\.tar\.gz' # Edit Formula/mcp-bash.rb in the tap repo with the new url + sha256
brew upgrade mcp-bashon a machine that has the tap installed. - Backfill assets (if CI release step failed) – if a race or duplicate prevented asset upload, generate the tarball and checksums locally and upload them:
git archive --format=tar.gz --prefix="mcp-bash-vX.Y.Z/" "vX.Y.Z" -o "mcp-bash-vX.Y.Z.tar.gz" shasum -a 256 "mcp-bash-vX.Y.Z.tar.gz" > SHA256SUMS gh release upload "vX.Y.Z" "mcp-bash-vX.Y.Z.tar.gz" SHA256SUMS --clobber