{
  "markdown": "# mcp-ssh-fleet\n\n**English** | [Русский](README.ru.md)\n\n[![Version](https://img.shields.io/github/v/tag/inhuman/mcp-ssh-fleet?sort=semver&style=flat-square&label=version)](https://github.com/inhuman/mcp-ssh-fleet/tags)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.inhuman%2Fmcp--ssh--fleet-blue?style=flat-square)](https://registry.modelcontextprotocol.io)\n[![Container](https://img.shields.io/badge/ghcr.io-inhuman%2Fmcp--ssh--fleet-2496ED?style=flat-square&logo=github)](https://github.com/inhuman/mcp-ssh-fleet/pkgs/container/mcp-ssh-fleet)\n[![Build](https://img.shields.io/github/actions/workflow/status/inhuman/mcp-ssh-fleet/docker-publish.yml?style=flat-square&logo=github)](https://github.com/inhuman/mcp-ssh-fleet/actions/workflows/docker-publish.yml)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/inhuman/mcp-ssh-fleet?style=flat-square&logo=go)](https://go.dev/)\n[![Go Report Card](https://goreportcard.com/badge/github.com/inhuman/mcp-ssh-fleet?style=flat-square)](https://goreportcard.com/report/github.com/inhuman/mcp-ssh-fleet)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)](LICENSE)\n[![Issues](https://img.shields.io/github/issues/inhuman/mcp-ssh-fleet?style=flat-square)](https://github.com/inhuman/mcp-ssh-fleet/issues)\n[![Last Commit](https://img.shields.io/github/last-commit/inhuman/mcp-ssh-fleet?style=flat-square)](https://github.com/inhuman/mcp-ssh-fleet/commits/main)\n\nMCP server that gives an agent two tools over SSH to a fleet of hosts outside\nKubernetes. The SSH key is a mounted secret (never enters model context); the\ninventory is a fail-closed allowlist.\n\n## Tools\n\n- **`ssh_probe(tags, check)`** — curated read-only diagnostics on every host\n  carrying the given tags (AND semantics, like GitLab runner tags). `check` is\n  one of a built-in set: `uptime`, `disk`, `mem`, `failed`, `logs`. Arbitrary\n  commands cannot be passed. Class: `read-only`.\n- **`ssh_exec(host, command)`** — one arbitrary non-interactive command on ONE\n  inventory host (by name or address; hosts outside the inventory are refused).\n  Class: `write-external`: the server executes the command, while access gating\n  (approval/RBAC) belongs to the MCP client.\n\nBoth: output size cap, per-host timeout, TOFU host-key check (fingerprint in\nlogs), output as one section per host.\n\n## Configuration (env)\n\n| Variable | Default | Meaning |\n|---|---|---|\n| `SSH_FLEET_TRANSPORT` | `http` | `http` (StreamableHTTP, endpoint `/mcp`) \\| `sse` \\| `stdio` |\n| `SSH_FLEET_ADDR` | `:8080` | listen address for http/sse |\n| `SSH_FLEET_AUTH_TOKEN` | — | optional `X-MCP-AUTH` token |\n| `SSH_FLEET_INVENTORY_PATH` | `/etc/ssh-fleet/inventory.yaml` | path to the inventory (configmap) |\n| `SSH_FLEET_KEY_PATH` | `/etc/ssh-fleet/id_ed25519` | path to the private key (secret) |\n| `SSH_FLEET_OUTPUT_CAP_BYTES` | `8192` | output cap per section |\n| `SSH_FLEET_CMD_TIMEOUT_SECONDS` | `20` | per-host timeout |\n| `SSH_FLEET_PROBE_CONCURRENCY` | `8` | probe parallelism pool |\n| `SSH_FLEET_PROBE_MAX_HOSTS` | `50` | safety cap on hosts per probe |\n\nInventory format — see `deploy/inventory.example.yaml`.\n\n## Quickstart (docker, stdio)\n\n```sh\ndocker run -i --rm \\\n  -v /path/to/inventory.yaml:/etc/ssh-fleet/inventory.yaml:ro \\\n  -v /path/to/id_ed25519:/etc/ssh-fleet/id_ed25519:ro \\\n  -e SSH_FLEET_TRANSPORT=stdio \\\n  ghcr.io/inhuman/mcp-ssh-fleet:latest\n```\n\nThis is the shape MCP clients use when installing from the\n[MCP Registry](https://registry.modelcontextprotocol.io)\n(`io.github.inhuman/mcp-ssh-fleet`).\n\n## Connecting an MCP client (http/sse)\n\nBy default the server speaks StreamableHTTP; register it as a regular HTTP MCP\nserver with endpoint `/mcp` (URL like `http://<host>:8080/mcp`). Both tools\nbecome available to the client.\n\nClient-side security recommendations:\n\n- `ssh_probe` is `read-only` (curated checks only) and can be granted broadly.\n- `ssh_exec` is arbitrary execution (`write-external`). Gate its access on the\n  client side (approval / RBAC / user allowlist) — the server merely executes a\n  command on an inventory host; it does not decide access policy.\n\n## Development\n\n```sh\nmake test        # unit tests + e2e against a real in-process SSH server\nmake vet\nmake vulncheck\nmake build\nmake docker\n```\n\nRelease: tag `vX.Y.Z` → GitHub Actions builds and publishes a multi-arch image\nto `ghcr.io/inhuman/mcp-ssh-fleet`.\n",
  "bytes": 4410,
  "sha": "55a77b5966d3b1b5256877731bf8a5bf47993304c3a6c048407d6fa34a8ce284",
  "repo_slug": "inhuman/mcp-ssh-fleet",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_inhuman_mcp_ssh_fleet_143ac533/readme"
}