redmine-mcp-proxy
Provides a proxy for multi-user, network-reachable access to a Redmine MCP server, with per-user impersonation and integration with the Redmine REST API.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@redmine-mcp-proxyshow my open issues"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
redmine-mcp-proxy
A Streamable HTTP → stdio bridge that turns a stdio Model Context Protocol Redmine server into a multi-user, network-reachable MCP endpoint — with per-user impersonation baked in.
Point your AI platform (Ozwell, Claude, etc.) at a single URL:
https://rm.os.mieweb.org/mcp…and every logged-in user transparently acts as themselves in Redmine — no shared service account, no per-user API keys, no prompt-injectable identity.
Why this exists
MCP Redmine servers speak stdio (one process, one identity). That's great for a single desktop user, but it doesn't work when:
Many people share one AI assistant, and each must act as their own Redmine user (correct "assigned to me", correct author, correct permissions).
The MCP client is a hosted web platform that can only reach an HTTP URL, not a local subprocess.
This proxy solves both: it exposes Streamable HTTP on /mcp, and for every
session it spawns a dedicated backend subprocess locked to the requesting
user's identity.
Related MCP server: Redmine MCP Server
How the Proxy works
sequenceDiagram
participant AI as AI Platform (Ozwell / Claude)
participant Proxy as redmine-mcp-proxy (HTTP :80/mcp)
participant Sub as redmine-mcp-rs subprocess (stdio)
participant RM as Redmine REST API
AI->>Proxy: POST /mcp (initialize)<br/>x-ozwell-user-email: rgara@mieweb.com
Note over Proxy: resolveUser() extracts identity
Proxy->>Sub: spawn(redmine-mcp-rs)<br/>REDMINE_ON_BEHALF_OF=rgara@mieweb.com<br/>REDMINE_LOCK_ON_BEHALF_OF=1
Proxy-->>AI: mcp-session-id: <uuid>
AI->>Proxy: POST /mcp (tools/call)<br/>mcp-session-id: <uuid>
Proxy->>Sub: forward JSON-RPC (stdin)
Sub->>RM: GET /issues.json<br/>X-Redmine-Switch-User: rgara
RM-->>Sub: issues visible to rgara
Sub-->>Proxy: JSON-RPC result (stdout)
Proxy-->>AI: Streamable HTTP responseStep by step:
Identity resolution. On the first request of a session,
resolveUser(req)determines who the caller is, in priority order:Priority
Source
Sent by
1
x-redmine-userheaderExplicit override
2
x-ozwell-user-emailheaderOzwell AI platform (auto)
3
x-ozwell-user-nameheaderOzwell AI platform (auto)
4
?user=query parameterManual / testing
5
Basic-auth username
Clients that send credentials
No identity → HTTP 401. Nobody gets an anonymous or admin session by accident.
Per-session subprocess. A new session spawns one backend MCP process (the Rust
redmine-mcp-rsbinary) with the environment locked to that user:env: { REDMINE_URL, REDMINE_API_KEY, // admin key, server-side only REDMINE_ON_BEHALF_OF: onBehalfOf, // the resolved user REDMINE_LOCK_ON_BEHALF_OF: "1", // AI cannot override this }REDMINE_LOCK_ON_BEHALF_OF=1is the security keystone: even if the model is tricked ("act as the admin", "switch to user X"), the backend ignores any per-call identity and stays pinned to the header-derived user.Bidirectional bridge. The proxy wires the two transports together:
StreamableHTTPServerTransport(facing the AI) ⇄StdioClientTransport(facing the subprocess). Messages are forwarded verbatim in both directions, so tool names and arguments pass through unchanged.Session tracking. Each session is keyed by the
mcp-session-idheader. Subsequent requests reuse the same subprocess; closing either transport tears down the pair and frees the process.Impersonation on the wire. The backend translates
REDMINE_ON_BEHALF_OFinto Redmine'sX-Redmine-Switch-Userheader on every REST call, so Redmine enforces that user's real permissions and ownership.
Configuration
Create /opt/redmine-mcp-proxy/.env (chmod 600 — it holds the admin key):
PORT=80
REDMINE_URL=https://pm.mieweb.com/
REDMINE_API_KEY=<redmine-admin-api-key>Variable | Required | Description |
| no | Listen port (default |
| yes | Redmine base URL |
| yes | Admin API key (needed for impersonation) |
The path to the backend binary is set in server.mjs (the command: field of
the StdioClientTransport). Swap it for node index.js to use the Node
redmine-mcp server instead of the
Rust one.
Run
npm install
node server.mjsAs a systemd service
/etc/systemd/system/redmine-mcp-proxy.service:
[Unit]
Description=Redmine MCP Streamable HTTP proxy
After=network.target
[Service]
Type=simple
User=pralambomanarivo
EnvironmentFile=/opt/redmine-mcp-proxy/.env
ExecStart=/usr/bin/node /opt/redmine-mcp-proxy/server.mjs
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now redmine-mcp-proxyBinding to port 80 as a non-root user requires
sudo setcap cap_net_bind_service=+ep "$(command -v node)".
Endpoints
Method | Path | Purpose |
|
|
|
|
| Streamable HTTP MCP endpoint |
|
| Terminate a session ( |
curl -s https://rm.os.mieweb.org/health
# {"status":"ok","sessions":1,"users":["rgara@mieweb.com"]}Security model
Admin key never leaves the server. The AI platform only sends a user identity header; the key lives in
.envand is injected into the subprocess.Locked impersonation.
REDMINE_LOCK_ON_BEHALF_OF=1makes identity header-driven and prompt-injection-proof.Fail-closed. No resolvable identity →
401, never an anonymous/admin fallback.Least privilege on the wire. Redmine evaluates every request against the impersonated user's actual permissions.
Related
redmine-mcp-rs— the Rust MCP backend this proxy spawns (single static binary, fast startup).redmine-mcp— the original Node MCP server (fully compatible backend).
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
An authenticated remote MCP server for user-owned devices and one-shot capability invocation.
Hosted MCP server for task-first delegation to remote workstations and workers.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interacting with a Redmine instance via REST API, allowing issues, projects, time logging, and generic endpoint calls through an MCP agent.28 npmMIT
- AlicenseCqualityDmaintenanceModel Context Protocol (MCP) server for Redmine that provides comprehensive access to the Redmine REST API, enabling users to operate Redmine from MCP clients such as Claude Desktop.9020 npmMIT
- AlicenseBqualityDmaintenanceMCP server for Redmine project management, enabling tools for managing projects, issues, users, time entries, groups, memberships, versions, wiki, news, attachments, search, and Agile sprints via the Redmine REST API.8921 npm1MIT
- AlicenseCqualityAmaintenanceModel Context Protocol (MCP) server for Redmine that provides comprehensive access to the Redmine REST API. It allows you to operate Redmine from MCP clients such as Claude Desktop.90541 npm26MIT