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
8 MCP tools:
bash_execute,read_file,write_file,edit_file,glob,grep,prepare_upload,prepare_downloadBinary / 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)
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 mymcpAir-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 --yesOptional: 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 |
| Migrate a 1.x |
| 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 migrate-from-legacy
sudo mymcp migrate-from-legacy --helpFlag | Description |
| Legacy 1.x install root (default |
| Show planned migration steps without changing files |
mymcp doctor
Use this when install, Python path, rg, or env-file resolution looks wrong:
mymcp doctorUpgrading from 1.x to 2.0
Breaking changes:
Environment variable prefix renamed:
MCP_*→MYMCP_*(no compat shim).Install layout:
/opt/mymcp/(1.x) →/etc/mymcp/(2.0). Code is now managed bypipx, not unpacked into/opt/mymcp/.Install method:
git clone + deploy/install.sh→pipx install algony-mymcp.
One-line migration:
pipx install algony-mymcp
sudo mymcp migrate-from-legacy
sudo rm -rf /opt/mymcp # after verifying the new service is healthymymcp migrate-from-legacy reads /opt/mymcp/.env, rewrites MCP_* keys to
MYMCP_*, copies tokens.json, installs the new systemd unit, and restarts
the service. Pass --dry-run to see what it would do without making changes.
The legacy deploy/install.sh and deploy/upgrade.sh scripts remain in the
repository through the 2.0.x lifecycle for users who can't migrate yet.
Configuration
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 |
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"}` | Create a token |
|
| 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 tokens can only use read_file, glob, grep, and prepare_download.rw tokens can use all eight 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).
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/observability/dashboard.json 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).
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
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