Skip to main content
Glama
mieweb

redmine-mcp-proxy

by mieweb

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 for Cursor

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 response

Step by step:

  1. 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-user header

    Explicit override

    2

    x-ozwell-user-email header

    Ozwell AI platform (auto)

    3

    x-ozwell-user-name header

    Ozwell AI platform (auto)

    4

    ?user= query parameter

    Manual / testing

    5

    Basic-auth username

    Clients that send credentials

    No identity → HTTP 401. Nobody gets an anonymous or admin session by accident.

  2. Per-session subprocess. A new session spawns one backend MCP process (the Rust redmine-mcp-rs binary) 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=1 is 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.

  3. 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.

  4. Session tracking. Each session is keyed by the mcp-session-id header. Subsequent requests reuse the same subprocess; closing either transport tears down the pair and frees the process.

  5. Impersonation on the wire. The backend translates REDMINE_ON_BEHALF_OF into Redmine's X-Redmine-Switch-User header 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

PORT

no

Listen port (default 80)

REDMINE_URL

yes

Redmine base URL

REDMINE_API_KEY

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.mjs

As 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.target
sudo systemctl enable --now redmine-mcp-proxy

Binding to port 80 as a non-root user requires sudo setcap cap_net_bind_service=+ep "$(command -v node)".


Endpoints

Method

Path

Purpose

GET

/health

{ status, sessions, users } liveness + who's on

POST/GET

/mcp

Streamable HTTP MCP endpoint

DELETE

/mcp

Terminate a session (mcp-session-id header)

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 .env and is injected into the subprocess.

  • Locked impersonation. REDMINE_LOCK_ON_BEHALF_OF=1 makes 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.


  • 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).

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    -
    quality
    D
    maintenance
    An MCP server providing 63 tools to interact with Redmine instances, covering issues, projects, time entries, and wiki pages. It utilizes streamable HTTP transport and supports per-client authentication for secure management of Redmine resources.
    Last updated
    35
  • A
    license
    B
    quality
    D
    maintenance
    MCP 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.
    Last updated
    89
    15
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • A MCP server built for developers enabling Git based project management with project and personal…

  • Self-hosted federated MCP gateway: one OAuth 2.1 MCP server in front of N apps, user-level scopes.

  • MCP server for generating rough-draft project plans from natural-language prompts.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mieweb/redmine-mcp-proxy'

If you have feedback or need assistance with the MCP directory API, please join our Discord server