@massapi/redmine-mcp
v1.0.4
Published
一个基于 Node.js 的 Redmine MCP 服务,使用 `stdio` 作为传输层,适合被支持 MCP 的桌面客户端、CLI 或编辑器直接拉起。
Readme
redmine-mcp
一个基于 Node.js 的 Redmine MCP 服务,使用 stdio 作为传输层,适合被支持 MCP 的桌面客户端、CLI 或编辑器直接拉起。
当前实现聚焦 只读查询,把 Redmine REST API 暴露为 4 个 MCP tools,方便大模型在不直接操作 Redmine 界面的情况下查询项目和问题信息。
功能概览
- 基于
@modelcontextprotocol/sdk实现 MCP Server - 使用
stdio传输,适合本地命令方式接入 - 只提供只读工具,不包含创建、编辑、关闭 Issue 等写操作
- 支持项目列表查询、问题列表查询、单个问题详情查询
- 支持按项目和时间段直接汇总 issue summary,减少上下文消耗
- 自动为项目和问题补充可直接打开的
link字段 - 查询单个 Issue 时始终附带
journals - 从
journals中提取progress_items,便于模型总结问题进展 - 提供结构化 JSON 日志,日志级别可配置
- 支持通过
REDMINE_TLS_INSECURE=true忽略 TLS 证书校验
已实现的 MCP Tools
1. redmine_list_projects
分页查询 Redmine 项目。
支持参数:
limit:返回数量,默认100,最大200offset:分页偏移,默认0include:可选,支持 Redmine 原生include参数,例如trackers、issue_categories、enabled_modules
返回结果包含:
total_countoffsetlimitprojects
每个项目会额外补充:
link:项目页面链接parent.link:父项目链接(如果存在父项目)
2. redmine_list_issues
按条件分页查询问题列表。
支持参数:
limit:返回数量,默认100,最大200offset:分页偏移,默认0project_id:项目 ID 或项目标识符subproject_idstatus_id:支持*表示全部状态assigned_to_idtracker_idpriority_idauthor_idquery_idcreated_from:可选,按created_on过滤的开始日期,YYYY-MM-DD,包含当天created_to:可选,按created_on过滤的结束日期,YYYY-MM-DD,包含当天closed_from:可选,按closed_on过滤的开始日期,YYYY-MM-DD,包含当天closed_to:可选,按closed_on过滤的结束日期,YYYY-MM-DD,包含当天sort:例如updated_on:descinclude:可选 Redmineinclude参数,但不允许attachments、children
返回结果包含:
total_countoffsetlimitissues
每个问题会额外补充:
link:问题页面链接project.link:所属项目链接(如果存在)progress_items:从journals中提取出的进展记录(仅在返回内容中包含可提取信息时出现)
同时会移除以下字段以减少上下文:
fixed_versiondescriptionis_privateestimated_hourstotal_estimated_hoursspent_hours
3. redmine_get_issue
查询单个问题详情。
支持参数:
issue_id:问题 ID,必填
返回结果包含:
issue
其中会额外补充:
linkproject.link(如果存在)
同时会做以下裁剪以减少上下文:
- 请求固定只向 Redmine 查询
journals - 去掉
fixed_version - 去掉
description journals仅保留最后 1 条- 最后 1 条
journal.notes最多保留64个字符
4. redmine_summarize_issues
按项目和时间段直接返回 issue 聚合统计,适合在不展开 issue 明细的情况下获取 summary;start_date 和 end_date 均可省略,也支持仅传其中一个作为开区间。特别注意:end_date 也是包含当天的。
支持参数:
project_id:项目 ID 或项目标识符,必填subproject_id:可选,子项目过滤start_date:可选,开始日期,YYYY-MM-DD,包含当天end_date:可选,结束日期,YYYY-MM-DD,包含当天,且统计会包含end_date当天的全部更新/关闭/新建记录
返回结果包含:
projectperiodsummaryissue_type_totalsby_tracker
统计口径:
total_count:项目当前 issue 总数,不区分时间段open_count:项目当前打开 issue 总数,不区分时间段done_ratio:完成率,计算方式为(total_count - open_count) / total_countcreated_count:时间范围内新建 issue 数;未传时间时表示全部历史closed_count:时间范围内关闭 issue 数;未传时间时表示全部历史active_count:时间范围内updated_on有更新的 issue 数;未传时间时表示全部历史issue_type_totals:按 issue 类型(tracker)汇总的总数by_tracker:按 issue 类型(tracker)分别统计上述全部指标,并额外返回created_issues、closed_issues、active_issues三组具体 issue 列表
直接调用示例:
{
"project_id": "demo-project",
"start_date": "2026-03-01",
"end_date": "2026-03-15"
}如果只传开始时间:
{
"project_id": "demo-project",
"start_date": "2026-03-01"
}如果需要包含子项目过滤:
{
"project_id": "demo-project",
"subproject_id": "frontend",
"start_date": "2026-03-01",
"end_date": "2026-03-15"
}环境要求
- Node.js
>=20 - 一个可访问的 Redmine 服务
- 对应 Redmine 的 API Key
环境变量
启动前需要设置以下环境变量:
| 变量名 | 必填 | 说明 |
| --- | --- | --- |
| REDMINE_BASE_URL | 是 | Redmine 基础地址,例如 https://redmine.example.com |
| REDMINE_API_KEY | 是 | Redmine API Key |
| LOG_LEVEL | 否 | 日志级别:DEBUG / INFO / WARN / ERROR,默认 WARN |
| REDMINE_TLS_INSECURE | 否 | 设为 true / 1 / yes / on 时忽略 HTTPS 证书校验 |
关于 TLS / 自签名证书
如果你的 Redmine 使用自签名证书或私有 CA,有两种方式:
- 推荐方式:设置
NODE_EXTRA_CA_CERTS=/path/to/ca.pem - 临时方式:设置
REDMINE_TLS_INSECURE=true
注意:启用 REDMINE_TLS_INSECURE=true 后,程序会设置 NODE_TLS_REJECT_UNAUTHORIZED=0,仅建议在受控环境下使用。
安装与构建
npm install
npm run build
npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN
npm publish --access public开发模式:
export REDMINE_BASE_URL="https://redmine.example.com"
export REDMINE_API_KEY="your-redmine-api-key"
export LOG_LEVEL="INFO"
npm run dev如果需要忽略证书校验:
export REDMINE_TLS_INSECURE="true"生产启动:
export REDMINE_BASE_URL="https://redmine.example.com"
export REDMINE_API_KEY="your-redmine-api-key"
export LOG_LEVEL="WARN"
npm start可用脚本
npm run dev # 使用 tsx 直接运行 TypeScript 源码
npm run build # 编译到 dist/
npm run start # 运行 dist/index.js
npm run typecheck # 仅做 TypeScript 类型检查命令行中直接启动 redmine-mcp
先安装依赖并构建:
npm install
npm run build然后在命令行里直接启动 MCP Server:
export REDMINE_BASE_URL="https://redmine.example.com"
export REDMINE_API_KEY="your-redmine-api-key"
export LOG_LEVEL="WARN"
node dist/index.js如果希望直接运行 TypeScript 源码:
export REDMINE_BASE_URL="https://redmine.example.com"
export REDMINE_API_KEY="your-redmine-api-key"
export LOG_LEVEL="INFO"
npx tsx src/index.ts注意:上面两个命令只是启动 redmine-mcp 这个 stdio MCP Server。它会等待 MCP Client 通过标准输入/输出发送协议消息,而不是像普通 REST API 那样直接在 shell 里追加一个 tool 名称就立即返回结果。
在命令行里调用 MCP tools
如果你想在命令行环境里直接调试并调用 redmine_list_projects()、redmine_list_issues()、redmine_get_issue(),推荐使用 MCP Inspector:
HOST=0.0.0.0 npx @modelcontextprotocol/inspector \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node /workspace/dist/index.js说明:
- 这个项目使用的是
stdioMCP 传输,dist/index.js本身不会暴露 HTTP API;网页入口由 Inspector 提供。 - 推荐使用
-e KEY=VALUE显式传递环境变量,避免 Inspector 子进程没有继承当前 shell 环境,导致 MCP Server 启动时报缺少REDMINE_BASE_URL或REDMINE_API_KEY。 HOST=0.0.0.0表示 Inspector 监听所有网卡地址;如果浏览器里打不开它输出的http://0.0.0.0:6274/...,请把地址里的0.0.0.0改成127.0.0.1或当前机器的实际 IP。- 如果你是在 Docker、远程开发机、云 IDE 或 Codespace 里运行,还需要额外暴露 / 转发 Inspector 使用的端口。
也可以先用 CLI 模式快速验证 MCP Server 是否启动成功:
npx @modelcontextprotocol/inspector --cli \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node /workspace/dist/index.js --method tools/list如果你要验证 npm 已发布版本,不要写成 node @massapi/[email protected]。
node 只能执行本地文件路径,这种写法会让子进程在 MCP 握手前直接退出,Inspector 通常只会看到:
Failed to connect to MCP server: MCP error -32000: Connection closed更稳妥的已发布包验证方式是先安装,再执行包内入口文件:
npm install @massapi/[email protected]
npx @modelcontextprotocol/inspector --cli \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node ./node_modules/@massapi/redmine-mcp/dist/index.js \
--method tools/list如果你想直接在命令行里测试具体 tool,可以继续使用 --cli 模式:
redmine_list_projects
npx @modelcontextprotocol/inspector --cli \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node /workspace/dist/index.js \
--method tools/call \
--tool-name redmine_list_projects \
--tool-arg limit=20 \
--tool-arg offset=0redmine_list_issues
npx @modelcontextprotocol/inspector --cli \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node /workspace/dist/index.js \
--method tools/call \
--tool-name redmine_list_issues \
--tool-arg project_id=demo \
--tool-arg status_id='*' \
--tool-arg created_from=2026-03-01 \
--tool-arg created_to=2026-03-15 \
--tool-arg limit=20 \
--tool-arg sort=updated_on:desc \
--tool-arg include=journalsredmine_get_issue
npx @modelcontextprotocol/inspector --cli \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node /workspace/dist/index.js \
--method tools/call \
--tool-name redmine_get_issue \
--tool-arg issue_id=12345redmine_summarize_issues
npx @modelcontextprotocol/inspector --cli \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node /workspace/dist/index.js \
--method tools/call \
--tool-name redmine_summarize_issues \
--tool-arg project_id=demo \
--tool-arg start_date=2026-03-01 \
--tool-arg end_date=2026-03-15只按开始时间过滤:
npx @modelcontextprotocol/inspector --cli \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node /workspace/dist/index.js \
--method tools/call \
--tool-name redmine_summarize_issues \
--tool-arg project_id=demo \
--tool-arg start_date=2026-03-01启动后,Inspector 会连接到该服务,你可以在界面里直接执行以下参数示例:
redmine_list_projects
{
"limit": 20,
"offset": 0,
"include": ["trackers", "enabled_modules"]
}redmine_list_issues
{
"project_id": "demo",
"status_id": "*",
"created_from": "2026-03-01",
"created_to": "2026-03-15",
"closed_from": "2026-03-10",
"closed_to": "2026-03-20",
"limit": 20,
"sort": "updated_on:desc",
"include": "journals"
}只按 closed_from / closed_to 查询:
{
"project_id": "demo",
"status_id": "closed",
"closed_from": "2026-03-10",
"closed_to": "2026-03-20",
"limit": 20,
"sort": "closed_on:desc"
}对应的 Inspector CLI 示例:
npx @modelcontextprotocol/inspector --cli \
-e REDMINE_BASE_URL=https://redmine.example.com \
-e REDMINE_API_KEY=your-redmine-api-key \
-e REDMINE_TLS_INSECURE=true \
-e LOG_LEVEL=WARN \
node /workspace/dist/index.js \
--method tools/call \
--tool-name redmine_list_issues \
--tool-arg project_id=demo \
--tool-arg status_id=closed \
--tool-arg closed_from=2026-03-10 \
--tool-arg closed_to=2026-03-20 \
--tool-arg limit=20 \
--tool-arg sort=closed_on:descredmine_get_issue
{
"issue_id": 12345
}redmine_summarize_issues
{
"project_id": "demo",
"start_date": "2026-03-01",
"end_date": "2026-03-15"
}{
"project_id": "demo",
"start_date": "2026-03-01"
}MCP 客户端接入
推荐先执行 npm run build,然后让 MCP 客户端启动 dist/index.js。
通用 MCP 配置示例
{
"mcpServers": {
"redmine": {
"command": "npx",
"args": ["-y","@massapi/redmine-mcp"],
"env": {
"REDMINE_BASE_URL": "https://redmine.example.com",
"REDMINE_API_KEY": "your-redmine-api-key",
"REDMINE_TLS_INSECURE": "true",
"LOG_LEVEL": "WARN"
},
"alwaysAllow": [
"redmine_list_issues",
"redmine_list_projects",
"redmine_get_issue",
"redmine_summarize_issues"
]
}
}
}如果你希望直接运行 TypeScript 源码:
{
"mcpServers": {
"redmine": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/redmine-mcp/src/index.ts"],
"env": {
"REDMINE_BASE_URL": "https://redmine.example.com",
"REDMINE_API_KEY": "your-redmine-api-key",
"REDMINE_TLS_INSECURE": "true",
"LOG_LEVEL": "INFO"
}
}
}
}Codex CLI 配置示例
如果你使用 Codex CLI,可以把它作为 MCP Server 加入配置:
[mcp_servers.redmine]
command = "node"
args = ["/absolute/path/to/redmine-mcp/dist/index.js"]
[mcp_servers.redmine.env]
REDMINE_BASE_URL = "https://redmine.example.com"
REDMINE_API_KEY = "your-redmine-api-key"
LOG_LEVEL = "WARN"如果直接跑源码:
[mcp_servers.redmine]
command = "npx"
args = ["tsx", "/absolute/path/to/redmine-mcp/src/index.ts"]
[mcp_servers.redmine.env]
REDMINE_BASE_URL = "https://redmine.example.com"
REDMINE_API_KEY = "your-redmine-api-key"
REDMINE_TLS_INSECURE = "true"
LOG_LEVEL = "INFO"返回结果说明
该服务对 Redmine 原始返回做了少量增强,便于大模型消费:
- 为项目和问题增加
link字段,方便直接跳转到 Redmine 页面 - 对项目的
parent也会补充link - 对问题的
project也会补充link - 从
journals中提取progress_items,用于表示可读的进展轨迹
progress_items 的来源是 Issue 的 journals。只有当某条 journal 含有 notes 或 details 时,才会被纳入结果。
日志行为
日志写入标准错误输出(stderr),格式为 JSON,包含以下典型字段:
timestamplevelcontextmessagedata
其中:
INFO级别会记录 Redmine 请求与响应摘要DEBUG级别会额外记录响应体预览- API Key 在日志中会被脱敏处理
- 响应体日志会做长度截断,避免输出过大
错误处理
当前实现包含以下主要错误场景:
- 缺少必要环境变量时,启动失败
- 输入参数类型不合法时,返回参数错误
- 无法连接 Redmine 时,返回上游连接错误
- Redmine 返回非 2xx 响应时,透传状态码并记录响应内容
- Redmine 返回非 JSON 内容时,返回解析错误
如果 MCP 客户端里看到:
Failed to connect to MCP server: MCP error -32000: Connection closed通常表示 MCP 子进程在握手前就退出了。优先按下面顺序排查:
- 先在仓库目录执行
npm install && npm run build - 如果客户端启动的是
dist/index.js,确认构建产物dist/index.js已存在 - 确认 MCP 配置里的
env传入了REDMINE_BASE_URL和REDMINE_API_KEY - 如果使用
npx拉起包,确认包名写的是@massapi/redmine-mcp,而不是其他同名包 - 不要把 npm 包名直接写在
node后面;node @massapi/[email protected]会被当成本地路径,最终报MODULE_NOT_FOUND - 在终端里直接运行
node dist/index.js或npx tsx src/index.ts,优先看stderr的真实报错
项目结构
src/
├── config.ts # 环境变量加载与校验
├── index.ts # 进程入口,启动 stdio MCP Server
├── logger.ts # JSON 日志封装
├── mcp-server.ts # MCP tools 注册
├── services/
│ └── redmine.ts # Redmine API 调用与结果增强
└── types.ts # 类型定义与错误类型当前边界
当前版本仅实现只读能力,尚未包含:
- 创建/更新/删除 Issue
- 评论 Issue
- 上传附件
- 查询用户、版本、工时等更多 Redmine 资源
- SSE / HTTP Stream 等其他传输方式
如果后续要扩展写操作,建议将读写工具分组,并为高风险操作增加更明确的参数校验与确认机制。
