Skip to content

Firefight ships a Model Context Protocol server, so AI agents like Claude can take part in your incidents directly. An agent connected over MCP can search incidents, pull a full incident timeline, inspect alerts and how they routed, look up ownership in the service catalog, and dry-run your alert routing rules. With permission it can also work an incident the way a person does: declare one, raise and pick up work, claim a runbook step, pull people into the channel, ask a named person to respond, and close it out. It can maintain your catalog, runbooks and routing rules, and resolve approvals, too. Everything an agent does is recorded under Gateway → Activity.

The server speaks Streamable HTTP at a single endpoint.

POST https://app.firefight.app/mcp

Every request is self-contained, and all data is scoped to the workspace of the token you authenticate with.

There are three ways to connect, depending on what is doing the connecting.

Clients that support MCP OAuth, such as Claude Code, connect without you ever handling a token. Add the server and start using it.

Terminal window
claude mcp add --transport http firefight https://app.firefight.app/mcp

On first use, your browser opens Firefight’s consent screen, which names the client asking for access and the workspace it would reach. If you belong to more than one workspace, pick the one you want it to reach. Click Authorize and the client is connected. The client registers itself automatically through dynamic client registration, PKCE is required, and access tokens are short-lived with refresh rotation. The connection acts as you, with the same access you have in the workspace.

An AI that takes part in incidents gets its own identity rather than borrowing yours. Create it under Gateway → Agents, which hands you its token once, and configure your client to send that.

Terminal window
claude mcp add --transport http firefight https://app.firefight.app/mcp \
--header "Authorization: Bearer ff_4kWm2xPqR8vNcT6yBhJd3fLzGaU9sEnQoXwA"

Everything the agent does is recorded under its own name, so an incident it declared says the agent declared it, and an action item it picked up shows the agent holding it. It holds only the abilities you granted it, whatever access you have yourself. Agent tokens do not expire, because what a leaked one can do is bounded by its grants and its approval rules rather than by how soon it has to be renewed. Rotate one at any time from its row. See Agents.

Automation with nothing to say on a timeline passes a Firefight API key as a Bearer token instead. Create one under Settings → API Keys, then configure your client to send it.

Terminal window
claude mcp add --transport http firefight https://app.firefight.app/mcp \
--header "Authorization: Bearer ff_4kWm2xPqR8vNcT6yBhJd3fLzGaU9sEnQoXwA"

For Cursor, put the same thing in .cursor/mcp.json.

{
"mcpServers": {
"firefight": {
"url": "https://app.firefight.app/mcp",
"headers": { "Authorization": "Bearer ff_4kWm2xPqR8vNcT6yBhJd3fLzGaU9sEnQoXwA" }
}
}
}

Any other MCP client works the same way, either through OAuth discovery at /.well-known/oauth-protected-resource or with the Authorization: Bearer header.

A connection reaches one workspace, whichever way you authenticated. An OAuth connection is granted for the single workspace you picked on the consent screen, and an API key belongs to the workspace you created it in. There is no setting that widens a connection to cover more.

To give an agent a second workspace, add the server again under a different name.

Terminal window
claude mcp add --transport http firefight-acme https://app.firefight.app/mcp

Authorize that one and pick the second workspace on the consent screen. For a headless agent, create an API key in the second workspace and pass it the same way. Each connection stands on its own, so its tools appear under the name you gave it, and revoking one leaves the other working.

An agent is told which workspace it reaches as soon as it connects, so you can ask it directly rather than working it out from what it returns.

The Connected agents list under Settings → API Keys shows the connections for the workspace you are viewing. Switch workspaces to see the rest.

These tools read your workspace and change nothing.

