MCP Hub
Back to servers

mcp-bash-framework

Portable Bash-only framework for building stdio Model Context Protocol (MCP) servers with zero dependencies.

GitHub
Stars
3
Forks
1
Tools
3
Updated
Jan 8, 2026
Validated
Jan 9, 2026

mcp-bash

mcp-bash framework banner

CI License Bash MCP Protocol Platform

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.

mcp-bash new my-server && cd my-server
mcp-bash scaffold tool my-tool   # edit tools/my-tool/tool.sh
mcp-bash config --client cursor  # paste into your MCP client
mcp-bash bundle                  # create distributable package

What you’ll build

flowchart TD
  Client["MCP client<br/>(Claude Desktop / Cursor / Windsurf)"]
  Transport["stdio (JSON-RPC)"]
  Framework["mcp-bash framework<br/>(registry + runtime + policy)"]
  Project["Your project<br/>tools/ resources/ prompts/ server.d/"]

  Client --> Transport --> Framework --> Project

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.

CategoryCoverageNotes
Core Protocol✅ FullLifecycle, ping, capabilities, downgrades
Tools✅ Fulllist, call, icons, errors, listChanged, annotations
Resources✅ Fulllist, read, subscriptions, templates, binary
Prompts✅ Fulllist, get, arguments, icons
Utilities✅ FullProgress, cancellation, logging, completion
Elicitation✅ FullForm, URL, enum, multi-choice modes
Roots✅ FullServer→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).

Full compliance matrix

For a complete feature-by-feature breakdown across all MCP versions, see the Feature Support Matrix in SPEC-COMPLIANCE.md.

Why Bash?

mcp-bashTypeScript SDKPython SDK
RuntimeBash 3.2+ (pre-installed)Node.js 18+Python 3.10+
Installcurl | bash or git clonenpm installpip install
StartupNo VM warmupNode.js startupPython startup
Dependenciesjq or gojqnpm packagespip packages
Best forShell automation, existing scripts, air-gapped/minimal environmentsNode.js applicationsPython 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)

# Preflight: Bash 3.2+ and jq/gojq for full functionality (tools/resources/prompts).
bash --version | head -1
command -v jq >/dev/null 2>&1 || command -v gojq >/dev/null 2>&1 || printf '%s\n' '⚠ jq/gojq missing: minimal mode only (tools/resources/prompts disabled)'

1. Install the Framework

Quick install (good for local dev / trusted networks):

curl -fsSL "https://raw.githubusercontent.com/yaniv-golan/mcp-bash-framework/v0.9.10/install.sh" | bash -s -- --yes --version "v0.9.10"

Verified install (recommended for production / security-sensitive environments):

version="v0.9.10"
file="mcp-bash-${version}.tar.gz"
curl -fsSLO "https://github.com/yaniv-golan/mcp-bash-framework/releases/download/${version}/${file}"
curl -fsSLO "https://github.com/yaniv-golan/mcp-bash-framework/releases/download/${version}/SHA256SUMS"

# Verify (macOS):
grep -E "([[:space:]]|\\*)${file}$" SHA256SUMS | shasum -a 256 -c -
# Verify (Linux):
grep -E "([[:space:]]|\\*)${file}$" SHA256SUMS | sha256sum -c -

curl -fsSLO "https://raw.githubusercontent.com/yaniv-golan/mcp-bash-framework/${version}/install.sh"
bash install.sh --archive "${file}" --version "${version}"

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):

git clone https://github.com/yaniv-golan/mcp-bash-framework.git ~/.local/share/mcp-bash
mkdir -p ~/.local/bin && ln -sf ~/.local/share/mcp-bash/bin/mcp-bash ~/.local/bin/mcp-bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc  # or ~/.zshrc (if not already in PATH)

Pin a release with the installer (auto-prefixes v for bare versions):

bash install.sh --verify <sha256-from-SHA256SUMS> --version 0.9.10

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).

mcp-bash doctor
# Expected output includes lines like:
#   ✓ Bash version: 5.x.x (>= 3.2 required)
#   ✓ jq installed: /usr/bin/jq
#   All checks passed! Ready to build MCP servers.

# Preview and apply managed-install repairs (shim + optional upgrade when --min-version is set):
mcp-bash doctor --dry-run
mcp-bash doctor --fix

# Quick end-to-end test (optional):
mcp-bash new demo-server
cd demo-server
mcp-bash run-tool hello --allow-self --args '{"name":"World"}'
# Expected output includes: "Hello, World!"

