Skip to main content
Glama

MCP Redmine

🇬🇧 English · 🇫🇷 Français

An MCP (Model Context Protocol) server to drive a Redmine instance from Claude Desktop or Claude CLI, via Redmine's REST API.

Requirements

  • Python 3.10+ (the code uses the X | None union syntax).

  • A Redmine instance with the REST API enabled (Administration → Settings → API) and an API key.

Related MCP server: Redmine MCP Server

Install

# 1. Clone
git clone https://github.com/NeveuGregor/mcp-redmineApi.git
cd mcp-redmineApi

# 2. Virtual environment
python3 -m venv venv
source venv/bin/activate          # Windows: venv\Scripts\activate

# 3. Dependencies
pip install -r requirements.txt

# 4. Configuration
cp .env.example .env              # then edit .env (URL + API key)

# 5. Smoke-test against your instance
python3 test_connection.py

Redmine API key

My account → API access key → Show, then paste it into .env (REDMINE_API_KEY=...).

Configuration

Environment variables (.env)

Variable

Required

Description

REDMINE_URL

âś…

Base URL (must start with http:// or https://)

REDMINE_API_KEY

âś…

API access key

REDMINE_DEFAULT_PROJECT_ID

—

Default project for issue creation

REDMINE_TIMEOUT

—

HTTP timeout in seconds (default: 30)

DEBUG

—

Debug logs on stderr (default: false)

REDMINE_UPLOAD_DIRS

—

Allowed upload directories (CSV). Empty = upload disabled

REDMINE_EXPOSE_USERS

—

Expose Redmine identities (default: false)

⚠️ Upload security: REDMINE_UPLOAD_DIRS only allows trusted directories. The server can read and upload any file under those paths. Left empty, file attachment is refused (safe default).

Redmine identities (REDMINE_EXPOSE_USERS)

The question is not "is this data sensitive" but who you are sending it to. With a sovereign local model, author and assignee are useful for diagnosis. With a remote model, they must not leave the machine.

false (default)

true

author / assigned_to / note writer

stripped before parsing

exposed

list_users tool

not registered (invisible to the model)

available

Directory in get_metadata

absent, and never even requested from Redmine

included

assigned_to_id on writes

works

works

Filtering happens in the client layer, not at render time: in restricted mode this data never transits through the process at all. Writes stay fully functional — the model can assign to user 42 without being told who 42 is.

Consequence: the exposed tool list varies by environment (7 or 8). In restricted mode an "Assigned to" line disappears rather than showing "Unassigned" — the information is masked, not absent.

Claude CLI (Claude Code)

# Local scope (current project) or user (all your projects)
claude mcp add redmine --scope user python3 -m src.main --cwd /absolute/path/to/redmine-mcp

# Check
claude mcp list

Claude Desktop

In claude_desktop_config.json:

{
  "mcpServers": {
    "redmine": {
      "command": "python3",
      "args": ["-m", "src.main"],
      "cwd": "/absolute/path/to/redmine-mcp"
    }
  }
}

File location: macOS ~/Library/Application Support/Claude/, Windows %APPDATA%\Claude\, Linux ~/.config/Claude/.

Note: the Python package is named src; the server runs via python3 -m src.main from the project root (the cwd field).

Available tools (7, or 8 with REDMINE_EXPOSE_USERS=true)

create_issue(subject, description, ...)

Create an issue. Params: subject, description, project_id, priority_id (1=Low … 5=Immediate), tracker_id, assigned_to_id, parent_issue_id, files (paths — requires REDMINE_UPLOAD_DIRS), estimated_hours.

update_issue(issue_id, ...)

Update an issue. Params: issue_id*, subject, description, status_id, priority_id, assigned_to_id, estimated_hours, notes.

search_issues(...)

Search issues. Params: project_id, assigned_to_id, status_id, tracker_id, subject, limit (default 25), offset.

By default Redmine returns only open issues. To widen, pass status_id as "open", "closed", "*" (all), or a specific status id. The result reports "X shown out of N total" when truncated.

get_issue(issue_id)

Full detail of an issue: description, metadata (progress, dates, target version), custom fields, attachments and note history.

list_projects()

List all accessible projects (pagination followed automatically).

list_users(name=None, limit=None)

List or search users (name filters server-side on login, first name, last name, email; limit bounds how many are fetched).

Registered only if REDMINE_EXPOSE_USERS=true. Otherwise the tool does not appear in the MCP tool list.

add_time_entry(hours, comments, ...)

Log time. Params: hours, comments, issue_id or project_id, spent_on (YYYY-MM-DD), activity_id.

get_metadata()

Trackers and statuses (ids/names) to feed the other tools. The user directory is included only if REDMINE_EXPOSE_USERS=true.

* = required parameter

Development & tests

Unit tests mock the HTTP API (respx) — no Redmine instance required.

# Dev dependencies
pip install -r requirements-dev.txt

# Run the suite
python3 -m pytest

# Smoke-test against a real instance (reads .env)
python3 test_connection.py

# Check the config
python3 -c "from src.config import config; print(config.redmine_url)"

Troubleshooting

Symptom

Likely cause

Access denied (403)

Invalid API key or insufficient Redmine permissions

Resource not found (404)

Wrong issue/project id

Invalid data (422)

Missing required field (Redmine's detail is surfaced)

Network error

Unreachable URL / timeout — raise REDMINE_TIMEOUT

Upload disabled

Set REDMINE_UPLOAD_DIRS

User directory disabled

Expected: set REDMINE_EXPOSE_USERS=true if the target LLM is sovereign

No "Assigned to" line in responses

Expected in restricted mode — see REDMINE_EXPOSE_USERS

Debug mode (verbose logs on stderr): DEBUG=true python3 -m src.main.

Architecture

src/
  main.py            entry point (def main)
  server.py          tool registration + centralized error handling
  config.py          configuration (.env) validated by pydantic
  errors.py          RedmineError (status_code, details)
  models.py          Pydantic models for Redmine entities
  redmine_client.py  HTTP client (httpx) + parsing
  tools/             one module per tool
tests/               pytest suite (respx mock)

Related MCP Connectors

Related MCP Servers