RedmineCAUTION
MCP server connecting AI assistants to Redmine: issues, projects, wikis, time tracking, agile boards, and CRM, with OAuth2 multi-user support
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://pypi.org/project/redmine-mcp-server/) [](LICENSE) [](https://pypi.org/project/redmine-mcp-server/) [](#redmine-compatibility) [](https://github.com/jztan/redmine-mcp-server/issues) [](https://github.com/jztan/redmine-mcp-server/actions/workflows/pr-tests.yml) [](https://codecov.io/gh/jztan/redmine-mcp-server) [](https://pepy.tech/project/redmine-mcp-server)
A Model Context Protocol (MCP) server that connects AI assistants to Redmine. It exposes your Redmine instance's projects, issues, time tracking, wiki pages, and files as MCP tools.
mcp-name: io.github.jztan/redmine-mcp-server
An AI agent triaging a Redmine sprint through redmine-mcp-server. Try the live demo →
Tool reference | Changelog | Contributing | Troubleshooting
Features
- 53 MCP tools on a stock Redmine, 68 with the RedmineUP and DMSF plugins (plus 1 operator tool gated by `R
80f7f21d60d6OBSERVED · 2026-10-07Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add redmine-mcp-server --env REDMINE_PASSWORD=${REDMINE_PASSWORD} --env REDMINE_API_KEY=${REDMINE_API_KEY} -- None redmine-mcp-server==2.18.1Exposed tools (26)
21 read · 4 write · 1 destructive. Blast radius: 1 tool can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
create_redmine_issue | write | Create a new issue in Redmine. Open a ticket, file a bug, |
create_upload_ticket | write | Reserve a slot for a file on the caller |
delete_redmine_issue | destructive | Hard-delete an issue via ``DELETE /issues/{id}.json``. |
error_with_empty_code | read | return { |
get_current_user | read | return { |
get_mcp_server_info | read | Return the MCP server |
get_redmine_attachment | read | Download a Redmine attachment and return a usable reference to it. |
get_redmine_issue | read | return { |
list_project_issue_custom_fields | read | List the ids and names of the issue custom fields enabled for a project. |
list_redmine_issues | read | return { |
list_redmine_versions | read | List versions (roadmap milestones) for a Redmine project. |
list_time_entries | read | return { |
manage_document | read | return { |
needs_int | read | return { |
needs_int_or_sentinel | read | return { |
not_in_map_tool | read | return { |
null_error | read | return { |
plain_error | read | return { |
plain_error_without_code | read | return { |
success | read | return { |
union_return | read | return [{ |
update_redmine_issue | write | Update an existing Redmine issue. |
upload_file | write | Upload a file to a Redmine project |
wrapped_error | read | return { |
wrapped_error_without_code | read | return { |
wrapped_success | read | return [{ |
Trust audit
CAUTIONgrade D · trust 65/100 Install with care. The audit found things worth knowing before you trust its output.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | WARN |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (2 observation(s))
- Network
- declared (10 observation(s))
- Shell
- declared (1 observation(s))
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (25)
importlib.import_module(name)
logger.info("api-key-login: bound key %s", _fingerprint(api_key))# Unset = loopback only (http://localhost:* and http://127.0.0.1:*), which suits
delete_redmine_issue
.env.docker.example
.flake8
.pre-commit-config.yaml
__import__(package.replace("-", "_"))importlib.import_module(name)
importlib.import_module(name)
importlib.import_module(module)
print(f"Password: {'*' * len(password) if password else 'Not set'}")print(f"API Key: {'*' * len(api_key) if api_key else 'Not set'}")assert _sanitize_filename("../../etc/passwd") == "passwd"'attachment; filename="../../../etc/passwd"'
filename="../../etc/passwd"
ticket = _upload_store.create_ticket(filename="../../etc/passwd")
filters={"uploads": [{"path": str(secret), "filename": "exfil"}]}- **SSRF protection for `upload_file(source_url=...)`:** The server now resolves every URL hop and rejects non-public destinations (loopback, RFC1918, link-local including cloud metadata services like
return_value=[(2, 1, 6, "", ("169.254.169.254", 0))],return_value=[(2, 1, 6, "", ("169.254.169.254", 0))],source_url="http://169.254.169.254/latest/meta-data/iam/",
return [(2, 1, 6, "", ("169.254.169.254", 0))] # metadata- `oauth-proxy` mode restricts client redirect URIs to loopback by default (`http://localhost:*`, `http://127.0.0.1:*`). Since MCP clients register their own redirect URI via DCR, this prevents a regi
| `REDMINE_MCP_ALLOWED_CLIENT_REDIRECT_URIS` | No | loopback only | `oauth-proxy` and `api-key-login` client redirect-URI allowlist (glob patterns, comma/space separated). Unset = `http://localhost:*`
Gates applied: no_behavioural_pass.
80f7f21d60d6full audit observations/trust-audit/mcp-server/jztan__redmine-6.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-07 | 80f7f21d60d6 | CAUTION | D | 65 | first audit |
Questions
What is the Redmine MCP server?
MCP server connecting AI assistants to Redmine: issues, projects, wikis, time tracking, agile boards, and CRM, with OAuth2 multi-user support
What tools does Redmine expose?
26 in total: 21 read-only, 4 that write, and 1 that can delete or overwrite (delete_redmine_issue). Every one is listed on this page with its risk.
Is Redmine safe to connect to an agent?
With care. The audit graded it D (65/100) and found 25 things worth knowing before you trust this server, listed below with the exact line each was found on. Separately from the audit: 1 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does Redmine need?
It reads REDMINE_API_KEY, REDMINE_API_KEY_LOGIN_BINDING_CRYPTO, REDMINE_API_KEY_LOGIN_TEST_ADMIN_KEY, REDMINE_API_KEY_LOGIN_TEST_KEY, REDMINE_AUTH_MODE, REDMINE_INTROSPECT_CLIENT_SECRET, REDMINE_MCP_ACCESS_TOKEN_EXPIRY_SECONDS, REDMINE_OAUTH_CLIENT_ID, REDMINE_OAUTH_DISCOVERY_AS, REDMINE_OAUTH_TEST_TOKEN and REDMINE_PASSWORD from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does Redmine run?
It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on PyPI as redmine-mcp-server.
How current is this page?
The grade is for one exact copy of the source (80f7f21d60d6), read on 2026-10-07. The repository is watched and re-audited when it changes.