Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-bashCreate a new Bash-based tool to check system disk usage"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-bash

Repository:
mcp-bash-framework• CLI/Binary:mcp-bash
Contents
The most complete MCP implementation in pure Bash. Tools, resources, prompts, elicitation, roots, progress, cancellation—the full spec, no runtimes beyond your shell.
Runs on Bash 3.2+ (macOS/Linux stock). No Node, no Python, no containers.
Handles concurrency, timeouts, and cancellation the way production systems need.
You write the tools. The framework stays out of your way.
TL;DR
Turn any Bash script into an MCP tool in minutes. No Node, no Python, no containers.
What you’ll build
Design Principles
Tools shouldn’t need another runtime to talk to AI.
Everything must be inspectable. No magic.
If it’s not needed in production, it isn’t in the framework.
Your project stays yours. The framework upgrades cleanly.
MCP Spec Coverage
mcp-bash targets the 2025-11-25 MCP specification with negotiated downgrades to older versions.
Category | Coverage | Notes |
Core Protocol | ✅ Full | Lifecycle, ping, capabilities, downgrades |
Tools | ✅ Full | list, call, icons, errors, listChanged, annotations |
Resources | ✅ Full | list, read, subscriptions, templates, binary |
Prompts | ✅ Full | list, get, arguments, icons |
Utilities | ✅ Full | Progress, cancellation, logging, completion |
Elicitation | ✅ Full | Form, URL, enum, multi-choice modes |
Roots | ✅ Full | Server→client request, listChanged |
Not yet implemented: Audio content, sampling. Tasks (async job/poll) and server-identity discovery are HTTP-oriented and not applicable to stdio.
Transport is stdio-only by design. See Remote Connectivity for HTTP/SSE proxy options, including the shared-secret guard (MCPBASH_REMOTE_TOKEN) and readiness probe (mcp-bash --health).
For a complete feature-by-feature breakdown across all MCP versions, see the Feature Support Matrix in SPEC-COMPLIANCE.md.
Why Bash?
mcp-bash | TypeScript SDK | Python SDK | |
Runtime | Bash 3.2+ (pre-installed) | Node.js 18+ | Python 3.10+ |
Install |
|
|
|
Startup | No VM warmup | Node.js startup | Python startup |
Dependencies | jq or gojq | npm packages | pip packages |
Best for | Shell automation, existing scripts, air-gapped/minimal environments | Node.js applications | Python applications |
If your tools are already shell scripts, wrapping them in Node or Python adds complexity for no benefit. mcp-bash lets you expose them directly.
Quick Start
When you run mcp-bash from inside a project (a directory containing server.d/server.meta.json), it auto-detects the project root. Running mcp-bash outside any project starts a temporary getting-started helper tool. For MCP clients, set MCPBASH_PROJECT_ROOT so the server can find your project regardless of working directory.
0. Requirements (10 seconds)
1. Install the Framework
Quick install (good for local dev / trusted networks):
Verified install (recommended for production / security-sensitive environments):
Why this is “verified”: you download the release tarball + SHA256SUMS, verify the checksum locally, then run the installer against the verified archive.
For tagged releases (vX.Y.Z), the installer also attempts to verify the archive against SHA256SUMS automatically when it’s available.
Manual/offline install (for policy-driven or air-gapped environments):
Pin a release with the installer (auto-prefixes v for bare versions):
1.5 Verify It Works (30 seconds)
Security defaults: hooks are disabled unless MCPBASH_ALLOW_PROJECT_HOOKS=true, and tools require an explicit allowlist (MCPBASH_TOOL_ALLOWLIST=* to allow all in trusted projects).
Symptom | Likely cause | Fix |
| PATH not configured |
|
“Operating in minimal mode…” / tools missing |
|
|
“blocked by policy” | Default-deny tool policy | CLI: re-run with |
Claude Desktop starts but shows no tools | GUI non-login env / PATH | Use |
macOS | Gatekeeper quarantine |
|
Windows Git Bash path weirdness | MSYS path conversion |
|
Still stuck? Run mcp-bash doctor (or mcp-bash doctor --json) and include output when opening an issue.
2. Create Your Project
Your server code lives in a separate project directory:
Already in a directory you created yourself? Run mcp-bash init --name my-mcp-server [--no-hello] instead.
3. Scaffold Your First Tool
This scaffolds tools/check-disk/tool.sh and tools/check-disk/tool.meta.json in your project. You write the logic.
Each scaffolded tool also includes tools/check-disk/smoke.sh—run it after edits to ensure your tool’s stdout is valid JSON (update the sample args in the script if you change tool.meta.json).
3.5 (Optional) Add a Test Harness
Create a lightweight runner for tool smoke tests:
The harness wraps mcp-bash run-tool, validates your project before running, and refuses to overwrite existing test/run.sh or test/README.md.
Configure Your MCP Client
Every client works the same way: point it at the framework and tell it where your project lives:
Set
MCPBASH_PROJECT_ROOT=/path/to/your/project.Point it at the
mcp-bashbinary (installed to~/.local/bin/mcp-bashby the installer).If you generated a wrapper via
mcp-bash config --wrapperor--wrapper-env, you can point clients at<project-root>/<server-name>.sh; the wrapper already wiresMCPBASH_PROJECT_ROOTfor you.
Generate Config (CLI)
config --show prints one labeled snippet per supported client (headings like # Claude Desktop, # Cursor, etc.) so you can see which block to copy; use --client <name> or --json when you only want a single paste-ready block.
Copy the snippet for your client (Claude Desktop/CLI/Code, Cursor, Windsurf, LibreChat, etc.) and paste it into the appropriate config file. This sets MCPBASH_PROJECT_ROOT and the mcp-bash command path for you. When run in a terminal (stdout is a TTY), config --wrapper writes <project-root>/<server-name>.sh, marks it executable, and prints the path to stderr; piping or redirecting prints the wrapper script to stdout.
Picking a wrapper:
Use
--wrapperwhen your PATH/env is already correct in non-login shells (e.g., Linux, or macOS with absolute paths).Use
--wrapper-envwhen you need your login shell to set PATH/version managers/vars before starting the server (common on macOS Claude Desktop).Distributing a server? Ship the env wrapper by default for GUI launches (macOS/Windows clients), and include a non-login wrapper or absolute runtime path for CI/WSL/Linux users who want fast, side-effect-free startups.
Per-Client Snippets
Claude Desktop: Edit
~/Library/Application Support/Claude/claude_desktop_config.json(macOS) or%APPDATA%\Claude\claude_desktop_config.json(Windows) and add:"mcpServers": { "mcp-bash": { "command": "/Users/you/.local/bin/mcp-bash", "env": {"MCPBASH_PROJECT_ROOT": "/Users/you/my-mcp-server"} } }macOS runtime note: Claude Desktop launches servers from a minimal, non-login shell, so your PATH, version managers (nvm/pyenv/uv/rbenv), and env vars from
.zshrc/.bash_profileare skipped. Use absolute paths to runtimes (e.g.,/opt/homebrew/bin/node) and set missing vars in theenvblock, or generate a login-aware wrapper:mcp-bash config --project-root /Users/you/my-mcp-server --wrapper-env > /Users/you/my-mcp-server/mcp-bash.sh chmod +x /Users/you/my-mcp-server/mcp-bash.shThen point Claude Desktop at
/Users/you/my-mcp-server/mcp-bash.shas thecommand.macOS quarantine: Gatekeeper can block quarantined downloads (typically from browsers/DMGs/AirDrop) even when paths are correct. CLI downloads (curl/wget/git) often skip quarantine. If you see
ENOENT,transport closed unexpectedly, orOperation not permitteddespite correct paths, clear quarantine and restart Claude Desktop:xattr -r -d com.apple.quarantine ~/.local/share/mcp-bash xattr -r -d com.apple.quarantine /Users/you/my-mcp-serverHelper:
scripts/macos-dequarantine.sh [path]will clear quarantine for the repo (or a specific path).xattr -crclears all extended attributes; only use it on trusted paths.macOS folder permissions: Desktop/Documents/Downloads are TCC-protected and Downloads is often quarantined. Move servers to a neutral folder (e.g.,
~/mcp-servers) or grant Claude “Full Disk Access” and “Files and Folders” in System Settings.
Claude CLI/Claude Code: Run once:
claude mcp add --transport stdio mcp-bash \ --env MCPBASH_PROJECT_ROOT="$HOME/my-mcp-server" \ -- "$HOME/.local/bin/mcp-bash"Cursor: Create
~/.cursor/mcp.json(or.cursor/mcp.jsonin a project) with the samemcpServersJSON as above.Windsurf (Cascade): Edit
~/.codeium/windsurf/mcp_config.jsonvia Settings → Advanced → Cascade, and add the samemcpServersentry.LibreChat: In
librechat.yamladd:mcpServers: mcp-bash: type: stdio command: /Users/you/.local/bin/mcp-bash env: MCPBASH_PROJECT_ROOT: /Users/you/my-mcp-serverOpenAI Agents SDK (Python): Use
MCPServerStdio(params=...); the constructor does not take anamekwarg.import os from agents.mcp import MCPServerStdio os.environ["MCPBASH_PROJECT_ROOT"] = "/Users/you/my-mcp-server" async with MCPServerStdio( params={ "command": "/Users/you/.local/bin/mcp-bash", # optionally add args/env/cwd if your server needs them } ) as server: ...Windows note: Git Bash (CI-tested) or WSL both work. Git Bash ships with Git for Windows; WSL behaves like Linux. See Windows Support for details.
Compatibility Notes
Client | Status | Known issues / notes |
Claude Desktop | Tested (macOS, Windows) | macOS: non-login shell PATH/env (use |
Claude CLI / Claude Code | Tested | Generally straightforward; ensure |
Cursor | Config documented | Config file location differs by install; use |
Windsurf (Cascade) | Config documented | Use the app’s MCP config UI/file; see snippet in README |
LibreChat | Config documented | YAML config format; see snippet in README |
OpenAI Agents SDK | Example provided | Python example only; verify SDK version and stdio wiring |
Tested = maintainers have manually verified end-to-end. Config documented = configuration instructions provided but not regularly tested.
CI-tested platforms: Ubuntu, macOS, Windows (Git Bash). CI validates the MCP protocol layer via integration tests, not specific client applications.
Using a different client? Any MCP-compliant stdio client should work. Open an issue if you hit compatibility problems.
MCPB Bundles
Package your server for one-click installation in Claude Desktop:
Double-click the .mcpb file to install, or drag it to Claude Desktop.
Quick Configuration
Create mcpb.conf in your project root to customize the bundle:
Without a config file, metadata is auto-resolved from server.meta.json, VERSION, and git config.
Bundle Options
The bundle includes your tools, resources, prompts, and an embedded copy of the mcp-bash framework—fully self-contained for distribution.
Project Structure
Direct Tool Execution (run-tool)
Use run-tool to invoke a single tool without starting the full MCP server. This wires the same environment as the server (SDK path, args, metadata, roots). Tool names must match ^[a-zA-Z0-9_-]{1,64}$; some clients, including Claude Desktop, enforce this and reject dotted names, so prefer hyphens/underscores for namespaces.
Flags: --args (JSON object), --roots (comma-separated paths), --dry-run, --timeout <secs>, --verbose (stream tool stderr), --no-refresh (reuse cached registry), --minimal (force degraded mode), --project-root <dir>, --print-env (dump wiring without executing). Elicitation is not supported in CLI mode.
The scaffolder and examples use per-tool directories (e.g., tools/check-disk/tool.sh); automatic discovery requires tools to live under subdirectories of tools/ (root-level scripts are not discovered).
See Project Structure Guide for detailed layouts, Docker deployment, and multi-environment setups.
Diagnostics & Validation
Readiness/health probe:
mcp-bash --health [--project-root DIR] [--timeout SECS](0=ready,1=unhealthy,2=misconfigured)Project checks:
mcp-bash validate [--project-root DIR] [--fix] [--json] [--explain-defaults] [--strict] [--inspector]Environment check:
mcp-bash doctor [--json] [--dry-run|--fix]Registry cache introspection:
mcp-bash registry status [--project-root DIR]Client config:
mcp-bash config --json(machine-readable),--client <name>(pasteable JSON),--wrapper(generate auto-install wrapper)
SDK Discovery
Every tool sources shared helpers from sdk/tool-sdk.sh. When mcp-bash launches a tool it exports MCP_SDK=/path/to/framework/sdk, so tool scripts can run:
If you copy a tool out of this repository (or build your own project layout) and run it directly, set MCP_SDK before executing the script:
If the SDK can’t be resolved, the script exits with a clear error.
Roots (scoping filesystem access)
If the client supports MCP Roots, mcp-bash requests them after
initializedand exposes them to tools via env (MCP_ROOTS_JSON,MCP_ROOTS_PATHS,MCP_ROOTS_COUNT) and SDK helpers (mcp_roots_list,mcp_roots_count,mcp_roots_contains).If the client does not provide roots or times out, you can supply them via
MCPBASH_ROOTS="/path/one:/path/two"or an optionalconfig/roots.jsonin your project. Paths are normalized and enforced consistently.
Completions
Completions are manually registered (they are not auto-discovered). Prefer declarative registration via server.d/register.json:
Paths are resolved relative to MCPBASH_PROJECT_ROOT, and registry refreshes pick them up automatically.
Tool Policy Hook (optional)
Projects can gate tool execution centrally by adding server.d/policy.sh with mcp_tools_policy_check(). The framework calls this before every tool run (default: allow all).
Use -32602 for policy/invalid-params blocks, -32600 for capability/auth failures. Keep logic lightweight; the hook runs on every invocation.
Learn by Example
The examples/ directory shows common patterns end-to-end:
Example | Concepts Covered |
Basic "Hello World" tool structure and metadata. | |
Handling JSON arguments and input validation. | |
Sending logs to the client and managing verbosity. | |
Long-running tasks, reporting progress, and handling user cancellation. | |
MCP roots scoping for tools; allows/denies file reads based on configured roots. | |
Listing and reading resources via the built-in file provider. | |
Embedding file content directly in tool responses. | |
Discovering and rendering prompt templates. | |
Client-driven elicitation prompts that gate tool execution. | |
Declarative registry overrides, live progress streaming, and a custom resource provider. | |
Completion registration, query filtering, and pagination/hasMore. | |
Resource template discovery, manual overrides, and client-side expansion. | |
Real-world application: video processing pipeline with media inspection (optional, heavy deps). |
Features at a Glance
Auto-Discovery: Place scripts in your project's
tools/,resources/, orprompts/directories—the framework finds them automatically.Scaffolding: Generate compliant tool, resource, prompt templates, and a test harness (
mcp-bash scaffold <type> <name>,mcp-bash scaffold test).Stdio Transport: Standard input/output. No custom daemons or sidecars.
Framework/Project Separation: Install the framework once, create unlimited projects.
Graceful Degradation: Automatically detects available JSON tools (
gojq,jq) or falls back to minimal mode if none are present.Progress Streaming: Emits progress and log notifications; set
MCPBASH_ENABLE_LIVE_PROGRESS=trueto stream them during execution (uses a lightweight background flusher).Debug Mode: Run
mcp-bash debugto capture all JSON-RPC messages for analysis. See docs/DEBUGGING.md.
Configuration
Required Configuration
Variable | Description |
| Required for MCP clients. Path to your project directory containing |
Optional Configuration
Variable | Default | Description |
| Derived from | Override content and server hook locations. |
|
| Registry cache location. |
|
| Cap concurrent worker slots. |
|
| Tool stdout limit; stderr/resources inherit when unset. |
|
| Log level; use |
|
| Include tool diagnostics in outputSchema validation errors (exit code, stderr tail, trace line). |
| (unset) | Override per-tool debug log path; SDK |
|
| Stream progress/log notifications during execution (starts a background flusher). |
|
| Spill args/metadata to temp files above this size. |
|
| Tool env isolation: |
|
| Must be |
|
| Default tool timeout (seconds). |
| (unset) | Shared secret for proxied deployments (minimum 32 chars; failures throttled). |
| (unset) | HTTPS provider host allow/deny lists; private/loopback always blocked. Allow list is required unless |
|
| Explicitly allow all public HTTPS hosts (unsafe; prefer |
| (unset) | CI defaults: safe tmp/log dirs, keep-logs, timestamped logs, failure summary ( |
Full list and defaults: see docs/ENV_REFERENCE.md.
Server Metadata
Server identity is configured via server.d/server.meta.json. All fields are optional—smart defaults are applied when omitted:
Field | Default | Description |
| Project directory name | Server identifier (e.g., |
| Titlecase of name | Human-readable display name (e.g., |
|
| Server version |
| (omitted) | Brief description of the server |
| (omitted) | URL to server homepage or documentation |
| (omitted) | Array of icon objects for visual identification |
Example server.d/server.meta.json:
If no server.meta.json exists, the server uses smart defaults based on your project directory name.
Tool SDK environment
MCPBASH_JSON_TOOLandMCPBASH_JSON_TOOL_BINpoint to the detected JSON processor (gojq/jq) and are injected into tool processes when available.MCPBASH_MODEisfullwhen JSON tooling is present andminimalotherwise; SDK helpers warn and downgrade behaviour when running in minimal mode.MCPBASH_DEBUG_LOGpoints to a per-invocation debug log file (when available); usemcp_debuginside tools to append file-based checkpoints.MCPBASH_TOOL_ENV_MODEcontrols isolation for tool processes (minimal,inherit, orallowlist), but MCPBASH/MCP-prefixed variables (including JSON tool hints) are always propagated. Example allowlist for minimal exposure:MCPBASH_TOOL_ENV_MODE=allowlist MCPBASH_TOOL_ENV_ALLOWLIST=HOME,PATH.
Capability Modes
Mode | Supported surface | Limitations / when it applies |
Full | Lifecycle, ping, logging/setLevel, tools/resources/prompts (list, call/read/subscribe), completion, pagination, | Requires |
Minimal | Lifecycle, ping, logging/setLevel | Tools/resources/prompts/completion are disabled and registry notifications are suppressed. Activated when no JSON tool is found or |
Registry Maintenance
Auto-refresh: registries re-scan on TTL expiry (default 5s) and use lightweight file-list hashing to skip rebuilds when nothing changed.
Manual refresh:
bin/mcp-bash registry refresh [--project-root DIR] [--no-notify] [--quiet] [--filter PATH]rebuilds.registry/*.jsonand returns a status JSON. In minimal mode the command is skipped gracefully.
Troubleshooting (quick hits)
PATHissues (mcp-bash not found): ensure~/.local/binis on PATH; rerunsource ~/.bashrcor~/.zshrc.Missing JSON tooling (
jq/gojq): install one; otherwise the server enters minimal mode (tools/resources/prompts disabled).macOS quarantine blocks execution: run
xattr -d com.apple.quarantine ~/.local/share/mcp-bash/bin/mcp-bash(and your project path if needed).Git Bash/MSYS exec-limit quirks: set
MCPBASH_JSON_TOOL=jqandMSYS2_ARG_CONV_EXCL="*"before runningmcp-bash.
Requirements
Runtime Requirements
Bash: version 3.2 or higher (standard on macOS, Linux, WSL, and Git Bash on Windows).
JSON Processor:
gojq(recommended) orjq.Note: If no JSON tool is found, the server runs in "Minimal Mode" (Lifecycle & Ping only).
Development Requirements
If you plan to contribute to the core framework, see CONTRIBUTING.md for setup instructions (linting, tests, etc).
Testing (quick start)
From the repo root:
Windows Notes
Signals from the client may not reliably terminate subprocesses on Git Bash; prefer explicit
shutdown/exitand short tool timeouts.Paths are normalized to
/c/...style; avoid mixing Windows- and POSIX-style roots in the same project.Large payloads can be slower under MSYS; keep registry TTLs reasonable. See docs/WINDOWS.md for full guidance and workarounds.
Documentation
Getting Started
Project Structure Guide - Layouts, Docker deployment, multi-environment setups.
Examples - Learn by example: hello-world, args, logging, progress, real-world video processing.
Feature Guides
MCPB Bundles - One-click distribution via Claude Desktop and MCP Registry.
Elicitation - Form and URL modes, SDK helpers, and client capability checks.
Roots - Roots/list flow, env wiring, validation, and fallbacks.
Completions - Manual registration, provider types, pagination, and script contracts.
Registry - Registry envelopes, TTL, manual registration, and cache formats.
Resource Templates - Auto/manual discovery, pagination, collisions, and client-side expansion.
Limits & Performance - Concurrency, payload ceilings, throttling.
Errors - Protocol errors vs tool execution errors (SEP-1303).
Best Practices - Development, testing, operations guidance.
Deep Dive
Architecture Guide - Internal architecture, lifecycle loop, concurrency model.
Protocol Compliance - Detailed MCP protocol support breakdown.
Performance Guide - Tuning concurrency, timeouts, and registry scans.
Security Policy - Input validation and execution safety.
Minimal Mode - Behavior when jq/gojq is missing or minimal mode is forced.
Changelog - Notable changes between releases.
Windows Support - Running on Git Bash/WSL.
Remote Connectivity - Exposing mcp-bash over HTTP/SSE via external gateways.
Scope and Goals
Bash-only Model Context Protocol server verified on macOS Bash 3.2, Linux Bash ≥3.2, and Windows (Git Bash is CI-tested; WSL behaves like Linux).
Targets MCP protocol version
2025-11-25while supporting negotiated downgrades.Transport support is limited to stdio; HTTP/SSE/OAuth transports remain out of scope (see Remote Connectivity for gateway options).
Embedded resources in tool output
Tools can attach files directly to the MCP response as type:"resource" content parts; binary files are auto-base64-encoded into the blob field, text stays in text.
Use mcp_result_text_with_resource to embed files with your tool result:
See the dedicated example at examples/06-embedded-resources/ and BEST-PRACTICES.md for full documentation.
Built with mcp-bash
If you've built an MCP server using this framework, show it off! Add this badge to your project's README:
We'd love to see what you build—consider opening a discussion to share your project with the community.
FAQ
Why is the repository named mcp-bash-framework but the CLI is mcp-bash?
The repository name mcp-bash-framework reflects what this project is: a framework you install once and use to create multiple MCP server projects. The CLI/binary is named mcp-bash because that's what you invoke—short and memorable. The name mcp-bash was already taken on GitHub, so we chose mcp-bash-framework to accurately describe the architecture while avoiding namespace conflicts.
mcp-bash is intentionally small. It gives you control, clarity, and a predictable surface for AI systems. Build tools, not infrastructure.