mcpField
R
Redmine MCP Server

Redmine MCP Server

本地服务
github.com生产力04 周前更新

关于 Redmine MCP Server

Redmine MCP Server 将企业 Redmine 实例连接到 AI Agent,用于处理项目、问题、Wiki、附件和工时。它结合了广泛的只读能力、版本分析,以及可选且可配置的写入工具。

主要功能

  1. 01浏览项目、问题和成员
  2. 02搜索问题、Wiki 与 Redmine 内容
  3. 03读取附件及支持的文档文本
  4. 04查看工时记录和参考数据
  5. 05分析工作量与版本风险
  6. 06启用或禁用写入及工具组

适用场景

  1. 01审查并分拣项目问题
  2. 02查找 Wiki 页面和附件中的信息
  3. 03检查用户工作量和逾期事项
  4. 04评估项目版本的风险

MCP 相关

它通过 stdio 将 Redmine 数据和操作作为 MCP 工具及提示词提供。默认提供七种写入工具,可通过 REDMINE_MCP_WRITE_ENABLED=false 禁用;也可单独禁用工具组。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"igorolv-redmine": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"REDMINE_URL",
"-e",
"REDMINE_API_KEY",
"-e",
"REDMINE_MCP_WRITE_ENABLED",
"ghcr.io/igorolv/redmine-mcp-server:0.1.1"
],
"env": {
"REDMINE_URL": "<REDMINE_URL>",
"REDMINE_API_KEY": "<REDMINE_API_KEY>",
"REDMINE_MCP_WRITE_ENABLED": "<REDMINE_MCP_WRITE_ENABLED>"
}
}
}
}
启动命令docker run -i --rm -e REDMINE_URL -e REDMINE_API_KEY -e REDMINE_MCP_WRITE_ENABLED ghcr.io/igorolv/redmine-mcp-server:0.1.1
需要配置的环境变量
REDMINE_URLBase URL of the Redmine instance, e.g. https://redmine.example.com
REDMINE_API_KEY密钥Redmine API key of the user the server acts as (My account -> API access key)
REDMINE_MCP_WRITE_ENABLEDSet to true to also expose the issue, note, attachment, time-entry and wiki write tools

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
ocighcr.io/igorolv/redmine-mcp-server:0.1.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

Redmine MCP 服务

CI Release License Java 25 MCP Glama score Listed on mcpservers.org

用于访问企业 Redmine 实例的本地 MCP 服务。除了读取工具外,它还提供一组有限的写入操作,用于处理问题、工时记录和 Wiki;设置 REDMINE_MCP_WRITE_ENABLED=false 即可仅以只读模式运行。它允许 AI Agent(Claude Code、Cursor、 VS Code Copilot 等)处理问题、项目、成员、版本、Wiki、附件、工时记录和参考数据。

快速开始

本文档介绍如何安装和连接 Redmine MCP Server 本身。AI 客户端的安装和配置不在本文档的讨论范围内。

  1. 安装 JDK 25+。
  2. 从最新版本下载 redmine-mcp-server.jar, 或自行构建:./gradlew bootJar(参见构建)。此外也提供 Docker 镜像。
  3. 获取 REDMINE_URL 和 REDMINE_API_KEY(参见配置)。
  4. 确认 JAR 可以启动(参见冒烟测试)。
  5. 将 JAR 添加到客户端的 MCP 配置中(参见连接 AI 客户端)。

对于 Claude Code,只需运行一条命令:

claude mcp add --scope user -e REDMINE_URL=https://redmine.example.com -e REDMINE_API_KEY=your_key -- redmine java -jar /path/to/redmine-mcp-server.jar

架构

该服务仅支持 stdio 传输方式。

Stdio
┌─────────────┐     stdio      ┌──────────────────┐    REST API    ┌──────────┐
│  AI agent   │ <------------> │  redmine-mcp-    │ -------------> │ Redmine  │
│ (Claude Code│   stdin/stdout │  server (Java)   │   HTTP + API   │ (corp.)  │
│  Cursor...) │                │                  │   Key          │          │
└─────────────┘                └──────────────────┘                └──────────┘

AI 客户端会将服务作为子进程启动;通信通过 stdin/stdout 按照 MCP 协议进行。

工具

该服务默认提供 32 个只读 MCP 工具,外加 7 个写入工具。设置 REDMINE_MCP_WRITE_ENABLED=false 可移除写入工具,并以纯只读模式运行。