ToolWhat it returns
search_incidentsIncident summaries, newest first. Filter by status, severity, lifecycle stage, free-text query, and declared-at time range.
get_incidentOne incident in full, by ID or identifier like INC-42. Details, timeline events, postmortem status, attached alerts, every incident role with whoever holds it, the open action items, and the attached runbooks with their steps.
search_alertsIngested alerts, newest first. Each shows its source, firing status, routing state, the rule that matched, and the incident it attached to.
search_catalogCatalog entries with their attributes and relationships, such as which team owns a service. Filter by type, name query, or exact slug.
evaluate_routingA dry run of alert routing against hypothetical alert fields. Returns the matching rule, the outcome, a per-condition trace, and warnings when a routing role your rules depend on is not set on any catalog attribute. Nothing is created or notified.
search_runbooksRunbook listings with name, summary, and step count. Filter by a name or summary query.
get_runbookOne runbook in full, by slug. The complete procedure content, ordered steps, and external link.
search_approvalsApproval requests and their status.
list_abilitiesEverything that can be granted, with its risk level and whether an approval rule can hold it.
list_principalsThe people, agents and service keys of the workspace, each with the grants it holds.
search_activityThe gateway’s audit log, filtered by decision or ability.
get_formOne lifecycle form and every field on it, hidden ones included, with each field’s type, whether it is visible, required, or locked, and any conditions gating it.
get_workspace_configHow the workspace is set up, in one call: severities, statuses with their lifecycle stage, incident types, incident roles, alert sources and webhooks. Disabled entries are included and marked.
list_agentsThe agents in the workspace, each with its live tokens and how many abilities it holds.
list_api_keysThe workspace’s service keys, with the abilities each holds and when it was last used. Never the token itself.
get_postmortemThe postmortem written for an incident, as HTML, with its status and who wrote it.
get_incident_transcriptWhat people said in the incident’s channel, oldest last, with who said it and when. Needs its own ability and the workspace setting.

These need a credential with permission to make the change, and every call is recorded.

ToolWhat it does
upsert_catalog_entryCreates or updates a catalog entry
delete_catalog_entryRemoves a catalog entry
upsert_catalog_typeCreates or changes a kind of thing the catalog holds, and the attributes its entries carry
delete_catalog_typeRemoves a catalog type and the entries under it
upsert_routing_ruleCreates or updates an alert routing rule
delete_routing_ruleRemoves a routing rule
update_routing_configChanges routing configuration
upsert_runbookCreates or updates a runbook
upsert_custom_fieldCreates or updates a custom field and its options
upsert_form_fieldAttaches a field to a form, or changes its visibility, required setting, or conditions
upsert_severity / delete_severityCreates, changes or removes a severity
upsert_status / delete_statusCreates, changes or removes a status
upsert_incident_type / delete_incident_typeCreates, changes or removes an incident type
upsert_incident_role / delete_incident_roleCreates, changes or removes an incident role
upsert_alert_source / delete_alert_sourceCreates, changes or removes an alert source
upsert_webhook / delete_webhookCreates, changes or removes an outbound webhook
test_webhookSends a test delivery to an outbound webhook, replaying the newest matching event from your workspace
upsert_agent / delete_agentCreates, changes or removes an agent
rotate_agent_token / revoke_agent_tokenIssues a new token for an agent, or ends one
upsert_api_key / delete_api_keyCreates, changes or removes a service key
declare_incidentOpens a new incident and its channel
post_incident_updatePosts an update on an incident
resolve_incidentCloses an incident
cancel_incidentCancels an incident that turned out not to be one
reopen_incidentReopens an incident that came back
create_action_itemAdds a piece of work to an incident and posts it in the channel
assign_action_itemTakes a piece of work, or hands it to someone else
complete_action_itemMarks a piece of work done
claim_runbook_stepTakes one step of an attached runbook
escalate_incidentAsks a named person to pick the incident up
invite_respondersBrings people into the incident channel
link_incidentLinks two incidents, or marks one a duplicate of the other
give_shoutoutThanks someone for their work on the incident
assign_incident_rolePuts one person in an incident role, or clears it
attach_runbookAttaches a runbook to an incident
dismiss_timeline_noteRemoves one AI note from an incident’s timeline
approve_approvalApproves a pending request
deny_approvalDenies a pending request
upsert_permission_setCreates or updates a permission set
delete_permission_setRemoves a permission set from everyone holding it
grant_abilityGrants an ability or a set to a person, agent or key
revoke_grantRevokes a grant
upsert_approval_ruleCreates or updates an approval rule
delete_approval_ruleRemoves an approval rule
start_postmortemOpens the postmortem for a resolved incident, empty or drafted by AI
update_postmortemReplaces the body of a postmortem
set_postmortem_statusMoves a postmortem to draft, in progress, in review or completed

