shell-aliases
Expose shell aliases as safe MCP tools via FastMCP.
Open source Open in the app JSON README (API)
About
Expose shell aliases as safe MCP tools via FastMCP.
Details
- Kind
- Plugins
- Topic
- Developer tools
- Publisher
- hestonhamilton
- Origin
- gemini
- Category
- ferramentas
- Version
- 0.1.0
- Stars
- 1
- Last push
- 2025-11-14T22:07:56Z
- Repository state
- ativo
- Language
- Python
- License
- GPL-3.0
- Added
- 2026-08-30 14:13:39
- Updated
- 2026-08-30 14:13:39
- Origin id
hestonhamilton/mcp-shell-aliases
README
# MCP Shell Aliases Server
A Model Context Protocol (MCP) server that exposes your shell aliases as safe, discoverable tools. It parses configured alias files (e.g. `~/.bash_aliases`) and surfaces them to MCP hosts such as the Gemini CLI.
## Features
- Discovers aliases from explicitly configured files.
- Emits MCP tools/resources for dry-run and real execution.
- Enforces allowlist-only safety rules and dry-run by default.
- Sandboxes execution with constrained environment, cwd policy, and timeouts.
- Writes structured audit logs for every invocation.
## Quick Start
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
# copy and edit a config
cp examples/sample_config.yaml config.yaml
# run the server over stdio
mcp-shell-aliases --config config.yaml --verbose
```
Point your MCP host at the `mcp-shell-aliases` executable (or `python3 -m mcp_shell_aliases`) with the same config file.
## Configuration
The server loads settings from `config.yaml`, environment variables (`MCP_SHELL_ALIASES_*`), and CLI flags. See `docs/CONFIGURATION.md` for the full reference. A minimal config:
```yaml
alias_files:
- ~/.bash_aliases
allow_patterns:
- '^ls\b'
```
## Safety Model
- Aliases are classified using allowlist regexes. Anything that fails to match stays in dry-run mode.
- Real execution requires `dry_run=false` and `confirm=true` tool arguments.
- Commands execute via `/bin/bash -lc` with a scrubbed environment, bounded output, and timeouts.
- Audit logs capture every call. See `docs/SECURITY.md` for details.
## Host Integration
Update your MCP host configuration to use the new server, for example in `gemini-extension.json`:
```json
{
"mcp_server": {
"command": [
"python3",
"-m",
"mcp_shell_aliases",
"--config",
"${extensionPath}/config.yaml"
]
}
}
```
Verify by listing the `alias.catalog` tool, reading the `alias://catalog` resource, and executing a safe alias with `dry_run`.
### HTTP/SSE Transports
Some agentic tools prefer to talk over HTTP instead of stdio. You can start the
server on a local port with:
```bash
mcp-shell-aliases \
--config config.yaml \
--transport http \
--http-host 127.0.0.1 \
--http-port 3921 \
--http-path /mcp
```
Then point your host at `http://127.0.0.1:3921/mcp`. Use `--transport sse` or
`--transport streamable-http` for alternative FastMCP transports.
If using the Gemini CLI, ensure your project’s `.gemini/settings.json` has an
`mcpServers` entry with `httpUrl` (not `command`) for HTTP transports:
```json
{
"mcpServers": {
"mcp-shell-aliases": {
"httpUrl": "http://127.0.0.1:3921/mcp"
}
}
}
```
To add an HTTP server to the Gemini CLI, you must explicitly use the `--transport http` flag:
## Gemini Extensions (Stdio)
This repository includes a `gemini-extension.json` manifest so it can be installed directly with the Gemini CLI:
```bash
gemini extensions install https://github.com/<you>/mcp-shell-aliases
```
The manifest configures the MCP server as a stdio server. It launches a small `bootstrap.py` that creates a local virtual environment under the extension folder, installs minimal runtime dependencies, and then starts the server via `-m mcp_shell_aliases` with the bundled `config.yaml`.
After installation, the server appears in the Gemini CLI under the extension’s name. You can override the config path by editing the installed extension’s manifest or by copying `config.yaml` into your project and updating your `.gemini/settings.json` entry.
### Minimal Docker Smoke Test
You can sanity-check that the bootstrap and dependencies work in a clean environment using Docker (no Gemini CLI required):
```bash
bash scripts/docker-smoke.sh
```
This builds a tiny image, provisions the venv inside the container, and starts the server in HTTP mode on `localhost:3921` so you can hit it with `curl` while confirming the package installs cleanly. For stdio, override the `CMD` when running the container and attach a client.
### Full Gemini Install Test (Docker)
Run a full install test that boots a fresh container, installs the Gemini CLI, installs this extension from a Git URL, and verifies it appears in `gemini extensions list`:
```bash
# Provide the Git URL for your repo and the Gemini CLI install command.
EXT_URL=https://github.com/<you>/mcp-shell-aliases \
GEMINI_INSTALL="npm i -g @google/gemini-cli" \
bash scripts/docker-gemini-extensions-test.sh
# Or pass the URL as an arg (EXT_URL is optional if repo has a remote):
bash scripts/docker-gemini-extensions-test.sh https://github.com/<you>/mcp-shell-aliases
```
Notes:
- The script uses `node:20-bookworm-slim` and installs Python 3. It requires network access to fetch the CLI and your repo.
- If the Gemini CLI package name differs in your environment, set `GEMINI_INSTALL` to the correct install command (e.g., `npm i -g <pkg>`).
```bash
gemini mcp add mcp-shell-aliases http://127.0.0.1:3921/mcp --transport http
```
**Note:** For HTTP and SSE transports, the `mcp-shell-aliases` server must be running independently before you add it to the Gemini CLI. The CLI will not automatically start HTTP/SSE servers.
If the CLI still can’t connect, switch the server to `--transport sse` and reuse
the same URL.
## Project Status
- ✅ Python/FastMCP implementation exposes `alias.exec` and browseable resources.
- ✅ Safety rails enforced: dry-run default, allowlist patterns, timeouts, cwd policy, audit logs.
- ✅ Hot reload is available via on-demand catalog refresh (no file watcher yet).
- 🚧 Prompt helpers, inotify-style hot reload, and advanced hardening are still on the roadmap (see `TODO.md`).
## Testing & Quality
```bash
# lint
ruff check mcp_shell_aliases tests
# unit + contract suite (includes in-process MCP smoke tests)
pytest --cov=mcp_shell_aliases --cov-report=term-missing
# type checking (requires stub package: python -m pip install types-PyYAML)
mypy mcp_shell_aliases
```
The test suite exercises alias parsing, sandbox execution, CLI entry points, and
the FastMCP server itself via the official Python client. See
`docs/Testing.md` for the complete breakdown and troubleshooting tips.
## Tool Usage Example
```json
{
"tool": "alias.exec",
"arguments": {
"name": "ll",
"args": "~/projects",
"dry_run": true
}
}
```
Unsafe aliases will always return dry-run results unless they match the configured allowlist patterns.
## Tool API and CWD Guidance
Use these parameters with `alias.exec` to control execution and working directory.
- name: alias name to run.
- args: optional string appended to the alias expansion.
- dry_run: true by default; set to false to execute.
- confirm: required when `dry_run` is false. Acts as a safety gate.
- cwd: working directory to run in; defaults to `default_cwd` (usually `~`). Must be inside `allow_cwd_roots`.
- timeout_seconds: optional positive integer; must be ≤ 5× `execution.default_timeout_seconds`.
Response fields include `command`, `cwd`, `exitCode`, `stdout`, `stderr`, `truncated`, `timedOut`, `dryRun`, plus `aliasSafe` and `sourceFile` for context.
### Running in the right directory (cwd)
- Default behavior: If you do not pass `cwd`, commands run in `default_cwd` (home by default).
- For repo‑specific aliases (e.g., git), pass a project path explicitly:
- `alias.exec {"name":"gst","dry_run": false, "confirm": true, "cwd": "/path/to/repo"}`
- With agents: Ask the agent to include a `cwd` that points at your project root when calling tools. Example instruction: “When running git aliases, set `cwd` to the current project directory.”
### Safety and allowlist
- An alias is “safe” only if its expansion matches `allow_patterns`.
- Unsafe aliases can still be previewed with `dry_run: true`.
- Real execution requires both `dry_run: false` and `confirm: true`.
### Hot reload vs. config changes
- The server re-parses alias files and re-applies the in-memory allowlist on each request (hot reload).
- Editing `config.yaml` itself (e.g., changing `allow_patterns`, `default_cwd`, or `alias_files`) requires restarting the server for changes to take effect.
## Contributing
See `gemini-shell-aliases/CONTRIBUTING.md` for development workflow and coding standards.