用户
工具描述
getCurrentUser当前用户:ID、登录名、用户组、项目。适用于筛选“我的问题”
项目
工具描述
listProjects列出所有可访问的项目
getProject项目详情:跟踪器、模块、描述
listProjectMembers项目成员及其角色
listVersions项目版本(里程碑)
问题
工具描述
listIssues问题列表,支持按项目、状态、跟踪器、指派人、优先级、版本、已保存的查询、自定义字段(customFieldFilters 采用 cf_<id>=value 格式)和排序进行筛选
searchIssues全文搜索问题并返回详细结果
getIssue问题详情:描述、状态、指派人、日期、备注、关联关系、自定义字段、附件和关联修订(changesets)。参数:issueId、focus(default、implementation、timeline、full;可选)
getIssueJournal获取一条完整的问题日志备注/事件,不压缩响应。参数:issueId、journalId
getMyIssues当前用户的问题。参数:projectId、statusId、sort、limit、offset
getIssueTree父级链和子任务。root 和 ancestors 保留 Issue JSON 结构,但只包含精简上下文;如需完整详情或关联关系,请调用 getIssue。参数:issueId、depth(默认值为 2,最大值为 5)
getIssueHistory创建记录和每条日志事件,以及状态时间段。长文本会被缩短;journalId 用于标识可通过 getIssueJournal 获取的完整条目。使用可选的 offset 参数跟进 nextOffset,直到该字段缺失。
问题、时间条目和 Wiki 写入(可选)

这些工具默认会出现在 tools/list 中;设置 REDMINE_MCP_WRITE_ENABLED=false 可将其移除:

工具描述
createIssue创建问题。支持 Redmine 核心字段和通过 customFieldsJson 指定的自定义字段
updateIssue部分更新现有问题的指定字段
addIssueNote向问题日志添加备注
attachFileToIssue从任意可读取的本地路径上传文件并将其附加到问题
createTimeEntry为 REDMINE_API_KEY 对应的用户创建时间条目;接受 issueId/projectId 中的且仅其中一个,以及工时、日期、活动、评论和自定义字段
createWikiPage创建 Wiki 页面;如果页面已存在,则拒绝请求
updateWikiPage完整替换 Wiki 页面文本;需要提供 getWikiPage 返回的乐观锁版本

Redmine 本身会强制执行 REDMINE_API_KEY 对应用户的权限、工作流和必填字段规则。MCP 服务不会额外定义“自己的”问题或备注。为便于识别由 AI 创建的问题,默认会在 createIssue 创建的问题描述前加上 AI_EDIT:(updateIssue 不会添加此前缀)。备注、时间条目评论、Wiki 修订评论和上传的文件名默认不会添加标记;每种标记都由单独的 REDMINE_MCP_WRITE_*_PREFIX 变量配置(参见配置),值为空时会关闭标记。问题描述和备注会在单独一行添加前缀,后接一个空行;单行字段(时间条目和 Wiki 修订评论)会添加前缀和一个空格;文件名会添加前缀,不加分隔符。Wiki 页面标记本身不会被更改。

当前未实现编辑和删除已有备注:目标版本 Redmine 4.0.4 未提供兼容的 REST API。编辑和删除时间条目、删除、重命名和保护 Wiki 页面,以及代表其他用户创建时间条目,均不属于当前操作范围。

搜索
工具描述
searchAllRedmine 全局搜索:问题、Wiki、新闻、文档、提交记录等。参数:searchQuery、projectId、types、limit、offset
附件和 Wiki
工具描述
getAttachment将原始附件文件下载到本地快照目录,返回 localPath/fileUri;如果格式受支持,则立即将文本上下文添加到 parts[]:txt/log/xml/json/csv、PDF、Word(.docx)、Excel(.xlsx)、PowerPoint(.pptx)、ZIP。ZIP 中的每个条目都可能生成单独的 part。.docx 会生成一个文本 part:有 pandoc 时为 pandoc markdown,否则为 POI 纯文本。参数:issueId、attachmentId、maxChars、partLimit(参见 处理限制)
getWikiPage项目 Wiki 页面的内容
listWikiPages列出项目的所有 Wiki 页面
searchWikiPages在 Wiki 页面中进行全文搜索。参数:searchQuery、projectId、limit、offset
时间条目
工具描述
listTimeEntries按项目、问题、用户和时间段筛选已记录的时间
getMyTimeEntries当前用户已记录的时间。参数:projectId、issueId、from、to、limit、offset
参考数据
工具描述
listQueries已保存的查询(自定义筛选条件)——ID + 名称。将 ID 与 listIssues(queryId) 搭配使用以应用筛选条件,包括自定义字段筛选条件
listStatuses所有问题状态(ID + 名称)——用于筛选 listIssues
listTrackers所有跟踪器(ID + 名称)——用于筛选 listIssues
listPriorities所有优先级(ID + 名称)——用于筛选 listIssues
listIssueCategories项目的问题类别(ID + 名称)
listTimeEntryActivities用于解读现有时间条目的活动类型(ID + 名称)
分析
工具描述
getProjectSummary项目汇总数据:未关闭/已关闭问题总数;按状态、跟踪器、优先级和负责人分类分析未关闭问题;逾期问题;预估/已用工时。最多分析 500 个未关闭问题,并返回截断标记。参数:projectId、versionId(可选)
getUserWorkload工作负载分析:按项目和优先级统计未关闭问题、逾期问题、重点问题。最多分析 500 个未关闭问题,并返回截断标记。参数:userId(可选,默认为当前用户)、projectId(可选)
getVersionChangelog按跟踪器对版本问题分组,并统计未关闭/已关闭问题。最多分析 500 个问题,并返回截断标记。参数:projectId、versionId
getBlockerChain递归遍历向上和向下的阻塞链(blocks/blocked_by),深度最多为 10,加载的问题最多为 30 个。参数:issueId
getStaleIssues按更新时间从早到晚列出 N 天内未更新的未关闭问题。参数:projectId、daysSinceUpdate(默认值为 30)、limit
getReleaseRisks发布风险评估:阻塞项、逾期事项、高优先级问题、未分配的问题。最多分析 500 个未关闭问题,并返回截断标记。参数:projectId、versionId
compareVersions比较两个版本:独有问题、共同问题、关闭率。每个版本最多分析 500 个问题,并返回截断标记。参数:projectId、versionId1、versionId2

