infrastructure-mcp
Offers tools to retrieve Cisco device configuration, version, interfaces, inventory, and syslog messages.
Enables interaction with Docker containers and images, listing, stats, logs, and restarting containers.
Supports querying Grafana alerts, dashboards, annotations, and executing raw datasource queries (PromQL, LogQL, etc.).
Allows querying Kubernetes resources such as pods, nodes, events, and logs, with optional namespace scoping.
Provides tools for monitoring and managing Linux servers, including disk usage, CPU utilization, memory usage, failed services, kernel version, and journal errors.
Provides management of Proxmox cluster nodes, VMs, and containers, including starting, stopping, and taking snapshots.
Infrastructure MCP Server
Give Claude Code, Cursor, and other AI agents safe access to your real infrastructure — without giving them raw SSH access.
A self-hosted Model Context Protocol server that exposes high-level, auditable tools (disk_usage(), docker_restart(), grafana_alerts(), ...) instead of execute(command). Every call is inventory-driven, structured, and logged — the agent reasons about infrastructure; this server is the only thing that actually touches it.
Status: early, actively developed. See Roadmap for what's implemented and what's coming.
Manage: ✓ Linux ✓ Docker ✓ Kubernetes ✓ Proxmox ✓ Grafana ✓ Cisco (MikroTik, UniFi, Prometheus/Loki, Home Assistant, and more are on the Roadmap — not shipped yet.)
Works with: ✓ Claude Code ✓ Cursor ✓ OpenAI Codex ✓ Gemini CLI ✓ Windsurf ✓ Hermes (MCP is an open, client-agnostic protocol — any spec-compliant client works; these are just the ones people actually use it with.)
Raw SSH access | Infrastructure MCP | |
Audit trail | ❌ | ✅ structured log per call ( |
Input validation | ❌ | ✅ every parameter validated, no shell interpolation |
Structured output | ❌ free text | ✅ JSON, every response |
Inventory-aware | ❌ agent picks the host | ✅ targets resolved by name/tag only |
Blast-radius control | ❌ | ✅ read-only by default, mutations require |
Credential exposure | ❌ agent sees them | ✅ credentials never leave the adapter layer |
Quick Start
git clone https://github.com/<your-org>/infrastructure-mcp.git
cd infrastructure-mcp
go build -o bin/infrastructure-mcp ./cmd/server
cp configs/inventory.example.yaml configs/inventory.yaml # fill in your own targetsPoint your MCP client at the binary — see Connecting an AI Agent for Docker and remote-HTTP setups too:
{
"mcpServers": {
"infrastructure": {
"command": "/path/to/bin/infrastructure-mcp",
"args": ["-inventory", "/path/to/configs/inventory.yaml"]
}
}
}Related MCP server: Shuttle
Example Conversation
You: My archive server feels slow, and I'm seeing errors in Grafana. Can you find out why?
Claude, using Infrastructure MCP:
1. cpu_usage(server: "archive") → 92% used, status: "warning"
2. docker_ps(server: "archive") → prometheus: "Restarting (1) 4 seconds ago"
3. docker_logs(server: "archive", container: "prometheus") → "panic: too many open files"
4. grafana_alerts(instance: "main") → firing: HighDiskUsage on archive:/
Claude: Root cause found — archive is at 91% disk usage, which is causing Prometheus
to crash-loop on startup ("too many open files" from a corrupted WAL it can't
compact into the remaining space). Free up space on `/` (or expand it), then run:
docker_restart(server: "archive", container: "prometheus", confirm: true)Four tool calls, one root cause, zero raw shell access. Every call above is inventory-driven, logged, and returns structured JSON — see Examples for the actual response shapes.
Current Features
Tools implemented and tested against the real MCP protocol so far:
Core (v0.1)
list_servers— list inventory targets, optionally filtered by tagrun_command— run an arbitrary command against an inventory targetuptime— uptime and load averagesdisk_usage— per-filesystem usage with warning/critical severitymemory_usage— memory utilization with warning/critical severity
Linux (v0.2)
failed_services— systemd units in the failed statecpu_usage— aggregate CPU utilization (Proxmox/KVM guest-time aware)reboot_required— pending-reboot detection (marker file + kernel comparison)running_processes— top processes by CPU usagejournal_errors— recent systemd journal entries at error priority+kernel_version— running kernel release
Docker (v0.3)
docker_ps— list containers (running or all)docker_images— list local imagesdocker_stats— point-in-time resource usage snapshotdocker_logs— recent combined stdout/stderr log linesdocker_restart— restart a container (destructive; requiresconfirm: true)
Kubernetes (v0.4)
kubectl_get_pods— list pods, optionally scoped to a namespacekubectl_logs— fetch a pod/container's log lineskubectl_events— recent cluster events, most recent firstkubectl_describe— structured pod summary (spec/status highlights + recent events)kubectl_nodes— node list with readiness, roles, and capacity
Grafana (v0.5)
grafana_alerts— currently firing/resolved alert instances from the alerting APIgrafana_dashboards— search dashboards by title text and/or taggrafana_annotations— annotations, optionally scoped to a time range and/or tagsgrafana_query— raw query against one datasource (PromQL/LogQL/SQL/...); response is a datasource-specific passthrough, not normalized
Proxmox (v0.6)
proxmox_nodes— list cluster nodes with status and resource usageproxmox_vms— list QEMU VMs and LXC containers on a nodeproxmox_tasks— recent tasks on a node, most recent firstproxmox_start_vm— start a VM/container (state-changing; requiresconfirm: true)proxmox_stop_vm— force-stop a VM/container (destructive; requiresconfirm: true)proxmox_snapshot— take a VM/container snapshot (state-changing; requiresconfirm: true)
Networking — Cisco (v0.7, partial: MikroTik/UniFi remain on the Roadmap)
cisco_backup— fetch the running configuration, as-iscisco_version— software version, hostname, and uptimecisco_interfaces— interface list with IP address, admin/link status, and line protocolcisco_inventory— hardware components (chassis, modules, PSUs) with PID/VID/serial numbercisco_logs— buffered syslog messages, optionally capped to the most recent N lines
Cross-cutting, since v0.1
Legacy network device support: Telnet transport, SSH legacy-crypto negotiation, transparent per-target protocol dispatch, SSH public-key auth for routers/switches
Structured error contract on every tool (
message,recommendation,retryable,category)Structured per-execution logging (
tool,user,target,duration,result,error)Host-key verification fail-closed by default, with explicit opt-outs for lab use
Dual MCP transport: stdio (local subprocess clients) and Streamable HTTP (remote clients), from the same binary — HTTP is fail-closed by default, requiring a bearer token (
MCP_HTTP_TOKEN) unless explicitly opted out for lab useDocker image (multi-arch, GHCR) + Docker Compose, with a self-check
-healthcheckmode for shell-less containersCI/CD: PR-gated build/vet/lint/race-tested-CI, automatic semantic versioning + changelog + image publish + Trivy scan on merge to
main— see CI/CD
See Roadmap for what's next.
Table of Contents
Why
AI agents are increasingly asked to help operate infrastructure — check disk space, restart a container, look at recent errors. The naive way to enable this is to hand the agent raw SSH/shell access. That's fast to build and dangerous to run: no audit trail, no input validation, no blast-radius control, and every agent has to independently learn how to safely operate every kind of system.
Infrastructure MCP Server is the alternative: a single, self-hosted service that exposes meaningful, structured, inventory-driven tools (disk_usage(), docker_restart(), grafana_alerts()) instead of execute(command). Agents reason about infrastructure; this server is the only thing that actually touches it.
Goals
Self-hosted
Production-ready
Secure by default
Extensible
Vendor agnostic
Infrastructure as Code friendly
Stateless where possible
Structured outputs only
Human-auditable
Open Source
Non-Goals
The project is not intended to become:
another SSH wrapper
another Ansible replacement
another monitoring system
another Kubernetes operator
Instead, it provides AI-friendly infrastructure primitives built on top of those things.
Architecture
AI Agent
(Hermes / Claude / Cursor)
│
│ MCP
▼
Infrastructure MCP Server
│
┌───────────┴────────────┐
│ │
Infrastructure APIs SSH / Telnet Layer
│ │
▼ ▼
Proxmox Linux Servers
Grafana Cisco / MikroTik
Prometheus UniFi
Docker Home Assistant
Kubernetes Storage / Bare MetalThree layers, wired top-down:
MCP layer (
mcp/tools/,mcp/prompts/,mcp/resources/) — registers tools with the MCP SDK. Tools call adapters; they never talk to infrastructure directly.Adapter layer (
internal/linux/,internal/docker/,internal/proxmox/,internal/grafana/, ...) — one isolated package per integration, all implementing a common interface. Authentication (SSH keys, API tokens, kubeconfig) lives inside adapters and is never exposed to AI agents.Foundation —
internal/inventory/(YAML config, validated, env-var expansion for secrets) andinternal/ssh/internal/telnet(pooled connections to targets, including legacy devices with obsolete crypto or no SSH at all).
Everything is inventory-driven. No IP addresses, hostnames, or credentials appear in tool implementations — targets are resolved by name/tag from the inventory YAML.
Architectural decisions and the reasoning behind them are recorded as ADRs — see docs/adr/.
Technology Stack
Concern | Choice |
Language | Go 1.26+ |
MCP SDK | Official Model Context Protocol Go SDK |
Configuration | YAML ( |
Logging |
|
SSH |
|
HTTP |
|
Serialization |
|
Testing | Go testing, Testcontainers, Docker Compose |
CI | GitHub Actions |
Project Structure
infrastructure-mcp/
├── cmd/
│ └── server/ # entry point (stdio MCP transport)
├── internal/
│ ├── inventory/ # YAML config, validation, secret expansion
│ ├── ssh/ # pooled SSH connectivity
│ ├── telnet/ # legacy device transport
│ ├── remote/ # SSH/Telnet dispatch by target protocol
│ ├── linux/ # Linux diagnostics adapter
│ ├── docker/ # Docker CLI-over-SSH adapter
│ ├── toolerr/ # structured error contract
│ ├── kubernetes/
│ ├── grafana/
│ ├── proxmox/
│ ├── prometheus/, loki/ # planned
│ ├── cisco/
│ ├── mikrotik/, unifi/ # planned
│ └── homeassistant/ # planned
├── mcp/
│ ├── tools/ # one file per MCP tool
│ ├── prompts/
│ └── resources/
├── configs/ # example inventory
├── docs/
│ ├── adr/ # architecture decision records
│ ├── TOOL_REFERENCE.md # every tool's params + example output
│ └── ADDING_AN_ADAPTER.md # how to add a new integration
├── examples/
│ ├── mcp-client-config/ # ready-to-adapt client JSON snippets
│ ├── inventory-snippets/ # focused single-concept YAML fragments
│ └── sample-tool-outputs/ # example JSON responses
├── scripts/
└── tests/Installation
Prerequisites
Go 1.26 or newer (bumped from 1.24 in v0.4 — required by
k8s.io/client-go's current release train)SSH access (key- or password-based) to the servers/devices you want to manage
An MCP-capable client (Claude Desktop, Claude Code, Cursor, or any other MCP client)
Build from source
git clone https://github.com/<your-org>/infrastructure-mcp.git
cd infrastructure-mcp
go build -o bin/infrastructure-mcp ./cmd/serverOr run via Docker
Pre-built multi-arch images (linux/amd64, linux/arm64) are published to GHCR on every merge to main (see CI/CD):
docker pull ghcr.io/<your-org>/infrastructure-mcp:latestOr with Docker Compose, which wires up the inventory and SSH volume mounts for you — see docker-compose.yaml:
cp configs/inventory.example.yaml inventory.yaml # fill in your real targets
cp .env.example .env # fill in real secrets, never commit
docker compose up -dRun tests
go build ./... # build
go vet ./... # static checks
go test ./... -race -cover # all tests, race detector, coverage
go test ./internal/linux -run TestName # a single testConfiguration
The server is entirely inventory-driven — copy the example inventory and fill in your own targets:
cp configs/inventory.example.yaml configs/inventory.yamlservers:
archive:
hostname: 10.0.0.5
user: hermes
key: ~/.ssh/archive
tags:
- linux
- ethereum
pve01:
hostname: 10.0.0.2
user: hermes
proxyjump: jumpbox # reached only via another inventory target
tags:
- proxmox
routers:
core:
hostname: 10.0.0.10
vendor: cisco
user: admin
password: ${CORE_ROUTER_PASSWORD} # resolved from the environment at load time
legacy-edge: # no SSH server at all — Telnet only
hostname: 10.0.0.12
vendor: cisco
user: admin
password: ${LEGACY_EDGE_PASSWORD}
protocol: telnet
switches:
ancient-sw: # obsolete SSH key exchange/cipher/MAC only
hostname: 10.0.0.21
vendor: cisco
user: admin
password: ${ANCIENT_SW_PASSWORD}
legacy_crypto: true
# Every category, including single-instance-feeling ones like Grafana and
# Proxmox, is a map keyed by name — so a second Grafana or a second Proxmox
# cluster is just another key, not a schema change.
grafana:
main:
url: https://grafana.lab.local
token: ${GRAFANA_TOKEN}
proxmox:
# token is a Proxmox API token in "user@realm!tokenid=uuid" form
# (Datacenter > Permissions > API Tokens in the PVE UI). Ticket/cookie
# login is not supported.
lab:
url: https://pve.lab.local:8006
token: ${PROXMOX_TOKEN}
# All auth (client cert, bearer token, exec plugin, ...) lives inside the
# kubeconfig file itself — nothing is inlined into the inventory.
kubernetes:
home:
kubeconfig: /etc/infrastructure-mcp/kubeconfig-home
context: home-adminSecrets are never written in plaintext. Any ${VAR} in the YAML is resolved from the process environment at load time, and load fails closed if the variable is unset — real credentials are never committed to the repo.
More focused, single-concept inventory fragments (key-authenticated network devices, multi-instance services, ...) live under examples/inventory-snippets/.
Server flags
./bin/infrastructure-mcp \
-inventory configs/inventory.yaml \
-known-hosts ~/.ssh/known_hosts \
-insecure-ignore-host-key=false \
-transport stdioFlag | Default | Description |
|
| Path to the inventory YAML file |
|
| Path used to verify target SSH host keys |
|
| Skip host key verification entirely — lab/dev only, never production |
|
|
|
|
| Address to listen on when |
|
| Instead of starting the server, GET |
|
| Allow |
Host key verification is fail-closed by default: an unrecognized target's connection is refused unless it's in known_hosts or you explicitly opt into insecure mode. -transport=http is fail-closed the same way: it refuses to start unless the MCP_HTTP_TOKEN environment variable is set (see below) or -allow-anonymous-http is passed explicitly.
Connecting an AI Agent
Infrastructure MCP Server supports two transports from the same binary, so it works with both local-subprocess and remote-network MCP clients:
stdio (default) — the client spawns the binary itself and talks over its stdin/stdout. This is what most desktop IDEs and agent CLIs (Claude Desktop, Claude Code, Cursor) expect.
Streamable HTTP (
-transport http) — the server listens on the network (/mcpendpoint, plus/healthz) and any remote MCP client connects over HTTP. Use this when the server runs elsewhere (a container, a VM, behind a reverse proxy) rather than on the same machine as the client.
stdio (local)
{
"mcpServers": {
"infrastructure": {
"command": "/path/to/bin/infrastructure-mcp",
"args": ["-inventory", "/path/to/configs/inventory.yaml"]
}
}
}Remote HTTP
-transport=http requires a bearer token — /mcp exposes every registered tool, including run_command, so the server refuses to start without one (fail-closed, like host key verification above). Generate one and set it as MCP_HTTP_TOKEN:
export MCP_HTTP_TOKEN=$(openssl rand -hex 32)
./bin/infrastructure-mcp -inventory configs/inventory.yaml -transport http -http-addr :8080(or docker compose up -d, which does this by default once MCP_HTTP_TOKEN is set in .env — see Installation). Every request to /mcp must then send Authorization: Bearer $MCP_HTTP_TOKEN; /healthz stays open for container/load-balancer health checks. -allow-anonymous-http disables this requirement — lab/dev only, never expose an anonymous instance to anything but localhost.
Point any remote-MCP-capable client at http://<host>:8080/mcp with that header set. For clients that only support stdio, bridge with mcp-remote or an equivalent local proxy:
{
"mcpServers": {
"infrastructure": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://<host>:8080/mcp", "--header", "Authorization: Bearer ${MCP_HTTP_TOKEN}"]
}
}
}Put the HTTP endpoint behind TLS and network-level access control (a reverse proxy, VPN, or private network) before exposing it beyond localhost — the server itself does not add its own transport-layer authentication.
Once connected, over either transport, the agent sees only the tools listed under Current Features — never raw shell access, never credentials.
Ready-to-adapt client config files (stdio and remote-HTTP-via-mcp-remote) live under examples/mcp-client-config/.
Examples
Full request/response walkthroughs for a few representative tools, run
against the inventory shown in Configuration. Values are
synthetic — copy the shape, not the data. Every tool's shape is documented
in docs/TOOL_REFERENCE.md; runnable inventory
fragments and MCP client configs live under examples/.
Check disk space on a server:
disk_usage(server: "archive"){
"server": "archive",
"filesystems": [
{
"filesystem": "/dev/sda1",
"mount_point": "/",
"total_kb": 51475068,
"used_kb": 46853200,
"available_kb": 2003212,
"used_percent": 91,
"status": "critical",
"recommendation": "Free disk space immediately or expand capacity."
}
],
"timestamp": "2026-07-30T09:00:00Z"
}List containers on a Docker host:
docker_ps(server: "archive"){
"server": "archive",
"containers": [
{
"id": "a1b2c3d4e5f6",
"image": "grafana/grafana:11.2.0",
"status": "Up 3 weeks",
"state": "running",
"ports": "0.0.0.0:3000->3000/tcp",
"names": "grafana"
}
],
"timestamp": "2026-07-30T09:00:00Z"
}Restart a container — the confirm-gate pattern every mutating tool uses. The first call, without confirm, is a no-op that reports what would happen:
docker_restart(server: "archive", container: "grafana"){
"server": "archive",
"container": "grafana",
"status": "confirmation_required",
"message": "Set confirm: true to restart this container. No action was taken.",
"timestamp": "2026-07-30T09:00:00Z"
}Only the confirmed call actually restarts it:
docker_restart(server: "archive", container: "grafana", confirm: true){
"server": "archive",
"container": "grafana",
"status": "restarted",
"message": "Container restarted.",
"timestamp": "2026-07-30T09:00:05Z"
}Interfaces on a Cisco switch reached over legacy-crypto SSH (legacy_crypto: true in inventory — see ADR 0005):
cisco_interfaces(device: "old-core-sw"){
"device": "old-core-sw",
"interfaces": [
{ "interface": "Vlan100", "ip_address": "10.0.0.23", "ok": "YES", "method": "NVRAM", "status": "up", "protocol": "up" },
{ "interface": "GigabitEthernet1/0/1", "ip_address": "unassigned", "ok": "YES", "method": "unset", "status": "up", "protocol": "up" }
],
"timestamp": "2026-07-30T09:00:00Z"
}A firing alert from Grafana:
grafana_alerts(instance: "main"){
"instance": "main",
"alerts": [
{
"status": "firing",
"labels": { "alertname": "HighDiskUsage", "instance": "archive", "severity": "critical" },
"starts_at": "2026-07-30T08:00:00Z",
"fingerprint": "9f2a1c7e0b3d4e5f"
}
],
"timestamp": "2026-07-30T09:00:00Z"
}A tool call against an unreachable target — the structured error envelope, never a raw Go error:
uptime(server: "archive"){
"message": "dial tcp 10.0.0.5:22: connect: connection refused",
"recommendation": "Retry the request; if it persists, check network connectivity to the target.",
"retryable": true,
"category": "network"
}Tool Design Philosophy
Never expose raw infrastructure:
execute(command) # avoidPrefer meaningful, structured actions:
check_disk()
check_memory()
docker_list()
grafana_alerts()
backup_switch()Every tool:
validates its inputs
never panics
returns structured JSON
includes severity where relevant
includes a recommendation on warning/critical states
includes a timestamp
{
"status": "warning",
"server": "archive",
"disk_usage": 91,
"recommendation": "Free disk space or expand storage.",
"timestamp": "2026-07-23T19:10:00Z"
}Logging
Every tool execution produces a structured log line with:
tool, user, duration, target, result, error
Error Handling
Tools never return a raw Go error. Every failure is shaped as:
message, recommendation, retryable, category
(category is one of not_found, auth, network, timeout, invalid_input, internal.)
Security
No secrets in logs
No secrets in prompts
No shell interpolation — any user-supplied value that reaches a remote command is validated against a strict whitelist pattern first
Validate all inputs
Whitelist inventory — no target is reachable unless it's named in the inventory
Least privilege
Read-only by default
Dangerous actions require explicit confirmation (e.g.
docker_restartrequiresconfirm: trueand is a no-op otherwise)-transport=httpis fail-closed: it refuses to start without a bearer token (MCP_HTTP_TOKEN) unless-allow-anonymous-httpis explicitly passed
Found a security issue? Please report it privately rather than opening a public issue — see Contributing.
Development
Testing standards
Unit tests target ~100% coverage for inventory, adapters, parsing, and validation
Integration tests use Testcontainers / Docker Compose (Ubuntu, Alpine, Grafana, Prometheus, Loki)
Every tool is exercised through a real MCP protocol round-trip (
mcp.NewInMemoryTransports()), not just unit-tested in isolation
Performance goals
SSH/Telnet connection pooling
Parallel execution
Context cancellation everywhere
Streaming responses
Timeout and retry support
Code conventions
Small packages, dependency injection, no globals, prefer interfaces
context.Contexteverywherelog/slogfor loggingAvoid reflection when possible
Functions under ~50 lines when practical
Structured errors, never raw ones
Document exported functions
Never expose credentials to the MCP layer
Never hardcode infrastructure — always resolve through inventory
Adding a new integration? See docs/ADDING_AN_ADAPTER.md for the full walkthrough.
CI/CD
Two GitHub Actions workflows, both required for anyone contributing:
ci.yml — required for every PR into main
Runs on every pull request and on push to main:
test —
go build ./...,go vet ./..., agofmt -lformatting check, andgo test ./... -race -coverlint —
golangci-lintagainst.golangci.yml(errcheck, staticcheck, govet, gosec, and more)
Branch protection on main must be configured by a repo admin (this is a repository setting, not something a workflow file can enforce) to require both the test and lint jobs to pass, and to require a pull request before merging — that gate only takes effect once the setting is turned on.
The release pipeline is designed to work with protected main: it creates and pushes only the release tag, creates the GitHub release from that tag, and opens a separate PR for CHANGELOG.md updates.
release.yml — runs on every merge to main
Version + tag — Cocogitto reads Conventional Commits since the last tag (config:
cog.toml) and computes the next semver. The workflow then creates and pushes thevX.Y.Ztag (no direct commit push tomain). A merge with no releasable commits (e.g. docs/chore-only) skips the rest of the pipeline.Build & scan — builds the Docker image and scans it with Trivy before publishing; a CRITICAL/HIGH finding blocks the release. Results are uploaded to the repo's Security tab either way.
Publish — once the scan is clean, builds and pushes the multi-arch (
linux/amd64,linux/arm64) image toghcr.io/<org>/infrastructure-mcp, taggedlatestandvX.Y.Z.Changelog PR — the workflow regenerates
CHANGELOG.mdand opens an automated PR so changelog updates still go through normal branch protection and review.
Commit messages therefore need to follow Conventional Commits (feat:, fix:, docs:, chore:, ...) — see Contributing.
Roadmap
Shipped: Linux · Docker · Kubernetes · Grafana · Proxmox · Cisco Not started: MikroTik · UniFi · Prometheus/Loki/Tempo/Alertmanager · Home Assistant · AI-composite tools · AWS/Azure/GCP/VMware/...
Implemented versions are listed under Current Features and tracked feature-by-feature in PROGRESS.md. Everything below is not started.
v0.7 — Networking (in progress: Cisco shipped, MikroTik/UniFi remain)
MikroTik: backup, interfaces, routes, firewall, system resources
UniFi: devices, clients, AP status, firmware, statistics
Note: Telnet transport and SSH legacy-crypto support for these vendors already shipped ahead of schedule in v0.1 — only the vendor-specific tools above remain.
v0.8 — Monitoring
Prometheus, Loki, Tempo, Alertmanager
v0.9 — Home Assistant
entitiesdevicesautomationssensorscameras
v1.0 — AI-oriented composite tools
Instead of calling 15 low-level tools, the agent calls one expert tool that composes them:
diagnose_linux()diagnose_docker()diagnose_kubernetes()diagnose_network()diagnose_storage()morning_brief()incident_summary()root_cause_analysis()backup_everything()check_infrastructure()
Further out
AWS, Azure, GCP, VMware, TrueNAS, Ceph, Synology, IPMI, Redfish, OpenStack, Nomad, Consul.
Contributing
Contributions are welcome — this is an early-stage project and there's a lot of surface area left on the roadmap above.
Fork the repo and create a feature branch.
Follow the existing package/adapter pattern: one isolated package per integration under
internal/, a matching set of tools undermcp/tools/, wired intocmd/server/main.go— seedocs/ADDING_AN_ADAPTER.mdfor the full walkthrough.Match the existing conventions: structured errors via
internal/toolerr, structured logging via thewithLoggingwrapper, inventory-driven targets, no shell interpolation of user input.Add tests — unit tests for adapters/parsing, and at least one test that exercises new tools through the real MCP protocol.
Run
go build ./... && go vet ./... && gofmt -l . && go test ./... -race -coverand, if you have it installed,golangci-lint run ./...before opening a PR — this is exactly whatci.ymlruns, and it's a required, non-optional check on every PR intomain(see CI/CD).Use Conventional Commits for your commit messages (
feat:,fix:,docs:,chore:,refactor:,test:,ci:, ...) — the version bump,CHANGELOG.md, and release on merge are generated automatically from them.Open a pull request describing what changed and why. For an architectural decision (not just "add tool #N following the existing pattern"), add an ADR under
docs/adr/.
For larger changes (a new adapter, a new version's worth of tools), consider opening an issue first to discuss the approach.
License
Licensed under the MIT License — free to use, modify, and distribute, including commercially.
A Note on How This Project Is Built
This project is vibe-coded: the vast majority of the implementation — code, tests, commit-by-commit progress — is written by AI (Claude Code), iterating directly against this README as the specification.
The design and architecture are human-authored by the repository owner: the layering (MCP → adapters → foundation), the inventory-driven philosophy, the tool-design rules, the security posture, and the version roadmap were all decided by a person before any code was written. AI implements against that spec; it doesn't set the direction.
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.
Related MCP Servers
- AlicenseBqualityAmaintenanceProvides policy-driven, auditable SSH access to server fleets for AI assistants with zero-trust security controls, command whitelisting, and comprehensive audit logging to safely manage infrastructure.Last updated1326Apache 2.0
- Alicense-qualityCmaintenanceEnables AI assistants to securely execute SSH commands on remote servers with connection pooling, session isolation, and a web audit panel.Last updated3MIT
- Alicense-qualityBmaintenanceGive Claude direct access to your AWS account, SSH into your servers, run shell commands on your laptop, query your databases, and manage PM2 processes — all from a Claude chat. No Claude Code subscription needed. Your keys never leave your machine.Last updated1MIT
- AlicenseAqualityBmaintenanceStateful, structured, safe shell sessions for AI agents, on real infrastructure.Last updated67Apache 2.0
Related MCP Connectors
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
Issue, rotate and revoke scoped API-key passes for 25+ providers — the agent never sees a real key
Pay-per-call cybersecurity for AI agents: vuln scans, threat intel, compliance, code security.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/radumalica/infrastructure-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server