# Cleanup (the demo-server directory persists until you remove it):
cd .. && rm -rf demo-server
Something not working? (click to expand)
SymptomLikely causeFix
mcp-bash: command not foundPATH not configuredexport PATH="$HOME/.local/bin:$PATH" then open a new shell
“Operating in minimal mode…” / tools missingjq/gojq missingbrew install jq or apt install jq
“blocked by policy”Default-deny tool policyCLI: re-run with --allow-self. MCP clients: set MCPBASH_TOOL_ALLOWLIST in client config
Claude Desktop starts but shows no toolsGUI non-login env / PATHUse mcp-bash config --wrapper-env and point the client at the wrapper
macOS Operation not permitted / quarantineGatekeeper quarantinescripts/macos-dequarantine.sh ~/.local/share/mcp-bash (trusted paths only), restart client
Windows Git Bash path weirdnessMSYS path conversionMSYS2_ARG_CONV_EXCL="*" (and prefer jq on Windows CI)

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:

mcp-bash new my-mcp-server
cd my-mcp-server

Already in a directory you created yourself? Run mcp-bash init --name my-mcp-server [--no-hello] instead.

3. Scaffold Your First Tool

mcp-bash scaffold tool check-disk

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:

mcp-bash scaffold test
./test/run.sh --verbose  # add run_test calls inside test/run.sh

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:

  1. Set MCPBASH_PROJECT_ROOT=/path/to/your/project.
  2. Point it at the mcp-bash binary (installed to ~/.local/bin/mcp-bash by the installer).
    • If you generated a wrapper via mcp-bash config --wrapper or --wrapper-env, you can point clients at <project-root>/<server-name>.sh; the wrapper already wires MCPBASH_PROJECT_ROOT for you.

Generate Config (CLI)

mcp-bash config --show
mcp-bash config --json           # machine-readable descriptor (name/command/env)
mcp-bash config --client cursor  # client-specific snippet
mcp-bash config --inspector      # ready-to-run Inspector command (stdio)
mcp-bash config --wrapper-env    # wrapper that sources your shell profile first (macOS-safe)
mcp-bash config --wrapper        # TTY: creates ./<server-name>.sh; piped/redirected: stdout

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 --wrapper when your PATH/env is already correct in non-login shells (e.g., Linux, or macOS with absolute paths).
  • Use --wrapper-env when 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_profile are skipped. Use absolute paths to runtimes (e.g., /opt/homebrew/bin/node) and set missing vars in the env block, 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.sh
      
      Then point Claude Desktop at /Users/you/my-mcp-server/mcp-bash.sh as the command.
    • 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, or Operation not permitted despite 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-server
      
      Helper: scripts/macos-dequarantine.sh [path] will clear quarantine for the repo (or a specific path). xattr -cr clears 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.json in a project) with the same mcpServers JSON as above.
  • Windsurf (Cascade): Edit ~/.codeium/windsurf/mcp_config.json via Settings → Advanced → Cascade, and add the same mcpServers entry.
  • LibreChat: In librechat.yaml add:
    mcpServers:
      mcp-bash:
        type: stdio
        command: /Users/you/.local/bin/mcp-bash
        env:
          MCPBASH_PROJECT_ROOT: /Users/you/my-mcp-server
    
  • OpenAI Agents SDK (Python): Use MCPServerStdio(params=...); the constructor does not take a name kwarg.
    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

ClientStatusKnown issues / notes
Claude DesktopTested (macOS, Windows)macOS: non-login shell PATH/env (use config --wrapper-env); macOS quarantine/TCC can block execution; restart required after config changes
Claude CLI / Claude CodeTestedGenerally straightforward; ensure MCPBASH_PROJECT_ROOT points at your project
CursorConfig documentedConfig file location differs by install; use mcp-bash config --client cursor
Windsurf (Cascade)Config documentedUse the app’s MCP config UI/file; see snippet in README
LibreChatConfig documentedYAML config format; see snippet in README
OpenAI Agents SDKExample providedPython 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:

mcp-bash bundle
# Creates: my-server-1.0.0.mcpb

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:

MCPB_NAME="my-server"
MCPB_AUTHOR_NAME="Your Name"
MCPB_AUTHOR_EMAIL="you@example.com"
MCPB_REPOSITORY="https://github.com/you/my-server"

Without a config file, metadata is auto-resolved from server.meta.json, VERSION, and git config.

Bundle Options

mcp-bash bundle --validate          # Check without creating
mcp-bash bundle --output ./dist     # Output to specific directory
mcp-bash bundle --verbose           # Show detailed progress

The bundle includes your tools, resources, prompts, and an embedded copy of the mcp-bash framework—fully self-contained for distribution.

Full bundling guide

Project Structure