upsert_catalog_entry takes attributes by name, and an attribute pointing at another entry accepts that entry’s slug, so an agent can set which team owns a service without looking up an ID.

upsert_catalog_type shapes the catalog itself, adding a kind of thing such as Datastore and saying what every entry under it carries. Attributes are matched by name, so resending a list renames rather than replaces and the entries already holding a value keep it, and sending no attributes leaves the shape alone. A reference attribute names the type it points at by slug. Built-in types keep their slug and their own attributes, and delete_catalog_type refuses a type another type points at, naming the attribute in the way. See Entries, attributes & relationships.

upsert_custom_field and upsert_form_field let an agent change what responders are asked during an incident, so they are worth granting deliberately. Options are matched by label, which means resending a list renames rather than replaces, and the incidents already holding an option keep pointing at it. Conditions accept slugs, so you can gate a field on production without looking up an ID first. A condition on a custom field names that field by its key and takes option labels or catalog entry slugs as its values, so gating on an Affected service field being checkout needs no IDs either. Severity and Status refuse to be hidden or made optional here exactly as they do in the dashboard. Call get_form first to see what a form holds, including hidden fields, because an update replaces the set rather than adding to it.

The gateway tools let an agent administer access the same way an admin does on the dashboard: see who holds what, bundle abilities into sets, grant and revoke, and decide which abilities wait for approval. They check permissions, which only an admin holds and which cannot be granted to a key, so they work over a personal token or an OAuth connection made by an admin, never a service key. approve_approval and deny_approval decide as whoever is behind the token. Connected as you, an agent can be your chief of staff, spotting a request that names you in search_approvals and approving it once you say so. Connected with its own service key, it can decide only the rules that name that key and have Agents may decide this rule switched on, and the decision is recorded under the agent’s name. See Permissions and Approvals.

attach_runbook takes the incident and a runbook slug, and posts that runbook’s steps in the incident channel. Runbooks whose conditions match attach on their own, so this is for the ones that do not. Attaching the same runbook twice does nothing the second time. It needs incidents: update, not a runbooks permission, because it changes the incident rather than the runbook.

dismiss_timeline_note takes the incident and the id of a note, and removes that note from the timeline. It is for the case where a note reads a conversation wrong, crediting the wrong person or taking a joke for a decision. The note is kept and marked dismissed rather than deleted, and stops coming back from get_incident. Note ids come from that same timeline, where each note also names its kind, so an agent can ask for the root cause of a past incident directly. See Timeline notes.

The incident tools are the same operations a person has in Slack, so an agent using them is a responder rather than a reporter. What it does shows up in the incident channel as it happens, and on the incident’s timeline under the agent’s own name.

declare_incident, post_incident_update, resolve_incident, cancel_incident and reopen_incident all ask exactly what your workspace’s incident forms ask a person, custom fields included. Call get_form first with the form you are about to submit, then pass the answers keyed the way it named them. A field the form does not ask for is refused rather than quietly dropped, and a missing required field comes back naming what is missing.

create_action_item adds a piece of work and posts it in the channel, exactly like /ff action. Pass kind as action for work during the incident or followup for work after it, and member to hand it straight to someone.

assign_action_item takes a piece of work when you leave member out, which is the I can take this button, and hands it over when you name someone else, which announces the handover in the channel. complete_action_item marks it done and posts the completion. Both take the item’s id, which comes from get_incident.

claim_runbook_step takes one step of a runbook already attached to the incident, which creates the action item behind that step, or hands over the one that already exists. Runbook and step ids come from get_incident.

invite_responders brings people into the incident channel so they can see what is happening. escalate_incident is the stronger one: it asks one named person to pick the incident up, posts the ask in the channel, messages them directly with an acknowledge button, and reminds them if they do not answer. Reach for it when the agent has gone as far as it can on its own.

