trackmcp
Back to directory

Give hands to AI. MCP server to run shell commands securely, auditably, and on demand.

102 stars GoOthers Updated Sep 4, 2026
aibashgollmmcpmodel-context-protocolos-execshellterminal

Documentation

mcp-shell

Trust Score
glama

MCP server that runs shell commands. Your LLM gets a tool; you get control over what runs and how.

Built on mark3labs/mcp-go. Written in Go.


Run it

Docker (easiest):

bash
docker run -it --rm -v /tmp/mcp-workspace:/tmp/mcp-workspace sonirico/mcp-shell:latest

From source:

bash
git clone https://github.com/sonirico/mcp-shell && cd mcp-shell
make install
mcp-shell

Configure it

Secure mode is the default. With no config file, `mcp-shell` boots in secure

mode and registers only typed tools: file reads, `grep`/`glob`, git inspection,

and (opt-in) file/git writes and operator-defined scripts. There is no raw

shell command. You only need a config file to change the defaults below. To

run fully unrestricted you must opt in explicitly:

bash
MCP_SHELL_ALLOW_UNSAFE=1 mcp-shell   # disables secure mode; the only tool is shell_exec

To customize the policy, point to a YAML config:

bash
export MCP_SHELL_SEC_CONFIG_FILE=/path/to/security.yaml
mcp-shell

Secure mode (default) — typed tools only, every path confined to `working_directory`:

yaml
security:
  enabled: true
  working_directory: /tmp/mcp-workspace
  max_execution_time: 30s
  max_output_size: 1048576
  run_as_user: ""
  audit_log: true

  # Expose file and git write tools (write_file, edit_file, mkdir, move,
  # delete, git_add, git_commit, git_switch, git_restore, git_stash). Off by
  # default.
  writes_enabled: false

  # Operator-defined scripts exposed through the run_script tool. The client
  # picks a name; the argv is yours and cannot be altered.
  # scripts:
  #   test: ["go", "test", "./..."]
  #   lint: ["golangci-lint", "run"]

Wire it up

Claude Desktop — add to your MCP config:

json
{
  "mcpServers": {
    "shell": {
      "command": "docker",
      "args": ["run", "--rm", "-i", "sonirico/mcp-shell:latest"],
      "env": { "MCP_SHELL_LOG_LEVEL": "info" }
    }
  }
}

For custom config, mount the file and set the env:

json
{
  "command": "docker",
  "args": ["run", "--rm", "-i", "-v", "/path/to/security.yaml:/etc/mcp-shell/security.yaml", "-e", "MCP_SHELL_SEC_CONFIG_FILE=/etc/mcp-shell/security.yaml", "sonirico/mcp-shell:latest"]
}

Tools

Secure mode (the default) registers these typed tools. `*` marks a required

parameter.

ToolParametersAvailable
`read_file`path*, offset, limit, tailalways
`list_dir`path, depth, include_hiddenalways
`glob`pattern*, path, newer_than, max_resultsalways
`grep`pattern*, path, glob, ignore_case, context, files_only, count, max_resultsalways
`stat`path*always
`diff_files`path_a*, path_b*always
`system_info`always
`git_status`always
`git_log`max_count, ref, path, author, grep, since, until, oneline, followalways
`git_diff`ref, ref_to, staged, path, stat_only, name_onlyalways
`git_show`ref, path, stat_onlyalways
`git_blame`path*, ref, line_start, line_endalways
`git_branches`all, mergedalways
`git_tags`patternalways
`git_rev_parse`ref*always
`git_ls_files`path, untrackedalways
`git_stash_list`always
`git_remotes`always
`write_file`path*, content*, appendwrites_enabled
`edit_file`path*, old_string*, new_string*, replace_allwrites_enabled
`mkdir`path*writes_enabled
`move`from*, to*writes_enabled
`delete`path*, recursivewrites_enabled
`git_add`paths, allwrites_enabled
`git_commit`message*, allwrites_enabled
`git_switch`branch*, createwrites_enabled
`git_restore`paths*, stagedwrites_enabled
`git_stash`action*, messagewrites_enabled
`run_script`name*scripts

