Linux MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Linux MCP Serverlist all files in /home"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Linux MCP Server
A Python MCP server that exposes full Linux system control to AI clients (Claude Desktop, Claude Code, Cursor, Gemini CLI, etc.) over Streamable HTTP.
Features
9 MCP tools:
bash_execute,read_file,write_file,edit_file,glob,grep,prepare_upload,prepare_download,server_overview(optional, requires the recorder module)Binary / large file transfer: bypass HTTP endpoints (
PUT/GET /files/raw/{ticket}) for streaming uploads and downloads — file bytes never enter the LLM context windowPer-token permissions: read-only (
ro) or read-write (rw) rolesAudit logging: JSON Lines audit trail with error details for all tool invocations
Application logging: errors and warnings output to stderr (captured by journald)
Protected paths: MCP's own files are protected from tool access
Multi-user auth: Bearer token authentication with per-token management
Admin API: create/revoke tokens without restarting the server
Streamable HTTP transport: stateless mode, each request is independent (no session issues on reconnect)
Related MCP server: mcp-remote-agent
Requirements
Python 3.11+
ripgrep(rg) — optional but recommended for fastergreptool (falls back to Python regex)
Install
Requires Python 3.11+ on Linux.
pipx install algony-mymcpThe PyPI distribution name is algony-mymcp (the bare name mymcp is reserved
on PyPI). After install the command and the Python import path are still
plain mymcp.
Plain pip works too (a venv is recommended):
python3 -m venv ~/.local/share/mymcp-env
~/.local/share/mymcp-env/bin/pip install algony-mymcp
ln -s ~/.local/share/mymcp-env/bin/mymcp ~/.local/bin/mymcpQuick try (foreground, no system service)
mymcp servemymcp prints a temporary admin and rw token to stderr, listens on
0.0.0.0:8765 by default, and discards both tokens on exit.
Production install (systemd)
sudo mymcp install-service --yes
sudo systemctl start mymcpThis writes /etc/mymcp/.env, generates an admin token (printed once),
optionally generates a metrics token, installs /etc/systemd/system/mymcp.service,
sets up logrotate for /var/log/mymcp/audit.log, and (by default) installs
ripgrep for fast file search.
Useful flags: --port 9000, --bind 127.0.0.1, --config-dir, --log-dir,
--service-user mymcp (run as a restricted user), --no-metrics,
--no-audit, --skip-ripgrep.
Upgrade
pipx upgrade algony-mymcp
sudo systemctl restart mymcpBackup and disaster recovery
See docs/operations/backup-and-disaster-recovery.md
for what to back up (token store, audit log, recorder data, .env),
restore procedures, and a failure-mode → response table.
Air-gapped install
Each GitHub Release ships a mymcp-X.Y.Z-offline-bundle.tar.gz containing
all wheels and ripgrep binaries:
tar xzf mymcp-2.0.0-offline-bundle.tar.gz
cd mymcp-2.0.0-offline-bundle
sudo ./install-offline.sh
sudo mymcp install-service --yesWhy we don't ship a Dockerfile
mymcp's purpose is to let an LLM operate the host Linux system: install
packages, edit config under /etc, manage processes, read/write files
under /home. Running mymcp inside a container defeats this — by default
the container sees only its own filesystem and PID namespace, so the LLM
can only operate the container itself.
To make a containerised mymcp actually control the host you'd need at
minimum --privileged --pid=host --net=host -v /:/host and a convention
that the LLM works against /host. At that point the container provides
no isolation; it's an awkward installer.
If you really want a container (e.g. as a sidecar that manages another containerised service), it is ~10 lines:
FROM python:3.13-slim
RUN pip install algony-mymcp
EXPOSE 8080
ENV MYMCP_HOST=0.0.0.0 MYMCP_PORT=8080
CMD ["mymcp", "serve"]The recommended deployment is pipx install algony-mymcp + the shipped
systemd unit (mymcp install-service), which gives the service direct
host access matching the product's purpose.
Optional: server overview recorder
pip install algony-mymcp[recorder-anthropic] (or recorder-openai, or
recorder for both) adds an asyncio module that maintains a self-updating
server overview document via LLM. Disabled by default; enable with
MYMCP_RECORDER_ENABLED=true. See docs/superpowers/specs/2026-05-29-llm-recorder-design.md
for full details.
CLI Reference
Top-level commands
Command | Purpose |
| Run the MCP server in the foreground |
| Print the installed version |
| Install the systemd service and config files |
| Remove the systemd service |
| Manage tokens in the local token store |
| Print environment and dependency diagnostics |
mymcp serve
mymcp serve --helpImportant flags:
Flag | Description |
| Load settings from a specific env file |
| Override bind host |
| Override bind port |
| Set application log level |
| Use text or JSON stderr logs |
| In temporary-token mode, also generate an ephemeral metrics token |
mymcp install-service
sudo mymcp install-service --helpImportant flags:
Flag | Description |
| Listen port (default |
| Bind address (default |
| Config directory (default |
| Audit log directory (default |
| Run as root or a restricted |
| Enable or disable |
| Enable or disable audit logging setup |
| Install or skip |
| Skip interactive confirmation |
mymcp uninstall-service
sudo mymcp uninstall-service --helpFlag | Description |
| Config directory to target |
| Log directory to target |
| Also delete config and log directories |
mymcp token
mymcp token --helpSubcommands:
Subcommand | Purpose |
| Show admin/metrics state and ro/rw tokens |
| Create a new token |
| Delete a token |
| Generate and persist a new admin token |
| Generate and persist a new metrics token |
| Disable the |
mymcp doctor
Use this when install, Python path, rg, or env-file resolution looks wrong:
mymcp doctorConfiguration
mymcp install-service writes /etc/mymcp/.env. The serve command also
honors --env-file PATH, MYMCP_ENV_FILE, and (in dev) ./.env.
Core
Variable | Default | Description |
| (required for /admin) | Admin token for managing user tokens |
| (empty = disabled) | Bearer for |
|
| Bind address |
|
| Listen port |
|
| Token store path |
| (empty) | Additional protected paths, comma-separated |
|
| Seconds to wait for in-flight bash children on SIGTERM |
Audit Logging
Variable | Default | Description |
|
| Enable audit logging |
|
| Audit log directory (auto-protected) |
|
| Max audit log file size before rotation (10MB) |
|
| Number of rotated log files to keep |
Tool Limits
All limits are configurable via environment variables. Default values work well for most use cases.
Variable | Default | Description |
|
| bash stdout/stderr default cap (100KB) |
|
| bash output hard cap (1MB) |
|
| read_file default lines per request |
|
| read_file max lines per request |
|
| Max bytes per line before truncation (32KB) |
|
| write_file max size (10MB) |
|
| edit_file max old/new string size (1MB) |
|
| Max file paths returned by glob |
|
| grep default max matches |
|
| grep hard max matches |
Recorder (optional)
These only apply when the [recorder] / [recorder-anthropic] /
[recorder-openai] extra is installed.
Variable | Default | Description |
|
| Enable the background recorder task and |
|
| Where overview + changelog + cursor live |
|
| How often the merge cycle runs |
|
| Cap on audit events folded per cycle |
|
| Max probe iterations during initial bootstrap |
|
| LLM token budget for bootstrap |
|
| Per-probe timeout during bootstrap |
|
| Retry interval if bootstrap fails |
|
|
|
| (provider default) | Model id override |
| (unset) | API key for the chosen provider |
| (unset) | Base URL override (e.g. DeepSeek for the OpenAI adapter) |
|
| Per-call output ceiling for the recorder's LLM. Must stay ≤ the chosen model's |
|
| Consecutive merge failures before the breaker opens. Once open, recovery is event-driven (a new event triggers a single retry; success clears the breaker). Set to |
Managing Tokens
The mymcp token subcommands operate on the local token store directly (no
admin API call required). They read /etc/mymcp/.env by default; use
MYMCP_ENV_FILE=... to point elsewhere.
# List all tokens (admin/metrics state + ro/rw entries)
sudo mymcp token list
# Create a read-only token
sudo mymcp token add --name my-claude-desktop --role ro
# Create a read-write token
sudo mymcp token add --name my-admin-client --role rw
# Revoke
sudo mymcp token revoke tok_abc123
# Rotate the admin or metrics token (rewrites .env)
sudo mymcp token rotate-admin
sudo mymcp token rotate-metrics
# Disable the /metrics endpoint by emptying the metrics token
sudo mymcp token disable-metricsThe HTTP /admin/* API still works for clients that need to manage tokens
remotely; it requires Authorization: Bearer <MYMCP_ADMIN_TOKEN>.
HTTP Endpoints
Public / operational endpoints
Method | Path | Auth | Purpose |
|
| none | Liveness check with version |
|
| none | Return just the server version |
|
| metrics token | Prometheus metrics |
|
| ro/rw token | Streamable HTTP MCP transport |
Examples:
curl http://your-server:8765/health
curl http://your-server:8765/version
curl -H "Authorization: Bearer $MYMCP_METRICS_TOKEN" \
http://your-server:8765/metricsNotes:
/metricsreturns401if the bearer token is wrong./metricsreturns503if metrics support is disabled or no metrics token is configured.
Admin API
All /admin/* endpoints require:
Authorization: Bearer <MYMCP_ADMIN_TOKEN>Method | Path | Body | Purpose |
|
| none | List managed ro/rw tokens |
|
| `{"name":"...", "role":"ro | rw"}` |
|
| none | Revoke a token |
Examples:
# List tokens
curl -H "Authorization: Bearer $MYMCP_ADMIN_TOKEN" \
http://your-server:8765/admin/tokens
# Create a read-only token
curl -X POST \
-H "Authorization: Bearer $MYMCP_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"ci-bot","role":"ro"}' \
http://your-server:8765/admin/tokens
# Revoke a token
curl -X DELETE \
-H "Authorization: Bearer $MYMCP_ADMIN_TOKEN" \
http://your-server:8765/admin/tokens/tok_abc123Connecting Clients
Claude Desktop / Cursor
Add to MCP settings:
{
"mcpServers": {
"linux-server": {
"type": "streamableHttp",
"url": "http://your-server:8765/mcp",
"headers": {
"Authorization": "Bearer tok_abc123"
}
}
}
}Claude Code
claude mcp add linux-server \
--transport streamable-http \
--url http://your-server:8765/mcp \
--header "Authorization: Bearer tok_abc123"MCP Tools
Permission model
Tool | Permission | Summary |
| rw | Run a shell command in a fresh subprocess |
| ro | Read a file with line numbers and pagination |
| rw | Create or overwrite a file |
| rw | Replace text in a file |
| ro | Find paths by glob pattern |
| ro | Search file contents with regex |
| rw | Mint a one-time signed URL for uploading bytes to a server path |
| ro | Mint a one-time signed URL for downloading bytes from a server path |
| ro | Return the maintained server overview (requires the recorder module; see below) |
ro tokens can use read_file, glob, grep, prepare_download, and
server_overview. rw tokens can use all nine tools.
bash_execute (rw)
Runs a shell command in a new subprocess. Commands are stateless: one call does not preserve cwd, environment changes, shell functions, or exports for the next.
Parameters:
Field | Type | Required | Default | Notes |
| string | yes | – | Shell command to run |
| integer | no |
| Clamped to |
| string | no |
| Command cwd |
| integer | no |
| Per-stream cap; hard max |
Returns:
stdoutstderrexit_codetimed_out
Example:
{
"command": "uname -a",
"timeout": 10,
"working_dir": "/tmp"
}read_file (ro)
Reads a file and returns numbered lines. Large reads support pagination.
Parameters:
Field | Type | Required | Default | Notes |
| string | yes | – | Absolute path |
| integer | no |
| 1-based start line |
| integer | no |
| Runtime max |
Returns:
contenttotal_linestruncated
Common errors:
FileNotFoundErrorIsADirectoryErrorPermissionErrorProtectedPath
Example:
{
"file_path": "/var/log/syslog",
"offset": 1,
"limit": 200
}write_file (rw)
Creates or overwrites a file in one shot.
Parameters:
Field | Type | Required | Default | Notes |
| string | yes | – | Absolute path |
| string | yes | – | Max size |
Notes:
Missing parent directories are created automatically.
Protected paths are rejected.
Example:
{
"file_path": "/tmp/hello.txt",
"content": "hello from mymcp\n"
}edit_file (rw)
Replaces text in an existing file.
Parameters:
Field | Type | Required | Default | Notes |
| string | yes | – | Absolute path |
| string | yes | – | Max size |
| string | yes | – | Max size |
| boolean | no |
| If false, |
Use this when the client wants a precise in-file replacement instead of full overwrite.
Example:
{
"file_path": "/tmp/app.conf",
"old_string": "PORT=8000",
"new_string": "PORT=8765"
}glob (ro)
Finds matching files under a root directory. Results are sorted by modified time descending.
Parameters:
Field | Type | Required | Default | Notes |
| string | yes | – | Example: |
| string | no |
| Root directory |
Runtime max results: 1000.
Example:
{
"pattern": "**/*.log",
"path": "/var/log"
}grep (ro)
Searches file contents with a regex. Uses ripgrep if available; otherwise falls back to a Python implementation.
Parameters:
Field | Type | Required | Default | Notes |
| string | yes | – | Regex pattern |
| string | no |
| File or directory to search |
| string | no | none | Filename filter, e.g. |
| string | no |
| One of |
| integer | no |
| Include surrounding lines |
| integer | no |
| Runtime max |
| boolean | no |
| Case-insensitive search |
Example:
{
"pattern": "Authorization",
"path": "/etc",
"glob": "*.conf",
"output_mode": "content",
"context_lines": 2
}prepare_upload (rw) and prepare_download (ro)
Use for binary files or files larger than 10 MB that don't need to be read into the conversation. The MCP tool only returns a small JSON object containing a one-time signed URL — the actual file bytes never enter the LLM context window. The client then drives the byte transfer with a regular curl from its local shell.
Workflow:
LLM calls
prepare_upload(dest_path="/tmp/foo.deb", max_bytes=20_000_000)→ server returns a JSON dict withurl,method: "PUT",expires_in(default 300 s),max_bytes, and a ready-to-runcurl_examplelikecurl -fsS -T /local/path/to/file 'https://server/files/raw/<ticket>'.LLM (or the user) runs the curl on the MCP client's local shell. Bytes stream straight to the server — no MCP message, no base64.
Server writes to a temp file alongside the destination, atomically replaces it on success, and returns
{"ok": true, "path": "...", "bytes_written": N}.
prepare_download is the mirror: it returns a GET URL, you curl URL -o local, and bytes stream back.
Tickets are single-use, path-scoped, byte-bounded, and expire after expires_in seconds (default 300, max 900). Both endpoints reuse the same check_protected_path and audit log as the file tools. Server tunables: MYMCP_TRANSFER_ENABLED, MYMCP_TRANSFER_MAX_BYTES (default 2 GB), MYMCP_TRANSFER_DEFAULT_TTL_SEC, MYMCP_TRANSFER_MAX_TTL_SEC, MYMCP_PUBLIC_BASE_URL (set when behind a reverse proxy).
server_overview (ro)
Returns the current contents of the server overview document maintained by
the optional recorder module. Only available when the recorder is installed
and MYMCP_RECORDER_ENABLED=true; otherwise the call fails with a clear
error message. Takes no parameters.
The recorder periodically folds successful mutating audit events into an
overview of what's installed and recently changed on the host. The
companion changelog.md in the same directory can be read with read_file.
See the "Optional: server overview recorder" section above for setup; full
design details are in docs/superpowers/specs/2026-05-29-llm-recorder-design.md.
Tool behavior notes
File tools enforce protected-path checks.
bash_executedoes not enforce protected-path checks; userotokens for untrusted clients.grepandglobare capped to protect the server from unbounded scans.read_filetruncates oversized individual lines and marks them with[LINE TRUNCATED].prepare_upload/prepare_downloadenforce protected-path checks at both mint and redeem time.
Logging
Audit Log
When enabled (MYMCP_AUDIT_ENABLED=true), all tool invocations are logged to <MYMCP_AUDIT_LOG_DIR>/audit.log in JSON Lines format:
{"ts":"2026-04-10T15:30:22Z","token_name":"my-client","role":"rw","ip":"203.0.113.5","tool":"bash_execute","params":{"command":"apt update"},"result":"ok","duration_ms":1523}Error entries include error_code and error_message:
{"ts":"2026-04-10T15:31:00Z","token_name":"ro-client","role":"ro","ip":"203.0.113.5","tool":"read_file","params":{"file_path":"/var/log/mymcp/audit.log"},"result":"error","error_code":"ProtectedPath","error_message":"Access denied: path is within protected directory","duration_ms":0}Logs rotate automatically (default 10MB with 5 backups).
Application Log
Tool errors and warnings are also output to stderr, which is captured by journald when running as a systemd service:
journalctl -u mymcp -fProtected Paths
MCP automatically protects its own installation directory and audit log directory from access via file tools (read_file, write_file, edit_file, glob, grep). This prevents AI clients from reading tokens, modifying server code, or tampering with audit logs.
Add extra protected paths via MYMCP_PROTECTED_PATHS=/path/one,/path/two.
Note: bash_execute is not subject to path protection — use ro tokens for untrusted clients.
Observability
mymcp emits metrics, traces, and logs via OpenTelemetry. The default install supports Prometheus pull at /metrics; the [otlp] extra adds OTLP push for any backend.
Quick reference
Capability | Default install |
|
| yes | yes |
OTLP push (metrics + traces + logs) | no | yes (when endpoint set) |
FastAPI/ASGI auto-instrumentation | no | yes |
Audit log → local file | yes | yes |
Audit log → OTLP push | no | yes |
Application logs → stderr (JSON) | yes | yes |
Recipe 1 — Grafana Cloud (free tier)
pip install algony-mymcp[otlp]
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-gateway-prod-us-central-0.grafana.net/otlp"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <base64(instanceId:token)>"
export OTEL_SERVICE_NAME=mymcp
mymcp serveImport deploy/grafana/mymcp-dashboard.json (metrics, incl. the Recorder
Health row) and deploy/grafana/mymcp-logs-dashboard.json (Loki+Tempo) into
Grafana Cloud.
Recipe 2 — Self-hosted LGTM stack
docker-compose.yml:
services:
collector:
image: otel/opentelemetry-collector-contrib:latest
ports: ["4318:4318"]
volumes: ["./otelcol-config.yaml:/etc/otelcol-contrib/config.yaml"]
mimir:
image: grafana/mimir:latest
command: -config.file=/etc/mimir.yaml
loki:
image: grafana/loki:latest
tempo:
image: grafana/tempo:latest
grafana:
image: grafana/grafana:latest
ports: ["3000:3000"]Then run mymcp with:
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 mymcp serveImport the dashboard JSON; configure Mimir/Loki/Tempo as data sources.
Recipe 3 — Pull-only Prometheus
No extra needed. Configure Prometheus:
scrape_configs:
- job_name: mymcp
bearer_token: <your MYMCP_METRICS_TOKEN>
static_configs:
- targets: ['localhost:8000']Import the dashboard JSON; the Traces and Logs panels remain empty (this is expected).
Audit log integrity
Metric | Type | Description |
| counter | Audit log writes rejected (disk full, permission denied, rotation race). Tool calls in this state return |
Silent audit loss is a SOC red line, so the Grafana dashboard ships an Audit Log Integrity row (cumulative + per-second-rate panels). The project does NOT ship alert rules — alerting is deployment-specific. Recommended PromQL recipe for operators:
rate(mymcp_audit_write_failures_total[5m]) > 0Recorder metrics ([recorder] extra)
When the recorder is enabled, these extra series appear on /metrics:
Metric | Type | Labels | Use |
| counter |
| One outcome per cycle. Reasons: |
| histogram |
| Wall-clock per merge cycle (incl. LLM). p95: |
| counter |
| HTTP boundary only — |
| counter |
| Throughput by |
| gauge | — | Backlog: mutating audit events past the cursor. A growing line means the recorder is stuck. |
| gauge | — | Unix seconds of the last merge attempt (success OR failure). Does not advance on idle ticks. Pair with |
| gauge | — | Unix seconds. |
| gauge | — |
|
| counter | — | Audit lines lost because rotation moved the file past the cursor. |
| counter |
| Per-tool count of mutating events folded into the overview. |
Recommended stale-recorder query (project ships metrics and dashboards only; alert rules are deployment-specific and not bundled):
( mymcp_recorder_pending_events > 0
AND time() - mymcp_recorder_merge_last_attempt_timestamp > 1800 )
OR mymcp_recorder_circuit_open == 1Both terms together avoid the historical false positive where an idle server (no events to process) appeared "stale" because the success-timestamp gauge hadn't moved.
The Grafana metrics dashboard's Recorder Health row materialises all of
the above. The supervisor's per-tick work runs inside a
recorder.supervisor.cycle span so recorder.supervisor.cycle_error log
lines carry the matching trace_id/span_id for jumping into Tempo from Loki.
Configuration knobs
All standard OTel env vars work. The most useful:
Variable | Default | Purpose |
|
| Service name |
| unset | OTLP target |
| unset | OTLP auth headers |
|
| http or grpc |
|
| Sampler |
|
| Sampling ratio |
|
| Push period |
|
| Application log level |
Testing
# Run all tests (excludes benchmarks)
python -m pytest tests/ -v --benchmark-disable
# Run with coverage report
python -m pytest tests/ -v --cov=. --cov-branch --cov-report=term-missing --benchmark-disable
# Run benchmark tests only
python -m pytest tests/test_benchmark.py --benchmark-only -v
# Save benchmark baseline for comparison
python -m pytest tests/test_benchmark.py --benchmark-save=baseline
# Run mutation testing
python -m mutmut run --max-children 1
python -m mutmut results
# Run load tests (start server first: mymcp serve)
export MYMCP_TEST_TOKEN=<your-rw-token>
locust -f tests/loadtest/locustfile.py --host http://localhost:8765Test Dimensions
Dimension | Tool | Target |
Line coverage | pytest-cov | 97%+ |
Branch coverage | pytest-cov --cov-branch | tracked |
Integration tests | httpx ASGITransport | full auth->tool->audit chain |
Boundary analysis | pytest | all parameter edge cases |
Performance benchmarks | pytest-benchmark | per-function timing |
Load testing | locust | multi-user concurrency |
Mutation testing | mutmut | 80%+ score |
Security Note
This server grants system access to AI clients. Security measures:
Permissions: New tokens default to
ro(read-only). Only grantrwto trusted clients.Audit: Enable audit logging to track all tool invocations.
Protected paths: Server files are automatically protected from tool access.
Network: Run behind a firewall and consider TLS (e.g. via nginx reverse proxy).
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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/algony-tony/mymcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server