Skip to main content
Glama

mcp-shell-sudo

English | Español

Warning: Use this MCP with caution. If sudo credentials are configured, it can execute privileged commands both on the host machine and on SSH-connected remote systems.

MCP server for Linux written in Python that executes local and remote SSH commands using explicit argv arrays, supports non-interactive local and remote sudo, provides an optional executable allowlist through ALLOW_COMMANDS, and can confine local filesystem writes to WORK_DIR using Bubblewrap.

Requirements

  • Linux.

  • Python 3.11+.

  • uv recommended.

  • MCP Python SDK 2.0.0.

  • sudo if elevated commands will be executed.

  • OpenSSH client (ssh) if remote execution will be used.

  • SSH login authentication configured through ~/.ssh/config, a key, or an SSH agent for non-interactive remote access.

  • bubblewrap if WORK_DIR is configured.

On Debian/Ubuntu:

sudo apt update
sudo apt install -y bubblewrap

Related MCP server: Dynamic Shell Command MCP Server

Environment Variables

PASSWORD_SUDO

Password used for local sudo. It is also the fallback password for remote sudo when PASSWORD_SUDO_SSH is not configured.

  • Empty or unset: local sudo uses sudo -n. Remote sudo also uses sudo -n unless PASSWORD_SUDO_SSH is configured.

  • Set: local sudo uses sudo -S, and the password is provided through stdin, never through argv or logs. Remote sudo reuses this value only when PASSWORD_SUDO_SSH is absent.

Example:

"PASSWORD_SUDO": "my-password"

The supported form is:

["sudo", "id"]

Custom sudo flags such as sudo -u postgres ... are not accepted. This prevents the policy layer from having to interpret the full sudo command grammar.

PASSWORD_SUDO_SSH

Optional password override used only for sudo on remote hosts executed through ssh_execute.

"PASSWORD_SUDO_SSH": "remote-sudo-password"

Password selection for remote sudo is:

  1. PASSWORD_SUDO_SSH when configured.

  2. Otherwise PASSWORD_SUDO.

  3. If neither is configured, remote sudo uses sudo -n and fails instead of waiting for an interactive password prompt.

This variable is not an SSH login password. ssh_execute does not inject SSH login credentials. SSH authentication must already work non-interactively through OpenSSH configuration, a key, or an SSH agent.

WORK_DIR

Optional working directory.

  • Empty or unset: the MCP server may work from any existing directory specified in the tool call.

  • Set: the server enters strict mode. directory must resolve inside WORK_DIR, and every process runs inside a Bubblewrap mount namespace where / is read-only, WORK_DIR is mounted read-write, and /tmp and /run are temporary.

Using cwd alone would not be sufficient to guarantee this isolation. A process could still write to /etc, /home/..., or follow symlinks outside the project. For this reason, the server fails at startup if WORK_DIR is configured but bwrap is unavailable.

In this mode, local sudo and all SSH execution are rejected. Host-level privilege escalation would break the local write-confinement guarantee, and local Bubblewrap confinement cannot restrict changes made on a remote host.

ALLOW_COMMANDS

Comma-separated list of executable names.

"ALLOW_COMMANDS": "git,ls,cat,grep,python,node,pnpm"
  • Empty or unset: all executables are allowed.

  • Set: only exact executable names from the list are allowed, and they must be invoked by name rather than through paths such as /usr/bin/git.

  • If a local command starts with sudo, the actual executable following sudo is validated.

  • For ssh_execute, both ssh and the remote target executable must be present in the allowlist.

  • Direct arbitrary ssh calls through shell_execute are rejected while an allowlist is active; use ssh_execute so the remote executable can also be validated. The simple compatibility form ["ssh", "host", "sudo", "command", ...] is recognized and validated.

The allowlist applies to executables, not arguments. Allowing bash, python, node, env, or another tool capable of executing processes significantly expands what the MCP client can do.

Installation

If you only want to use the MCP and do not need a local source checkout, install it directly from the repository with uv:

uv tool install git+https://github.com/eaangrino/mcp-shell-sudo.git