当 REDMINE_MCP_WRITE_ENABLED=false 时,所有工具均为只读,不会修改 Redmine 中的任何数据。

工具组(启用/禁用)

工具按领域分组,每组都可以通过环境变量禁用。 默认情况下所有组均已启用——开箱即用的工具清单保持不变。禁用 工具组会缩小 MCP tools/list 清单,客户端会在会话开始时将其加载到模型上下文中。 这有助于上下文较小的(本地)模型:禁用不需要的工具组,只保留模型实际需要的工具。

变量组(工具)
REDMINE_MCP_TOOLS_ISSUE问题(核心):listIssues、searchIssues、getIssue、getMyIssues、getIssueJournal
REDMINE_MCP_TOOLS_ISSUE_STRUCTURE问题结构/历史:getIssueTree、getIssueHistory
REDMINE_MCP_TOOLS_PROJECT项目:listProjects、getProject、listProjectMembers、listVersions
REDMINE_MCP_TOOLS_SEARCH搜索:searchAll
REDMINE_MCP_TOOLS_ATTACHMENT附件:getAttachment
REDMINE_MCP_TOOLS_WIKIWiki:getWikiPage、listWikiPages、searchWikiPages
REDMINE_MCP_TOOLS_TIME_ENTRY时间条目:listTimeEntries、getMyTimeEntries
REDMINE_MCP_TOOLS_REFERENCE_DATA参考数据:listQueries、listStatuses、listTrackers、listPriorities、listIssueCategories、listTimeEntryActivities
REDMINE_MCP_TOOLS_USER用户:getCurrentUser
REDMINE_MCP_TOOLS_ISSUE_ANALYTICS问题分析:getBlockerChain、getStaleIssues
REDMINE_MCP_TOOLS_RELEASE_ANALYTICS发布/项目分析:getProjectSummary、getUserWorkload、getVersionChangelog、getReleaseRisks、compareVersions

每个变量都接受 true(默认值)或 false。示例:若只保留问题和项目相关工作, 请禁用其余工具组——REDMINE_MCP_TOOLS_RELEASE_ANALYTICS=false、 REDMINE_MCP_TOOLS_WIKI=false 等。MCP 提示词不受这些标志影响;如果某个工具已禁用,提示词会告诉模型跳过相应步骤。

MCP 提示词

