io.github.runframe/runframe-mcp-server
MCP server for Runframe incident management covering incidents, on-call, postmortems, and more.
Open source Open in the app JSON README (API)
About
MCP server for Runframe incident management covering incidents, on-call, postmortems, and more.
Details
- Kind
- MCP servers
- Topic
- Cloud & DevOps
- Publisher
- runframe
- Origin
- official
- Category
- ferramentas
- Transport
- local
- Version
- 0.1.5
- Stars
- 4
- Forks
- 1
- Last push
- 2026-04-26T18:34:04Z
- Repository state
- ativo
- Language
- TypeScript
- License
- MIT
- Added
- 2026-08-29 04:01:19
- Updated
- 2026-08-29 04:01:19
- Origin id
io.github.runframe/runframe-mcp-server
README
# runframe-mcp-server
[](https://github.com/runframe/runframe-mcp-server/actions/workflows/ci.yml)
[](https://npmjs.com/package/@runframe/mcp-server)
[](LICENSE)
[](https://nodejs.org)
**[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.
17 tools covering incidents, on-call, services, postmortems, teams, and people lookup. Requires Node.js 20+.
## Why Use This
- **Stay in your editor** — acknowledge incidents, page responders, and write postmortems without switching to a browser
- **Let agents handle the routine** — AI agents can triage, escalate, and update incidents autonomously using scoped API keys
- **Zero infrastructure** — runs via `npx`, no server to deploy for local use
## How It Works
```
Your IDE / Agent
↓ (stdio or HTTP)
MCP Server (this package)
↓ (HTTPS, scoped API key)
Runframe API
```
The server is stateless. It translates MCP tool calls into Runframe API requests, scoped by your API key permissions. No data is stored locally.
## Examples
Ask your agent:
- *"Acknowledge incident INC-2026-001"* → calls `runframe_acknowledge_incident`
- *"Who is on call right now?"* → calls `runframe_get_current_oncall`
- *"Create a postmortem for the database outage"* → calls `runframe_create_postmortem`
- *"Page the backend team lead about the API latency spike"* → calls `runframe_page_someone`
- *"List all open SEV1 incidents"* → calls `runframe_list_incidents` with severity filter
- *"Find Alex so I can check their open incidents"* → calls `runframe_find_user`
## Install
Get your API key from settings inside [Runframe.io](https://runframe.io), then add to your agent:
**Claude Code:**
```bash
claude mcp add runframe -e RUNFRAME_API_KEY=rf_your_key_here -- npx -y @runframe/mcp-server
```
**Cursor** (`~/.cursor/mcp.json`) · **VS Code** (`.vscode/mcp.json`) · **Claude Desktop** (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"runframe": {
"command": "npx",
"args": ["-y", "@runframe/mcp-server"],
"env": { "RUNFRAME_API_KEY": "rf_your_key_here" }
}
}
}
```
**Other MCP clients:** Add the JSON config above to your client's MCP config file.
**Interactive setup wizard:**
```bash
npx @runframe/mcp-server --setup
```
## Environment Variables
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `RUNFRAME_API_KEY` | Yes | — | API key (starts with `rf_`) |
| `RUNFRAME_API_URL` | No | `https://runframe.io` | API base URL |
| `MCP_ACCESS_TOKEN` | HTTP only | — | Bearer token for HTTP transport. Comma-separated for rotation (`new_token,old_token`). |
## Transports
**stdio** (default) — used by MCP clients like Claude Code and Cursor. No network exposure. This is what the install commands above configure.
**Streamable HTTP** — for containerized or remote deployments. Requires `MCP_ACCESS_TOKEN` for bearer auth:
```bash
RUNFRAME_API_KEY=rf_... \
MCP_ACCESS_TOKEN=your_token \
npx @runframe/mcp-server --transport http --port 3100 --host 127.0.0.1
```
## Security Model
Responsibility is split across three boundaries:
- **Runframe API** handles authorization and scopes via `RUNFRAME_API_KEY`.
- **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.
- **Your reverse proxy** handles TLS, rate limiting, and streamed-body enforcement if you expose HTTP mode to a network.
The server stores nothing. It is a pass-through to the Runframe API.
## Tools
### Incidents (9)
| Tool | Scopes | Description |
|------|--------|-------------|
| `runframe_list_incidents` | `incidents:read` | List incidents with filters and pagination |
| `runframe_get_incident` | `incidents:read` | Get incident by ID or number |
| `runframe_create_incident` | `incidents:write` | Create an incident |
| `runframe_update_incident` | `incidents:write` | Update title, description, severity, or assignment |
| `runframe_change_incident_status` | `incidents:write` | Move to a new status (new, investigating, fixing, monitoring, resolved, closed) |
| `runframe_acknowledge_incident` | `incidents:write` | Acknowledge (auto-assigns, tracks SLA) |
| `runframe_add_incident_event` | `incidents:write` | Add a timeline entry |
| `runframe_escalate_incident` | `incidents:write` | Escalate to the next policy level |
| `runframe_page_someone` | `incidents:write` | Page a responder via Slack or email |
### On-call (1)
| Tool | Scopes | Description |
|------|--------|-------------|
| `runframe_get_current_oncall` | `oncall:read` | Who is on call right now |
### Services (2)
| Tool | Scopes | Description |
|------|--------|-------------|
| `runframe_list_services` | `services:read` | List services |
| `runframe_get_service` | `services:read` | Get service details |
### Postmortems (2)
| Tool | Scopes | Description |
|------|--------|-------------|
| `runframe_create_postmortem` | `postmortems:write` | Create a postmortem |
| `runframe_get_postmortem` | `postmortems:read` | Get postmortem for an incident |
### Teams (2)
| Tool | Scopes | Description |
|------|--------|-------------|
| `runframe_list_teams` | `teams:read` | List teams |
| `runframe_get_escalation_policy` | `oncall:read` | Get escalation policy for a severity level |
### Users (1)
| Tool | Scopes | Description |
|------|--------|-------------|
| `runframe_find_user` | `users:read` | Search users by name or email, with optional inactive-user support for historical lookups |
## Direct API alignment
This MCP server follows the public Runframe direct API contract.
- Incident create requires `service_ids` containing public service keys like `svc_K7M4Q9TZ2H`, not internal UUIDs.
- `runframe_get_service` now looks up services by public `service_key`, not UUID.
- Incident tools now follow the latest V1 contract: use incident numbers like `INC-2026-001` in path parameters.
- Incident update and list filters now use the latest public identifiers where V1 does: assignee/resolver email and `team_name`.
- `runframe_create_incident` accepts an optional `idempotency_key`, which is forwarded as the `Idempotency-Key` header for retry-safe creates.
- `runframe_create_incident` defaults `severity` to `SEV2` when omitted, matching the V1 API.
- 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.
- Incident creation depends on valid SLA configuration for the requested severity. If acknowledge or closure deadlines are missing, the API rejects the create.
- Use `runframe_list_services` to discover valid `service_key` values before creating incidents.
- `runframe_page_someone` now uses the latest V1 delivery contract: `email`, `channels`, and optional `message`.
- 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`.
- Use `runframe_find_user` to resolve a person name to an email address before filtering incidents by `assigned_to` or `resolved_by`.
- Set `include_inactive=true` on `runframe_find_user` when you need to resolve former employees in historical incident queries.
- Set `is_active=true` or `is_active=false` on `runframe_find_user` when you need an explicit V1 active-state filter.
- Use `runframe_list_teams` with `search` to resolve the exact `team_name` before filtering incidents.
## Docker
The Docker image runs HTTP transport by default on port 3100:
```bash
docker build -t runframe-mcp-server .
docker run -e RUNFRAME_API_KEY=rf_... -e MCP_ACCESS_TOKEN=your_token -p 3100:3100 runframe-mcp-server
```
## Deploying HTTP Mode
HTTP mode is meant for private networks. If you put it on the internet:
- Run behind TLS (nginx, Caddy, cloud LB). This server does not do TLS.
- Use a reverse proxy for rate limiting and request buffering.
- Prefer private subnets or VPNs over public exposure.
- Rotate `MCP_ACCESS_TOKEN` regularly. Pass old and new tokens comma-separated for zero-downtime swaps.
### Rate limiting
The 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.
### Token rotation
`MCP_ACCESS_TOKEN` accepts comma-separated tokens:
1. Set `MCP_ACCESS_TOKEN=new_token,old_token`
2. Update clients to `new_token`
3. Drop the old one: `MCP_ACCESS_TOKEN=new_token`
## Limitations
- Read-only for schedules — you can query on-call and escalation policies but not modify them via MCP
- Requires a [Runframe](https://runframe.io) account and API key
## Contributing
Issues and PRs welcome at [github.com/runframe/runframe-mcp-server](https://github.com/runframe/runframe-mcp-server).
## License
MIT — [Runframe](https://runframe.io) · [npm](https://npmjs.com/package/@runframe/mcp-server)