The suckless MCP gateway. Turn any CLI tool into an MCP endpoint.
One binary. One config file. One key file. One dir of skills. Same --flags everywhere.
cargo install suckless-mcp# Install with one command
curl -fsSL https://raw.githubusercontent.com/roverbird/suckless-mcp/main/install.sh -o install.sh
chmod +x install.sh
./install.sh
# Check status
suckless-mcp --statusThe installer does everything:
- Downloads the pre-compiled binary from GitHub Releases
- Copies skills from the repository to
/opt/skills - Creates
/etc/suckless-mcp/config.tomlwith defaults - Generates an API key in
/etc/suckless-mcp/keys.toml - Creates a
sucklesssystem user - Installs a systemd service (auto-start on boot)
# Copy binary
cp suckless-mcp /usr/local/bin/
# Create config
mkdir -p /etc/suckless-mcp
cat > /etc/suckless-mcp/config.toml << EOF
listen_host = "127.0.0.1"
listen_port = 8080
max_concurrent_tools = 5
EOF
# Add a skill
mkdir -p /opt/skills/weather
cat > /opt/skills/weather/skill.toml << EOF
name = "weather"
description = "Get weather forecast for a city"
public = false # true = no auth required
[runtime]
entrypoint = "weather.py"
timeout_secs = 30
[inputs.city]
type = "string"
flag = "--city"
required = true
description = "City name"
EOF
# Add your CLI tool
cp weather.py /opt/skills/weather/
# Add an API key
suckless-mcp --keys-add --id admin --key "your-secret-key"
# Run
suckless-mcp --serve./install.sh --uninstallsuckless-mcp is a gateway that exposes your existing CLI tools as MCP endpoints.
- AI agents connect to suckless-mcp over HTTP
- suckless-mcp reads
skill.tomlto understand your tool - suckless-mcp calls your CLI tool with
--flags - Your tool outputs JSON back to the AI
AI Agent → Caddy → suckless-mcp → your CLI tool (--flags)
← suckless-mcp ← JSON output
| Problem | Solution |
|---|---|
| MCP SDK requires rewriting tools | Keep your tools, add skill.toml |
| Need authentication | Built into gateway |
| Each tool needs its own server | One gateway, many tools |
| Setup complexity | One binary, two configs |
- suckless-mcp binary (this)
- config.toml - host, port, concurrency limits
- keys.toml - API keys (managed via CLI)
- /opt/skills/ - one subfolder per tool
- skill.toml - describes your tool to AI
- Your CLI tool - must use
--flagsand output JSON
suckless-mcp supports mixed auth on a single endpoint:
| Tool type | public flag |
tools/list visibility |
Can be called without auth |
|---|---|---|---|
| Public | true |
Visible to everyone | ✓ Yes |
| Private | false (default) |
Only visible to authenticated clients | ✗ No (returns 401) |
# Public tool example (weather data, public API)
name = "weather"
public = true
# Private tool example (database query)
name = "db_query"
public = false # or omit the field entirelyThis gives you:
- One endpoint (
/mcp) for both public and private tools - Clean discovery - agents only see tools they can actually call
- No complex OAuth - simple Bearer tokens for private tools
/opt/skills/weather/
├── skill.toml # Machine-readable manifest
└── weather.py # Your CLI tool
- Use
--flagsonly - no positional args, no shell string concatenation - Output valid JSON - nothing else to stdout
- Exit 0 on success, 1 on error
Everything else (auth, concurrency, timeouts) is handled by suckless-mcp.
suckless-mcp itself uses --flags — no positional subcommands, no hidden state.
# All gateway commands are flags
suckless-mcp --help
suckless-mcp --status
suckless-mcp --skills
suckless-mcp --skills --name weather
suckless-mcp --keys-list
suckless-mcp --keys-add --id admin --key secret
suckless-mcp --keys-revoke --id admin
suckless-mcp --serveSame pattern as your skills. LLMs learn once, apply everywhere.
Before (not compliant):
# old.py
import sys
city = sys.argv[1] # positional arg
print(f"Weather in {city}: sunny") # not JSONAfter (compliant):
#!/usr/bin/env python3
import argparse, json
parser = argparse.ArgumentParser()
parser.add_argument("--city", required=True)
args = parser.parse_args()
result = {"city": args.city, "forecast": "sunny", "temp": 22}
print(json.dumps(result))skill.toml (public tool):
name = "weather"
description = "Get weather forecast for a city"
public = true
[runtime]
entrypoint = "weather.py"
timeout_secs = 30
[inputs.city]
type = "string"
flag = "--city"
required = true
description = "City name"Deploy:
cp weather.py /opt/skills/weather/
suckless-mcp --servePrompt any LLM:
Generate skill.toml for this CLI tool:
{paste your script}
Rules:
- One [inputs] section per flag
- Include: type, flag, required, description
- Use standard table syntax (no multi-line inline)
- Add public = true if this tool is safe for unauthenticated access
suckless-mcp does not make unsafe tools safe. It only reads skill.toml to explain the tool to AI agents.
If your CLI tool deletes files, the AI can still delete files. The gateway adds:
- Authentication (API keys for private tools)
- Timeouts
- Concurrent execution limits
But the tool itself must be trusted.
mcp.yourdomain.com {
# Rate limiting (recommended)
rate_limit {
zone dynamic {
key {remote_host}
events 30
window 1m
}
}
# Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
-Server
}
reverse_proxy localhost:8080
}Then AI agents connect to https://mcp.yourdomain.com/mcp
All commands use --flags. Output is always JSON. Exit 0 = success, 1 = error.
| Action | Command |
|---|---|
| Start gateway | suckless-mcp --serve |
| Show server state | suckless-mcp --status |
| List all skills | suckless-mcp --skills |
| Show one skill | suckless-mcp --skills --name weather |
| List key IDs | suckless-mcp --keys-list |
| Add a key | suckless-mcp --keys-add --id admin --key secret |
| Revoke a key | suckless-mcp --keys-revoke --id admin |
| Show help | suckless-mcp --help |
config.toml (/etc/suckless-mcp/config.toml by default)
listen_host = "127.0.0.1"
listen_port = 8080
max_concurrent_tools = 5keys.toml (managed via CLI, never edit by hand)
[[keys]]
id = "admin"
key = "your-secret-key"
active = trueSkills root is hardcoded to /opt/skills. Each skill is a subdirectory containing skill.toml and your executable script.
suckless-mcp does one thing: expose CLI tools as MCP endpoints.
- No web dashboard
- No admin API
- No plugin system
- No database
- No hot reload
- No rate limiting (delegate to Caddy)
- No transport negotiation (POST /mcp only)
- No positional subcommands (gateway uses
--flagsjust like skills) - No mandatory auth on all tools (per-tool
publicflag gives flexibility)
Just a binary, one config file, one key file, and /opt/skills/.
mcpub.dev: Searchable list of remote MCP endpoints for AI Agents, free open access for all. List any remote endpoint - no review, no github, no registration, no vendor lock-in.
MIT
For deployment support, contact: kibervarnost@proton.me
suckless-mcp — only your tools matter