jira-alerts-mcp
Enables interaction with Jira Service Management Operations alerts and on-call schedules, including searching alerts, reading notes and activity logs, acknowledging, closing, annotating, adding responders, and querying current and next on-call rotations.
README
<div align="center">
Jira Alerts MCP
Find what is paging you, and who is on call — from your agent.
</div>
An MCP server for Jira Service Management Operations — the alert surface that replaced Opsgenie, which no other Jira MCP server covers.
Search alerts and read their notes and activity timeline; acknowledge, close, annotate them and add responders; and look up who is on call now and next. Twelve tools, four of them writes.
Quickstart
You need Node ≥ 24 and an Atlassian Cloud site with JSM Operations enabled. There is nothing to clone or build — your MCP client runs the published package.
1. Find your cloud id. Open this while logged in to your site:
https://<your-site>.atlassian.net/_edge/tenant_info
It answers with one line — {"cloudId":"..."} — and that UUID is what
JSM_CLOUD_ID wants. If you'd rather not rely on that endpoint, the cloud id is
also the segment after /s/ in the URL at
admin.atlassian.com → Apps → Sites → your site.
2. Create an API token at id.atlassian.com.
3. Add the server.
Claude Code:
claude mcp add jira-alerts-mcp \
--env JSM_CLOUD_ID='your-cloud-id' \
--env JSM_EMAIL='you@example.com' \
--env JSM_API_TOKEN="${JSM_API_TOKEN}" \
-- npx -y jira-alerts-mcp
Claude Desktop: open the config from the app rather than by hand — the Claude menu in your menu bar (not the settings inside the window) → Settings → Developer → Edit Config. That creates the file if it doesn't exist yet:
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
{
"mcpServers": {
"jira-alerts-mcp": {
"command": "npx",
"args": ["-y", "jira-alerts-mcp"],
"env": {
"JSM_CLOUD_ID": "your-cloud-id",
"JSM_EMAIL": "you@example.com",
"JSM_API_TOKEN": "your-api-token"
}
}
}
}
mcpServers is a top-level key, and the file holds every server you have
configured. If it already has an mcpServers block, add jira-alerts-mcp as
another entry inside it — pasting the whole block above over the file replaces
whatever was already there.
Then quit Claude Desktop completely and reopen it — the file is read only at startup, and closing the window is not quitting. The server then appears under the connectors panel in the message composer.
Most other MCP clients accept that same JSON shape.
4. Check it works. Ask your agent to list your open alerts. That runs
jsm_list_alerts, which needs no ids and confirms your credentials and the
read:ops-alert scope that eight of the twelve tools share.
Then ask who is on call, which runs jsm_list_schedules. That is a separate
check, because schedules need read:ops-config — if alerts work and schedules
return 401, nothing is wrong with your token; see
Required scopes below.
Things that catch people out: with claude mcp add the server name is the first
positional argument, before any flags; -y on npx skips the install prompt,
which an MCP client has no way to answer; and in zsh ${VAR} needs quoting. For
GUI-launched sessions the token has to live in the env block of the config
itself — the shell environment isn't inherited, which is why the JSON above
carries the credentials inline.
If the server never shows up in Claude Desktop, two causes account for almost all of it, and neither announces itself:
npxwasn't on the PATH. A GUI app is launched by the window manager, not a shell, so a Node installed through nvm often isn't visible to it. Set"command"to the absolute path fromwhich nodeand point"args"at the installeddist/index.js, or install Node system-wide. A Node older than 24 that is found fails asEBADENGINErather than anything readable.- The server exited during startup. Credentials are validated before the
handshake, so a bad cloud id or token stops it dead — and because stdout is
the protocol channel, that message goes to stderr only. Claude Desktop keeps
it at
~/Library/Logs/Claude/mcp-server-jira-alerts-mcp.log(Windows:%APPDATA%\Claude\logs\), named after the key you used undermcpServers. Look forStartup failed:— it names exactly what is wrong.
<details> <summary><b>Came here from this repository's Packages panel?</b></summary>
You found @rrvrs/jira-alerts-mcp on GitHub Packages. That is a mirror of the
same build, published so the panel is not empty. GitHub Packages requires a
personal access token even for public packages, so installing from it needs auth
that npmjs.com does not.
Use npx jira-alerts-mcp above — that is
the package on npmjs.com,
installable anonymously, and the only supported install route. The two are
separate names on separate registries; nothing redirects between them.
</details>
<details> <summary><b>Running from a clone instead</b></summary>
Only needed to work on the server itself, or to run a revision that has not been released:
git clone https://github.com/rrvrs/jira-alerts-mcp.git
cd jira-alerts-mcp
npm install
npm run build
Then point your client at the build rather than at npx, so edits take effect without republishing:
-- node /absolute/path/to/jira-alerts-mcp/dist/index.js
</details>
Configuration
| Variable | Required | Notes |
|---|---|---|
JSM_CLOUD_ID |
yes | Your Atlassian site's cloud id (a UUID) |
JSM_EMAIL + JSM_API_TOKEN |
one of | Create a token |
JSM_OAUTH_TOKEN |
one of | OAuth 3LO bearer; takes precedence if set |
TRANSPORT |
no | stdio (default) or http |
PORT / HOST |
no | HTTP transport; defaults to 127.0.0.1:3000 |
ALLOWED_HOSTS |
no | Comma-separated Host allowlist. Required if you set HOST beyond loopback — see SECURITY.md |
Credentials are validated at startup, so a bad config fails immediately with an actionable message rather than on the first tool call.
.env.example lists these for reference. The server does not
read .env itself — an MCP server is launched by its client, and the client owns
the environment. Use the file as a checklist for your client's env block, or
set -a; source .env; set +a for local development.
Required scopes. Alerts and on-call sit behind different scopes, which is the single most common setup mistake:
| Tools | Scope |
|---|---|
| The 5 alert reads | read:ops-alert:jira-service-management |
| The 4 alert writes | read:ops-alert:… and write:ops-alert:… — both |
jsm_list_schedules, jsm_get_on_call, jsm_get_next_on_call |
read:ops-config:jira-service-management |
Two consequences worth knowing before you mint a token:
- Writes need the read scope too. A token carrying only
write:ops-alert:jira-service-managementfails. Atlassian requires the read scope alongside it on every write endpoint. ops-configis a separate grant, and a missing one returns 401, not 403. Omit it and the nine alert tools work perfectly while the three on-call tools fail — which reads like a broken credential and is not one. Both are supported configurations: granting only the read scopes, or onlyops-alert, is a deliberate way to narrow what the agent can reach.
Team visibility. The account also needs JSM Operations access on the relevant team. Alerts and schedules hang off a team's Operations page, so credentials that can't see the team will get empty lists rather than errors.
Example
Asking who is on call resolves to jsm_list_schedules, then jsm_get_on_call:
you — who's on call for payments right now?
# Currently on-call for Payments — Primary
- Dana Okafor
Acknowledging an alert returns a receipt, not the updated alert — because JSM applies alert actions out of band:
you — ack alert 4f2a9c1e-…-1718395200000, I'm looking at it
Acknowledge request accepted for alert `4f2a9c1e-…-1718395200000`.
- **Request id**: `c7b41f30-…`
- **Result**: Request will be processed
JSM applies alert actions asynchronously, so the alert may not reflect this
change immediately. Confirm with jsm_get_request_status using the request id
above, or re-read the alert after a moment.
That last paragraph is the point: without it an agent re-reads the alert, sees it still unacknowledged, and acknowledges it again.
Tools
| Tool | Endpoint | Read/Write |
|---|---|---|
jsm_list_alerts |
GET /v1/alerts |
read |
jsm_get_alert |
GET /v1/alerts/{id} or GET /v1/alerts/alias |
read |
jsm_list_alert_notes |
GET /v1/alerts/{id}/notes |
read |
jsm_list_alert_logs |
GET /v1/alerts/{id}/logs |
read |
jsm_get_request_status |
GET /v1/alerts/requests/{id} |
read |
jsm_acknowledge_alert |
POST /v1/alerts/{id}/acknowledge |
write |
jsm_close_alert |
POST /v1/alerts/{id}/close |
write |
jsm_add_alert_note |
POST /v1/alerts/{id}/notes |
write |
jsm_add_alert_responder |
POST /v1/alerts/{id}/responders |
write |
jsm_list_schedules |
GET /v1/schedules |
read |
jsm_get_on_call |
GET /v1/schedules/{id}/on-calls |
read |
jsm_get_next_on_call |
GET /v1/schedules/{id}/next-on-calls |
read |
Deliberately not implemented: DELETE /v1/alerts/{id} and alert creation.
Deleting alerts destroys audit history with no undo, and alert creation belongs
to the integration API (/jsm/ops/integration/v2/alerts) with an integration
key, not to an interactive agent. Open an issue if you have a concrete need.
What this server handles for you
Three API behaviours silently break naive integrations. Each is stated in the tool descriptions, where the model will actually read it:
-
Writes are asynchronous. Every mutating endpoint returns
{ result, requestId, took }immediately and applies the change out of band. Re-reading the alert right after an ack will often show it still unacknowledged.jsm_get_request_statusis the correct verification path, and each write tool points at it. -
tinyIdis not an id. The short number in the JSM UI (#4821) is rejected by/v1/alerts/{id}, which accepts only the fulluuid-timestampid. Aliases need a different endpoint entirely (/v1/alerts/alias?alias=). Both the schema descriptions and the 404 handler say so explicitly, so the model self-corrects instead of retrying the same call. -
The search window caps at 20,000.
offset + limitmust stay under it.jsm_list_alertsrejects deeper paging locally with a message telling the model to narrow the query instead of burning a round trip on a guaranteed 400.
Why this exists
Alerts are not work items. They live behind a different API — /jsm/ops/api,
the rehosted Opsgenie surface — with its own scopes, its own id format and its
own asynchronous write semantics. The MCP Registry lists 30 Jira servers; every
one of them talks to work items. None can tell you what is paging you right now.
atlassian/atlassian-mcp-server
does not close the gap either: it covers Jira, Confluence, JSM requests,
Bitbucket, Compass and the Teamwork Graph, but has no tool for alerts, schedules
or on-call — and being a hosted, closed server, that gap is Atlassian's to close
rather than something a contribution can fix.
The Opsgenie MCP servers that do exist speak an API with an end date.
giantswarm/mcp-opsgenie,
burakdirin/opsgenie-mcp-server
and daviddykeuk/opsgenie-mcp all
call api.opsgenie.com with a GenieKey. Opsgenie
reached end-of-sale on 4 June 2025 and shuts down on 5 April 2027,
at which point those REST APIs stop responding. This server targets the surface
that replaces them: https://api.atlassian.com/jsm/ops/api/{cloudId}/v1.
Compatibility. For Atlassian Cloud tenants with JSM Operations — sites
already migrated off standalone Opsgenie, or provisioned after the merge. If your
team still logs in at app.opsgenie.com and authenticates with a GenieKey, this
server will not reach your data; one of the Opsgenie servers above will, until
2027.
Project layout
src/
├── index.ts # transports and startup credential validation
├── server.ts # assembles the tool domains
├── constants.ts # API root, limits
├── types.ts # JSM API interfaces
├── schemas/common.ts # Zod fragments shared across domains
├── services/
│ ├── client.ts # auth, request, envelope normalisation, error mapping
│ └── format.ts # markdown rendering, truncation, result envelopes
└── tools/
├── define.ts # defineTool() + registerTools()
├── list-executor.ts # the shared list pipeline
├── alerts/ # read tools — one file per tool, plus shapes.ts
├── actions/ # write tools, all via execute-action.ts
└── oncall/ # schedules and on-call
One tool per file. A tool module owns its input shape, its description and its
handler, and nothing else — the largest is ~100 lines. server.ts concatenates
the three domains' exported arrays; index.ts only knows about transports.
Three conventions in here are load-bearing, and changing them by accident is the most likely way to break the server subtly. They are written up, with the bugs that motivated each, under Conventions worth preserving.
Contributing
See CONTRIBUTING.md for the development loop, the conventions worth preserving, and how to add a tool. Issues and PRs must not contain cloud ids, tokens, or real alert data.
Security
This server holds Atlassian credentials, and the HTTP transport performs no authentication of its own — see SECURITY.md for the threat model, hardening notes, and how to report a vulnerability privately.
License
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。