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.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.