Skip to main content
Glama
PanuwatChinpratan

safe-runbook-mcp

README.md
# safe-runbook-mcp

A policy-gated MCP server for operational runbooks. It lets an AI inspect and run known commands without giving it an unrestricted shell.

## Why it exists

AI agents are useful for operations, but handing one a terminal is a large trust decision. This project keeps the useful part—repeatable diagnostics and maintenance—inside a small, reviewable boundary:

`AI client → inspect plan → policy checks → optional human approval → exact command`

## Safety model

- Runbooks are version-controlled JSON; the AI cannot invent a command.
- Execution is off by default.
- Executables must be explicitly allowlisted.
- Variables are regex-validated and become complete process arguments.
- Commands run with `shell: false` inside a realpath-confined workspace.
- Mutating and destructive plans require a short-lived HMAC approval token created outside MCP.
- The token is bound to the runbook and exact plan hash, so changed inputs invalidate it.
- Processes have time and output limits; declared secrets are redacted.

MCP tool annotations are also provided for clients, while server-side checks remain the authority.

## Stack

TypeScript 7, Node.js 22, MCP TypeScript SDK v2, Zod 4, Vitest 4, Biome 2, Docker, and GitHub Actions. The project is open source and has no paid API dependency.

## Quick start

```bash
npm install
npm run cli -- list
npm run cli -- plan docker-service-status --var service=api
npm test
```

Execution must be enabled explicitly:

```bash
RUNBOOK_EXECUTION_ENABLED=true npm run cli -- run disk-usage
```

For a mutating runbook, generate approval outside the MCP connection and use the same variables for approval and execution:

```bash
export RUNBOOK_EXECUTION_ENABLED=true
export RUNBOOK_APPROVAL_SECRET='replace-with-a-long-random-secret'

TOKEN=$(npm run --silent cli -- approve restart-compose-service --var service=api)
npm run cli -- run restart-compose-service --var service=api --approval "$TOKEN"
```

## Connect an MCP client

Build once, then add this stdio server to an MCP-compatible client. Replace the paths with absolute paths on your machine.

```json
{
  "mcpServers": {
    "safe-runbooks": {
      "command": "node",
      "args": ["/absolute/path/safe-runbook-mcp/dist/server.js"],
      "env": {
        "RUNBOOK_DIRECTORY": "/absolute/path/safe-runbook-mcp/runbooks",
        "RUNBOOK_WORKSPACE": "/workspace/to/manage",
        "RUNBOOK_EXECUTION_ENABLED": "false"
      }
    }
  }
}
```

The server exposes:

- `list_runbooks` — discover available runbooks and risk levels.
- `inspect_runbook` — resolve variables and return the exact plan plus its hash.
- `execute_runbook` — execute the already-defined plan after policy checks.
- `runbook://catalog` — read-only catalog resource.

Logs go to stderr because stdout is reserved for MCP JSON-RPC traffic.

## Add a runbook

Create a JSON file in `runbooks/`:

```json
{
  "id": "service-status",
  "title": "Inspect a service",
  "description": "Read one Compose service state.",
  "risk": "diagnostic",
  "variables": {
    "service": {
      "description": "Compose service name",
      "pattern": "[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}",
      "required": true
    }
  },
  "steps": [
    {
      "id": "status",
      "title": "Read status",
      "executable": "docker",
      "args": ["compose", "ps", "{{service}}"]
    }
  ]
}
```

Choose `diagnostic`, `mutating`, or `destructive`. Variables must occupy a complete argument such as `"{{service}}"`; string interpolation is intentionally rejected.

## Docker

```bash
docker build -t safe-runbook-mcp .
docker run --rm -i \
  -v "$PWD:/workspace:ro" \
  -e RUNBOOK_WORKSPACE=/workspace \
  -e RUNBOOK_DIRECTORY=/app/runbooks \
  safe-runbook-mcp
```

Keep execution disabled for a read-only mount. If a runbook needs Docker, mount only the required socket or remote context after reviewing that trust boundary.

## Development

```bash
npm run check
npm run typecheck
npm test
npm run build
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for the branch workflow and [AGENTS.md](AGENTS.md) for repository rules used by coding agents.

## References

- [MCP TypeScript SDK packages](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/get-started/packages.md)
- [Build an MCP server](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/server.md)
- [Serve over stdio](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/serving/stdio.md)

## License

MIT

TDQS

A4.2/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: inspect validates and previews, execute runs commands, and list enumerates available runbooks. There is no overlap or ambiguity between them.

Naming Consistency5/5

All three tool names follow a consistent verb_noun pattern: inspect, execute, and list all pair with 'runbook'. The naming is uniform and predictable.

Tool Count4/5

With only three tools, the server is lean but covers the essential operations for runbook management: discover, preview, and execute. It is slightly minimal but appropriate for a focused purpose.

Completeness4/5

The server provides the core lifecycle for runbooks: list, inspect, and execute. Missing are update/delete operations, but since runbooks are version-controlled externally, those may be intentionally out of scope. No critical gaps for safe execution.

Maintenance

ActivityMaintained
ResponsivenessNo issues