The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Redmine MCP Server listing page.
A local MCP server for accessing a corporate Redmine instance. By default the server is fully read-only; an optional flag enables a limited set of write operations for issues and time entries. It lets AI agents (Claude Code, Cursor, VS Code Copilot, etc.) work with issues, projects, members, versions, wiki, attachments, time entries, and reference data.
This documentation covers installing and connecting Redmine MCP Server itself. Installing and configuring the AI clients themselves is out of scope here.
redmine-mcp-server.jar from the latest release,
or build it yourself: ./gradlew bootJar (see Build). A Docker image is
published as well.REDMINE_URL and REDMINE_API_KEY (see Configuration).For Claude Code that is one command:
The server supports only the stdio transport.
The AI client launches the server as a child process; communication follows the MCP protocol over stdin/stdout.
By default the server exports 32 read-only MCP tools. When
REDMINE_MCP_WRITE_ENABLED=true is set, 7 more write tools are added.
| Tool | Description |
|---|---|
getCurrentUser | Current user: ID, login, groups, projects. Useful for "my issues" filtering |
| Tool | Description |
|---|---|
listProjects | List of all accessible projects |
getProject | Project details: trackers, modules, description |
listProjectMembers | Project members with roles |
listVersions | Project versions (milestones) |
| Tool | Description |
|---|---|
listIssues | Issue list with filters: project, status, tracker, assignee, priority, version, saved query, custom fields (customFieldFilters in cf_<id>=value format), sorting |
searchIssues | Full-text issue search with detailed results |
getIssue | Issue details: description, status, assignee, dates, notes, relations, custom fields, attachments, linked revisions (changesets). Parameters: issueId, focus (default, implementation, timeline, full; optional) |
getIssueJournal | A single complete issue journal note/event without response compression. Parameters: issueId, journalId |
getMyIssues | Issues of the current user. Parameters: projectId, statusId, sort, limit, offset |
getIssueTree | Parent chain and subtasks. root and ancestors keep the Issue JSON shape but contain compact context; call getIssue for full details or relations. Parameters: issueId, depth (default 2, max 5) |
getIssueHistory | Creation and every journal event, with status intervals. Long text is shortened; journalId identifies the full entry for getIssueJournal. Follow nextOffset with the optional offset parameter until it is absent. |
These tools appear in tools/list only when REDMINE_MCP_WRITE_ENABLED=true:
| Tool | Description |
|---|---|
createIssue | Creates an issue. Supports core Redmine fields and custom fields via customFieldsJson |
updateIssue | Partially updates the specified fields of an existing issue |
addIssueNote | Adds a note to the issue journal |
attachFileToIssue | Uploads a file from any readable local path and attaches it to the issue |
createTimeEntry | Creates a time entry for the user from REDMINE_API_KEY; accepts exactly one of issueId/projectId, hours, date, activity, comment, and custom fields |
createWikiPage | Creates a wiki page and rejects the request if the page already exists |
updateWikiPage | Fully replaces the wiki page text, requiring the optimistic-lock version returned by getWikiPage |
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.
| Tool | Description |
|---|---|
searchAll | Global Redmine search: issues, wiki, news, documents, commits, etc. Parameters: searchQuery, projectId, types, limit, offset |
| Tool | Description |
|---|---|
getAttachment | Downloads the original attachment file into a local snapshot directory, returns localPath/fileUri, and immediately adds text context to parts[] if the format is supported: txt/log/xml/json/csv, PDF, Word (.docx), Excel (.xlsx), PowerPoint (.pptx), ZIP. A ZIP may yield a separate part per entry. A .docx yields one text part: pandoc markdown when pandoc is available, POI plain text otherwise. Parameters: issueId, attachmentId, maxChars, partLimit (see Processing Limits) |
getWikiPage | Content of a project wiki page |
listWikiPages | List of all wiki pages of a project |
searchWikiPages | Full-text search across wiki pages. Parameters: searchQuery, projectId, limit, offset |
| Tool | Description |
|---|---|
listTimeEntries | Logged time with filters: project, issue, user, period |
getMyTimeEntries | Logged time of the current user. Parameters: projectId, issueId, from, to, limit, offset |
| Tool | Description |
|---|---|
listQueries | Saved queries (custom filters) — ID + name. Use the ID with listIssues(queryId) to apply the filter, including custom-field filters |
listStatuses | All issue statuses (ID + name) — for filtering in listIssues |
listTrackers | All trackers (ID + name) — for filtering in listIssues |
listPriorities | All priorities (ID + name) — for filtering in listIssues |
listIssueCategories | Issue categories of a project (ID + name) |
listTimeEntryActivities | Activity types for interpreting existing time entries (ID + name) |
| Tool | Description |
|---|---|
getProjectSummary | Aggregated project summary: overall open/closed count; analyzed open issues broken down by status, tracker, priority, assignee; overdue issues; estimated/spent hours. Analyzes up to 500 open issues and returns a truncation flag. Parameters: projectId, versionId (optional) |
getUserWorkload | Workload analysis: open issues by project and priority, overdue issues, top issues. Analyzes up to 500 open issues and returns a truncation flag. Parameters: userId (optional, defaults to current user), projectId (optional) |
getVersionChangelog | Version issues grouped by tracker, open/closed statistics. Analyzes up to 500 issues and returns a truncation flag. Parameters: projectId, versionId |
getBlockerChain | Recursive traversal of the blocking chain (blocks/blocked_by) upward and downward, limited to depth 10 and 30 loaded issues. Parameters: issueId |
getStaleIssues | Open issues not updated for N days, oldest first. Parameters: projectId, daysSinceUpdate (default 30), limit |
getReleaseRisks | Release risk assessment: blockers, overdue items, high-priority issues, unassigned issues. Analyzes up to 500 open issues and returns a truncation flag. Parameters: projectId, versionId |
compareVersions | Compares two versions: unique issues, shared issues, closure percentage. Analyzes up to 500 issues per version and returns a truncation flag. Parameters: projectId, versionId1, versionId2 |
Without REDMINE_MCP_WRITE_ENABLED=true all tools are read-only and no data in Redmine is modified.
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.
| Variable | Group (tools) |
|---|---|
REDMINE_MCP_TOOLS_ISSUE | Issues (core): listIssues, searchIssues, getIssue, getMyIssues, getIssueJournal |
REDMINE_MCP_TOOLS_ISSUE_STRUCTURE | Issue structure/history: getIssueTree, getIssueHistory |
REDMINE_MCP_TOOLS_PROJECT | Projects: listProjects, getProject, listProjectMembers, listVersions |
REDMINE_MCP_TOOLS_SEARCH | Search: searchAll |
REDMINE_MCP_TOOLS_ATTACHMENT | Attachments: getAttachment |
REDMINE_MCP_TOOLS_WIKI | Wiki: getWikiPage, listWikiPages, searchWikiPages |
REDMINE_MCP_TOOLS_TIME_ENTRY | Time entries: listTimeEntries, getMyTimeEntries |
REDMINE_MCP_TOOLS_REFERENCE_DATA | Reference data: listQueries, listStatuses, listTrackers, listPriorities, listIssueCategories, listTimeEntryActivities |
REDMINE_MCP_TOOLS_USER | User: getCurrentUser |
REDMINE_MCP_TOOLS_ISSUE_ANALYTICS | Issue analytics: getBlockerChain, getStaleIssues |
REDMINE_MCP_TOOLS_RELEASE_ANALYTICS | Release/project analytics: getProjectSummary, getUserWorkload, getVersionChangelog, getReleaseRisks, compareVersions |
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.
The server also exports MCP prompts for typical issue-handling scenarios. Each takes one required
argument, issueId — the Redmine issue number (12345 or #12345).
| Prompt | Description |
|---|---|
incident-brief | Quick incident overview: fetches the issue via getIssue, downloads all attachments via getAttachment with short previews, and produces a concise Markdown report |
incident-implementation | Implementation context: fetches the issue with focus=implementation, picks relevant attachments by name, description and date, recovers compressed journal data only when it matters, and produces requirements, revision evidence, and a verification checklist |
incident-timeline | Incident chronology: uses getIssue(focus=timeline) for issue and changeset context, then reads every getIssueHistory page for journal events and status intervals |
issue-remaining-work | What is still unfinished: combines getIssue, getIssueTree (including siblings when relevant), getBlockerChain, and getIssueHistory when needed, and reports open items without trusting the status alone |
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.
PATH; otherwise the server uses POIgradle/libs.versions.toml)Linux/macOS:
Windows PowerShell:
Result: build/libs/redmine-mcp-server.jar
The server needs REDMINE_URL and REDMINE_API_KEY; the remaining variables are optional:
| Variable | Description |
|---|---|
REDMINE_URL | Base URL of the Redmine instance (e.g. https://redmine.example.com) |
REDMINE_API_KEY | Redmine user's API key |
REDMINE_MCP_WRITE_ENABLED | Adds the createIssue, updateIssue, addIssueNote, attachFileToIssue, createTimeEntry, createWikiPage, updateWikiPage tools to tools/list; defaults to false |
REDMINE_MCP_WRITE_ISSUE_DESCRIPTION_PREFIX | Marker prepended to the description of issues created by createIssue; defaults to AI_EDIT:. Set to an empty value to disable |
REDMINE_MCP_WRITE_ISSUE_NOTE_PREFIX | Marker prepended to notes added by addIssueNote; empty (disabled) by default |
REDMINE_MCP_WRITE_TIME_ENTRY_COMMENT_PREFIX | Marker prepended to createTimeEntry comments; counts toward Redmine's 1024-character limit; empty (disabled) by default |
REDMINE_MCP_WRITE_WIKI_COMMENT_PREFIX | Marker prepended to wiki revision comments of createWikiPage / updateWikiPage; empty (disabled) by default |
REDMINE_MCP_WRITE_ATTACHMENT_FILENAME_PREFIX | Prefix added to file names uploaded by attachFileToIssue (e.g. AI_EDIT__); must not contain / \ ? % * : | " ' < >; empty (disabled) by default |
REDMINE_MCP_DATA_DIR | Local data directory of the server; defaults to ~/.redmine-mcp-server |
REDMINE_MCP_HTTP_CONNECT_TIMEOUT_SECONDS | Timeout for opening a connection to Redmine; defaults to 10 seconds |
REDMINE_MCP_HTTP_READ_TIMEOUT_SECONDS | Timeout for Redmine to answer one request (including the request upload); defaults to 30 seconds. Tool calls are processed one at a time, so a stalled request otherwise delays every later call |
REDMINE_MCP_HTTP_SLOW_REQUEST_WARN_MILLIS | Redmine requests slower than this are logged as warnings; defaults to 5000 ms |
REDMINE_MCP_ATTACHMENT_PER_PART_CHARS | Text limit per single part (e.g., one file inside a ZIP) for getAttachment calls without limits; defaults to 30000 characters. The tool's partLimit parameter replaces it, and so does maxChars when partLimit is omitted. |
REDMINE_MCP_ATTACHMENT_PER_ATTACHMENT_CHARS | Total limit of extracted text per attachment in getAttachment calls without maxChars; defaults to 40000 characters, which keeps a default response below REDMINE_MCP_RESPONSE_MAX_CHARS. |
REDMINE_MCP_ATTACHMENT_MAX_REQUEST_CHARS | Ceiling for the maxChars and partLimit a caller passes to getAttachment; defaults to 200000 characters. Larger requests are reduced to it and the response limits.note says so. |
REDMINE_MCP_RELATED_MAX_SIBLINGS | Maximum sibling issues added to related when reading an issue; defaults to 20 |
REDMINE_MCP_RELATED_MAX_CHILDREN | Maximum child issues added to related when reading an issue; defaults to 20 |
REDMINE_MCP_RELATED_MAX_RELATED | Maximum related issues from relations added to related when reading an issue; defaults to 10 |
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 |
REDMINE_URLOpen Redmine in your browser and copy the address-bar value without the path — scheme and domain only.
Examples:
| In browser address bar | REDMINE_URL value |
|---|---|
https://redmine.example.com/projects/myproject | https://redmine.example.com |
http://192.168.1.50:3000/issues/123 | http://192.168.1.50:3000 |
http://10.0.0.5/redmine/projects | http://10.0.0.5/redmine |
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.
REDMINE_API_KEYREDMINE_API_KEY valueIf the "API access key" block is not shown, contact the Redmine administrator — the REST API may be disabled in settings.
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.
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 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.
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.
Add to the client configuration:
Where exactly:
| Client | How to connect |
|---|---|
| Claude Code | claude 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 Desktop | claude_desktop_config.json -> "mcpServers" -> "redmine" |
Restart the client afterwards.
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.
REDMINE_API_KEY.REDMINE_MCP_WRITE_ENABLED=true seven explicitly
listed write tools for issues, time entries, and wiki become available; the server neither extends
the API user's rights nor bypasses the Redmine workflow.REDMINE_MCP_WRITE_*_PREFIX markers (such as the default AI_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.attachFileToIssue deliberately accepts any readable local path without an allow-list of directories.
In write mode 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..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. Do not run integrationTest with write enabled against a production installation.
The AI client receives exactly the data it requests through MCP tools:
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.
There are protective limits in the code so that a single large document or a related network of issues cannot overload the MCP client:
| Area | Limit |
|---|---|
Each text part of getAttachment.parts[] | up to 30,000 characters by default, beyond that the text is truncated |
One attachment in getAttachment in total | up to 40,000 characters by default |
Explicit maxChars / partLimit in getAttachment | honored up to 200,000 characters each |
| ZIP depth | 1 level |
| ZIP archives | up to 100 entries |
| ZIP file inside an archive | up to 10 MB |
| ZIP archive in total | up to 50 MB of extracted data |
getIssueTree | depth up to 5, max 50 issues |
getIssueHistory | Each JSON page fits REDMINE_MCP_RESPONSE_MAX_CHARS in both characters and UTF-8 bytes; all events remain available through nextOffset |
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.
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.
401, 403, 404, 5xx) are currently handled mostly at the Spring RestClient
level; the message seen by the AI-client user may be less friendly than a dedicated MCP tool error.journalId/attachmentId may stay
undefined if Redmine or a concurrent user modifies the issue between confirmation reads. The operation
itself is still considered completed./search.json is disabled by the administrator,
searchAll, searchIssues, and searchWikiPages may not return the expected results.getAttachment returns the path to the original file; text parts[]
for images remain empty.JAVA_HOME at JDK 25+REDMINE_URL and REDMINE_API_KEY. Test: curl -H "X-Redmine-API-Key: <key>" <url>/users/current.json/search.json is available in Redmine (it may be disabled by the administrator)