stayhomer.png

Treat without the trick!

Be brave and face your Redmine fears Horribly awesome discounts wait for you!

Halloween special offer has begun!

MCP server: connecting AI clients to Redmine

The Model Context Protocol (MCP) is an open standard that lets AI clients call tools of external systems. The Agent plugin makes your Redmine an MCP server: a client such as Claude, ChatGPT, Cursor, Codex or Gemini CLI can search and read issues, projects, wiki and time entries, create and update issues, add notes and log time, as the signed-in user and within that user's permissions. The full list is in MCP tools reference.

Endpoints

Method and path Purpose
POST /mcp the MCP endpoint (Streamable HTTP, JSON-RPC 2.0). GET /mcp answers 405
GET /.well-known/oauth-protected-resource/mcp OAuth resource metadata (RFC 9728)
GET /.well-known/oauth-authorization-server OAuth authorization server metadata (RFC 8414)
GET /mcp/authorize authorization endpoint advertised to MCP clients, narrows the scopes and redirects to /oauth/authorize
POST /oauth/token, POST /oauth/revoke token and revocation endpoints of Redmine (Doorkeeper)

The server answers 404 on all of them until the MCP server is enabled. Protocol: version 2025-03-26, methods initialize, ping, tools/list, tools/call; notifications get 202. The server exposes tools only (no resources or prompts).

Enable the server

  1. Enable the REST web service: Administration → Settings → API → Enable REST web service. Core Redmine accepts OAuth tokens and API keys only when it is on.
  2. Open Administration → Plugins → Redmine Agent → Configure and tick Enable MCP server. The MCP server URL is shown below the field: https://your-redmine.example.com/mcp.
  3. Make sure Administration → Settings → General → Host name and path and the protocol are correct: OAuth metadata is built from them (important behind a reverse proxy).

Create an OAuth application for each client

  1. Open Administration → Applications → New application.
  2. Give it a name, enter the Redirect URI of the client (table below) and tick the scopes that the client may use. Tools of the client are limited to the ticked scopes and the roles of the user. The client may request more scopes: it gets only the ticked ones.
  3. Save. Redmine shows the secret only once; copy it with the UID (client ID). Every application is confidential, so each client needs both.

Connect a client

Client Redirect URI Where to enter the client ID and secret
claude.ai, Claude Desktop https://claude.ai/api/mcp/auth_callback Settings → Connectors → Add custom connector → Advanced settings → OAuth Client ID and Secret
Claude Code http://localhost:8765/callback see the command below
ChatGPT the callback URL shown in the connector form Connector → Advanced → User-defined OAuth client
Codex, Gemini CLI, Cursor and other local clients the loopback URL from the OAuth settings of the client the OAuth client ID and secret settings of the client
Claude Code:
MCP_CLIENT_SECRET=CLIENT_SECRET claude mcp add --transport http \
  --client-id CLIENT_ID --client-secret --callback-port 8765 \
  redmine https://your-redmine.example.com/mcp

Redmine ignores the port of a redirect URI only for 127.0.0.1, so a localhost redirect needs a fixed callback port. After adding the server the client opens the Redmine consent page: sign in, review the scopes and approve.

Prompt for your AI agent

Paste this prompt into the AI agent that should be connected (Claude Code, Codex, Gemini CLI, Cursor…), after replacing the three values in capitals. The agent adds the server with the commands of its own client and checks the connection. Do not paste a secret into a shared chat: use a local agent.

Connect the Redmine MCP server to this AI client and check that it works.

Server URL: https://YOUR-REDMINE/mcp (Streamable HTTP, JSON-RPC 2.0, name "redmine")
Authentication: OAuth 2.0 with a pre-registered client
  client ID: CLIENT_ID
  client secret: CLIENT_SECRET
  redirect URI: http://localhost:8765/callback (fixed callback port 8765)

Steps:
1. Find out which client you run in (Claude Code, Codex, Gemini CLI, Cursor, other) and add the server with the MCP command or the config file of that client, HTTP transport, the name "redmine", the client ID and the secret. For Claude Code the command is:
   MCP_CLIENT_SECRET=CLIENT_SECRET claude mcp add --transport http --client-id CLIENT_ID --client-secret --callback-port 8765 redmine https://YOUR-REDMINE/mcp
2. Start the OAuth sign-in and tell me to approve the access in the browser. Do not invent another redirect URI or port.
3. When the sign-in is done, call get_current_user and list_projects and show me who I am and the first projects.
4. Do not print the secret again, do not write it to a file inside a repository.

If the client can only send a fixed bearer token, use the API key instead of OAuth: send the header "Authorization: Bearer API_KEY" and skip steps 1-2 of the sign-in.

After the connection works you can give the agent these working rules (put them into its memory file, for example CLAUDE.md or AGENTS.md):

Redmine is available through the MCP server "redmine". Rules:
- Before creating an issue call get_project_metadata for the project to get valid tracker, status, priority, category and custom field ids.
- Find things with list_issues (filters: project, status, assigned_to "me", version_id, query_id) or search_redmine; do not guess ids.
- For long lists pass fields (only the columns you need) or compact true, and page with limit and offset.
- Call get_issue with include only for what you need (journals, relations, children, attachments).
- Writes happen immediately as my Redmine user: before delete_*, manage_* or send_helpdesk_reply tell me what you are about to do and wait for my confirmation.
- Never put secrets or personal data into issues, notes or wiki pages.

Scopes and permissions

A tool is listed and callable when both the token scopes and the roles of the user grant the Redmine permission that the tool needs (for example view_issues, add_issues, log_time), in any project the user can see; each call is checked again against the project. The scopes advertised by the server are the permissions of the registered tools, view_private_notes (private notes in get_issue) and the scopes that plugins declare for their extensions (tags, checklists). Private notes and issues of projects the user cannot access are never returned.

Access with an API key

Clients that can only send a fixed bearer token (xAI, Grok and others) can use the user's API key. Tick Allow MCP access with API key in the plugin settings (off by default) and send:

Authorization: Bearer API_KEY

or the header X-Redmine-API-Key. The key query parameter and X-Redmine-Switch-User are not supported. An API key has no scopes and no expiry, so the client gets every right of the user, writes included. Prefer OAuth. Without this setting an API key is rejected with 401.

Try it with curl

Obtain an access token through the OAuth flow of your client (or use an API key if allowed) and call:

curl -s https://your-redmine.example.com/mcp \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Call a tool:

curl -s https://your-redmine.example.com/mcp \
  -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
       "params":{"name":"list_issues","arguments":{"project":"support","assigned_to":"me","limit":5}}}'

Security recommendations

  • Writes run immediately, without a confirmation, as the user and in every project the user can reach. An external AI that reads a hostile issue or wiki page could be tricked into writing on the user's behalf. Keep the tool approval prompt of the client enabled and tick only the scopes the client needs (for example read-only scopes for reporting clients).
  • Create one application per client so that it can be revoked separately (delete the application in Administration → Applications).
  • Tokens are kept out of the logs. A tool failure returns isError: true with "Tool failed"; details stay in the Rails log.
  • Use HTTPS.

See also MCP tools reference and MCP troubleshooting.

Was this article helpful? Yes  No