
Redmine MCP Server
io.github.igorolv由 GitHub 帳號 igorolv 發布v0.1.1更新於 Oct 24, 2026
Redmine for AI agents: issues, projects, wiki, attachments, time entries and release analytics
概覽
在本機執行的 MCP 伺服器,讓 AI 助理連接 Redmine 實例,處理議題、專案、Wiki、附件、工時與發佈分析。
- 可以做什麼
- 讀取與搜尋議題,包括全文搜尋、我的議題、議題樹、歷史記錄與單一日誌,以及已儲存的查詢和狀態、追蹤標籤、優先順序等參考資料。瀏覽專案、成員、版本與目前使用者。讀取、列出與搜尋專案 Wiki 頁面。將附件下載到本機快照,並從 PDF、Office、ZIP 與純文字檔擷取文字。列出已登記工時與目前使用者的工時。執行分析,例如專案彙總、使用者工作量、版本變更日誌、阻塞鏈、長期未更新議題、發佈風險與版本比較。可選擇建立與更新議題、新增備註、上傳附件、登記工時,以及建立或取代 Wiki 頁面。
- 適用情境
- 適合團隊以 Redmine 追蹤工作、希望助理彙整議題、產出事件簡報與時間軸、檢查剩餘工作、評估發佈風險,或跨議題、Wiki 與附件回答問題而不必手動複製資料的情境。
- 執行需求
- 以本機 Java 程序執行(需 JDK 25+),從 JAR 或已發佈的 Docker 映像啟動;不開放網路連接埠,透過標準輸入輸出通訊。需要 REDMINE_URL(實例基礎位址)與 REDMINE_API_KEY(所代表使用者的 API 金鑰),且該帳號需啟用 Redmine REST API。選用變數可控制寫入工具、工具分組、前綴、逾時與回應上限。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Redmine MCP Server,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
Redmine MCP Server
[CI] [Release] [License] [Java 25] [MCP] [Glama score] [Listed on mcpservers.org]
A local MCP server for accessing a corporate Redmine instance. It exposes a limited set of write
operations for issues, time entries, and wiki alongside the read tools; set
REDMINE_MCP_WRITE_ENABLED=false to run fully read-only. It lets AI agents (Claude Code, Cursor,
VS Code Copilot, etc.) work with issues, projects, members, versions, wiki, attachments, time
entries, and reference data.
Quick Start
This documentation covers installing and connecting Redmine MCP Server itself. Installing and configuring the AI clients themselves is out of scope here.
- Install JDK 25+.
- Download
redmine-mcp-server.jarfrom the latest release, or build it yourself:./gradlew bootJar(see Build). A Docker image is published as well. - Obtain
REDMINE_URLandREDMINE_API_KEY(see Configuration). - Verify that the JAR starts (see Smoke Test).
- Add the JAR to your client's MCP configuration (see Connecting to an AI Client).
For Claude Code that is one command:
Architecture
The server supports only the stdio transport.
Stdio
The AI client launches the server as a child process; communication follows the MCP protocol over stdin/stdout.
Tools
The server exports 32 read-only MCP tools plus 7 write tools by default. Set
REDMINE_MCP_WRITE_ENABLED=false to remove the write tools and run fully read-only.
User
Projects
Issues
Issue, Time Entry, and Wiki Writes (optional)
These tools appear in tools/list by default; set REDMINE_MCP_WRITE_ENABLED=false to remove them:
Redmine itself enforces the permissions, workflow, and required-field rules of the REDMINE_API_KEY
user. The MCP server introduces no additional model of "own" issues or notes. To make AI-created
issues recognizable, the description of an issue created by createIssue is prefixed with AI_EDIT:
by default (updateIssue does not add it). Notes, time-entry comments, wiki revision comments, and
uploaded file names are not marked by default; each marker is configured separately with a
REDMINE_MCP_WRITE_*_PREFIX variable (see Configuration), and an empty value
turns it off. Issue descriptions and notes get the prefix on its own line followed by a blank line;
single-line fields (time-entry and wiki revision comments) get the prefix and a space; file names
get the prefix with no separator. Wiki page markup itself is never changed.
Editing and deleting existing notes is not implemented: the targeted Redmine 4.0.4 does not provide a compatible REST API for it. Editing and deleting time entries; deleting, renaming, and protecting wiki pages; and creating time entries on behalf of another user are outside the current operation set.
Search
Attachments and Wiki
Time Entries
Reference Data
Analytics
With REDMINE_MCP_WRITE_ENABLED=false all tools are read-only and no data in Redmine is modified.
Tool Groups (enable/disable)
Tools are grouped by domain, and each group can be disabled via an environment variable.
All groups are enabled by default — the out-of-the-box tool manifest is unchanged. Disabling
groups shrinks the MCP tools/list manifest that the client loads into model context at session
start. This helps small-context (local) models: disable unneeded groups so only the tools the
model actually needs remain.
Each variable accepts true (default) or false. Example: to keep only issue and project work,
disable the remaining groups — REDMINE_MCP_TOOLS_RELEASE_ANALYTICS=false,
REDMINE_MCP_TOOLS_WIKI=false, etc. MCP prompts are not affected by these flags; a prompt tells the model
to skip a step whose tool is disabled.
MCP Prompts
The server also exports MCP prompts for typical issue-handling scenarios. Each takes one required
argument, issueId — the Redmine issue number (12345 or #12345).
Clients that build command templates by requesting a prompt with a placeholder argument (for example
opencode 1.x, which sends $1) get the template with the placeholder left in place, so their own
substitution keeps working.
Tech Stack
- Java 25, Spring Boot 4.2.0-M2, Spring AI MCP 2.1.0-M1 (stdio transport)
- Apache PDFBox 3.0.5 — text extraction from PDFs
- Apache POI 5.4.0 — text extraction from Word, Excel, PowerPoint
- Apache Tika 3.2.0 (core + parsers-standard) — fallback parser and metadata extraction
- Pandoc (optional, external binary) — improved DOCX to text/markdown conversion when available on
PATH; otherwise the server uses POI - Gradle 9.3.1 with version catalog (
gradle/libs.versions.toml)
Build
Linux/macOS:
Windows PowerShell:
Result: build/libs/redmine-mcp-server.jar
Configuration
The server needs REDMINE_URL and REDMINE_API_KEY; the remaining variables are optional:
getIssue resolves the related context with one lightweight read of the parent and one batched
lookup for siblings, children and relation targets; related issues are not snapshotted. The
timeline and changesets focus modes omit related and skip these requests entirely.
| REDMINE_MCP_RESPONSE_MAX_CHARS | Target response size limit before stepwise compression of getIssue and getAttachment; defaults to 50000 characters |
| REDMINE_MCP_RESPONSE_JOURNAL_TAIL_KEEP | How many most-recent journal entries the budget compression of getIssue keeps before more aggressive reduction; defaults to 30 |
| REDMINE_MCP_RESPONSE_ATTACHMENT_TEXT_PART_CHARS | Text limit per attachment part during response compression of getAttachment calls without maxChars/partLimit; defaults to 10000 characters. Calls with explicit limits are never truncated below them. |
| REDMINE_MCP_RESPONSE_JOURNAL_NOTE_CHARS | Text limit per journal note during response compression of getIssue; defaults to 5000 characters |
| REDMINE_MCP_RESPONSE_IMAGE_PARTS_KEEP | How many image parts the response compression of getAttachment keeps; defaults to 5 |
| REDMINE_MCP_PAGINATION_DEFAULT_LIMIT | Default page size for list/search tools; defaults to 25 |
| REDMINE_MCP_PAGINATION_DEFAULT_OFFSET | Default offset for list/search tools; defaults to 0 |
| REDMINE_MCP_PAGINATION_MEMBERS_DEFAULT_LIMIT | Default page size for listProjectMembers; defaults to 100 |
| REDMINE_MCP_TREE_DEFAULT_DEPTH | Default depth for getIssueTree; defaults to 2 |
| REDMINE_MCP_TREE_MAX_DEPTH | Maximum depth of getIssueTree; defaults to 5 |
| REDMINE_MCP_TREE_MAX_ISSUES | Maximum issues loaded by getIssueTree; defaults to 50 |
| REDMINE_MCP_ANALYSIS_MAX_PAGES | Maximum Redmine pages read by analytics tools; defaults to 5 |
| REDMINE_MCP_ANALYSIS_PAGE_SIZE | Redmine page size for analytics tools; defaults to 100 |
| REDMINE_MCP_ANALYSIS_TOP_ISSUES_LIMIT | Maximum issues in top lists of analytics responses; defaults to 10 |
| REDMINE_MCP_ANALYSIS_MAX_BLOCKER_DEPTH | Maximum traversal depth for getBlockerChain; defaults to 10 |
| REDMINE_MCP_ANALYSIS_MAX_BLOCKER_ISSUES | Maximum issues loaded by getBlockerChain; defaults to 30 |
| REDMINE_MCP_ANALYSIS_STALE_ISSUES_DEFAULT_DAYS_SINCE_UPDATE | Default daysSinceUpdate for getStaleIssues; defaults to 30 |
| REDMINE_MCP_ANALYSIS_STALE_ISSUES_DEFAULT_LIMIT | Default result limit for getStaleIssues; defaults to 25 |
| REDMINE_MCP_ANALYSIS_STALE_ISSUES_MAX_LIMIT | Maximum result limit for getStaleIssues; defaults to 100 |
| REDMINE_MCP_EXTRACTION_PANDOC_ENABLED | Enables the use of Pandoc for DOCX when the binary is found on PATH; defaults to true |
| REDMINE_MCP_EXTRACTION_PANDOC_PROBE_TIMEOUT_SECONDS | Timeout for probing Pandoc availability at startup; defaults to 2 seconds |
| REDMINE_MCP_EXTRACTION_PANDOC_CONVERSION_TIMEOUT_SECONDS | Timeout for a single DOCX conversion via Pandoc; defaults to 30 seconds |
| REDMINE_MCP_EXTRACTION_LIMITS_MAX_DEPTH | Maximum recursion depth for processing nested documents and archives; defaults to 1 |
| REDMINE_MCP_EXTRACTION_LIMITS_MAX_TOTAL_PARTS | Maximum text/metadata parts per extraction; defaults to 100 |
| REDMINE_MCP_EXTRACTION_LIMITS_MAX_TOTAL_BYTES | Total bytes-read limit per extraction; defaults to 52428800 bytes |
| REDMINE_MCP_EXTRACTION_LIMITS_MAX_ENTRY_BYTES | Limit for a single entry inside an archive; defaults to 10485760 bytes |
| REDMINE_MCP_EXTRACTION_ZIP_MAX_ENTRIES_PER_ARCHIVE | Maximum entries per ZIP archive; defaults to 100 |
| REDMINE_MCP_EXTRACTION_TIKA_BODY_LIMIT_BYTES | Body size limit passed to the Tika fallback parser; defaults to 5242880 bytes |
| REDMINE_MCP_EXTRACTION_TIKA_METADATA_MAX_FIELDS | Maximum Tika metadata fields in the response; defaults to 40 |
How to Get REDMINE_URL
Open Redmine in your browser and copy the address-bar value without the path — scheme and domain only.
Examples:
If Redmine is reachable only by IP address (no domain name), use the IP as-is, including the port if it differs from the standard one (80/443). If Redmine is deployed under a subpath (e.g.
/redmine), include it in the URL too.
How to Get REDMINE_API_KEY
- Log in to Redmine with your account
- Click "My account" (top right corner)
- In the right column find the "API access key" block
- Click "Show" — your personal API key will be displayed
- Copy the key and use it as the
REDMINE_API_KEYvalue
If the "API access key" block is not shown, contact the Redmine administrator — the REST API may be disabled in settings.
Smoke Test
Before connecting an AI client it is worth verifying that the JAR starts correctly with the same environment variables that will later go into the client configuration.
Linux/macOS:
Windows PowerShell:
The server runs over stdio and opens no HTTP port: after a successful start it silently waits
for MCP requests on stdin/stdout. A successful start shows as the absence of errors in the log
and no immediate process exit. Press Ctrl+C to stop.
Docker
The image is published to GHCR with every release:
The same command is what an MCP client should launch (-i keeps stdin open for the stdio
transport). Mount a host directory at /data to keep logs and issue snapshots between runs.
To build the image locally: docker build -t redmine-mcp-server .
Logs
Logs are written to ${REDMINE_MCP_DATA_DIR:-~/.redmine-mcp-server}/logs/redmine-mcp-server.log.
The file rotates by date and size: 10MB, retention 30 days, total cap 512MB.
Issue Snapshots
When loading an issue the server persists a snapshot to disk under
${REDMINE_MCP_DATA_DIR:-~/.redmine-mcp-server}/issues/<issue-id>/: issue.json,
snapshot.json with snapshot metadata, attachments.json, and an extracted/<attachment-id>/
directory for derived files. Attachments are materialized under attachments/ with names like
<attachment-id>__<filename> and can be reused across snapshots when the local file already
exists and its size matches the Redmine metadata.
Connecting to an AI Client
Add to the client configuration:
Where exactly:
Restart the client afterwards.
Operations and Security
This MCP server is designed to run locally alongside the AI client. It opens no HTTP port and
accepts no incoming network connections: the client launches the JAR as a child process and
communicates with it via stdin/stdout.
Access Model
- The server uses the permissions of the Redmine user whose API key is set in
REDMINE_API_KEY. - Seven explicitly listed write tools for issues, time entries, and wiki are available by default;
set
REDMINE_MCP_WRITE_ENABLED=falseto run fully read-only. The server neither extends the API user's rights nor bypasses the Redmine workflow. - Accessible projects, issues, attachments, and time entries are determined by the user's permissions in Redmine. If a user cannot see an object in Redmine, the server must not gain access to it either.
- The
REDMINE_MCP_WRITE_*_PREFIXmarkers (such as the defaultAI_EDIT:on created issues) are search labels, not an authorization mechanism: authorship of a change is reliably established by the Redmine account that owns the API key. attachFileToIssuedeliberately accepts any readable local path without an allow-list of directories. Since write tools are on by default, run the server only next to a trusted AI client, keeping in mind that the client will be able to pass the contents of any file readable by the process into Redmine.- Treat the API key as a secret. Do not commit it to the repository, shell scripts,
.vscode/mcp.json,.cursor/mcp.json, or other shared files of the project.
For development and verification of write operations use a separate test Redmine and a separate
API key. Because writes are on by default, set REDMINE_MCP_WRITE_ENABLED=false when pointing
integrationTest or a manual smoke test at a production installation.
What Data Is Passed to the AI Client
The AI client receives exactly the data it requests through MCP tools:
- issue cards: subject, description, status, priority, assignee, author, dates, relations, subtasks, journals/comments, custom fields;
- information about projects, versions, members, reference data, and time entries;
- wiki pages;
- attachment metadata;
- local paths to the original attachment files and text extracted from PDF, DOCX, XLSX, PPTX, ZIP, and text files via
getAttachment.
Before connecting an external or cloud AI client, check your company's internal policies: Redmine data may contain trade secrets, personal data, logs, keys, error dumps, and document contents.
Processing Limits
There are protective limits in the code so that a single large document or a related network of issues cannot overload the MCP client:
getAttachment reports the limits it applied in limits (maxChars, partLimit, and a note when
a requested value was reduced to the ceiling); a cut part carries totalChars with its full length.
Without explicit limits, a response that still exceeds REDMINE_MCP_RESPONSE_MAX_CHARS (for example,
many ZIP entries) is compressed: extra image parts are collapsed, then text parts are cut to
REDMINE_MCP_RESPONSE_ATTACHMENT_TEXT_PART_CHARS. With explicit limits, only image parts are
collapsed. The original file remains on disk at localPath; for pandoc DOCX extraction, the
markdown part also points to its saved text file. Other document parts can point to a PDF or Office
source file rather than a separate extracted-text file.
getIssue supports the focus parameter. default keeps the usual
response shape and applies compression only when the response budget is exceeded. implementation
targets implementation work on the issue: the full issue is still persisted to disk, while the tool
response keeps the description, human notes, attachment metadata, and all changeset revisions;
verbose history and commit message bodies are omitted. timeline targets
"who did what and when" questions: it keeps journals and changesets but omits attachments,
custom fields, and related context. full is an explicit choice of the full form with protective
budget compression.
getIssueTree still loads and snapshots every fetched issue in full, but returns only compact
Issue context for root and ancestors; their description, journals, custom fields, attachments,
and changesets are omitted from this view. Its subtree remains the hierarchy view. This changes
the contents of those existing Issue fields: clients that previously read full details from the
tree should call getIssue(id) instead. getIssueTree does not include direct relations.
getIssueHistory includes the creation event and each journal event, including journals without a
note or a recognized field change. It shortens long notes and old/new field values when needed,
keeps journalId on each update, and explains reductions in compressionNotes. For exact wording
or a complete old/new value, call getIssueJournal(issueId, journalId). Start with
getIssueHistory(issueId); when nextOffset is present, pass that number as offset in the next
call. Continue until nextOffset is absent. totalEvents includes creation. Status intervals in
statusDurations belong to events on that page; combine them across pages. Compare
sourceUpdatedOn across pages and restart if it changes. The server uses the existing
REDMINE_MCP_RESPONSE_MAX_CHARS setting; no new environment variable is needed.
If one event cannot fit after text shortening, its page keeps the event and journalId but
reduces the event to metadata; compressionNotes identify any omitted status intervals and
point to getIssueJournal for the full entry.
If the note you need was dropped from the getIssue response by budget compression or the note was
shortened, call getIssueJournal(issueId, journalId): it re-takes the issue snapshot and
returns the selected journal entry without response compression.
Some regular list tools (listIssues, listProjects, listTimeEntries, listQueries) accept limit
and offset directly. For reliable operation avoid requesting excessively large pages; a practical
range is 25-100 items per call.
Diagnostics
Environment check:
Redmine REST API access check:
Build check:
Integration tests against a live Redmine:
Integration tests require a reachable Redmine and real test data. Unit tests exclude tests tagged
integration by default.
Known Operational Limitations
- HTTP timeouts and the retry policy are currently not configurable separately. If Redmine is slow to respond, an MCP call may wait longer than is convenient for the AI client.
- Redmine errors (
401,403,404,5xx) are currently handled mostly at the SpringRestClientlevel; the message seen by the AI-client user may be less friendly than a dedicated MCP tool error. - A note or attachment may be written successfully, but its new
journalId/attachmentIdmay stay undefined if Redmine or a concurrent user modifies the issue between confirmation reads. The operation itself is still considered completed. - Search depends on Redmine settings. If
/search.jsonis disabled by the administrator,searchAll,searchIssues, andsearchWikiPagesmay not return the expected results. - Text extraction from PDF works only for PDFs with a text layer. Scanned documents without OCR are detected as PDFs with no extractable text.
- Images are not re-encoded.
getAttachmentreturns the path to the original file; textparts[]for images remain empty.
Project Structure
Troubleshooting
- "Gradle requires JVM 17 or later" — point
JAVA_HOMEat JDK 25+ - Connection refused / 401 — check
REDMINE_URLandREDMINE_API_KEY. Test:curl -H "X-Redmine-API-Key: <key>" <url>/users/current.json - No search results — verify that
/search.jsonis available in Redmine (it may be disabled by the administrator)
來源:README.md,提交 f62b3e5
工具
0版本歷史
2- v0.1.1最新Sep 29, 2026
- v0.1.0Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分