This installs mcp-shell-sudo in an isolated uv tool environment. You do not need to clone the repository manually.

Verify that the executable is available:

command -v mcp-shell-sudo

If the uv tool bin directory is not yet in your PATH, run:

uv tool update-shell

The executable is typically available as ~/.local/bin/mcp-shell-sudo.

Option 2 — Clone the repository (development or local changes)

Clone the project when you want to inspect, modify, or contribute to the source code:

git clone https://github.com/eaangrino/mcp-shell-sudo.git
cd mcp-shell-sudo
uv sync

Install development dependencies with:

uv sync --extra dev

To expose the executable while keeping the local source editable:

uv tool install --force --editable .

Manual Execution

uv run mcp-shell-sudo

The transport is stdio. Logging is never written to stdout in order to avoid corrupting JSON-RPC messages; logs are written to stderr instead.

MCP Configuration

Example with unrestricted commands and sudo enabled:

{
  "mcpServers": {
    "shell": {
      "command": "uv",
      "args": [
        "--directory",
        "/ABSOLUTE/PATH/mcp-shell-sudo",
        "run",
        "mcp-shell-sudo"
      ],
      "env": {
        "PASSWORD_SUDO": "YOUR_PASSWORD",
        "WORK_DIR": "",
        "ALLOW_COMMANDS": ""
      }
    }
  }
}

Example using the installed executable with separate local and remote sudo passwords:

{
  "mcpServers": {
    "mcp-shell-sudo": {
      "command": "/home/user/.local/bin/mcp-shell-sudo",
      "env": {
        "PASSWORD_SUDO": "LOCAL_SUDO_PASSWORD",
        "PASSWORD_SUDO_SSH": "REMOTE_SUDO_PASSWORD"
      }
    }
  }
}

If local and remote sudo use the same password, omit PASSWORD_SUDO_SSH; PASSWORD_SUDO is reused automatically for remote sudo.

Example confined to a specific project:

{
  "mcpServers": {
    "shell-project": {
      "command": "uv",
      "args": [
        "--directory",
        "/ABSOLUTE/PATH/mcp-shell-sudo",
        "run",
        "mcp-shell-sudo"
      ],
      "env": {
        "PASSWORD_SUDO": "",
        "WORK_DIR": "/home/user/projects/app",
        "ALLOW_COMMANDS": "git,ls,cat,grep,find,python,node,pnpm"
      }
    }
  }
}

shell_execute Tool

Basic input:

{
  "command": ["ls", "-la"]
}

With a working directory:

{
  "command": ["git", "status"],
  "directory": "backend"
}

With stdin:

{
  "command": ["cat"],
  "stdin": "hello\n"
}

With sudo:

{
  "command": ["sudo", "id"]
}

Response:

{
  "stdout": "uid=0(root) gid=0(root) groups=0(root)\n",
  "stderr": "",
  "status": 0,
  "execution_time": 0.031,
  "timed_out": false,
  "output_limited": false
}

ssh_execute Tool

Use ssh_execute when the command must run on another machine. The command array must contain the remote executable and arguments without sudo; request elevation with sudo: true.

Basic remote execution:

{
  "host": "server-alias",
  "command": ["id"]
}

Remote sudo:

{
  "host": "server-alias",
  "command": ["systemctl", "status", "docker", "--no-pager"],
  "sudo": true
}

Optional SSH port and TTY:

{
  "host": "my-server",
  "command": ["id"],
  "sudo": true,
  "port": 2222,
  "tty": true,
  "timeout": 120
}

For non-default usernames, identity files, or other SSH options, configure an OpenSSH alias first:

Host my-server
    HostName example.com
    User user
    IdentityFile ~/.ssh/my-server
    Port 2222

Then pass only the alias in host.

  • host: an OpenSSH destination or alias. Authentication must already work non-interactively using ~/.ssh/config, a default SSH key, or an SSH agent. An alias is recommended when a specific user, non-default identity file, or other SSH options are required.

  • command: remote argv excluding sudo.

  • sudo: when true, runs the remote command as sudo -S -p '' -- ... when a remote sudo password is configured, otherwise as sudo -n -- ....

  • stdin: optional data delivered to the remote command after the sudo password.

  • port: optional TCP port from 1 to 65535. It controls the SSH connection port; it does not provide authentication credentials.

  • tty: uses ssh -tt; enable it only if the remote sudo policy requires a TTY. It does not make ssh_execute handle an interactive SSH login password prompt.

  • timeout: 60 seconds by default, capped at 600 seconds.