Framework (Install Once)               Your Project (Version Control This)
~/.local/share/mcp-bash/               ~/my-mcp-server/
├── bin/mcp-bash                       ├── tools/
├── lib/                               │   └── check-disk/
├── handlers/                          │       ├── tool.sh
└── ...                                │       └── tool.meta.json
                                       ├── prompts/
~/.local/bin/                          ├── resources/
└── mcp-bash → ../share/mcp-bash/...   ├── server.d/
                                       │   └── server.meta.json (optional)
                                       └── .registry/ (auto-generated)

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.

# Basic invocation (project inferred from CWD or MCPBASH_PROJECT_ROOT)
mcp-bash run-tool my-tool --args '{"value":"hello"}'

# Simulate roots (comma-separated), stream stderr, override timeout, or print env
mcp-bash run-tool my-tool --args '{"value":"hi"}' --roots /tmp/project,/data/shared --verbose --timeout 15
# Inspect wiring without executing
mcp-bash run-tool my-tool --print-env --dry-run

# Dry-run validates metadata/args without executing the tool
mcp-bash run-tool my-tool --dry-run

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:

source "${MCP_SDK}/tool-sdk.sh"

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:

export MCP_SDK=~/.local/share/mcp-bash/sdk
./tools/check-disk/tool.sh

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 initialized and 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 optional config/roots.json in 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:

{
  "version": 1,
  "completions": [
    {"name":"example.completion","path":"completions/example.sh","timeoutSecs":5}
  ]
}

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).

# server.d/policy.sh
mcp_tools_policy_check() {
	local tool_name="$1"
	if [ "${MYPROJECT_READ_ONLY:-0}" = "1" ] && [[ "${tool_name}" != myProj.get* ]]; then
		mcp_tools_error -32602 "Read-only mode: ${tool_name} disabled"
		return 1
	fi
	return 0
}

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:

ExampleConcepts Covered
00-hello-toolBasic "Hello World" tool structure and metadata.
01-args-and-validationHandling JSON arguments and input validation.
02-logging-and-levelsSending logs to the client and managing verbosity.
03-progress-and-cancellationLong-running tasks, reporting progress, and handling user cancellation.
04-roots-basicsMCP roots scoping for tools; allows/denies file reads based on configured roots.
05-resources-basicsListing and reading resources via the built-in file provider.
06-embedded-resourcesEmbedding file content directly in tool responses.
07-prompts-basicsDiscovering and rendering prompt templates.
08-elicitationClient-driven elicitation prompts that gate tool execution.
09-registry-overridesDeclarative registry overrides, live progress streaming, and a custom resource provider.
10-completionsCompletion registration, query filtering, and pagination/hasMore.
11-resource-templatesResource template discovery, manual overrides, and client-side expansion.
Advanced: ffmpeg-studioReal-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/, or prompts/ 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=true to stream them during execution (uses a lightweight background flusher).
  • Debug Mode: Run mcp-bash debug to capture all JSON-RPC messages for analysis. See docs/DEBUGGING.md.

Configuration

Required Configuration

VariableDescription
MCPBASH_PROJECT_ROOTRequired for MCP clients. Path to your project directory containing tools/, prompts/, resources/. CLI commands (mcp-bash scaffold, mcp-bash validate, etc.) auto-detect the project root from the current directory.

Optional Configuration

VariableDefaultDescription
MCPBASH_TOOLS_DIR / MCPBASH_RESOURCES_DIR / MCPBASH_PROMPTS_DIR / MCPBASH_SERVER_DIRDerived from MCPBASH_PROJECT_ROOTOverride content and server hook locations.
MCPBASH_REGISTRY_DIR$MCPBASH_PROJECT_ROOT/.registryRegistry cache location.
MCPBASH_MAX_CONCURRENT_REQUESTS16Cap concurrent worker slots.
MCPBASH_MAX_TOOL_OUTPUT_SIZE10485760Tool stdout limit; stderr/resources inherit when unset.
MCPBASH_LOG_LEVELinfoLog level; use debug for discovery traces.
MCPBASH_DEBUG_ERRORSfalseInclude tool diagnostics in outputSchema validation errors (exit code, stderr tail, trace line).
MCPBASH_DEBUG_LOG(unset)Override per-tool debug log path; SDK mcp_debug appends to it.
MCPBASH_ENABLE_LIVE_PROGRESSfalseStream progress/log notifications during execution (starts a background flusher).
MCPBASH_ENV_PAYLOAD_THRESHOLD65536Spill args/metadata to temp files above this size.
MCPBASH_TOOL_ENV_MODEminimalTool env isolation: minimal, inherit, or allowlist.
MCPBASH_TOOL_ENV_INHERIT_ALLOWfalseMust be true to allow MCPBASH_TOOL_ENV_MODE=inherit.
MCPBASH_DEFAULT_TOOL_TIMEOUT30Default tool timeout (seconds).
MCPBASH_REMOTE_TOKEN(unset)Shared secret for proxied deployments (minimum 32 chars; failures throttled).
MCPBASH_HTTPS_ALLOW_HOSTS / MCPBASH_HTTPS_DENY_HOSTS(unset)HTTPS provider host allow/deny lists; private/loopback always blocked. Allow list is required unless MCPBASH_HTTPS_ALLOW_ALL=true.
MCPBASH_HTTPS_ALLOW_ALLfalseExplicitly allow all public HTTPS hosts (unsafe; prefer MCPBASH_HTTPS_ALLOW_HOSTS).
MCPBASH_CI_MODE(unset)CI defaults: safe tmp/log dirs, keep-logs, timestamped logs, failure summary (failure-summary.jsonl), env snapshot (env-snapshot.json); MCPBASH_CI_VERBOSE=true starts at debug; GH annotations when tracing provides file/line.

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:

