OpenProject MCP Server
Allows interaction with OpenProject's API, providing tools for managing work packages, projects, statuses, types, priorities, comments, time logging, and assignments, with support for dry-run and protected transitions.
Click on "Install 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., "@OpenProject MCP Serverlist my work packages"
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.
openproject-agent
A pnpm monorepo that connects OpenProject to Claude Code:
Package | What it is |
OpenProject API v3 client — typed errors, HAL→DTO mapping, pagination, retry/backoff, lockVersion handling. | |
An MCP (stdio) server exposing OpenProject as tools Claude Code can call. | |
A CLI that pulls work packages, runs headless Claude Code ( |
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.
Related MCP server: OpenProject MCP Server
Install & build
pnpm install
pnpm build # tsc --build across all packages
pnpm test # vitest (mocked; no network)
pnpm lint # eslintGet 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_KEYEdit
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.jsOptional 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 resetrun 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.jsonTesting
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.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/kkurt/openproject-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server