SSH login authentication is handled entirely by the local OpenSSH client. ssh_execute does not inject an SSH login password and does not currently accept an explicit identity-file parameter equivalent to ssh -i. If a non-default private key is required, configure it with IdentityFile in ~/.ssh/config or load it into an SSH agent.

For compatibility, shell_execute also recognizes the common simple form:

{
  "command": ["ssh", "server-alias", "sudo", "id"]
}

For explicit remote execution or more complex SSH requirements, prefer ssh_execute.

shell_config Tool

Returns the effective non-secret configuration.

It never returns PASSWORD_SUDO or PASSWORD_SUDO_SSH. It reports only non-secret state such as whether local/remote sudo password injection is configured, whether ssh is available, whether WORK_DIR confinement is active, and the effective allowlist.

Implemented Security Measures

  • Uses create_subprocess_exec; it does not use shell=True.

  • command is passed as an explicit argv array.

  • Local and remote sudo passwords never appear in process argv or the child process environment; configured secrets are also redacted from stdout/stderr before results are returned.

  • If no applicable sudo password is configured, sudo -n prevents the process from hanging while waiting for an interactive password prompt.

  • SSH login authentication remains delegated to OpenSSH configuration, keys, and agents; the MCP server does not handle SSH login passwords.

  • SSH_AUTH_SOCK is forwarded when present so OpenSSH can use the current SSH agent.

  • Remote argv elements are quoted with shlex semantics before being passed to OpenSSH.

  • ALLOW_COMMANDS validates the local executable after a simple sudo invocation and, for ssh_execute, validates both ssh and the remote target executable.

  • Uses a fixed and reduced PATH to avoid resolving executables from . or arbitrary inherited paths.

  • Uses a reduced child environment instead of inheriting the entire MCP server environment.

  • Per-call timeout: 60 seconds by default, with a maximum of 600 seconds.

  • Output limit: 2 MiB per stream. If the limit is exceeded, the entire process group is terminated.

  • Processes run in a new session, and the entire process group is terminated on timeout.

  • WORK_DIR uses Bubblewrap and fails closed if isolation cannot be provided. SSH execution and sudo are disabled while WORK_DIR is active where confinement cannot be guaranteed.

Important Limitations

  1. ALLOW_COMMANDS="" means arbitrary command execution with the permissions of the user running the MCP server. If a sudo password is also configured, the MCP client can request root actions locally and, through ssh_execute, on SSH hosts for which authentication is already available. Use this configuration only with a client and model you control.

  2. An executable allowlist does not semantically validate command arguments. python, node, bash, sh, perl, and similar tools are effectively equivalent to allowing arbitrary code execution.

  3. WORK_DIR is a local filesystem confinement mechanism, not a VM or network sandbox. Because it cannot constrain remote filesystem changes, SSH execution is intentionally disabled whenever WORK_DIR is configured.

  4. Remote execution can modify another machine with the permissions of the SSH account or root when sudo: true succeeds. OpenSSH host verification and trust remain governed by the user's SSH configuration and known_hosts.

  5. PASSWORD_SUDO and PASSWORD_SUDO_SSH stored in the MCP client configuration remain secrets stored in that file. Restrict the file permissions with chmod 600 and never commit it to version control.

Tests

uv run --extra dev pytest
uv run --extra dev ruff check .

Available Tools

2 tools
shell_configA