Every path parameter is resolved against `working_directory` (symlinks

followed); anything outside it is rejected. Git paths and refs are passed

positionally and validated: a ref starting with `-` is rejected. There are no

network tools; push, fetch and clone are not offered.

Unrestricted mode: `shell_exec` exists only with `MCP_SHELL_ALLOW_UNSAFE=1`, runs the command through `bash -c` with no validation, by design, and it is the only tool registered in that mode.


Environment variables

VariableDescription
`MCP_SHELL_SEC_CONFIG_FILE`Path to security YAML (overrides built-in secure defaults)
`MCP_SHELL_ALLOW_UNSAFE`Set `1` (or `true`) to disable secure mode and expose `shell_exec` instead of the typed tools (opt-in)
`MCP_SHELL_SERVER_NAME`Server name (default: "mcp-shell 🐚")
`MCP_SHELL_LOG_LEVEL`debug, info, warn, error, fatal
`MCP_SHELL_LOG_FORMAT`json, console
`MCP_SHELL_LOG_OUTPUT`stdout, stderr, file

Development

bash
make install dev-tools   # deps + goimports, golines
make fmt test lint
make docker-build       # build image locally
make release            # binary + docker image

Security

  • Default: Secure mode. The server builds every command's argv itself; the

client never supplies a shell string. Only typed tools are registered.

  • Path confinement: every path parameter is resolved against

`working_directory`, symlinks followed, and anything that resolves outside

it is rejected.

  • Git hardening: paths are passed after `--`, refs after

`--end-of-options`, and a ref starting with `-` is rejected. Git runs with

`GIT_CONFIG_NOSYSTEM=1`, `GIT_CONFIG_GLOBAL=/dev/null`, `core.fsmonitor`,

`core.pager` and `core.hooksPath` neutralised, and `--no-ext-diff

--no-textconv` on log/diff/show/blame.

  • Minimal environment: child processes get only `PATH`, `HOME` and `LANG`,

never the server's own environment or `.env` secrets.

  • Writes and scripts are opt-in: `writes_enabled: true` exposes the

file/git write tools; a non-empty `scripts` map exposes `run_script`. Both

are off by default.

  • Unrestricted: only via `MCP_SHELL_ALLOW_UNSAFE=1`. The only tool

registered is `shell_exec`, which runs `bash -c` with no validation. Fine

for local dev, dangerous otherwise.

  • Docker: Runs as non-root, Alpine-based. Use it in production. Best paired with an OS sandbox (read-only FS, dropped caps) as defense-in-depth.

Threat model, guarantees, and the scope for vulnerability reports live in SECURITY.md. Read it before opening an advisory.


Migrating from 0.x

Secure mode no longer validates a `shell_exec` command string; it exposes

typed tools instead. A config file's `security:` block no longer accepts:

Removed keyReplacement
`use_shell_execution`not needed; typed tools never shell out
`allowed_executables`not needed; each tool runs a fixed, server-built argv
`allowed_commands`not needed; same as above
`blocked_commands`not needed; same as above
`blocked_patterns`not needed; same as above

Loading a config file that still sets one of these fails at startup with an

error naming the key. There is no more "legacy mode" and no

`security-legacy.yaml` example. If you need raw shell access, set

`MCP_SHELL_ALLOW_UNSAFE=1` to get `shell_exec` back; it is no longer

constrained by the `security:` block at all.


Contributing

Fork, branch, `make fmt test`, open a PR.

Frequently asked questions

What is mcp-shell?

mcp-shell is Give hands to AI. MCP server to run shell commands securely, auditably, and on demand.

How do I install mcp-shell?

Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

Is mcp-shell open source?

Yes — it is hosted on GitHub at https://github.com/sonirico/mcp-shell and has 102 stars.

Related MCP tools

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP