Metadata-Version: 2.4
Name: mcp-shell-tools
Version: 5.1.0
Summary: 33 workstation tools for MCP — filesystem, editor, search, shell, notes, system
Author-email: Ulrich Cuber <sonstige@uc-it.de>
License-Expression: MIT
Project-URL: Homepage, https://www.uc-it.de
Project-URL: Repository, https://github.com/cuber-it/mcp-shell-tools
Keywords: mcp,shell,filesystem,tools,workstation
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: psutil>=5.9
Provides-Extra: server
Requires-Dist: mcp<3,>=2; extra == "server"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: pylint; extra == "dev"
Dynamic: license-file

# mcp-shell-tools

Workstation tools: files, editing, searching, running commands, notes that
survive a restart, and a look at the machine.

Three ways to use them, all on the same code:

- **as a server** — `mcp-shell-tools serve`, over stdio or HTTP
- **as a plugin** — loaded by the MCP proxy
- **as a library** — `from mcp_shell_tools import _files` and call the functions

Only the server touches the MCP SDK, and only through `server.py`. The tools
themselves know nothing about the protocol, which is why the same module works
in all three.

## Coming from version 4

The command `mcp-shell-tools` works as before, with `serve` in front of it:
`mcp-shell-tools serve` instead of `mcp-shell-tools`. The 4.x releases have
been withdrawn from PyPI, so there is nothing to fall back to.

Two differences in the tool set: the tool `command` is gone, because it steered
logging in the old server and the logging concept it needs does not exist in
this one. And version 5 needs Python 3.12, where version 4 ran on 3.10.

## Installation

```bash
pip install mcp-shell-tools            # tools, command line, plugin
pip install "mcp-shell-tools[server]"  # and the standalone server
```

## As a server

```bash
mcp-shell-tools serve                                   # stdio
mcp-shell-tools serve --transport streamable-http --port 8000
```

In a client that starts the server itself:

```json
{
  "mcpServers": {
    "shell": {
      "command": "mcp-shell-tools",
      "args": ["serve", "--working-dir", "/home/you/projects"]
    }
  }
}
```

`--allowed-root` confines the tools to a directory and may be repeated.
Without it they may touch the whole disk.

## On the command line

Every tool is a subcommand. Paths keep their place on the line, numbers and
switches are flags.

```bash
mcp-shell-tools file_list src
mcp-shell-tools grep "def register" --glob "**/*.py"
mcp-shell-tools head CHANGES.md --lines 20
mcp-shell-tools find_replace alt neu --apply
mcp-shell-tools sysinfo
```

The subcommands are read from the tool set itself, so a tool added to the
plugin appears here without anything being written twice.

## What it publishes

Thirty-three tools, in eight groups. Names are given without prefix; the proxy
puts one in front of them.

| Group | Tools |
|---|---|
| Files | `file_read`, `file_write`, `file_append`, `file_list`, `file_delete`, `file_move`, `file_copy`, `tree` |
| Inspecting | `file_info`, `head`, `tail` |
| Editing | `str_replace`, `diff_preview`, `find_replace` |
| Finding | `glob_search`, `grep` |
| Running | `exec`, `env`, `set_env`, `which` |
| Place | `cwd`, `cd`, `project_context` |
| Remembering | `memory_add`, `memory_show`, `memory_clear`, `session_save`, `session_resume`, `session_list` |
| Machine | `ps`, `sysinfo`, `port_check`, `disk_usage` |

`file_write` earns its place next to `exec`: a heredoc inside a long command
line is where quoting goes wrong, and writing a file is too common to leave to
that.

`find_replace` does nothing until `apply` is true, and it never descends into
`.git`, `.venv`, `node_modules` or `__pycache__`. A rewrite across many files
should be read before it happens, and it has no business inside a repository's
own bookkeeping.

`ps` reports memory, not a CPU share. A share is a measurement over a span of
time, and a single listing has no span to measure over.

## Interface

A module with `register(mcp, config)`. What arrives as `mcp` is the proxy's
registrar rather than an SDK server, so this package needs neither the SDK nor
the proxy to be imported or tested. Ruff refuses an import from `mcp` anywhere
in it. The only runtime dependency is `psutil`, which the machine tools use.

## Configuration

Read by the proxy from `<plugin-dir>/shell/config.yaml`:

```yaml
prefix: "shell_"                  # put in front of every tool name
working_dir: /home/ucuber/Workspace
timeout: 120                      # seconds a command may run
max_output: 200000                # characters of output kept
max_results: 200                  # rows a listing or search returns
state_dir: /home/ucuber/.mcp-shell-sessions
allowed_roots: []                 # empty means no limit
```

`allowed_roots` confines every path the tools touch. Left empty there is no
limit, which is what a workstation tool set is for; set it when the proxy is
reachable by someone who should not have the whole disk.

## Development

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
ruff check src tests
pylint src tests
pytest
```

## Use in the proxy

```bash
~/Workspace/projects/mcp-tools/mcp-proxy/.venv/bin/pip install -e .
```

Then `--load mcp_shell_tools.shell` in the unit, or `proxy_load` with that
reference while the proxy runs.