Return the effective non-secret shell policy configuration.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description serves as the only behavioral disclosure. It implies a read-only operation ('Return') but does not explicitly state that it has no side effects or that it is safe. It does clarify that secrets are excluded, which is a useful constraint. However, it does not mention any authentication or permission requirements, which could be relevant.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, concise sentence that front-loads the action ('Return') and specifies the resource. There is no wasted verbiage.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that there are no parameters, the description sufficiently conveys the tool's function. The existence of an output schema covers return details, so the description need not elaborate. It does not mention usage context, but that is already addressed in usage_guidelines; for a simple config retrieval, this is complete enough.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, so the description is not required to explain parameter syntax. The phrase 'non-secret' adds context about the output scope but does not relate to parameters. For a parameterless tool, this is adequate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Return') and a clear resource ('effective non-secret shell policy configuration'). It distinguishes itself from the sibling tool by nature (configuration retrieval vs. execution), though it does not explicitly name the alternative. The purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given for when to use this tool versus the sibling shell_execute. An agent must infer that this is for reading configuration, not executing commands. The description does not mention any prerequisites, alternatives, or context for selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

shell_executeA

Execute one command as an argv array.

Args: command: Executable and arguments, for example ["ls", "-la"] or ["sudo", "systemctl", "status", "ssh"]. Shell syntax is not interpreted. stdin: Optional text sent to the command's standard input. directory: Optional working directory. With WORK_DIR configured, this path must resolve inside WORK_DIR. Without WORK_DIR, any existing directory may be used. timeout: Execution timeout in seconds. Values above 600 seconds are capped at 600.

Returns: stdout, stderr, exit status, execution time, timeout flag, and output-limit flag.

ParametersJSON Schema
NameRequiredDescriptionDefault
stdinNo
commandYes
timeoutNo
directoryNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of disclosing behavioral traits. It mentions that shell syntax is not interpreted, that the timeout is capped at 600 seconds, and that directory paths must resolve inside WORK_DIR if configured. However, it does not warn about the potentially destructive nature of executing arbitrary commands or the side effects of the executed process, which is a notable omission for a command execution tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is structured with a clear one-line summary, a detailed 'Args' section, and a 'Returns' section. It is appropriately detailed for a tool with multiple parameters but remains readable. The example for the command parameter adds clarity without bloat.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the essential invocation details: command format, directory constraints, timeout cap, and the return fields (stdout, stderr, exit status, etc.). It does not explain prerequisites such as the meaning of WORK_DIR, but this is likely a global configuration rather than tool-specific. Given the presence of an output schema (though not shown), the return-field listing is sufficient. Overall, it provides enough for an agent to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema provides no descriptions for any of the four parameters (schema coverage 0%), so the description must fully compensate. It does so thoroughly by explaining each parameter: the command array with examples, optional stdin, directory restrictions relative to WORK_DIR, and timeout cap. This adds substantial meaning beyond the schema's type definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Execute one command as an argv array.' It clearly distinguishes from the sibling tool 'shell_config' by implying execution vs. configuration, and provides a concrete example to clarify the argv format.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear guidance on how to invoke the tool, including the requirement to pass an argv array rather than shell syntax, and clarifies timeout and directory constraints. However, it does not explicitly state when to prefer this tool over shell_config, though the purpose difference is evident from the name and description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 2 tool updatesv0.1.0
    • First observedshell_config
    • First observedshell_execute

TDQS

A3.9/5.0
Disambiguation5/5

The two tools have completely distinct purposes: one executes commands and the other returns configuration. There is no overlap or potential for misselection between them.

Naming Consistency5/5

Both tools follow the same snake_case verb_noun pattern (shell_execute, shell_config). The naming is clear, predictable, and consistent.

Tool Count3/5

With only two tools, this server feels thin, but the narrow scope (shell execution and configuration) justifies the limited surface. It is at the lower edge of what is reasonable, as stated in the calibration.

Completeness4/5

The tool surface covers the core functionality of executing shell commands and retrieving configuration. There is no obvious missing operation for the stated purpose; the only minor gap might be a way to list allowed commands or test, but that is not essential.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to securely execute shell commands on local machines through an SSH interface with session management, command execution, and sudo support.
    1
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides a secure, token-authenticated command execution tool over MCP Streamable HTTP, with a default-deny allowlist and shell metacharacter rejection.
    16
    Apache 2.0

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/eaangrino/mcp-shell-sudo'

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