Skip to main content
Glama
sonirico

mcp-shell

by sonirico

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

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

From source:

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

Related MCP server: MCP Shell Server

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:

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:

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

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

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:

{
  "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:

{
  "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.

Tool

Parameters

Available

read_file

path*, offset, limit, tail

always

list_dir

path, depth, include_hidden

always

glob

pattern*, path, newer_than, max_results

always

grep

pattern*, path, glob, ignore_case, context, files_only, count, max_results

always

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, follow

always

git_diff

ref, ref_to, staged, path, stat_only, name_only

always

git_show

ref, path, stat_only

always

git_blame

path*, ref, line_start, line_end

always

git_branches

all, merged

always

git_tags

pattern

always

git_rev_parse

ref*

always

git_ls_files

path, untracked

always

git_stash_list

always

git_remotes

always

write_file

path*, content*, append

writes_enabled

edit_file

path*, old_string*, new_string*, replace_all

writes_enabled

mkdir

path*

writes_enabled

move

from*, to*

writes_enabled

delete

path*, recursive

writes_enabled

git_add

paths, all

writes_enabled

git_commit

message*, all

writes_enabled

git_switch

branch*, create

writes_enabled

git_restore

paths*, staged

writes_enabled

git_stash

action*, message

writes_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

Variable

Description

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

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 key

Replacement

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.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    A secure and pluggable MCP server to run terminal commands on your local machine or cloud server — remotely, safely, and with LLMs or agentic clients.
    -
  • A
    license
    B
    quality
    A
    maintenance
    A secure MCP server for shell operations, terminal management, and process control, enabling AI assistants to safely execute commands and manage interactive sessions.
    13
    204
    6
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Universal MCP server that wraps any CLI tool, enabling AI assistants to run commands via natural language.
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sonirico/mcp-shell'

If you have feedback or need assistance with the MCP directory API, please join our Discord server