From 42606783a1d18aaf31d48564164050069e5ce1e0 Mon Sep 17 00:00:00 2001 From: fabolous005 Date: Thu, 5 Nov 2026 10:17:21 +0100 Subject: [PATCH] shellmcp: README and ollmcp config --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ examples/ollmcp.json | 12 ++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 README.md create mode 100644 examples/ollmcp.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..c363cbb --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# shellmcp + +An MCP server (stdio, Python stdlib only) with one tool, `run`: a bash command, its exit code +and its output. Gives any MCP client's model a terminal. + + python3 shellmcp.py [--mode readonly|all] [--cwd DIR] [--timeout 60] [--max-output 8000] [--hide PATH]... + +- `--mode readonly` (default): every command runs in bubblewrap. The filesystem is read-only + except a private /tmp; no network; no other processes visible; ~/.ssh, ~/.gnupg and each + `--hide PATH` look empty. Needs `bwrap`. +- `--mode all`: the user's full permissions (here: wheel and docker, so effectively root). + Use it only with a client that asks before each tool call. + +The tool description names the host, user, directory, limits and which modern tools +(rg, fd, jq, ...) are installed, so the model prefers them. + +## Where commands run + +Wherever this process runs. The client starts it (stdio), so with `"command": "python3"` the +commands run on the client's machine. To act on the GPU host from any machine, start it +over ssh (key login needed): + + "command": "ssh", "args": ["fabian@192.168.2.169", "python3", "/home/fabian/coding/misc/shellmcp/shellmcp.py", "--mode", "readonly"] + +## Clients + +ollmcp with gemma4 on vLLM (`examples/ollmcp.json` registers `shell` and `shell-rw`): + + ollmcp -p openai -H http://127.0.0.1:8000/v1 -m gemma4 -j examples/ollmcp.json + +Claude Code: + + claude mcp add shell -- python3 /home/fabian/coding/misc/shellmcp/shellmcp.py --mode readonly + +OpenAI-API apps without MCP (Open WebUI and the like): wrap it as an OpenAPI server with +`uvx mcpo --port 8001 -- python3 shellmcp.py --mode readonly`. + +## Test + + python3 -m unittest -v test_shellmcp diff --git a/examples/ollmcp.json b/examples/ollmcp.json new file mode 100644 index 0000000..77ed795 --- /dev/null +++ b/examples/ollmcp.json @@ -0,0 +1,12 @@ +{ + "mcpServers": { + "shell": { + "command": "python3", + "args": ["/home/fabian/coding/misc/shellmcp/shellmcp.py", "--mode", "readonly", "--cwd", "/home/fabian", "--max-output", "4000"] + }, + "shell-rw": { + "command": "python3", + "args": ["/home/fabian/coding/misc/shellmcp/shellmcp.py", "--mode", "all", "--cwd", "/home/fabian", "--max-output", "4000"] + } + } +}