Escalating, inviting and giving a shoutout all post in the incident channel, so all three refuse an incident that has been resolved or canceled, and one whose channel Firefight is still creating. The refusal names which it is.

link_incident records a related link on both incidents’ timelines and changes nothing else. Passing duplicate instead also cancels this incident, naming the one that absorbed it, so use it only when the two really are the same event seen twice.

give_shoutout thanks a named person in the incident channel, the same as /ff shoutout.

Every one of these needs incidents: create or incidents: update, so an agent granted only incidents: read can follow an incident and change nothing about it.

assign_incident_role takes the incident, the role slug, and the person as an email address or Slack user ID. Leave the person out to clear the role. Each role holds one person, so assigning hands the role over from whoever had it. Call get_incident first to see which roles exist and who currently holds them. Every role change announces itself in the incident channel, so the tool refuses any of them on a resolved or canceled incident and names the role it would have changed. See Incident roles.

An incident that has been resolved can have its write-up started, edited and moved along without anyone opening the dashboard. start_postmortem opens it. Leave generate out for an empty one you write yourself, or pass it to have Firefight draft the first version from the incident.

Generating takes a moment, so the response comes back immediately with a generation state to poll on. Read it back with get_postmortem until the state clears.

update_postmortem sends the whole document as HTML and replaces what was there rather than appending to it, so read the current one first if you mean to add a section. Every version is kept, so a rewrite can be compared and rolled back from the dashboard. set_postmortem_status moves it to draft, in_progress, in_review or completed, which is how your team knows whether it still needs writing or reading.

get_postmortem gives you a version, and update_postmortem takes it back. This matters because a person is often writing the same document in the dashboard at the same time. If they saved while the agent was composing, the agent’s write is refused rather than replacing what they wrote, and the agent reads again and reapplies. Moving the status needs no version, since it changes nothing anybody is typing.

Starting one is refused while the incident is still open, and refused outright for a canceled incident, which has nothing to write up. An incident that already has a postmortem is refused too, so read before you start. All four tools check incidents, not a permission of their own. See Postmortems.

get_incident_transcript returns what people actually said in the incident channel, which is where the reasoning lives that a timeline only summarises. Read it when you know what happened and need to know why.

It needs the Incident Transcripts ability, which is separate from incidents on purpose, and the workspace has to have turned transcript access on under Settings → Workspace. An agent granted every incident ability reads nothing until both are true. See Incident conversations.

Messages come back oldest last, 100 at a time and 500 at most, with a more_before cursor for walking further into the past. Each message says whether anything in it was redacted.

Every settings screen has tools behind it. That means you can ask an agent connected as you to do the setup, rather than clicking through it. “Add a SEV0 above our current top severity, and a Mitigating status in the active stage” is one conversation instead of two screens.

Call get_workspace_config first. It returns your severities, statuses, incident types, incident roles, alert sources and webhooks in one response, and the slugs it gives back are what every other tool takes.

Each list has its own pair of tools rather than one tool with a type argument, because the lists do not ask for the same things. A status belongs to a lifecycle stage, a severity’s position says how severe it is, and only some are colored or have a default. Each of these four lists takes position, 1 being first, so “add a SEV0 above our current top severity” is position: 1. Separate tools mean the fields an agent is offered are the fields that list actually has.

Passing a slug changes the one that already has it, and leaving the slug out creates a new one. Renaming never moves the slug, because the slug is what your existing incidents point at. A slug that matches nothing comes back as an error rather than quietly creating a second entry under a fresh name.

Deleting is refused while anything still points at the entry, and the refusal says how many. Disabling is what you want then. A disabled entry keeps its slug and stops being offered to responders, and get_workspace_config still returns it so an agent can turn it back on.

Creating an agent, rotating its token and minting a service key are all available here, and they behave differently from everything else on this page. They check permissions and api_keys, which are admin-only and cannot be granted to anyone. A connection acting as an admin reaches them. A service key or an agent never can, whatever it has been granted, so an agent cannot create another agent or widen its own access.

