MCP Servers

模型上下文协议服务器、框架、SDK 和模板的综合目录。

MCP server for Pegatron internal Redmine (stdio + streamable HTTP)

创建于 4/21/2026
更新于 about 4 hours ago
Repository documentation and setup instructions

redmine-mcp

🌐 繁體中文:README.zh-TW.md

MCP (Model Context Protocol) server for a self-hosted Redmine instance. Exposes read + limited-write tools to LLM agents via both stdio (per-user, single tenant) and Streamable HTTP (shared, multi-tenant via header pass-through) transports.

Works with any MCP host that speaks those transports — Claude Desktop, Cursor, custom orchestrators, and similar.

Status

🧪 v0.1 complete. Both transports, all 9 planned tools, unit tests, CI, Helm chart, integration guide. Not yet released — the HTTP transport requires the MCP host to forward X-Redmine-API-Key per request to be multi-tenant safe (see docs/INTEGRATION.md).

Quickstart (stdio, single user)

npm ci
npm run typecheck
npm run test
npm run build

export REDMINE_BASE_URL="https://redmine.example.com"
export REDMINE_API_KEY="<your personal API key from My Account → API access key>"

# Run end-to-end smoke against the real Redmine
npm run smoke

HTTP mode (multi-user, hosted)

export REDMINE_BASE_URL="https://redmine.example.com"
export PORT=8080
node dist/bin/http.js

The server requires every incoming MCP request to carry an X-Redmine-API-Key header. It holds no key itself — each call runs under the caller's identity via AsyncLocalStorage. See docs/INTEGRATION.md for how to wire this into an MCP host.

MCP client registration (mcpServers JSON)

Most MCP hosts accept the standard mcpServers configuration. Paste one of the following into your host's MCP config.

stdio — npx from source

{
  "mcpServers": {
    "redmine": {
      "command": "npx",
      "args": ["-y", "github:OWNER/redmine-mcp"],
      "env": {
        "REDMINE_BASE_URL": "https://redmine.example.com",
        "REDMINE_API_KEY": "<your personal API key>",
        "NODE_EXTRA_CA_CERTS": "/path/to/private-ca.pem"
      }
    }
  }
}

The first run clones the repo, installs deps, and triggers the prepare script to build dist/. Subsequent invocations use npm's cache. If the source repo is private, the host running npx needs working git credentials (SSH key loaded, or a PAT configured in the git credential helper).

stdio — pinned local binary

{
  "mcpServers": {
    "redmine": {
      "command": "node",
      "args": ["/absolute/path/to/redmine-mcp/dist/bin/stdio.js"],
      "env": { "REDMINE_BASE_URL": "...", "REDMINE_API_KEY": "..." }
    }
  }
}

streamable_http — hosted

{
  "mcpServers": {
    "redmine": {
      "url": "https://redmine-mcp.example.internal/mcp"
    }
  }
}

The MCP host must forward the end user's API key as X-Redmine-API-Key on every request.

Tools (v0.1)

Read (6)

| Tool | Purpose | |---|---| | list_projects(limit?, search?) | List accessible projects, optional name substring filter | | get_project(id_or_identifier, include?) | Single project with optional trackers/categories/modules | | list_my_issues(status_filter?, limit?) | Issues assigned to the API-key owner, sorted by updated | | search_issues(project?, status?, assigned_to?, subject_contains?, updated_after?, ...) | Cross-cutting issue search | | get_issue(id, include?) | Full issue with optional journals/attachments/relations/children/watchers | | list_time_entries(user?, project?, issue_id?, from?, to?) | Time entries with auto-sum |

Write (3) — all support dry_run?: boolean

| Tool | Purpose | |---|---| | add_comment(issue_id, notes, private_notes?) | Add a note; attributed to key owner | | log_time(issue_id? or project_id?, hours, spent_on?, activity_id?, comments?) | Create a time entry; auto-picks default activity if not specified | | update_issue(issue_id, status_id?, done_ratio?, assigned_to_id?, priority_id?, notes?) | Update metadata fields only — intentionally does not edit subject/description |

Write tools with dry_run: true return a redacted preview of the HTTP request instead of calling Redmine.

Architecture

redmine-mcp/
├── bin/
│   ├── stdio.ts          # Entry: env var auth, single-user
│   └── http.ts           # Entry: Streamable HTTP, header pass-through
├── src/
│   ├── auth.ts           # AuthContext + AsyncLocalStorage dispatch
│   ├── errors.ts         # RedmineError + LLM-safe humanization
│   ├── server.ts         # Shared McpServer builder
│   ├── redmine/          # Per-resource fetch wrappers
│   │   ├── client.ts     # GET/POST/PUT + redacted previewRequest
│   │   ├── projects.ts
│   │   ├── issues.ts
│   │   └── time.ts
│   └── tools/            # One MCP tool per file
├── test/unit/            # Vitest: errors, auth, client
├── scripts/smoke.ts      # Live MCP client against real Redmine
├── deploy/helm/          # Kubernetes chart for HTTP mode
├── Dockerfile            # Multi-stage, node:20-alpine, non-root
└── .github/workflows/ci.yml

Design decisions

| # | Decision | Choice | |---|---|---| | 1 | Target Redmine | Self-hosted 5.x / 6.x | | 2 | Capability scope | Read + comment + time-logging + issue status/progress/assignee updates | | 3 | Language / SDK | TypeScript + @modelcontextprotocol/sdk | | 4 | Transports | Both stdio and streamable_http (single codebase, two entry points) | | 5 | Auth model | stdio via env vars; http via X-Redmine-API-Key header pass-through |

Why header pass-through for HTTP

Redmine API keys are per-user — writes (comments, time entries, status changes) are attributed to the key owner. A shared service account would mis-attribute all writes. Header pass-through lets a single hosted MCP serve every user with their correct identity, as long as the surrounding MCP host can forward a per-user secret as a request header.

TLS note (private CA)

If your Redmine is fronted by a private / internal CA that Node does not trust by default:

  • Recommended: NODE_EXTRA_CA_CERTS=/path/to/ca.pem
  • Insecure fallback (dev only): NODE_TLS_REJECT_UNAUTHORIZED=0

The Helm chart exposes extraCaCerts.enabled=true to mount a Secret at /etc/ssl/extra/ and wire up NODE_EXTRA_CA_CERTS automatically.

License

License TBD.

快速设置
此服务器的安装指南

安装包 (如果需要)

npx @modelcontextprotocol/server-redmine-mcp

Cursor 配置 (mcp.json)

{ "mcpServers": { "pegaai-redmine-mcp": { "command": "npx", "args": [ "pegaai-redmine-mcp" ] } } }