mcp-server for ops
MCP Server Collector
A Go-based Model Context Protocol (MCP) server that exposes system metrics, Docker observability, and secure command execution as tools consumable by AI clients (Claude, Cursor, etc.). Designed for AI-assisted operations (ai-ops) with a layered security boundary.
Features
- System metrics — CPU, memory, disk, disk I/O, network, OS info, and process lists via gopsutil
- Docker observability — List/inspect containers, images, networks, volumes; view and stream container logs; fetch live resource stats
- Secure command execution — Run host commands and
docker execthrough a full security pipeline (classification, blocklist/allowlist, argument constraints, approval gates) - Layered security boundary — Rate limiting, shell injection detection, command risk classification, result size limits, container-scope filtering, and audit logging
- Nacos service discovery — Auto-register with Nacos for gateway routing and service discovery
- MCP Streamable HTTP transport — Implements the MCP Streamable HTTP protocol with Bearer token authentication
- Production-ready — Structured JSON logging, graceful shutdown, configurable timeouts, Docker support
Quick Start
Prerequisites
- Go 1.25+ (to build from source)
- Docker daemon (optional, for Docker tools)
- Nacos server (optional, for service registration)
Build
go build -o mcp-server ./cmd/
Run
# Copy and edit the example config
cp configs/config.example.yaml config.yaml
# Start the server
./mcp-server --config config.yaml
CLI flags:
| Flag | Default | Description |
|------|---------|-------------|
| --config | config.yaml | Path to configuration file |
| --log-level | (from config) | Override log level: debug, info, warn, error |
| --log-format | (from config) | Override log format: json, text |
Docker
docker compose build
# Binary is output to ./dist/mcp-server
MCP Tools
System Info
| Tool | Risk | Description |
|------|------|-------------|
| get_cpu_info | safe | CPU model, cores, and usage percentage |
| get_memory_info | safe | Physical and swap memory usage |
| get_disk_info | safe | Disk partitions, usage, and mount points |
| get_disk_io | restricted | Disk read/write I/O statistics |
| get_network_info | safe | Network interfaces, IPs, MAC addresses, traffic counters |
| get_os_info | safe | Hostname, platform, kernel version, uptime |
| get_process_list | restricted | Running processes (disabled by default) |
Docker Info
| Tool | Risk | Description |
|------|------|-------------|
| docker_list_containers | safe | List containers with name/status filter |
| docker_inspect_container | restricted | Detailed container inspect (env vars sanitized) |
| docker_container_stats | restricted | CPU, memory, network, and block I/O stats |
| docker_list_images | safe | List images with dangling filter |
| docker_list_networks | safe | List networks with driver, scope, subnet info |
| docker_list_volumes | safe | List volumes with driver and mountpoint |
Docker Logs
| Tool | Risk | Description |
|------|------|-------------|
| docker_logs_tail | restricted | Last N lines of container logs |
| docker_logs_since | restricted | Logs since a duration or RFC3339 timestamp |
| docker_logs_range | restricted | Logs between two timestamps |
| docker_logs_follow | sensitive | Real-time log streaming (concurrency-limited) |
Command Execution
| Tool | Risk | Description |
|------|------|-------------|
| exec_command | dynamic | Execute a command on the host (boundary-checked) |
| docker_exec | sensitive | Execute a command inside a running container |
HTTP API
| Endpoint | Method | Description |
|----------|--------|-------------|
| /mcp | POST | JSON-RPC 2.0 endpoint for all MCP operations |
| /health | GET | Health check, returns {"status":"ok"} |
JSON-RPC Methods
| Method | Description |
|--------|-------------|
| initialize | Server handshake; returns protocol version and capabilities |
| tools/list | List all registered tools with JSON Schema input schemas |
| tools/call | Invoke a tool by name with arguments |
| notifications/cancelled | Cancel a session (cleans up active streams) |
Authentication
Clients pass auth via the Authorization: Bearer <token> header. For gateway-to-server proxy scenarios, the X-Auth: <token> header is also accepted.
Configuration
All configuration lives in a single YAML file. See configs/config.example.yaml for a fully annotated example.
Environment Variable Substitution
Config values support ${ENV_VAR} and ${ENV_VAR:default} placeholders. Use this for secrets:
server:
auth:
token: "${MCP_AUTH_TOKEN}"
Key Settings
server:
port: 9090
host: "0.0.0.0"
auth:
enabled: true
token: "${MCP_AUTH_TOKEN}"
mcp:
name: "server-collector"
version: "1.0.0"
docker:
enabled: true # Enable Docker tools
socket: "" # Auto-detect; override to set a custom socket path
server_info:
process_list_enabled: false # Enable get_process_list (privacy consideration)
process_sanitize: true # Redact command-line arguments in process list
logging:
level: "info" # debug | info | warn | error
format: "json" # json | text
output: "stdout" # stdout | stderr | file:./path/to/log
Security Boundary
The command execution path (exec_command, docker_exec) passes through a multi-stage security pipeline:
- Rate Limiting — Token bucket (default 100 RPS) prevents abuse
- Command Classification — Analyzes the command and assigns a risk level (
safe,restricted,sensitive,dangerous,blocked) - Shell Injection Detection — Blocks command substitution (
$(...),`...`), pipe-to-shell patterns (curl ... | sh), fork bombs, and other injection patterns - Policy Evaluation — Checks against configurable blocklist (regex patterns + command names), allowlist (if enabled), argument constraints, and auto-approve thresholds
- Approval Gate (optional) — Sensitive+ commands require a one-time approval token
- Container Scope — Glob-based allowlist restricts which containers
docker_execcan target - Result Limiting — Output truncated at configurable byte limit (default 1 MB)
Risk Levels
| Level | Examples | Behavior |
|-------|----------|----------|
| safe | df, du, free, uptime, ls, pwd, whoami, docker ps | Auto-approved |
| restricted | cat, tail, grep, ps, netstat, ping, ss, find | Auto-approved (configurable threshold) |
| sensitive | systemctl restart/start/stop, docker kill/pause, kill, killall | May require approval |
| dangerous | rm, mv, chmod, apt, yum, pip, shutdown, reboot | May require approval |
| blocked | Shell injection, iptables, nc, rm -rf /, mkfs.* | Always rejected |
Command Argument Constraints
Per-command sub-command restrictions prevent dangerous operations:
arg_constraints:
systemctl:
sub_commands: ["status", "restart", "start", "stop", "reload", "enable", "disable"]
docker:
sub_commands: ["ps", "inspect", "logs", "stats", "images"]
blocked_sub: ["rm", "rmi", "prune", "system"]
kubectl:
sub_commands: ["get", "describe", "logs", "top"]
blocked_sub: ["delete", "apply", "create", "edit", "patch"]
Nacos Integration
The server can auto-register with Nacos for service discovery. On startup it:
- Authenticates with Nacos
- Registers MCP server metadata (name, version, protocol, tool list)
- Registers as a Nacos service instance
- Starts periodic heartbeat
On shutdown it cleanly deregisters.
nacos:
enabled: false
server_addr: "127.0.0.1:8848"
namespace: "public"
group: "DEFAULT_GROUP"
username: "nacos"
password: "${NACOS_PASSWORD}"
service_name: "server-collector"
protocol: "streamable"
export_path: "/mcp"
heartbeat_interval: 5
Project Structure
mcp-server/
├── cmd/
│ └── main.go # Application entry point
├── internal/
│ ├── config/
│ │ └── config.go # Configuration loading, defaults, env resolution
│ ├── mcp/
│ │ ├── server.go # MCP JSON-RPC handlers (initialize, tools/list, tools/call)
│ │ ├── transport.go # HTTP transport, middleware, routing
│ │ ├── auth.go # Bearer + X-Auth token authentication
│ │ └── logging.go # Structured logging (slog)
│ ├── tools/
│ │ ├── registry.go # Thread-safe tool registry
│ │ ├── server_info.go # System metrics tool registration
│ │ ├── docker_info.go # Docker info tool registration
│ │ ├── docker_logs.go # Docker log tool registration
│ │ ├── command_exec.go # exec_command + docker_exec registration
│ │ └── stream_manager.go # Concurrent log stream tracking
│ ├── collectors/
│ │ ├── system.go # gopsutil system metric collection
│ │ └── docker.go # Docker SDK client
│ ├── registration/
│ │ ├── nacos.go # Nacos client (login, register, heartbeat, deregister)
│ │ └── connection_info.go # Console + file connection info output
│ └── boundary/
│ ├── pipeline.go # Security pipeline orchestration
│ ├── classifier.go # Command risk classification
│ ├── policy_engine.go # Blocklist/allowlist/arg-constraint enforcement
│ ├── approval.go # One-time approval token management
│ ├── rate_limiter.go # Token bucket rate limiter
│ ├── result_limiter.go # Output size truncation
│ └── container_scope.go # Glob-based container name allowlist
├── configs/
│ └── config.example.yaml # Annotated example configuration
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Docker Compose build
├── go.mod
└── go.sum