Redmine MCP server for Cursor
A small Model Context Protocol (MCP) server that talks to your Redmine instance over its REST API. After you wire it into Cursor, the Agent can list/create/update issues, query projects, log time, and call any documented Redmine endpoint via a generic tool.
This repo runs over stdio (standard MCP transport): Cursor starts node index.js and exchanges JSON-RPC over stdin/stdout. You do not need to expose an HTTP port.
Prerequisites
- Node.js 18+ (includes
fetch) - A Redmine account with an API access key
- In Redmine: My account → API access key (or your admin’s equivalent)
- Permission to use Redmine’s REST API for the actions you care about (varies by role/project)
Quick setup (for anyone cloning this repo)
1. Install dependencies
cd /path/to/this-repo
npm install
2. Configure environment variables
Create a .env file in the same directory as index.js (the repo root). Do not commit .env to git.
RedmineURL=https://your-redmine.example.com
RedmineAPIKEY=your_api_key_here
Rules:
RedmineURL— Base URL only, no trailing slash, e.g.https://redmine.company.comRedmineAPIKEY— Your personal API key (treat it like a password)
Optional check from the shell (does not print your key):
node -e "require('dotenv').config(); console.log(process.env.RedmineURL ? 'RedmineURL OK' : 'missing RedmineURL')"
3. Smoke test (optional)
The MCP entrypoint is meant to be launched by Cursor. If you run it manually it will wait on stdio:
npm start
You should see no errors on startup if .env is valid. Stop with Ctrl+C.
Connecting Cursor
Option A — Project-only MCP (recommended for teams)
Check in .cursor/mcp.json at the repo root so everyone who opens this project gets the same server definition.
This repo’s .cursor/mcp.json uses ${workspaceFolder} so paths work for any clone location:
{
"mcpServers": {
"redmine-all-in-one": {
"command": "node",
"args": ["${workspaceFolder}/index.js"],
"cwd": "${workspaceFolder}"
}
}
}
Why cwd: dotenv loads .env from the current working directory. cwd must be the folder that contains .env and index.js.
If your Cursor build does not expand ${workspaceFolder}, switch to absolute paths under args and cwd for your machine.
Option B — User-global MCP
Add the same server block under your user MCP settings (Cursor’s global MCP config). Use absolute paths to wherever you cloned this repo.
After editing MCP config:
- Open Cursor Settings → MCP (or Features → MCP)
- Confirm
redmine-all-in-oneappears and is enabled - Use Reload / restart Cursor if the server stays disconnected
Using it from chat
- Use Agent mode (or any chat mode where tools are allowed).
- Ask clearly that answers should come from Redmine, e.g.
- “Using Redmine MCP, list my open issues assigned to me.”
- “Create a Feature in project
identifierwith subject…for version….”
- If the model forgets to use tools, say: “Only use Redmine MCP tools for Redmine data.”
The server authenticates with X-Redmine-API-Key; Redmine treats requests as the user who owns that key.
Tools reference
| Tool | Purpose |
|---|---|
redmine_api_request |
Generic REST call: method, path (e.g. /issues.json), optional query string, optional JSON body string. Use this whenever no helper fits. |
redmine_list_projects |
Paginated project list. |
redmine_list_issues |
Issues with common filters (project_id, status_id, assigned_to_id, pagination). Special values often include me, open, *. |
redmine_get_issue |
One issue by id; optional include (e.g. journals). |
redmine_create_issue |
Create issue (project, subject, tracker, dates, assignee, fixed_version_id, estimated_hours, etc.). |
redmine_update_issue |
Partial update; supports estimated_hours. Clear assignee via API: put empty assigned_to_id (see Redmine REST docs / use redmine_api_request). |
redmine_log_time |
POST a time entry (issue_id, hours, optional activity_id, spent_on, comments). Defaults activity_id to 164 if omitted (your server may differ—override when needed). |
redmine_list_users |
List users (permissions required). |
redmine_get_current_user |
Who the API key belongs to. |
For endpoint paths and payloads, your installation follows Redmine’s REST API (see Redmine REST API).
Practical notes (save debugging time)
Validation errors (HTTP 422)
Your Redmine may enforce:
- Priority required on create → set
priority_id(discover viaGET /enumerations/issue_priorities.json). - Estimated time on certain trackers → set
estimated_hourson create/update or inextra_fields_jsonif using an older MCP schema cache.
Clearing assignee
Some setups accept PUT /issues/:id.json with "assigned_to_id": "". If your Redmine behaves differently, use the UI or check your Redmine version’s REST notes.
Security
- Rotate the API key if it was ever committed or pasted in an insecure channel.
- Prefer per-user keys—not shared accounts.
- Restrict file permissions on
.envon shared machines (chmod 600 .env).
MCP schema cache
After upgrading index.js, reload MCP servers in Cursor so new/changed tool arguments appear in the UI.
Development
- Entry:
index.js - Start:
npm start→ runsnode index.js - Dependencies:
@modelcontextprotocol/sdk,dotenv,zod
License
MIT (see LICENSE). Dependencies retain their own licenses; Redmine is a separate project under its own license.