New:Socket for Asana Is Now Available.Learn more
Get Started

@systemdox/runbook-mcp

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@systemdox/runbook-mcp

Your runbooks, as agent tools. Declare scripts in a runbooks.json manifest and serve them to Claude Code, Cursor and any MCP client as typed, allowlisted tools - no free text ever reaches your shell.

latest
Source
npmnpm
Version
0.1.2
Version published
Maintainers
1
Created
Source

@systemdox/runbook-mcp

Your runbooks, as agent tools.

SystemDox gives AI coding agents your architecture context — the checks, rules, decisions and docs that say what good looks like. This server gives them hands, safely: declare the scripts your team already runs in a runbooks.json manifest, and every one of them becomes an MCP tool with a typed, allowlisted input schema that Claude Code, Cursor and any other MCP client can call.

No free text ever reaches your shell. That is the whole design.

// runbooks.json
{
  "version": 1,
  "runbooks": [
    {
      "name": "sync_repos",
      "description": "Fetch every repo and fast-forward clean checkouts. Run before researching a repository.",
      "script": "ops/sync-repos.ps1",
      "interpreter": "powershell",
      "params": {
        "reportOnly": { "type": "boolean", "flag": "-ReportOnly", "description": "Fetch and report; change nothing." }
      }
    }
  ]
}

Result, as the agent sees it:

sync_repos(reportOnly?: boolean)
  "Fetch every repo and fast-forward clean checkouts. Run before researching a repository.
   Runs sync-repos.ps1 (powershell); timeout 300s."

Why not just give the agent a shell?

A shell is an unbounded surface: any command, any argument, no record of which ones the team sanctioned. A runbook server is a declared surface:

An agent with a shellAn agent with runbooks
Runs anything it can typeRuns only the scripts in the manifest
Composes arguments as free textFills typed parameters that must match a pattern or an enum
No timeouts, unbounded outputPer-runbook timeout, bounded output (the tail, with the drop reported)
Nothing tells the client what is safereadOnly / destructive / idempotent annotations on every tool
The operator learns what ran afterwardsEvery result starts with the exact command line that ran

The manifest is the contract. Agents cannot extend it; they can only call what it offers, with what it allows.

Quick start

npx @systemdox/runbook-mcp init       # writes runbooks.json + runbooks/hello.mjs
npx @systemdox/runbook-mcp validate   # shows exactly what agents will get

Then register the server with your MCP client. Claude Code, project scope (.mcp.json in the repository root):

{
  "mcpServers": {
    "runbooks": {
      "command": "npx",
      "args": ["-y", "@systemdox/runbook-mcp", "--manifest", "./runbooks.json"]
    }
  }
}

Restart the client and ask: "List the runbooks you have and run hello with name set to the team."

The manifest is found via --manifest <path>, then $RUNBOOK_MCP_MANIFEST, then ./runbooks.json in the working directory.

Manifest reference

Runbook

