This stack runs an HTTP MCP server with one tool (ssh.exec) and a LAN/WG-only reverse proxy.
AUTH_TOKEN) on every MCP/API request.192.168.11.0/24100.127.1.0/28config/targets.yaml remote allowlistconfig/command_policy.yaml (safe/risky/deny)Ignore Safeguards then Yes Really)data/audit-repo/<host>/events.jsonl and events.log.data/audit-repo is a configured git repo).docker-compose.ymlconfig/nginx.confconfig/targets.yamlconfig/command_policy.yamlapp/main.pyscripts/init_audit_repo.shscripts/push_audit_repo.shcd /home/nate/rpc-dashboard/mcp-ssh
cp .env.example .env
# set AUTH_TOKEN in .env
Create directories:
mkdir -p data/keys data/audit-repo data
touch data/known_hosts
chmod 700 data/keys
chmod 600 data/known_hosts
Place SSH keys used by this service in data/keys/.
Use deploy key or PAT-backed remote before production.
./scripts/init_audit_repo.sh git@git.resilientpathconsulting.net:nate/mcp-audit-log.git main
This makes data/audit-repo a local clone. The app commits/pushes on rotation.
docker compose up -d --build
Service endpoint:
http://192.168.11.89:8765Proxy exposure is host-bound to LAN IP only (192.168.11.89:8765:8765).
Allow source 100.127.1.0/28 to destination 192.168.11.89 port 8765/TCP.
Send bearer token on every request:
Authorization: Bearer <AUTH_TOKEN>
curl -sS http://192.168.11.89:8765/mcp \
-H "Authorization: Bearer $AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
curl -sS http://192.168.11.89:8765/mcp \
-H "Authorization: Bearer $AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
ssh.execcurl -sS http://192.168.11.89:8765/mcp \
-H "Authorization: Bearer $AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0",
"id":3,
"method":"tools/call",
"params":{
"name":"ssh.exec",
"arguments":{
"host":"192.168.11.1",
"user":"root",
"command":"uptime",
"timeout_sec":30
}
}
}'
For remote blocked/risky commands:
allow_unsafe=trueconfirm_unsafe='Ignore Safeguards'allow_unsafe=trueconfirm_unsafe='Yes Really'Yes Really executes and logs overridden=true.targets.yaml)Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"rpc-ssh": {
"url": "http://192.168.11.89:8765/mcp",
"headers": {
"Authorization": "Bearer <AUTH_TOKEN>"
}
}
}
}
Restart Claude Desktop after saving. The server uses the 2025-03-26 streamable
HTTP transport: POST for requests, GET SSE channel for keepalive.
If you want periodic push in addition to rotation-trigger push:
crontab -e
# every 15 min
*/15 * * * * /home/nate/rpc-dashboard/mcp-ssh/scripts/push_audit_repo.sh >/tmp/mcp-audit-push.log 2>&1
Implemented an MCP SSH stack under mcp-ssh/ with:
/mcp) and direct tool endpoint (/tools/ssh.exec)AUTH_TOKEN) required for requestsmcp-ssh/app/main.pymcp-ssh/docker-compose.ymlmcp-ssh/config/nginx.confmcp-ssh/config/targets.yamlmcp-ssh/config/command_policy.yamlmcp-ssh/.env.examplemcp-ssh/scripts/init_audit_repo.shmcp-ssh/scripts/push_audit_repo.shmcp-ssh/README.mdssh_exec (Claude-compatible)ssh_execssh.exec192.168.11.0/24100.127.1.0/28targets.yaml allowlistcommand_policy.yamlFor remote blocked/risky commands:
allow_unsafe=trueconfirm_unsafe='Ignore Safeguards'confirm_unsafe='Yes Really'Per host folder:
data/audit-repo/<host>/events.jsonldata/audit-repo/<host>/events.logIncludes:
Redaction includes common patterns for:
250 MBdata/audit-repo is a git repo with working credentialsAdded /mcp route under client.resilientpathconsulting.net:
http://192.168.11.89:8765/mcpAdjusted real-client handling and allow rules so proxied requests evaluate correctly with forwarded IP context.
Found env mismatch:
MCP_AUTH_TOKEN=...AUTH_TOKENResolved by adding AUTH_TOKEN in /opt/mcp-ssh/.env (same value), then redeploying.
health endpoint returns 200/mcp without token returns 401/mcp with token returns 200tools/list returns tool name ssh_execRecommended config uses mcp-remote:
{
"mcpServers": {
"RPC_SSH": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://client.resilientpathconsulting.net/mcp",
"--header",
"Authorization: Bearer <AUTH_TOKEN>"
]
}
}
}
A token value was shared in chat during troubleshooting. Rotate AUTH_TOKEN after confirming stable connection.