FieldDefaultDescription
nameProject directory nameServer identifier (e.g., my-server)
titleTitlecase of nameHuman-readable display name (e.g., My Server)
versionVERSION file, package.json, or 0.0.0Server version
description(omitted)Brief description of the server
websiteUrl(omitted)URL to server homepage or documentation
icons(omitted)Array of icon objects for visual identification

Example server.d/server.meta.json:

{
  "name": "weather-api",
  "title": "Weather API Server",
  "version": "1.0.0",
  "description": "Provides weather data for any location",
  "websiteUrl": "https://example.com/weather-api",
  "icons": [
    {"src": "https://example.com/icon.svg", "sizes": ["any"], "mimeType": "image/svg+xml"}
  ]
}

If no server.meta.json exists, the server uses smart defaults based on your project directory name.

Tool SDK environment

  • MCPBASH_JSON_TOOL and MCPBASH_JSON_TOOL_BIN point to the detected JSON processor (gojq/jq) and are injected into tool processes when available.
  • MCPBASH_MODE is full when JSON tooling is present and minimal otherwise; SDK helpers warn and downgrade behaviour when running in minimal mode.
  • MCPBASH_DEBUG_LOG points to a per-invocation debug log file (when available); use mcp_debug inside tools to append file-based checkpoints.
  • MCPBASH_TOOL_ENV_MODE controls isolation for tool processes (minimal, inherit, or allowlist), 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

ModeSupported surfaceLimitations / when it applies
FullLifecycle, ping, logging/setLevel, tools/resources/prompts (list, call/read/subscribe), completion, pagination, listChanged notificationsRequires jq/gojq available; default mode.
MinimalLifecycle, ping, logging/setLevelTools/resources/prompts/completion are disabled and registry notifications are suppressed. Activated when no JSON tool is found or MCPBASH_FORCE_MINIMAL=true.

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/*.json and returns a status JSON. In minimal mode the command is skipped gracefully.

Troubleshooting (quick hits)

  • PATH issues (mcp-bash not found): ensure ~/.local/bin is on PATH; rerun source ~/.bashrc or ~/.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=jq and MSYS2_ARG_CONV_EXCL="*" before running mcp-bash.

Requirements

Runtime Requirements

  • Bash: version 3.2 or higher (standard on macOS, Linux, WSL, and Git Bash on Windows).
  • JSON Processor: gojq (recommended) or jq.
    • 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:

./test/lint.sh
./test/unit/run.sh
./test/integration/run.sh
# Optional:
# ./test/compatibility/run.sh
# ./test/stress/run.sh

Windows Notes

  • Signals from the client may not reliably terminate subprocesses on Git Bash; prefer explicit shutdown/exit and 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

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-25 while 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.

Write paths to MCP_TOOL_RESOURCES_FILE (TSV: path<TAB>mime<TAB>uri or JSON array of {path,mimeType,uri}) during tool execution:

payload_path="${MCPBASH_PROJECT_ROOT}/resources/report.txt"
printf 'Report content' >"${payload_path}"
if [ -n "${MCP_TOOL_RESOURCES_FILE:-}" ]; then
	printf '%s\ttext/plain\n' "${payload_path}" >>"${MCP_TOOL_RESOURCES_FILE}"
fi
printf 'See embedded report for details'

See the dedicated example at examples/06-embedded-resources/.

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:

MCP Bash Framework

[![MCP Bash Framework](https://img.shields.io/badge/MCP-MCP_Bash_Framework-green?logo=modelcontextprotocol)](https://github.com/yaniv-golan/mcp-bash-framework)

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.

Reviews

No reviews yet

Sign in to write a review