FieldRequiredDefaultMeaning
nameyesTool name; snake_case (^[a-z][a-z0-9_]{0,63}$)
descriptionyesWhat it does and when to use it — this is what the agent reads
scriptyesPath to the script, relative to the manifest (absolute allowed)
interpreteryespowershell, pwsh, bash, sh, node, python or exe
cwdnomanifest folderWorking directory, relative to the manifest
timeoutSecondsno300Hard limit; the whole process tree is killed when it passes
maxOutputCharsno60000Per stream. The tail is kept and the drop is reported
envnoExtra environment for the script (literal values — put secrets in the client's env)
readOnly / destructive / idempotentnofalsePublished as MCP tool annotations
paramsno{}The tool's input schema — see below

Parameter

Every parameter maps to one of: a fixed flag from the manifest, or a positional argument. Booleans emit their flag when true and nothing when false.

FieldApplies toMeaning
typeallboolean, string, number or array (of strings)
flagallThe literal flag to emit, e.g. --name or -ReportOnly (^-{1,2}[A-Za-z][A-Za-z0-9-]*$)
positionalstring, number, arrayEmit the value without a flag
requiredallRefuse the call when missing
defaultallApplied when the agent omits the argument; must satisfy the constraint
descriptionallShown to the agent
patternstring, arrayAnchored regex (^...$) every value must match
enumstring, arrayThe only values accepted
integer, minimum, maximumnumberBounds
joinarrayEmit one flag with the items joined by this separator instead of repeating the flag
maxItemsarrayUpper bound on the number of items

A string or array parameter must declare pattern or enum. There is no "any string" parameter type. Values containing a double quote or a control character are refused whatever the pattern says.

Interpreters

interpreterRunsWindows default
powershellpowershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "& '<script>' <args>; exit $LASTEXITCODE"Windows PowerShell 5.1 (pwsh elsewhere)
pwshsame, via PowerShell 7pwsh
bash / sh<bash> <script> <args>Git for Windows bash ($RUNBOOK_MCP_BASH to override)
nodethe running Node binary
pythonpython <script> <args>python (python3 elsewhere)
exethe script itself is the executable

Override any of them per manifest:

"interpreters": { "bash": "C:\\Program Files\\Git\\bin\\bash.exe" }

PowerShell scripts are invoked through -Command rather than -File because -File cannot bind array parameters and cannot set the console encoding. Every value is single-quoted, with embedded quotes doubled — inside single quotes PowerShell performs no expansion, so a value that passed its pattern cannot change the shape of the command. Array parameters arrive as real PowerShell arrays (-Keep 'a','b'). All other interpreters receive an argument array directly; nothing goes through a shell.

What the agent gets back

clean_worktrees: exit 0 (41.3s)
$ powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "... & 'C:\ops\clean-worktrees.ps1' -ReportOnly -Match 'sdx*'; exit $LASTEXITCODE"

--- stdout ---
Would delete 7 worktrees (3 held back: uncommitted changes)
...

A non-zero exit, a timeout or a process that failed to start comes back as an MCP error result with the same layout, so the agent can read the log and decide — it is never a protocol error.

Safety model

  • Declared surface. Only manifest entries are callable; the agent cannot add scripts, flags or arguments.
  • Allowlisted values. Strings and arrays must match an anchored pattern or an enum; numbers are bounded; booleans are flags. Double quotes and control characters are refused regardless.
  • No shell. POSIX-style interpreters get an argv array; PowerShell gets single-quoted tokens.
  • Bounded. Per-runbook timeout with process-tree kill; per-stream output cap keeping the tail.
  • Fail closed. The server refuses to start if the manifest is invalid or any script is missing — validate tells you first.
  • Secrets stay in the client. Pass them through the MCP client's env (for example "${SENTRY_ACCESS_TOKEN}" in Claude Code's .mcp.json); the manifest holds literals only.
  • Dry run. RUNBOOK_MCP_DRY_RUN=1 makes every tool report the command it would run instead of running it — useful in CI and when reviewing a new manifest.

Composing with SystemDox

The manifest says what the agent can run. The when belongs in your standards, where every agent in every repository reads it at write time:

  • a SystemDox project rule"Run sync_repos before researching a repository checkout; research the fresh tree, never a stale one";
  • a prompt template for incident investigation that names the Sentry and CloudWatch tools to call and the runbook to run afterwards.

One .mcp.json then carries the whole toolbelt:

{
  "mcpServers": {
    "systemdox": {
      "type": "http",
      "url": "https://<your-workspace>.mcp.systemdox.com/mcp",
      "headers": { "Authorization": "Bearer ${SYSTEMDOX_API_KEY}" }
    },
    "runbooks": {
      "command": "npx",
      "args": ["-y", "@systemdox/runbook-mcp", "--manifest", "./runbooks.json"]
    },
    "sentry": {
      "command": "npx",
      "args": ["-y", "@sentry/mcp-server@latest", "--host=de.sentry.io"],
      "env": { "SENTRY_ACCESS_TOKEN": "${SENTRY_ACCESS_TOKEN}" }
    },
    "cloudwatch": {
      "command": "uvx",
      "args": ["awslabs.cloudwatch-mcp-server@latest"],
      "env": { "AWS_REGION": "eu-west-2", "AWS_PROFILE": "${AWS_PROFILE:-default}" }
    }
  }
}

Full guide: Runbooks as agent tools.

CLI

systemdox-runbook-mcp [--manifest <path>]   Start the MCP server (stdio)
systemdox-runbook-mcp init                   Write a starter manifest and example script
systemdox-runbook-mcp validate               Check the manifest; list tools and the command each would run
systemdox-runbook-mcp --help | --version
Environment variablePurpose
RUNBOOK_MCP_MANIFESTManifest path (alternative to --manifest)
RUNBOOK_MCP_DRY_RUN=1Report commands instead of running them
RUNBOOK_MCP_BASHPath to bash.exe on Windows

Library use

import { loadManifest, createServer } from "@systemdox/runbook-mcp";

const server = createServer(loadManifest("./runbooks.json"));
// connect it to any transport from @modelcontextprotocol/sdk

License

ISC — PuglieseWeb LTD.

Keywords

mcp

FAQs

Package last updated on 30 Aug 2026

Related posts