该服务还提供用于典型问题处理场景的 MCP 提示词。每个提示词都需要一个参数, issueId——Redmine 问题编号(12345 或 #12345)。

提示词描述
incident-brief快速了解事件:通过 getIssue 获取问题,通过 getAttachment 下载所有附件并提供简短预览,然后生成简洁的 Markdown 报告
incident-implementation实施背景:使用 focus=implementation 获取问题,按名称、描述和日期挑选相关附件,仅在必要时恢复压缩的日志数据,然后生成需求、修订依据和验证清单
incident-timeline事件时间线:使用 getIssue(focus=timeline) 获取问题和变更集背景,然后读取 getIssueHistory 的每一页,以获取日志事件和状态区间
issue-remaining-work尚未完成的事项:结合 getIssue、getIssueTree(相关时包括同级问题)、getBlockerChain,并在需要时使用 getIssueHistory,报告未解决事项,而不单凭状态作判断

通过使用占位符参数请求提示词来构建命令模板的客户端(例如发送 $1 的 opencode 1.x)会获得保留占位符的模板,因此客户端自身的替换机制可以继续正常工作。

技术栈

  • Java 25、Spring Boot 4.2.0-M2、Spring AI MCP 2.1.0-M1(stdio 传输)
  • Apache PDFBox 3.0.5——从 PDF 中提取文本
  • Apache POI 5.4.0——从 Word、Excel、PowerPoint 中提取文本
  • Apache Tika 3.2.0(core + parsers-standard)——备用解析器和元数据提取
  • Pandoc(可选,外部二进制程序)——如果 PATH 中有该程序,可改进 DOCX 到文本/Markdown 的转换;否则服务会使用 POI
  • 使用版本目录(gradle/libs.versions.toml)的 Gradle 9.3.1

构建

Linux/macOS:

# Point to JDK 25+ if it is not the default JDK:
export JAVA_HOME="$HOME/.jdks/jdk-25.0.2"

./gradlew build

Windows PowerShell:

# Point to JDK 25+ if it is not the default JDK:
$env:JAVA_HOME="C:\Program Files\Java\jdk-25"

.\gradlew.bat build

结果:build/libs/redmine-mcp-server.jar

配置

服务需要 REDMINE_URL 和 REDMINE_API_KEY;其余变量均为可选项:

变量描述
REDMINE_URLRedmine 实例的基础 URL(例如 https://redmine.example.com)
REDMINE_API_KEYRedmine 用户的 API 密钥
REDMINE_MCP_WRITE_ENABLED将 createIssue、updateIssue、addIssueNote、attachFileToIssue、createTimeEntry、createWikiPage、updateWikiPage 工具添加到 tools/list;设为 false 可移除这些工具并以只读模式运行;默认为 true
REDMINE_MCP_WRITE_ISSUE_DESCRIPTION_PREFIX添加到 createIssue 创建的问题描述前的标记;默认为 AI_EDIT:。设为空值可禁用
REDMINE_MCP_WRITE_ISSUE_NOTE_PREFIX添加到 addIssueNote 添加的备注前的标记;默认为空(禁用)
REDMINE_MCP_WRITE_TIME_ENTRY_COMMENT_PREFIX添加到 createTimeEntry 评论前的标记;计入 Redmine 的 1024 个字符限制;默认为空(禁用)
REDMINE_MCP_WRITE_WIKI_COMMENT_PREFIX添加到 createWikiPage / updateWikiPage 的 wiki 修订评论前的标记;默认为空(禁用)
REDMINE_MCP_WRITE_ATTACHMENT_FILENAME_PREFIX添加到 attachFileToIssue 上传文件名的前缀(例如 AI_EDIT__);不得包含 / \ ? % * : | " ' < >;默认为空(禁用)
REDMINE_MCP_DATA_DIR服务的本地数据目录;默认为 ~/.redmine-mcp-server
REDMINE_MCP_HTTP_CONNECT_TIMEOUT_SECONDS打开与 Redmine 的连接时的超时时间;默认为 10 秒
REDMINE_MCP_HTTP_READ_TIMEOUT_SECONDS等待 Redmine 响应单个请求(包括请求上传)的超时时间;默认为 30 秒。工具调用逐个处理,因此请求卡住会导致之后的所有调用延迟
REDMINE_MCP_HTTP_SLOW_REQUEST_WARN_MILLIS超过此时长的 Redmine 请求会记录为警告;默认为 5000 毫秒
REDMINE_MCP_ATTACHMENT_PER_PART_CHARS不带限制的 getAttachment 调用中,每个单独 part(例如 ZIP 中的一个文件)的文本上限;默认为 30000 个字符。工具的 partLimit 参数会覆盖此值;未提供 partLimit 时,maxChars 也会覆盖此值。
REDMINE_MCP_ATTACHMENT_PER_ATTACHMENT_CHARS不带 maxChars 的 getAttachment 调用中,每个附件提取文本的总上限;默认为 40000 个字符,可使默认响应低于 REDMINE_MCP_RESPONSE_MAX_CHARS。
REDMINE_MCP_ATTACHMENT_MAX_REQUEST_CHARS调用方传给 getAttachment 的 maxChars 和 partLimit 上限;默认为 200000 个字符。超过此上限的请求会被缩减至该值,响应中的 limits.note 会说明这一点。
REDMINE_MCP_RELATED_MAX_SIBLINGS读取问题时添加到 related 的同级问题数量上限;默认为 20
REDMINE_MCP_RELATED_MAX_CHILDREN读取问题时添加到 related 的子问题数量上限;默认为 20
REDMINE_MCP_RELATED_MAX_RELATED读取问题时,从关系中添加到 related 的相关问题数量上限;默认为 10
getIssue 通过一次轻量级读取父项,以及一次批量查询兄弟项、子项和关联目标,解析 related 上下文;不会对关联问题创建快照。timeline 和 changesets 聚焦模式会省略 related,并完全跳过这些请求。
REDMINE_MCP_RESPONSE_MAX_CHARSgetIssue 和 getAttachment 逐步压缩前的目标响应大小上限;默认为 50000 个字符
REDMINE_MCP_RESPONSE_JOURNAL_TAIL_KEEP在进一步大幅精简前,getIssue 的预算压缩保留的最新日志条目数量;默认为 30
REDMINE_MCP_RESPONSE_ATTACHMENT_TEXT_PART_CHARS在未指定 maxChars/partLimit 的 getAttachment 调用中,响应压缩期间每个附件部分的文本上限;默认为 10000 个字符。对于明确指定限制的调用,截断后的长度不会低于这些限制。
REDMINE_MCP_RESPONSE_JOURNAL_NOTE_CHARSgetIssue 响应压缩期间每条日志备注的文本上限;默认为 5000 个字符
REDMINE_MCP_RESPONSE_IMAGE_PARTS_KEEPgetAttachment 响应压缩保留的图片部分数量;默认为 5
REDMINE_MCP_PAGINATION_DEFAULT_LIMIT列表/搜索工具的默认页大小;默认为 25
REDMINE_MCP_PAGINATION_DEFAULT_OFFSET列表/搜索工具的默认偏移量;默认为 0
REDMINE_MCP_PAGINATION_MEMBERS_DEFAULT_LIMITlistProjectMembers 的默认页大小;默认为 100
REDMINE_MCP_TREE_DEFAULT_DEPTHgetIssueTree 的默认深度;默认为 2
REDMINE_MCP_TREE_MAX_DEPTHgetIssueTree 的最大深度;默认为 5
REDMINE_MCP_TREE_MAX_ISSUESgetIssueTree 加载的问题数量上限;默认为 50
REDMINE_MCP_ANALYSIS_MAX_PAGES分析工具读取的 Redmine 页面数量上限;默认为 5
REDMINE_MCP_ANALYSIS_PAGE_SIZE分析工具使用的 Redmine 页大小;默认为 100
REDMINE_MCP_ANALYSIS_TOP_ISSUES_LIMIT分析响应的热门列表中问题数量上限;默认为 10
REDMINE_MCP_ANALYSIS_MAX_BLOCKER_DEPTHgetBlockerChain 的最大遍历深度;默认为 10
REDMINE_MCP_ANALYSIS_MAX_BLOCKER_ISSUESgetBlockerChain 加载的问题数量上限;默认为 30
REDMINE_MCP_ANALYSIS_STALE_ISSUES_DEFAULT_DAYS_SINCE_UPDATEgetStaleIssues 的默认 daysSinceUpdate;默认为 30
REDMINE_MCP_ANALYSIS_STALE_ISSUES_DEFAULT_LIMITgetStaleIssues 的默认结果数量上限;默认为 25
REDMINE_MCP_ANALYSIS_STALE_ISSUES_MAX_LIMITgetStaleIssues 的最大结果数量上限;默认为 100
REDMINE_MCP_EXTRACTION_PANDOC_ENABLED当在 PATH 中找到 Pandoc 可执行文件时,启用对 DOCX 使用 Pandoc;默认为 true
REDMINE_MCP_EXTRACTION_PANDOC_PROBE_TIMEOUT_SECONDS启动时检测 Pandoc 是否可用的超时时间;默认为 2 秒
REDMINE_MCP_EXTRACTION_PANDOC_CONVERSION_TIMEOUT_SECONDS通过 Pandoc 转换单个 DOCX 的超时时间;默认为 30 秒
REDMINE_MCP_EXTRACTION_LIMITS_MAX_DEPTH处理嵌套文档和归档文件时的最大递归深度;默认为 1
REDMINE_MCP_EXTRACTION_LIMITS_MAX_TOTAL_PARTS每次提取的文本/元数据部分数量上限;默认为 100
REDMINE_MCP_EXTRACTION_LIMITS_MAX_TOTAL_BYTES每次提取的读取总字节数上限;默认为 52428800 字节
REDMINE_MCP_EXTRACTION_LIMITS_MAX_ENTRY_BYTES归档文件中单个条目的大小上限;默认为 10485760 字节
REDMINE_MCP_EXTRACTION_ZIP_MAX_ENTRIES_PER_ARCHIVE每个 ZIP 归档文件的条目数量上限;默认为 100
REDMINE_MCP_EXTRACTION_TIKA_BODY_LIMIT_BYTES传递给 Tika 回退解析器的正文大小上限;默认为 5242880 字节
REDMINE_MCP_EXTRACTION_TIKA_METADATA_MAX_FIELDS响应中 Tika 元数据字段的数量上限;默认为 40
如何获取 REDMINE_URL

在浏览器中打开 Redmine,复制地址栏中的值,不包含路径——只保留协议和域名。

示例:

浏览器地址栏中的内容REDMINE_URL 的值
https://redmine.example.com/projects/myprojecthttps://redmine.example.com
http://192.168.1.50:3000/issues/123http://192.168.1.50:3000
http://10.0.0.5/redmine/projectshttp://10.0.0.5/redmine

如果 Redmine 只能通过 IP 地址访问(没有域名),请直接使用 IP;如果端口不是标准端口(80/443),也要包含端口。如果 Redmine 部署在子路径下(例如 /redmine),也要将其包含在 URL 中。

如何获取 REDMINE_API_KEY
  1. 使用你的帐户登录 Redmine
  2. 点击 “My account”(右上角)
  3. 在右侧栏找到 “API access key” 区块
  4. 点击 “Show”,系统会显示你的个人 API 密钥
  5. 复制密钥,并将其用作 REDMINE_API_KEY 的值

如果没有显示“API access key”区块,请联系 Redmine 管理员——设置中可能禁用了 REST API。

冒烟测试

连接 AI 客户端之前,建议先验证 JAR 能否使用之后将配置到客户端中的同一组环境变量正常启动。

Linux/macOS:

REDMINE_URL=https://redmine.example.com REDMINE_API_KEY=your_key \
  java -jar build/libs/redmine-mcp-server.jar

Windows PowerShell:

$env:REDMINE_URL="https://redmine.example.com"
$env:REDMINE_API_KEY="your_key"
java -jar .\build\libs\redmine-mcp-server.jar

服务通过 stdio 运行,不会开放 HTTP 端口:成功启动后,它会静默等待通过 stdin/stdout 发送的 MCP 请求。日志中没有错误且进程没有立即退出,即表示启动成功。按 Ctrl+C 停止。

Docker

每次发布时都会将镜像推送到 GHCR:

docker run -i --rm   -e REDMINE_URL=https://redmine.example.com   -e REDMINE_API_KEY=your_key   ghcr.io/igorolv/redmine-mcp-server:latest

MCP 客户端应启动的命令也是如此(-i 会让 stdin 在 stdio 传输期间保持打开)。将主机目录挂载到 /data,即可在多次运行之间保留日志和问题快照。 若要在本地构建镜像:docker build -t redmine-mcp-server .

日志

日志写入 ${REDMINE_MCP_DATA_DIR:-~/.redmine-mcp-server}/logs/redmine-mcp-server.log。 文件按日期和大小轮转:10MB,保留 30 天,总上限为 512MB。

问题快照

加载问题时,服务会将快照保存到磁盘上的 ${REDMINE_MCP_DATA_DIR:-~/.redmine-mcp-server}/issues/<issue-id>/:issue.json、 包含快照元数据的 snapshot.json、attachments.json,以及用于存放派生文件的 extracted/<attachment-id>/ 目录。附件会保存到 attachments/ 目录下,文件名类似 <attachment-id>__<filename>;如果本地文件已存在且其大小与 Redmine 元数据相符,则可在不同快照之间重复使用。

连接到 AI 客户端

在客户端配置中添加:

{
  "command": "java",
  "args": ["-jar", "<absolute-path>/redmine-mcp-server.jar"],
  "env": {
    "REDMINE_URL": "https://redmine.example.com",
    "REDMINE_API_KEY": "your_api_key"
  }
}

具体配置位置:

客户端连接方式
Claude Codeclaude mcp add --scope user -e REDMINE_URL=... -e REDMINE_API_KEY=... -- redmine java -jar /path/to/redmine-mcp-server.jar
Qwen Code~/.qwen/settings.json -> "mcpServers" -> "redmine"
VS Code.vscode/mcp.json -> "servers" -> "redmine"
Cursor.cursor/mcp.json -> "mcpServers" -> "redmine"
Claude Desktopclaude_desktop_config.json -> "mcpServers" -> "redmine"

之后重启客户端。

运维与安全

此 MCP 服务旨在与 AI 客户端一同在本地运行。它不会开放 HTTP 端口,也不会接受任何传入的网络连接:客户端会将 JAR 作为子进程启动,并通过 stdin/stdout 与其通信。

访问模型
  • 服务使用 REDMINE_API_KEY 中设置了 API 密钥的 Redmine 用户权限。
  • 默认情况下,七个明确列出的 issue、工时记录和 wiki 写入工具可用; 设置 REDMINE_MCP_WRITE_ENABLED=false 即可完全以只读模式运行。服务既不会扩大 API 用户的权限,也不会绕过 Redmine 工作流。
  • 用户在 Redmine 中的权限决定其可访问的项目、issue、附件和工时记录。如果用户在 Redmine 中无法查看某个对象,服务也不得访问该对象。
  • REDMINE_MCP_WRITE_*_PREFIX 标记(例如创建 issue 时默认使用的 AI_EDIT:)是 搜索标签,而非授权机制:修改的作者身份由拥有 API 密钥的 Redmine 账户可靠地确定。
  • attachFileToIssue 会有意接受任何可读取的本地路径,不会限制目录白名单。由于默认 启用了写入工具,请仅在可信 AI 客户端旁运行服务,并注意客户端可以将进程可读取的 任意文件内容传入 Redmine。
  • 将 API 密钥视为机密。请勿将其提交到项目仓库、shell 脚本、.vscode/mcp.json、 .cursor/mcp.json 或项目的其他共享文件中。

开发和验证写入操作时,请使用单独的测试 Redmine 和单独的 API 密钥。由于默认启用写入, 将 integrationTest 或手动冒烟测试指向生产环境时,请设置 REDMINE_MCP_WRITE_ENABLED=false。

传递给 AI 客户端的数据

AI 客户端只会收到其通过 MCP 工具请求的数据:

  • issue 卡片:主题、描述、状态、优先级、受派人、作者、日期、关联关系、子任务、 日志/评论、自定义字段;
  • 项目、版本、成员、参考数据和工时记录的信息;
  • wiki 页面;
  • 附件元数据;
  • 原始附件文件的本地路径,以及通过 getAttachment 从 PDF、DOCX、XLSX、PPTX、 ZIP 和文本文件中提取的文本。

连接外部或云端 AI 客户端之前,请查看公司的内部政策:Redmine 数据可能包含商业机密、 个人数据、日志、密钥、错误转储和文档内容。

处理限制

代码中设有保护性限制,以防单个大型文档或相关 issue 网络使 MCP 客户端过载:

区域限制
getAttachment.parts[] 中的每个文本部分默认最多 30,000 个字符,超出部分将被截断
getAttachment 中的单个附件总量默认最多 40,000 个字符
getAttachment 中显式指定的 maxChars / partLimit每项最多支持 200,000 个字符
ZIP 深度1 层
ZIP 归档最多 100 个条目
归档中的 ZIP 文件最大 10 MB
ZIP 归档总量最多 50 MB 的解压数据
getIssueTree深度最多为 5,issue 最多为 50 个
getIssueHistory每个 JSON 页面在字符数和 UTF-8 字节数上都不超过 REDMINE_MCP_RESPONSE_MAX_CHARS;所有事件仍可通过 nextOffset 获取

getAttachment 会在 limits 中报告其应用的限制(maxChars、partLimit,以及当请求值 被调低至上限时的 note);被截断的部分会携带其完整长度 totalChars。未显式指定限制时, 如果响应仍超过 REDMINE_MCP_RESPONSE_MAX_CHARS(例如,ZIP 条目很多),则会压缩响应: 先合并额外的图像部分,再将文本部分截断至 REDMINE_MCP_RESPONSE_ATTACHMENT_TEXT_PART_CHARS。显式指定限制时,只会合并图像部分。 原始文件仍保存在磁盘上的 localPath;对于 pandoc DOCX 提取,markdown 部分也会指向 其保存的文本文件。其他文档部分可能指向 PDF 或 Office 源文件,而非单独的提取文本文件。 getIssue 支持 focus 参数。default 会保留常规响应结构,仅在超出响应预算时进行压缩。implementation 面向该问题的实现工作:完整问题仍会保存到磁盘,而工具响应会保留描述、人类备注、附件元数据和所有变更集修订;省略详细历史记录和提交消息正文。timeline 面向“谁在何时做了什么”这类问题:保留日志和变更集,但省略附件、自定义字段和相关上下文。full 是显式选择完整形式,并启用保护性预算压缩。

getIssueTree 仍会完整加载并快照每个获取的问题,但只为 root 和 ancestors 返回精简的 Issue 上下文;此视图会省略它们的描述、日志、自定义字段、附件和变更集。其 subtree 仍是层级视图。这会改变这些现有 Issue 字段的内容:此前从树中读取完整详情的客户端应改为调用 getIssue(id)。getIssueTree 不包含直接关联。

getIssueHistory 包含创建事件和每个日志事件,包括没有备注或无法识别的字段变更的日志。必要时会缩短较长的备注以及字段的新旧值,在每次更新中保留 journalId,并通过 compressionNotes 说明内容缩减情况。要获取确切措辞或完整的新旧值,请调用 getIssueJournal(issueId, journalId)。先调用 getIssueHistory(issueId);如果存在 nextOffset,就在下一次调用中将该数字作为 offset 传入。持续调用,直到 nextOffset 不再存在。totalEvents 包含创建事件。statusDurations 中的状态区间属于当前页的事件;请跨页合并。比较各页的 sourceUpdatedOn,如果它发生变化,则重新开始查询。服务使用现有的 REDMINE_MCP_RESPONSE_MAX_CHARS 设置;无需新增环境变量。 如果单个事件在缩短文本后仍无法容纳,其所在页面会保留该事件和 journalId,但将事件缩减为元数据;compressionNotes 会标明省略的状态区间,并指向 getIssueJournal 以获取完整条目。

如果你需要的备注因预算压缩而从 getIssue 响应中删除,或备注被缩短,请调用 getIssueJournal(issueId, journalId):它会重新获取问题快照,并在不进行响应压缩的情况下返回所选日志条目。

一些常规列表工具(listIssues、listProjects、listTimeEntries、listQueries)直接接受 limit 和 offset。为确保运行可靠,请避免请求过大的页面;每次调用请求 25-100 条是较为实用的范围。

诊断

环境检查:

java -version
echo "$REDMINE_URL"
test -n "$REDMINE_API_KEY" && echo "REDMINE_API_KEY is set"

Redmine REST API 访问检查:

curl -H "X-Redmine-API-Key: <key>" <url>/users/current.json

构建检查:

./gradlew test
./gradlew build

针对运行中 Redmine 的集成测试:

REDMINE_URL=<url> REDMINE_API_KEY=<key> ./gradlew integrationTest

集成测试需要可访问的 Redmine 和真实测试数据。默认情况下,单元测试不包含标记为 integration 的测试。

已知运行限制
  • HTTP 超时和重试策略目前无法分别配置。如果 Redmine 响应缓慢,MCP 调用的等待时间可能超出 AI 客户端用户的预期。
  • Redmine 错误(401、403、404、5xx)目前主要由 Spring RestClient 层处理;AI 客户端用户看到的消息可能不如专门的 MCP 工具错误友好。
  • 笔记或附件可能已成功写入,但如果 Redmine 或其他用户在确认读取之间修改了问题,其新的 journalId/attachmentId 可能仍未定义。操作本身仍视为已完成。
  • 搜索取决于 Redmine 设置。如果管理员禁用了 /search.json,searchAll、searchIssues 和 searchWikiPages 可能无法返回预期结果。
  • 只有带有文本层的 PDF 才能提取文本。没有 OCR 的扫描文档会被识别为无法提取文本的 PDF。
  • 图片不会重新编码。getAttachment 会返回原始文件的路径;图片的文本 parts[] 仍为空。

项目结构

├── src/main/java/ru/it_spectrum/ai/redmine/mcp/
│   ├── RedmineMcpServerApplication.java   — Spring Boot entry point
│   ├── api/                                — stable MCP wire format: records returned by tools/services
│   │   ├── Issue.java
│   │   ├── AttachmentContent.java
│   │   ├── Project.java
│   │   ├── IssueMutationResult.java        — stable result of issue write operations
│   │   ├── TimeEntryMutationResult.java    — stable result of time-entry creation
│   │   ├── WikiMutationResult.java         — stable result of wiki-page writes
│   │   └── ...                             — tool response DTOs and analytics DTOs
│   ├── client/
│   │   ├── RedmineClient.java              — read-only wrapper over the Redmine REST API
│   │   ├── RedmineMutationClient.java      — optional POST/PUT for issues, time entries, and wiki
│   │   └── model/                          — raw Redmine REST API DTOs, never exported directly to MCP
│   │       ├── RedmineIssue.java
│   │       ├── RedmineAttachment.java
│   │       ├── RedmineProject.java
│   │       └── ...
│   ├── config/
│   │   ├── RedmineClientProperties.java   — url + apiKey from env
│   │   ├── RedmineMcpProperties.java      — all redmine-mcp.* runtime settings
│   │   ├── RedmineConfig.java             — RestClient
│   │   ├── McpServerConfig.java           — stdio MCP customizer with immediateExecution(true)
│   │   └── JsonConfig.java                — ObjectMapper for MCP JSON
│   ├── extraction/
│   │   ├── ExtractionPipeline.java        — document-to-text pipeline
│   │   ├── DocumentParser.java            — parser interface
│   │   ├── FileTypeDetector.java          — file type detection
│   │   ├── PandocAvailability.java        — external pandoc probe at startup
│   │   └── parser/
│   │       ├── PlainTextParser.java       — txt/log/csv/json/xml
│   │       ├── PdfTextParser.java         — PDF via PDFBox
│   │       ├── DocxTextParser.java        — DOCX via POI
│   │       ├── DocxPandocParser.java      — DOCX via Pandoc when available
│   │       ├── XlsxTextParser.java        — XLSX via POI
│   │       ├── PptxTextParser.java        — PPTX via POI
│   │       ├── ZipParser.java             — ZIP with bounded recursion
│   │       ├── ImagePassthroughParser.java
│   │       ├── TikaTextFallbackParser.java
│   │       ├── TikaMetadataParser.java
│   │       └── BinaryFallbackParser.java
│   ├── service/
│   │   ├── IssueService.java              — issue business logic and mapping client.model -> api
│   │   ├── IssueMutationService.java      — optional issue writing and AI marking
│   │   ├── TimeEntryMutationService.java  — optional time-entry creation
│   │   ├── WikiMutationService.java       — safe wiki writing with optimistic locking
│   │   ├── AttachmentService.java         — attachment snapshot, download, and extraction
│   │   ├── IssueSnapshotService.java      — local issue and attachment snapshots
│   │   ├── AnalysisService.java           — analytics, risks, blocker chain
│   │   └── ...                            — services for projects, wiki, search, reference data, time entries
│   └── tools/
│       ├── AttachmentTools.java           — 1 MCP tool for files and attachment context
│       ├── IncidentPrompts.java           — 4 MCP prompts for issue investigation
│       ├── IssueAnalyticsTools.java       — 2 issue-analytics MCP tools (blocker chain, stale)
│       ├── IssueStructureTools.java       — 2 MCP tools: issue tree and change history
│       ├── IssueTools.java                — 5 core issue MCP tools
│       ├── IssueWriteTools.java           — 4 optional issue-write MCP tools
│       ├── ProjectTools.java              — 4 project MCP tools
│       ├── ReferenceDataTools.java        — 6 reference-data MCP tools
│       ├── ReleaseAnalyticsTools.java     — 5 release/project analytics MCP tools
│       ├── SearchTools.java               — 1 global-search MCP tool
│       ├── TimeEntryTools.java            — 2 time-entry MCP tools
│       ├── TimeEntryWriteTools.java       — 1 optional time-entry creation MCP tool
│       ├── UserTools.java                 — 1 current-user MCP tool
│       ├── WikiTools.java                 — 3 wiki MCP tools
│       └── WikiWriteTools.java            — 2 optional wiki-write MCP tools
└── src/main/resources/
    ├── application.yml                    — MCP server configuration (stdio)
    └── logback-spring.xml                 — logging configuration

故障排除

  • “Gradle requires JVM 17 or later” — 将 JAVA_HOME 指向 JDK 25+
  • 连接被拒绝 / 401 — 检查 REDMINE_URL 和 REDMINE_API_KEY。测试:curl -H "X-Redmine-API-Key: <key>" <url>/users/current.json
  • 没有搜索结果 — 确认 Redmine 中的 /search.json 可用(管理员可能已将其禁用)

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。