jira-mcp
Provides tools for interacting with a self-hosted Jira Server, enabling searching issues, creating and updating issues, managing transitions and comments, listing projects and issue types, and validating authentication.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@jira-mcpFind all unresolved bugs in the Billing project."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
jira-mcp —— 自托管 Jira 的轻量 MCP Server
一个面向 自托管 Jira Server 7.3.6(私有化部署,如 https://jira.gacrnd.com:8443)
的最小 MCP 服务器。官方 Atlassian Rovo MCP 只支持 Cloud(*.atlassian.net),
这个项目填补自托管场景的空缺,直连 Jira REST API v2,通过 MCP 协议把 Jira 能力
暴露给 Claude Desktop / Cursor / Hermes / VS Code Copilot 等 AI 客户端。
本文档既包含快速上手,也包含完整的设计说明,供维护 / 扩展 / 接入使用。
目录
Related MCP server: jira-mcp-bridge
特性
stdio 传输,任何 MCP 客户端都能挂(Claude Desktop / Cursor / Hermes / VS Code Copilot)
Basic Auth 认证(7.3.6 无 PAT),支持自签证书(默认不校验 SSL)
13 个工具:搜索 / 查询 / 建单 / 改单 / 流转 / 评论 / 项目与类型枚举 / 身份校验 / 保存筛选器 / 问题表格
服务端做 payload 精简,抗 LLM 工具结果截断
快速上手
环境要求
Python 3.10+ ,已装
mcp、requests
安装
cd /media/tommy/win_documents/code/mcp/jira-mcp
pip install -r requirements.txt配置
复制 .env.example 内容到你的客户端配置或 export 环境变量:
export JIRA_URL=https://jira.gacrnd.com:8443
export JIRA_USERNAME=<你的账号>
export JIRA_PASSWORD=<密码>认证说明:Jira 7.3.6 没有 Personal Access Token(8.14 才引入),只能用 Basic Auth(账号 + 密码)。建议用一个专用服务账号,别用个人主账号。 若账号走 SSO/LDAP,确认该账号能用密码做 REST 认证。
挂载示例
Claude Desktop(claude_desktop_config.json)
{
"mcpServers": {
"jira-gac": {
"command": "python3",
"args": ["/media/tommy/win_documents/code/mcp/jira-mcp/server.py"],
"env": {
"JIRA_URL": "https://jira.gacrnd.com:8443",
"JIRA_USERNAME": "你的账号",
"JIRA_PASSWORD": "你的密码",
"JIRA_VERIFY_SSL": "false"
}
}
}
}Hermes Agent
见 hermes mcp 相关命令或 hermes-mcp-setup skill,把上面的 command/args/env
加到 MCP 服务器列表即可(stdio 类型)。
快速自测
# 仅测工具注册(不连 Jira)
python3 - <<'PY'
import server
print("tools:", [t for t in dir(server) if t.startswith("jira_")])
PY工具清单
工具 | 说明 |
jira_get_myself | 校验账号可用(排查认证) |
jira_search | JQL 搜索 issue |
jira_list_filters | 列出当前账号的保存筛选器 |
jira_search_by_filter | 按筛选器(id/名称)搜索 |
jira_issue_table | 问题导航器表格(页面同款列配置) |
jira_get_issue | 按 key 查单个 issue 全字段 |
jira_list_projects | 列出可见项目 |
jira_get_issue_types | 列项目可用 issue 类型(可能是中文) |
jira_create_issue | 建单 |
jira_update_issue | 改单(summary/description/assignee/priority) |
jira_list_transitions | 列可用的状态流转 |
jira_transition_issue | 按名称流转状态 |
jira_add_comment | 加评论 |
背景与动机
官方 Atlassian Rovo MCP Server(github.com/atlassian/atlassian-mcp-server)仅面向
Cloud(*.atlassian.net),其入口 mcp.atlassian.com 无法代理自托管(Server / Data Center)
实例。本项目直连 自托管 Jira Server 7.3.6 的 REST API v2,填补自托管场景的空缺。
关键约束(决定了多项设计选择)
约束 | 影响 |
Jira 7.3.6 < 8.14,无 Personal Access Token(PAT 8.14 才引入) | 认证只能走 Basic Auth(账号 + 密码) |
自托管实例使用自签证书(8443 端口) | 默认关闭 SSL 校验,并抑制 |
社区 | 不依赖它,自己实现最小 server |
账号可能走 SSO/LDAP | Basic Auth 仍按用户目录校验;建议用专用服务账号 |
AI 客户端工具结果有大小上限(沙箱 ~ 数百 KB) | 搜索结果必须精简摘要,丢弃巨型字段 |
设计目标
最小依赖、单文件:
server.py一个文件即可运行,仅依赖mcp+requests。stdio 传输:任何 MCP 客户端都能挂,无需网络端口 / 进程常驻管理。
AI 友好:工具返回值统一
{"ok": bool, ...},永不抛异常,错误信息可读, 让 LLM 客户端能读取错误并继续,而不是被异常打断。抗截断:对搜索 / 表格等大 payload 做结构化精简,只保留对 LLM 有用的字段。
可诊断:提供身份校验工具、端到端验证脚本,便于排查认证 / 连通性问题。
整体架构
┌─────────────────────────────────────────────────────────────┐
│ MCP 客户端 (Claude Desktop / Cursor / Hermes / Copilot) │
└───────────────────────────────┬─────────────────────────────┘
│ stdio (JSON-RPC 2.0)
│ initialize / tools/list / tools/call
┌───────────────────────────────▼─────────────────────────────┐
│ FastMCP("jira-gac") ← MCP SDK 层 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 13 个 @mcp.tool() 处理器 │ │
│ │ jira_get_myself / jira_search / jira_list_filters / │ │
│ │ jira_search_by_filter / jira_issue_table / │ │
│ │ jira_get_issue / jira_create_issue / jira_update_issue │ │
│ │ jira_list_transitions / jira_transition_issue / │ │
│ │ jira_add_comment / jira_list_projects / │ │
│ │ jira_get_issue_types │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ JiraClient ← HTTP 客户端层(requests.Session)│ │
│ │ · Basic Auth / Bearer / SSL 开关 │ │
│ │ · request() 统一请求 + 错误规整 │ │
│ │ · post_issue_table() 内部接口专用(CSRF 头) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ JiraError ← 错误规整层 │ │
│ │ · errorMessages / errors → 可读字符串 │ │
│ └─────────────────────────────────────────────────────────┘ │
└───────────────────────────────┬─────────────────────────────┘
│ HTTPS (verify 可关)
┌───────────────────────────────▼─────────────────────────────┐
│ 自托管 Jira Server 7.3.6 │
│ · REST API v2 : /rest/api/2/... │
│ · 内部接口 : /rest/issueNav/1/issueTable │
└─────────────────────────────────────────────────────────────┘分层职责:
工具层(
@mcp.tool())只做「入参校验 → 调 client → 精简 → 包_ok/_err」,不含 HTTP 细节。客户端层(
JiraClient)只做「拼 URL → 发请求 → 解析 JSON → 抛JiraError」。规整层(
JiraError/_name/_summarize_*)负责「原始 Jira 数据 → LLM 友好输出」。
配置设计
全部通过环境变量注入,避免硬编码凭据,便于客户端配置与 CI 隔离。
环境变量 | 默认值 | 说明 |
|
| Jira 根地址,末尾 |
| 空 | Basic Auth 用户名(7.3.6 主认证方式) |
| 空 | Basic Auth 密码 |
| 空 | 可选;Jira 8.14+ 的 PAT,7.3.6 忽略 |
|
|
|
| 空 | 预留:缺省 project key(当前工具未消费,留作扩展) |
认证优先级(见 JiraClient.__init__):
若设
JIRA_PERSONAL_TOKEN→Authorization: Bearer <token>(8.14+);否则若设
JIRA_USERNAME→requests的session.auth = (username, password)(HTTP Basic);两者皆无 → 匿名请求(工具调用会收到 401,规整为
ok=false错误,不崩溃)。
SSL 处理:
JIRA_VERIFY_SSL = os.environ.get("JIRA_VERIFY_SSL", "false").lower() in ("1", "true", "yes")
if not JIRA_VERIFY_SSL:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)session.verify = JIRA_VERIFY_SSL决定 TLS 证书校验;关闭校验时抑制
InsecureRequestWarning,避免 stdio 上刷屏。
安全建议:优先用专用服务账号而非个人主账号;
JIRA_DEFAULT_PROJECT为预留字段, 当前未在工具逻辑中消费,后续可用来简化建单参数。
HTTP 客户端层设计
JiraError — 错误规整
把 Jira 返回的错误体规整成一条可读字符串,供 LLM 直接展示:
class JiraError(Exception):
def __init__(self, status, data):
self.status = status
self.data = data
msgs = []
if isinstance(data, dict):
msgs.extend(data.get("errorMessages") or []) # 顶层错误消息数组
msgs.extend(f"{k}: {v}" for k, v in (data.get("errors") or {}).items()) # 字段级错误
super().__init__("; ".join(msgs) or f"HTTP {status}")兼容 Jira 两种错误体:全局
errorMessages(字符串数组)与字段级errors(dict)。两者皆无时退化为
HTTP <status>,保证总有可读信息。
JiraClient — 请求封装
class JiraClient:
def __init__(self):
self.session = requests.Session() # 连接复用(连接池 / Keep-Alive)
self.session.verify = JIRA_VERIFY_SSL
self.session.headers["Accept"] = "application/json"
# ... 认证设置见「配置设计」使用
requests.Session复用底层连接,避免每次工具调用重新握手(自签 8443 握手开销不小)。_url(path):JIRA_URL + "/rest/api/2/" + path.lstrip("/"),统一 API v2 前缀。request(method, path, **kwargs):核心统一方法——默认
timeout=30;204 No Content→ 返回None;尝试
resp.json(),解析失败则退化为{"raw": resp.text[:2000]}(截断防超大文本);status >= 400→ 抛JiraError。
get/post/put为便捷方法。post_issue_table(...):内部接口专用(见「内部接口专项设计」),直接 POST 而非走request(),因为目标/rest/issueNav/1/issueTable不在/rest/api/2/下,且需要form-urlencodedbody + CSRF 免检头 + XHR 头。
工具 API 设计
统一响应规约
每个工具只返回 JSON,不抛异常,两种形态:
def _ok(data): return {"ok": True, "data": data}
def _err(e): return {"ok": False, "error": str(e)}成功:
{"ok": true, "data": <精简后的结构>}失败:
{"ok": false, "error": "<可读错误>"}
设计意图:AI 客户端通过
ok判断成败,失败时读error继续推理或重试, 不会被 Python 异常中断整条工具调用链路。
工具清单与数据流
工具 | 方法 | Jira 端点 | 写副作用 | 输出精简策略 |
| GET |
| 无 | 原始(诊断用) |
| GET |
| 无 |
|
| GET |
| 无 |
|
| GET |
| 无 |
|
| POST |
| 无 |
|
| GET |
| 无 | 原始(单条) |
| GET |
| 无 |
|
| GET |
| 无 |
|
| POST |
| 有 |
|
| PUT |
| 有 |
|
| GET |
| 无 |
|
| POST |
| 有 |
|
| POST |
| 有 |
|
各工具设计要点
jira_get_myself — 身份诊断入口。返回 client.get("myself") 原始结果,用于排查
认证是否可用。匿名/密码错误时返回 ok=false 且含可读错误,不崩溃。
jira_search(jql, max_results=20, fields=DEFAULT_FIELDS, raw=False)
DEFAULT_FIELDS = "summary,status,priority,issuetype,assignee,reporter,created,updated", 显式指定字段列表,避免拉取全字段(默认会带 avatarUrls/expand 等冗余)。raw=False走精简;raw=True返回 Jira 原始完整结果(调用方明确需要 description/attachments 等大字段时才用)。
jira_list_filters / jira_search_by_filter — 保存筛选器支持
Jira 保存的筛选器在
GET /filter/favourite(收藏)与/filter/my(我的), 每项含id/name/jql。_resolve_filter_jql(filter_ref)解析规则:filter_ref是纯数字 → 当作 id 直接GET /filter/{id}读 jql;否则在
favourite/my两个端点里按 id 或名称匹配;都未命中 → 返回
ok=false,提示可用jira_list_filters查看。
结果额外附
filter(名称)与jql(解析出的 JQL),便于调用方继续扩展 JQL。
jira_issue_table — 问题导航器内部接口(详见「内部接口专项设计」)
jira_get_issue(key) — 按 key 查单条,返回原始字段(单条 payload 小,无需精简)。
jira_get_issue_types(project_key) — 建单前的类型枚举
调
GET /issue/createmeta?projectKeys=<k>&expand=projects.issuetypes;返回
[{id, name}]。name 可能本地化(中文「任务/缺陷」),建单前必须用它确认。
jira_create_issue(project_key, summary, description="", issue_type="Task", assignee="", priority="")
issue_type/priority/assignee均用名称(Server 版语义,非 Cloud 的 accountId):issuetype: {"name": ...}、priority: {"name": ...}、assignee: {"name": ...};空值字段不写入
fields,避免误提交;
成功返回
{key, id, url},url直接拼成/browse/{key}供用户点击。
jira_update_issue(key, summary/description/assignee/priority)
只把非空字段放入
fields(增量更新);全空 → 返回
ok=false「没有传入任何要更新的字段」,避免无意义 PUT。
jira_list_transitions / jira_transition_issue
list返回[{id, name}];transition支持按名称或 id定位目标流转(名称本地化,所以支持 id 兜底);未命中 → 返回
ok=false并列出所有可用名称,方便客户端纠正。
抗截断设计
MCP 工具结果过大(如一次 raw 搜索 50 条 issue 约 180 KB)会撑爆 LLM 的工具结果沙箱。 本项目在服务端做精简,把体积压到 ~1/10:
_name(obj) — 字段规整
Jira 字段值可能是 dict(如 {"name": ..., "displayName": ..., "key": ...})、str 或
None。统一规整成可读字符串:
def _name(obj):
if isinstance(obj, dict):
return obj.get("name") or obj.get("displayName") or obj.get("key") or ""
if isinstance(obj, str):
return obj
return ""_summarize_issue — 单条 issue 精简
return {
"key", "summary", "status", "priority", "type",
"assignee", "reporter", "created", "updated",
}丢弃
avatarUrls/iconUrl/expand/ 嵌套对象等冗余字段;状态/优先级/类型/经办人/报告人全部 flatten 成字符串。
_summarize_search — 搜索结果精简
保留分页元信息 total / startAt / maxResults + 精简后的 issues 列表。
_summarize_issue_table — 表格结果精简(最激进)
issueTable 接口返回的 table 字段是渲染好的 HTML(几百 KB)。只保留:
total, displayed, page, pageSize, startIndex, sortBy, columnConfig, columns, issueKeys丢弃 HTML table 字段本身。
内部接口专项设计
jira_issue_table 是对 Jira 问题导航器内部接口的封装,与标准 REST v2 不同:
端点:
POST /rest/issueNav/1/issueTable(不在/rest/api/2/前缀下);请求体:
application/x-www-form-urlencoded;参数:
startIndex/filterId/jql/layoutKey;必要请求头:
X-Atlassian-Token: no-check— 跳过 Jira 的 XSRF 校验;X-Requested-With: XMLHttpRequest— 标记为 AJAX 请求。
与 jira_search 的区别:本工具返回 Jira 页面同款的列配置与排序
(columnConfig / sortBy),更适合还原「我在 Jira 页面上看到的那个列表」。
默认 JQL:assignee = currentUser() AND resolution = Unresolved order by updated DESC,
即「当前账号未解决的问题」,配合 jira-unresolved-issues skill 使用。
错误处理设计
场景 | 行为 |
HTTP 4xx/5xx |
|
JSON 解析失败 | 退化为 |
204 无内容 | 返回 |
筛选器未命中 |
|
状态流转未命中 |
|
更新无字段 |
|
无凭据 | 请求返回 401 → 规整为 |
设计原则:所有错误都走 {"ok": false, "error": <可读文本>},错误文本尽量带上
「下一步建议」(如「可用 jira_list_filters 查看」)。
关键设计决策与权衡
决策 | 理由 | 权衡 |
单文件 | 部署极简,stdio 挂载无路径依赖 | 扩展性靠新增函数,非模块化 |
服务端做 payload 精简 | 抗截断,省 LLM token |
|
认证走 Basic Auth | 7.3.6 无 PAT 的硬约束 | 密码明文走 HTTPS,需专用账号 |
默认关 SSL 校验 | 自签证书环境 | 有中间人风险,仅内网可接受 |
工具永不抛异常 | LLM 能读错误继续推理 | 客户端需自己判断 |
| Server 版语义 | Cloud 用 |
名称 + id 双通道定位(流转/筛选器) | 名称本地化易错,id 稳定 | 略增解析逻辑 |
测试与验证设计
项目内置三类验证脚本,分层覆盖:
脚本 | 层 | 说明 |
| 传输 + 注册 | 以真实 MCP 客户端身份拉起 server,验证握手 + 工具注册 + 一次调用(无凭据 → 应得 |
| 端到端 | 从 |
| 只读工具 | 直接 import server,覆盖 |
| 实连 | 加载 |
验证原则:不要只 import 模块做 Python 内省 —— 必须走 MCP stdio 传输做
initialize + list_tools + call_tool,才能发现传输层 / 注册层的 bug。
已知坑:stdio server 会把 INFO 日志(Processing request of type ...)打到 stdout,
握手时无害(客户端读 JSON-RPC 帧而非裸 stdout),但 shell 一行式调用时应 2>/dev/null 抑制。
已知限制与注意点
建单前先确认类型名:
issue_type/priority名称可能本地化(中文环境「任务/缺陷」), 先用jira_get_issue_types确认精确名称。description是纯字符串:7.x 上 wiki/plain 渲染按字段配置,纯字符串两者兼容。代理会破坏自托管 Jira 的 TLS:
jira.gacrnd.com解析到内网 IP,但 shell 的https_proxy(如 Clash127.0.0.1:7897)仍会命中,因为no_proxy的 CIDR 条目 (172.16.0.0/12)匹配的是主机名而非解析后的 IP。CONNECT 隧道导致 TLS 握手 失败报SSL: UNEXPECTED_EOF_WHILE_READING(非证书错误)。修复:把主机名加入no_proxy(如.gacrnd.com),或对 session 设trust_env=False/ 显式空代理。编辑 server.py 后需重启会话:Hermes 在会话启动时发现 MCP 工具;改动后需
/reset(CLI)//restart(gateway)才生效。JIRA_DEFAULT_PROJECT尚未消费:预留字段,后续可用于建单默认项目。工具永不抛异常:每个工具返回
{"ok": true, "data": ...}或{"ok": false, "error": ...},失败不会抛异常,便于 AI 客户端读取错误继续处理。
扩展方向
分页遍历:
jira_search当前单页返回,可加startAt遍历;消费
JIRA_DEFAULT_PROJECT:建单时缺省 project key;附件 / 字段配置读取:接入
raw=True已有数据,封装成专用工具;8.14+ PAT 兼容:
JIRA_PERSONAL_TOKEN已预留,升级实例后自动走 Bearer;权限白名单:为写操作(建单/改单/流转/评论)加项目级 / 账号级开关,控制 AI 写权限。
附录:文件清单
文件 | 作用 |
| 主程序,全部工具 + 客户端实现 |
| 依赖: |
| 本文档:快速上手 + 详细设计 |
| 环境变量模板 |
| 端到端握手 + 新工具探测 |
| stdio 握手 + 注册自测 |
| 只读工具覆盖测试 |
| 实连冒烟测试 |
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityCmaintenanceMCP server that wraps the jira-cli command-line tool to enable AI assistants to interact with Jira.149MIT
- Alicense-qualityDmaintenanceA local-only MCP server providing safe, typed Jira tools for AI agents via Atlassian ACLI, enabling search, get issue, add comment, and transition issues with policy guardrails.MIT
- Alicense-qualityCmaintenanceA server that exposes Jira Cloud operations as MCP tools, enabling programmatic management of Epics, Stories, Tasks, and Sprints directly from an AI chat or agentic workflow.1MIT
- Alicense-qualityCmaintenanceA lightweight MCP server that exposes Jira issue operations (get, search, create) as tools for AI clients like Claude.55ISC
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
MCP server exposing the Backtest360 engine API as tools for AI agents.
MCP server for AI access to SmartBear tools, including BugSnag, Reflect, Swagger, PactFlow, QTM4J.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Pandacli/jira-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server