{
  "markdown": "# runframe-mcp-server\n\n[![CI](https://github.com/runframe/runframe-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/runframe/runframe-mcp-server/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/@runframe/mcp-server)](https://npmjs.com/package/@runframe/mcp-server)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Node 20+](https://img.shields.io/badge/node-≥20-brightgreen)](https://nodejs.org)\n\n**[Runframe](https://runframe.io)** is the complete incident lifecycle platform for engineering teams, covering incident response, on-call, and status pages. This MCP server lets you manage those workflows from your IDE or AI agent.\n\n17 tools covering incidents, on-call, services, postmortems, teams, and people lookup. Requires Node.js 20+.\n\n## Why Use This\n\n- **Stay in your editor** — acknowledge incidents, page responders, and write postmortems without switching to a browser\n- **Let agents handle the routine** — AI agents can triage, escalate, and update incidents autonomously using scoped API keys\n- **Zero infrastructure** — runs via `npx`, no server to deploy for local use\n\n## How It Works\n\n```\nYour IDE / Agent\n    ↓ (stdio or HTTP)\nMCP Server (this package)\n    ↓ (HTTPS, scoped API key)\nRunframe API\n```\n\nThe server is stateless. It translates MCP tool calls into Runframe API requests, scoped by your API key permissions. No data is stored locally.\n\n## Examples\n\nAsk your agent:\n\n- *\"Acknowledge incident INC-2026-001\"* → calls `runframe_acknowledge_incident`\n- *\"Who is on call right now?\"* → calls `runframe_get_current_oncall`\n- *\"Create a postmortem for the database outage\"* → calls `runframe_create_postmortem`\n- *\"Page the backend team lead about the API latency spike\"* → calls `runframe_page_someone`\n- *\"List all open SEV1 incidents\"* → calls `runframe_list_incidents` with severity filter\n- *\"Find Alex so I can check their open incidents\"* → calls `runframe_find_user`\n\n## Install\n\nGet your API key from settings inside [Runframe.io](https://runframe.io), then add to your agent:\n\n**Claude Code:**\n\n```bash\nclaude mcp add runframe -e RUNFRAME_API_KEY=rf_your_key_here -- npx -y @runframe/mcp-server\n```\n\n**Cursor** (`~/.cursor/mcp.json`) · **VS Code** (`.vscode/mcp.json`) · **Claude Desktop** (`claude_desktop_config.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"runframe\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@runframe/mcp-server\"],\n      \"env\": { \"RUNFRAME_API_KEY\": \"rf_your_key_here\" }\n    }\n  }\n}\n```\n\n**Other MCP clients:** Add the JSON config above to your client's MCP config file.\n\n**Interactive setup wizard:**\n\n```bash\nnpx @runframe/mcp-server --setup\n```\n\n## Environment Variables\n\n| Variable | Required | Default | Description |\n|----------|----------|---------|-------------|\n| `RUNFRAME_API_KEY` | Yes | — | API key (starts with `rf_`) |\n| `RUNFRAME_API_URL` | No | `https://runframe.io` | API base URL |\n| `MCP_ACCESS_TOKEN` | HTTP only | — | Bearer token for HTTP transport. Comma-separated for rotation (`new_token,old_token`). |\n\n## Transports\n\n**stdio** (default) — used by MCP clients like Claude Code and Cursor. No network exposure. This is what the install commands above configure.\n\n**Streamable HTTP** — for containerized or remote deployments. Requires `MCP_ACCESS_TOKEN` for bearer auth:\n\n```bash\nRUNFRAME_API_KEY=rf_... \\\n  MCP_ACCESS_TOKEN=your_token \\\n  npx @runframe/mcp-server --transport http --port 3100 --host 127.0.0.1\n```\n\n## Security Model\n\nResponsibility is split across three boundaries:\n\n- **Runframe API** handles authorization and scopes via `RUNFRAME_API_KEY`.\n- **This MCP server** handles process isolation (stdio) and bearer-token validation (HTTP). It also enforces method filtering, Host/Origin checks on localhost, declared Content-Length validation (1 MB limit), 8 KB header limit, and 15s upstream timeout.\n- **Your reverse proxy** handles TLS, rate limiting, and streamed-body enforcement if you expose HTTP mode to a network.\n\nThe server stores nothing. It is a pass-through to the Runframe API.\n\n## Tools\n\n### Incidents (9)\n\n| Tool | Scopes | Description |\n|------|--------|-------------|\n| `runframe_list_incidents` | `incidents:read` | List incidents with filters and pagination |\n| `runframe_get_incident` | `incidents:read` | Get incident by ID or number |\n| `runframe_create_incident` | `incidents:write` | Create an incident |\n| `runframe_update_incident` | `incidents:write` | Update title, description, severity, or assignment |\n| `runframe_change_incident_status` | `incidents:write` | Move to a new status (new, investigating, fixing, monitoring, resolved, closed) |\n| `runframe_acknowledge_incident` | `incidents:write` | Acknowledge (auto-assigns, tracks SLA) |\n| `runframe_add_incident_event` | `incidents:write` | Add a timeline entry |\n| `runframe_escalate_incident` | `incidents:write` | Escalate to the next policy level |\n| `runframe_page_someone` | `incidents:write` | Page a responder via Slack or email |\n\n### On-call (1)\n\n| Tool | Scopes | Description |\n|------|--------|-------------|\n| `runframe_get_current_oncall` | `oncall:read` | Who is on call right now |\n\n### Services (2)\n\n| Tool | Scopes | Description |\n|------|--------|-------------|\n| `runframe_list_services` | `services:read` | List services |\n| `runframe_get_service` | `services:read` | Get service details |\n\n### Postmortems (2)\n\n| Tool | Scopes | Description |\n|------|--------|-------------|\n| `runframe_create_postmortem` | `postmortems:write` | Create a postmortem |\n| `runframe_get_postmortem` | `postmortems:read` | Get postmortem for an incident |\n\n### Teams (2)\n\n| Tool | Scopes | Description |\n|------|--------|-------------|\n| `runframe_list_teams` | `teams:read` | List teams |\n| `runframe_get_escalation_policy` | `oncall:read` | Get escalation policy for a severity level |\n\n### Users (1)\n\n| Tool | Scopes | Description |\n|------|--------|-------------|\n| `runframe_find_user` | `users:read` | Search users by name or email, with optional inactive-user support for historical lookups |\n\n## Direct API alignment\n\nThis MCP server follows the public Runframe direct API contract.\n\n- Incident create requires `service_ids` containing public service keys like `svc_K7M4Q9TZ2H`, not internal UUIDs.\n- `runframe_get_service` now looks up services by public `service_key`, not UUID.\n- Incident tools now follow the latest V1 contract: use incident numbers like `INC-2026-001` in path parameters.\n- Incident update and list filters now use the latest public identifiers where V1 does: assignee/resolver email and `team_name`.\n- `runframe_create_incident` accepts an optional `idempotency_key`, which is forwarded as the `Idempotency-Key` header for retry-safe creates.\n- `runframe_create_incident` defaults `severity` to `SEV2` when omitted, matching the V1 API.\n- Incident create now mirrors the V1 API limits: `title` must be 1-200 chars, `description` maxes at 10000 chars, and `service_ids` allows at most 50 items.\n- Incident creation depends on valid SLA configuration for the requested severity. If acknowledge or closure deadlines are missing, the API rejects the create.\n- Use `runframe_list_services` to discover valid `service_key` values before creating incidents.\n- `runframe_page_someone` now uses the latest V1 delivery contract: `email`, `channels`, and optional `message`.\n- Postmortem tools now follow the latest V1 contract: use `incident_number` and snake_case nested fields like `users_affected`, `owner_email`, and `time_to_acknowledge`.\n- Use `runframe_find_user` to resolve a person name to an email address before filtering incidents by `assigned_to` or `resolved_by`.\n- Set `include_inactive=true` on `runframe_find_user` when you need to resolve former employees in historical incident queries.\n- Set `is_active=true` or `is_active=false` on `runframe_find_user` when you need an explicit V1 active-state filter.\n- Use `runframe_list_teams` with `search` to resolve the exact `team_name` before filtering incidents.\n\n## Docker\n\nThe Docker image runs HTTP transport by default on port 3100:\n\n```bash\ndocker build -t runframe-mcp-server .\ndocker run -e RUNFRAME_API_KEY=rf_... -e MCP_ACCESS_TOKEN=your_token -p 3100:3100 runframe-mcp-server\n```\n\n## Deploying HTTP Mode\n\nHTTP mode is meant for private networks. If you put it on the internet:\n\n- Run behind TLS (nginx, Caddy, cloud LB). This server does not do TLS.\n- Use a reverse proxy for rate limiting and request buffering.\n- Prefer private subnets or VPNs over public exposure.\n- Rotate `MCP_ACCESS_TOKEN` regularly. Pass old and new tokens comma-separated for zero-downtime swaps.\n\n### Rate limiting\n\nThe Runframe API enforces rate limits server-side. If you hit a limit, tools return a 429 error with a retry hint. For HTTP transport deployments, your reverse proxy can add additional request-level throttling.\n\n### Token rotation\n\n`MCP_ACCESS_TOKEN` accepts comma-separated tokens:\n\n1. Set `MCP_ACCESS_TOKEN=new_token,old_token`\n2. Update clients to `new_token`\n3. Drop the old one: `MCP_ACCESS_TOKEN=new_token`\n\n## Limitations\n\n- Read-only for schedules — you can query on-call and escalation policies but not modify them via MCP\n- Requires a [Runframe](https://runframe.io) account and API key\n\n## Contributing\n\nIssues and PRs welcome at [github.com/runframe/runframe-mcp-server](https://github.com/runframe/runframe-mcp-server).\n\n## License\n\nMIT — [Runframe](https://runframe.io) · [npm](https://npmjs.com/package/@runframe/mcp-server)\n",
  "bytes": 9471,
  "sha": "17c6c18f1a07424d3e2a065367a22ffbd18cd3693093695c6dd3e9271a53273d",
  "repo_slug": "runframe/runframe-mcp-server",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_runframe_runframe_mcp_server_ee68374a/readme"
}