upsert_agent returns the new agent’s token once, in that response, and never again. So does rotate_agent_token. Neither list_agents nor list_api_keys ever carries a token.

Rotating is an overlap rather than a swap. The new token works immediately while the old one keeps working, so the agent stays up while you update its configuration, and revoke_agent_token ends the old one when you are ready. See Agents.

Every capability you switch on under Configure → Integrations also appears here, so an agent can query PlanetScale or open a Linear issue through the same connection. Nothing appears until you enable it, and who may call it is set in Permissions. An agent’s tool list only carries the capabilities its key may call, so a narrowly scoped key never sees the rest of your connections. See Connect an integration.

Search tools return 25 results by default and accept a limit of up to 50. When more results exist than the cap allows, the response includes a truncated flag set to true, so agents know to narrow their filters instead of assuming they saw everything. Incident timelines in get_incident are capped at 50 events with their own timeline_truncated flag. Each token may make up to 1,000 MCP requests per minute.

What a connected agent can query depends on the credential it authenticates with.

CredentialAccess
OAuth connectionActs as you, with your access
Personal tokenActs as you, with your access
Agent tokenActs as the agent, with only what the agent was granted
Service keyOnly what it has been granted, and nothing by default

Agent tokens and service keys map to tools by resource.

ToolRequired permission
search_incidentsincidents: read
get_incidentincidents: read
search_alertsalerts: read
search_catalogcatalog: read
evaluate_routingpolicies: read
search_runbooksrunbooks: read
get_runbookrunbooks: read
search_approvalsapprovals: read
get_formforms: read
upsert_catalog_entrycatalog: create or catalog: update
delete_catalog_entrycatalog: delete
upsert_routing_rulepolicies: create or policies: update
delete_routing_rulepolicies: delete
update_routing_configpolicies: update
upsert_runbookrunbooks: create or runbooks: update
upsert_custom_fieldcustom_fields: create or custom_fields: update
get_workspace_configincidents: read
upsert_severity / delete_severityseverities: create, update or delete
upsert_status / delete_statusstatuses: create, update or delete
upsert_incident_type / delete_incident_typeincident_types: create, update or delete
upsert_incident_role / delete_incident_roleincident_roles: create, update or delete
upsert_alert_source / delete_alert_sourcealerts: create, update or delete
upsert_webhook / delete_webhookwebhooks: create, update or delete
test_webhookwebhooks: update
list_agents, upsert_agent, rotate_agent_token, revoke_agent_token, delete_agentpermissions, admin-only and ungrantable
list_api_keys, upsert_api_key, delete_api_keyapi_keys, admin-only and ungrantable
upsert_form_fieldforms: update
declare_incidentincidents: create
post_incident_updateincidents: update
resolve_incidentincidents: update
cancel_incidentincidents: update
reopen_incidentincidents: update
create_action_itemincidents: update
assign_action_itemincidents: update
complete_action_itemincidents: update
claim_runbook_stepincidents: update
escalate_incidentincidents: update
invite_respondersincidents: update
link_incidentincidents: update
give_shoutoutincidents: update
assign_incident_roleincidents: update
attach_runbookincidents: update
dismiss_timeline_noteincidents: update
approve_approvalapprovals: update
deny_approvalapprovals: update
list_abilitiespermissions: read
list_principalspermissions: read
search_activitypermissions: read
upsert_permission_setpermissions: create or permissions: update
delete_permission_setpermissions: delete
grant_abilitypermissions: create
revoke_grantpermissions: delete
upsert_approval_rulepermissions: create or permissions: update
delete_approval_rulepermissions: delete

A tool call without the needed permission returns an error naming the missing permission, and the agent can keep using the tools it does have. See API overview for how keys and permissions work.

Everything connected over OAuth appears under Settings → API Keys in the Connected agents section, where you can revoke any connection. Revoking immediately invalidates its tokens, and the client has to go through consent again to reconnect. Automation using an API key is managed like any other key on the same page: deactivate or delete the key to cut it off. An AI with its own identity lives under Gateway → Agents instead, where you rotate or revoke its tokens, change what it may do, or switch it off without losing what it did. See Agents.