OpenProject MCP Server
Exposes OpenProject project management tools to Claude Code via MCP, enabling listing, reading, and updating work packages, projects, and statuses with safety features like dry-run and protected transitions.
README
openproject-agent
A pnpm monorepo that connects OpenProject to Claude Code:
| Package | What it is |
|---|---|
@openproject-agent/core |
OpenProject API v3 client — typed errors, HAL→DTO mapping, pagination, retry/backoff, lockVersion handling. |
@openproject-agent/mcp |
An MCP (stdio) server exposing OpenProject as tools Claude Code can call. |
@openproject-agent/orchestrator |
A CLI that pulls work packages, runs headless Claude Code (claude -p) against each, and writes the result back as a comment + status change. |
The design goal is safe, authorized automation: dry-run by default, protected status transitions blocked, no git operations, secrets never logged.
Prerequisites
- Node.js 20+ (developed on 24)
- pnpm (
npm i -g pnpm) - Claude Code CLI (
claude) available on yourPATH— the orchestrator shells out to it. - An OpenProject instance and an API key.
Install & build
pnpm install
pnpm build # tsc --build across all packages
pnpm test # vitest (mocked; no network)
pnpm lint # eslint
Get an OpenProject API key
In OpenProject: My account → Access tokens → API → Generate. The key is used as the
HTTP Basic password with the fixed username apikey
(Authorization: Basic base64("apikey:" + KEY)).
Configure
-
Copy the env template and fill it in (never commit the real
.env):cp .env.example .env # edit .env -> OPENPROJECT_URL, OPENPROJECT_API_KEY -
Edit
openproject-agent.config.json. Key fields:project— your project id or identifier.targetRepo— absolute path to the repo Claude Code should work in.filters— which work packages to pull (types,statuses,assignee: "me", ...).statusFlow—{ start, success, blocked }status names the orchestrator advances to.protectedTransitions— statuses that always require human approval (defaultClosed,Rejected).claude.allowedTools/disallowedTools— the tools spawned Claude Code may use.claude.maxTurns— turn cap (see note below).
apiKeyis written as"env:OPENPROJECT_API_KEY"and resolved from the environment; the raw key is never stored in the config file.
Use the MCP server with Claude Code
Build first (pnpm build), then register the stdio server. The path below points at the
built bin:
claude mcp add openproject \
-e OPENPROJECT_URL=https://openproject.example.com \
-e OPENPROJECT_API_KEY=your-api-key \
-- node ./packages/mcp/dist/bin.js
Optional env: OPENPROJECT_READONLY=true (block all writes),
OPENPROJECT_PROTECTED_TRANSITIONS=Closed,Rejected, and OPENPROJECT_START_STATUS="In progress"
(the status start_work_package moves a work package to).
Or add a project-scoped .mcp.json (checked into a repo Claude Code runs in):
{
"mcpServers": {
"openproject": {
"command": "node",
"args": ["/absolute/path/to/openproject-mcp/packages/mcp/dist/bin.js"],
"env": {
"OPENPROJECT_URL": "https://openproject.example.com",
"OPENPROJECT_API_KEY": "your-api-key",
"OPENPROJECT_READONLY": "true"
}
}
}
}
Prefer environment variables over hard-coding the API key in
.mcp.json; if you must, keep that file out of version control.
Tools exposed
Read: list_projects, list_work_packages, get_work_package, get_next_work_package,
list_statuses, list_types, list_priorities, get_allowed_status_transitions,
get_attachment (images are returned as viewable image content; text files are inlined).
Boards: list_boards, get_board, list_board_column, get_next_board_card
(boards are status-based Kanban boards; each column is a saved query).
Write (each supports a dryRun flag and honors global read-only mode):
add_comment, update_work_package_status, start_work_package (move a WP to the start
status, default "In progress" — call when you begin work), assign_work_package, log_time.
Critical transitions in protectedTransitions are refused with a "human approval required"
error, and work-package deletion is never exposed.
Use the orchestrator
# Show the queue without running anything
node packages/orchestrator/dist/cli.js list
# Dry run (DEFAULT): Claude Code runs, but OpenProject is NOT written
node packages/orchestrator/dist/cli.js run --wp 1234
# Really write results back to OpenProject
node packages/orchestrator/dist/cli.js run --write --yes --limit 3
# State summary / reset
node packages/orchestrator/dist/cli.js status
node packages/orchestrator/dist/cli.js reset
run flags: --project <id>, --types bug,feature, --limit <n>, --wp <id>,
--board <name>, --column <name>, --dry-run (default), --write, --yes (no per-WP
prompt), --max-turns <n>, --verbose, --config <path>, --template <path>.
Board mode
Instead of filters.statuses, you can drive the queue from a board column. Add a
board block to the config (or pass --board/--column):
"board": { "name": "MetaAdmin", "sourceColumn": "New" }
The queue is pulled from that column via its saved query (preserving board order), then
still narrowed by filters.types / filters.assignee. Because these are status-based
boards, advancing a card across columns is just a status change — so statusFlow already
moves cards on the board. Board names are unique only within a project, so the board is
resolved within config.project.
Per work package the orchestrator: fetches full detail → renders
templates/work-package.md → runs claude -p --output-format stream-json in targetRepo (with this MCP server wired in via --mcp-config) → logs the
stream to .openproject-agent/logs/wp-<id>.jsonl → parses the agent's JSON result block →
in --write mode, posts a review comment and advances status per statusFlow → records
progress in .openproject-agent/state.json. Runs are sequential (concurrency 1) and
resumable (already-finished work packages are skipped).
Safety notes
- Dry-run is the default. Writing to OpenProject requires
--write(orwrite: truein config). In dry-run the MCP server is passedOPENPROJECT_READONLY=true. - Protected transitions (e.g.
Closed,Rejected) are never performed automatically, by either the MCP server or the orchestrator. - No git. The prompt forbids git commands and the runner passes
--disallowedTools "Bash(git:*)"; only the working tree is modified. - Secrets are never written to the repo, logs, or state; the API key is masked in output.
- Unknown results (no structured result block) are routed to human review, not auto-advanced.
Note on maxTurns
Claude Code has no --max-turns CLI flag (verified against v2.1.186). The orchestrator
enforces claude.maxTurns itself by counting assistant turns in the stream-json output
and terminating the child process if it is exceeded; a wall-clock timeoutMs is a safety net.
Project layout
packages/core/ OpenProject API client, DTOs, retry, errors
packages/mcp/ MCP stdio server (uses core)
packages/orchestrator/ CLI, prompt rendering, Claude runner, state store
templates/work-package.md
openproject-agent.config.json
Testing
pnpm test runs the full suite with msw-mocked HTTP and an in-memory MCP client — no
live OpenProject or Claude Code process is needed. pnpm build (tsc) and pnpm lint must
also pass.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。