Irm
Grafana IRM incident and on-call read integration, for Grafana Cloud and self-hosted Grafana alike. Incident actions: list_incidents (recent incidents via IncidentsService.QueryIncidents), get_incident (one incident by ID), get_timeline (the incident activity feed via ActivityService.QueryActivity, filterable by tag and activity kind), list_fields (custom incident metadata fields). These call the Grafana Incident JSON RPC API at /api/plugins/grafana-irm-app/resources/api/v1 on the same Grafana instance as the grafana tool, authenticated with the same service account token injected by the host as a Bearer header, with the hostname read from the shared workspace file `grafana/host`. On-call actions: list_on_call (schedules with their on_call_now membership via GET /api/v1/schedules/, filterable by name and team_id), list_escalation_chains (the chains to choose from via GET /api/v1/escalation_chains/), get_escalation_policy (ordered steps for one chain via GET /api/v1/escalation_policies/?escalation_chain_id=...). These call the separate Grafana OnCall API, which has its own hostname (workspace file `grafana/oncall_host`) and its own API token injected as a raw Authorization header with no scheme. The OnCall allowlist names those three exact path prefixes rather than all of /api/v1/, because on a self-hosted deployment the OnCall host is usually the Grafana host, where /api/v1/provisioning is Grafana's own alert-rule API and belongs to the grafana tool. Read-only throughout: the tool declares, updates, resolves, and pages nobody. INSTALL EDIT REQUIRED: replace YOUR_GRAFANA_HOST (2 places) with your Grafana hostname and YOUR_ONCALL_HOST (4 places) with the OnCall API hostname from your OnCall settings page before installing. On self-hosted deployments the two are usually the same value.
Description
Read access to incidents and on-call rotations in Grafana IRM, cloud or self-hosted.
The tool is read-only. It declares, updates, resolves, and pages nobody.
Pairs with the grafana tool: same stack, same service account token, same
grafana/host workspace file. Use grafana for what is firing, irm for what was
declared, who responded, what happened, and who to reach.
Actions
Incidents, via the Incident API, a JSON RPC surface served by the IRM app on your Grafana instance:
| Action | RPC method | Purpose |
|---|---|---|
list_incidents | IncidentsService.QueryIncidents | Recent incidents, newest first by default |
get_incident | IncidentsService.GetIncident | One incident by ID, with severity, status, and roles |
get_timeline | ActivityService.QueryActivity | The incident activity feed |
list_fields | FieldsService.GetFields | Custom incident metadata fields on the stack |
Every one is a POST to
/api/plugins/grafana-irm-app/resources/api/v1/{Service}.{Method} with a JSON body.
On-call, via the OnCall API, a REST surface on its own host:
| Action | Endpoint | Purpose |
|---|---|---|
list_on_call | GET /api/v1/schedules/ | Schedules with their on_call_now membership, filterable by schedule_name and team_id |
list_escalation_chains | GET /api/v1/escalation_chains/ | The chains to choose from |
get_escalation_policy | GET /api/v1/escalation_policies/ | Ordered escalation steps for one chain, by required escalation_chain_id |
Chain IDs are not guessable, so discovery is its own action rather than a mode of
get_escalation_policy. Folding both into one action would let a caller ask for a policy,
receive a list of chains, and report chains as though they were the policy.
All three on-call endpoints are paginated. Pass page to walk them; the response carries
count, next, and total_pages.
The timeline is the useful part
get_timeline returns the activity feed, which is where the investigation narrative
lives: status changes, severity changes, notes people wrote, and automated events. For
"what actually happened during this incident", it beats the incident record itself.
Filter it with activity_kind to separate human notes from machine events, and with
tag to pull a single labelled slice:
{ "action": "get_timeline", "incident_id": "1a2b3c", "activity_kind": ["userNote"], "limit": 50 }
Auth and hostnames
This tool talks to two APIs with two credentials, because Grafana serves them that way.
Incidents. Grafana IRM runs on your Grafana instance, so it reuses the credential and
host configuration of the grafana tool. Replace YOUR_GRAFANA_HOST in the capabilities
file in both places (allowlist.host and the credential's host_patterns) with your
Grafana hostname, then store the token:
export GRAFANA_SERVICE_ACCOUNT_TOKEN=<service account token>
The hostname is read from the workspace file grafana/host, shared with the grafana
tool. The host injects the token as Authorization: Bearer.
On-call. Grafana OnCall has its own base URL and its own token. Open OnCall, go to
Settings, and read the API URL shown there. Replace YOUR_ONCALL_HOST in the capabilities
file in all four places (three allowlist entries and the credential's host_patterns),
write the same hostname to the workspace file grafana/oncall_host, and store the token:
export GRAFANA_ONCALL_API_TOKEN=<oncall api token>
The host injects this one as a bare Authorization header with no Bearer prefix,
which is what the OnCall API expects and why it cannot share the incident credential.
On a self-hosted deployment the two hostnames are normally the same value. Grafana Cloud serves OnCall from a regional hostname instead, which is why it has to be configured rather than derived.
Neither token is ever visible to the tool. Both are injected host-side, scoped by host and path prefix.
That path scoping is load-bearing when the two hostnames are the same. The OnCall
allowlist names three exact prefixes rather than all of /api/v1/, because Grafana's own
alert provisioning API lives at /api/v1/provisioning on the same host and belongs to the
grafana tool. A broad prefix would hand this tool a surface it has no reason to reach.
Limits
- The on-call actions need their own credential. Configure only the Grafana service
account token and the incident actions work while
list_on_callandget_escalation_policyreturn a clear "token not configured" error. That is the intended behaviour, not a partial install. on_call_nowis a point-in-time answer. It reflects the rotation at the moment of the call. For a historical or future window,GET /api/v1/schedules/<id>/final_shiftsexists and is not exposed here; it needs an explicit date range and belongs in its own action rather than as a mode of this one.- Write methods exist on both APIs (
CreateIncident,UpdateStatus,UpdateSeverity,AssignRole,AddActivityon incidents; create, update, and delete across schedules, chains, and policies on OnCall) and are deliberately not exposed. - The incident query surface is intentionally minimal:
limitandorderDirection, plustagandactivityKindfor activity. Additional documented filters exist and will be added once they can be verified against a live stack. - The OnCall list endpoints filter on what the API actually accepts, which is
nameandteam_idfor schedules andescalation_chain_idfor policies. There is no free-text search and no server-side "who is on call for this alert" lookup. - One Grafana host and one OnCall host per installation, pinned in the capabilities file at install time.
Access & Credentials
Bearer token
Bearer token
grafana_service_account_tokenBearer token
grafana_oncall_api_tokenNetwork & Permissions
Implementation
Resources
Review implementation and setup instructions before installing.