关于 OpenProject
OpenProject MCP Server 将 OpenProject API v3 接入 MCP,面向使用 Community 版实例的团队。它提供涵盖项目管理多类数据的结构化工具,并支持只读和权限控制。
主要功能
- 01覆盖工作包、项目、工时等 API
- 02工具返回带类型的结构化数据
- 03提供报告与工作流提示词
- 04支持只读、管理员及分组开关
- 05适配 OpenProject 14 至 17.x
适用场景
- 01查询并更新工作包及评论
- 02管理项目成员、会议和文档
- 03查看工时、预算与报告数据
MCP 相关
作为 MCP 服务,向 MCP 客户端开放 91 个 OpenProject API v3 工具、4 个报告/工作流提示词和 3 个资源模板。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx openproject-mcp-serverOPENPROJECT_URLOpenProject instance root URL, e.g. https://openproject.example.comOPENPROJECT_API_KEY密钥API key from My account -> Access tokens in OpenProjectOPENPROJECT_OAUTH_TOKEN密钥OAuth bearer token used instead of the API key (OAuth deployments)OPENPROJECT_MCP_READ_ONLYSet to 1 to serve read tools onlyOPENPROJECT_MCP_ADMIN_TOOLSSet to 1 to enable the membership-write tools (hidden by default)OPENPROJECT_MCP_DISABLEComma-separated tool groups to drop, e.g. meetings,budgetsOPENPROJECT_MCP_PROFILEcore (default) or full: core hides the module-backed tool groups at startup本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
88收录的工具列表 · 更新于 1 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| mode | enum | 否 | “quick”(默认)会匹配主题、ID、项目名称以及类型/状态名称——这与 OpenProject 页眉搜索的行为相同,也是“查找名为 X 的工单”的正确选择。“fulltext”还会匹配描述文本、评论和可搜索的自定义字段;用于查找“提到 Y 的工单”。quick | fulltext |
| page | integer | 否 | 从 1 开始的页码。 |
| query | string | 是 | 要查找的自由文本。在“quick”模式下,单独的数字也会匹配工作包 ID,因此“1234”会找到 #1234。 |
| page_size | integer | 否 | 每页结果数(最多 100 条)。 |
| project_id | any | 否 | 将搜索范围限制为一个项目:数字 ID 或项目标识符(OpenProject URL 中的 slug)。两者均可通过 list_projects 获取。省略时会搜索用户可见的所有项目。 |
| status_scope | enum | 否 | 要搜索的状态。默认值为“all”,因为搜索通常是为了查找已关闭的项目;传入“open”可隐藏已完成的工作。始终会发送显式状态筛选器,因此服务器隐式的仅限开放状态的默认值不会生效。open | closed | all |
详细介绍
OpenProject MCP 服务
一个用于 OpenProject API v3 的 MCP(Model Context Protocol)服务。它为 Claude 和任何其他 MCP 客户端提供 91 个工具,涵盖工作包、评论和关系、附件、Git/PR 活动、项目、已保存的查询、通知、时间跟踪、版本、人员和成员身份、会议、新闻、文档、预算和报告;此外还提供 4 个报告/工作流提示词和 3 个资源模板。基于 FastMCP 3.x 和 httpx(HTTP/2)构建。
此项目面向 OpenProject Community 版。OpenProject 的 Enterprise 版现已内置 MCP 集成;此服务为可自托管的 Community 实例提供相同的功能。它也能在任何版本上正常运行,只需使用公开的 API v3。
设计原则均已通过代码落实:
- 一切皆结构化。 每个工具都会返回类型化模型,因此客户端会获得
outputSchema和机器可读的structuredContent,而不是散文。错误会以 JSON 信封形式返回,其中包含稳定的type、上游的http_status、message,以及说明如何修正调用的hint。 - 诚实地处理降级。 OpenProject 实例因版本、已安装的模块和权限而异。工具会以带内注释的形式报告无法读取的内容——模块缺失时会返回附有说明的空页面,而不会伪装成功或只返回原始回溯信息。
- 默认安全。 提供只读模式、仅限管理员的成员身份写入操作、按组禁用工具、所有破坏性工具均带有
confirm=true防护、始终验证 TLS,且凭据绝不会出现在日志中。 - 适配不同版本。 支持 OpenProject 14 LTS 至 17.x;通过延迟执行并缓存的功能探测来检测 API 差异,而非依赖假设(参见支持的 OpenProject 版本)。
效果示例
以下是针对虚构的“网站重新上线”项目进行的两轮交互——下文中的每个 ID、名称和日期都是虚构的。你描述期望结果;模型会选择工具,而返回给模型的是类型化对象,而非需要重新解析的散文。
You What is still open in Website Relaunch and due by Friday? The checkout
bug is urgent — raise it and leave a note for whoever owns it.
→ list_work_packages(project="website-relaunch", status_scope="open",
due_before="2026-03-13", sort_by=[["due_date", "asc"]])
{ "items": [
{ "id": 4821, "subject": "Checkout fails on expired coupon codes",
"type": {"id": 7, "name": "Bug"}, "status": {"id": 7, "name": "In progress"},
"assignee": {"id": 118, "name": "Dana Okafor"}, "due_date": "2026-03-11" },
{ "id": 4830, "subject": "Move press-kit assets to the new CDN",
"type": {"id": 1, "name": "Task"}, "status": {"id": 1, "name": "New"},
"assignee": null, "due_date": "2026-03-13" }],
"pagination": {"total": 2, "page": 1, "page_size": 20, "has_more": false} }
→ update_work_package(id=4821, priority="High")
→ add_work_package_comment(id=4821, comment="Raised to High — it blocks the
launch checklist. Dana, can you take a look today?")
Assistant Two open items are due by Friday. #4821 is High now and the note is on
its thread; #4830 is due Friday and still has nobody on it.
上面的行经过了简化:每行还包含 priority、project、start_date、percentage_done 和 updated_at;对于会填充这些内容的调用,信封还保留了 groups、sums 和 notes 字段。
提示词模板省去了工具的往返调用:服务会自行读取 OpenProject,并直接返回完整文档,而不是提供指示让你去获取文档。文档开头会附上一条说明,指出其中的数字已计算完成,不应重新计算或润色。
You /weekly_report project=website-relaunch
# WEEKLY REPORT - AGILE SCRUM
_Generated from live OpenProject data_
...
## B. EXECUTIVE SUMMARY
**Progress against the sprint goal:** Not assessed — sprint goal and completion dates are not available
**Currently closed work updated in the window:**
1. #4802 - Ship the new pricing page
2. #4795 - Halve the hero image payload
...
### Data notes
- open/closed bucketing uses each status's isClosed flag from
GET /statuses, not status names; a status this instance renamed
or translated is still bucketed correctly
最后这部分体现了我们的惯例:报告会说明哪些数字是部分数据;工具无法读取某项内容时,会通过注释说明数据缺口,而不是猜测。完整功能请参阅工具和提示词与资源。
要求
- Python >= 3.12
- OpenProject 实例,版本为 14 LTS 至 17.x(任何版本均可;面向 Community 版,Enterprise 版自带 MCP 集成)
- OpenProject API 密钥:在 OpenProject 中前往我的账户 → 访问令牌并生成 API 令牌
安装
分发包名称为 openproject-mcp-server。它会安装两个完全相同的控制台脚本:openproject-mcp-server 和 openproject-mcp;长名称是规范名称(另一个无关的 PyPI 包也会安装一个名为 openproject-mcp 的可执行文件)。
使用 uv 运行一次,无需安装:
uvx openproject-mcp-server
或者进行持久安装:
uv tool install openproject-mcp-server
# or
pip install openproject-mcp-server
最简配置需要两个环境变量:
export OPENPROJECT_URL=https://openproject.example.com
export OPENPROJECT_API_KEY=your-api-key
无需启动服务即可验证配置:
openproject-mcp-server --check
--check 会验证配置并退出;它不会连接到你的实例。通过客户端连接后,调用 get_instance_info 工具进行实时端到端检查。如果配置缺失或无效,服务会将具体问题输出到 stderr,并以代码 2 退出——绝不会输出回溯信息。
Claude Code
claude mcp add openproject \
--env OPENPROJECT_URL=https://openproject.example.com \
--env OPENPROJECT_API_KEY=your-api-key \
-- uvx openproject-mcp-server
Claude Desktop 和其他 MCP 客户端
添加到 claude_desktop_config.json(或客户端对应的 mcpServers 配置):
{
"mcpServers": {
"openproject": {
"command": "uvx",
"args": ["openproject-mcp-server"],
"env": {
"OPENPROJECT_URL": "https://openproject.example.com",
"OPENPROJECT_API_KEY": "your-api-key"
}
}
}
}
从源码运行
git clone https://github.com/kar-thik/openproject-mcp
cd openproject-mcp
uv sync
uv run openproject-mcp-server
更新或轮换 API 令牌
令牌重新生成、撤销或失效时(OpenProject 重大版本升级可能导致这种情况——其表现为所有工具突然因 authentication_failed / HTTP 401 而失效),请在 OpenProject 的 我的账户 → 访问令牌 下生成新令牌,并在密钥所在的位置更新它:
-
Shell 环境(最便于轮换)。 服务会直接从操作系统环境读取
OPENPROJECT_API_KEY,因此你可以全局导出该变量——例如,在~/.zshenv中——并注册服务,无需任何--env标志:claude mcp add openproject -- uvx openproject-mcp-server轮换时只需编辑导出语句、打开一个新终端并重新连接。客户端配置中不会包含密钥。(这不适用于 Claude Desktop 等 GUI 应用,因为它们不会读取你的 shell 配置文件。)
-
使用
--env的 Claude Code。 注册信息中会保存密钥,因此需要替换它:claude mcp remove openproject claude mcp add openproject \ --env OPENPROJECT_URL=https://openproject.example.com \ --env OPENPROJECT_API_KEY=new-key \ -- uvx openproject-mcp-server然后通过
/mcp重新连接(正在运行的会话会继续使用旧环境,直到重新连接)。 -
Claude Desktop 和其他使用 JSON 配置的客户端。 编辑客户端配置中的
OPENPROJECT_API_KEY值,然后重启客户端。 -
.env文件。 编辑该文件并重启服务。
近期版本的 OpenProject 允许同时使用多个 API 令牌,因此可以实现零停机轮换:创建新令牌,将客户端切换到新令牌,然后撤销旧令牌。
配置
配置完全由环境变量控制。下表是权威参考:服务仅绑定这 26 个名称,不绑定其他名称。未加前缀的名称(如 READ_TIMEOUT 或 API_KEY)会被有意忽略(shell 中意外存在的变量不会更改或破坏服务),其他任何未知变量也会被忽略。服务工作目录中的 .env 文件会使用相同的名称读取;实际环境变量优先级更高。从源码运行的用户可以从 .env.example 开始配置。
| 变量 | 默认值 | 用途 |
|---|---|---|
OPENPROJECT_URL | —(必填) | 实例根 URL,例如 https://openproject.example.com。允许末尾带有 /api/v3,该部分会被移除。 |
OPENPROJECT_API_KEY | —(必填*) | 从 我的账户 → 访问令牌 获取的 API 密钥。以 HTTP Basic apikey:<token> 形式发送。 |
OPENPROJECT_OAUTH_TOKEN | 未设置 | OAuth bearer token,可替代 API 密钥。*两种凭据必须提供其一。 |
OPENPROJECT_MCP_ACCEPT_LANGUAGE | 未设置 | 作为 Accept-Language 标头发送;OpenProject 会据此对验证消息进行本地化。 |
OPENPROJECT_MCP_CA_BUNDLE | 系统信任存储 | 为使用私有 CA 的实例指定 CA bundle(PEM)路径。始终验证 TLS;不会提供关闭验证的选项。 |
OPENPROJECT_MCP_READ_ONLY | false | 仅提供读取工具:启动时会移除所有写入、破坏性和管理工具。 |
OPENPROJECT_MCP_ADMIN_TOOLS | false | 提供三个受管理员权限控制的成员资格写入工具(默认隐藏)。 |
OPENPROJECT_MCP_DISABLE | 空 | 以逗号分隔的分组标签,用于在启动时移除整个工具组(见下文)。 |
OPENPROJECT_MCP_PROFILE | core | core 会在启动时隐藏由模块提供的分组;会话可通过 enable_tool_group 重新启用其中某个分组(见下文)。full 会列出所有分组。 |
OPENPROJECT_MCP_INSECURE | false | 允许 --transport http 在没有身份验证令牌的情况下启动。仅用于本地开发。 |
OPENPROJECT_MCP_DOWNLOAD_DIR | ./openproject-downloads | download_attachment 写入文件的目录(若目录不存在则会创建;默认路径相对于服务的工作目录)。 |
OPENPROJECT_MCP_UPLOAD_ROOT | 未设置 | 设置后,upload_attachment 和 create_work_package(attachment_paths) 只会读取此现有目录下的文件;解析到目录外的路径和符号链接会被拒绝。建议与 --transport http 搭配使用。 |
OPENPROJECT_MCP_DOWNLOAD_ROOT | 未设置 | 设置后,download_attachment 只会写入此现有目录下,并默认保存到此目录;目录外的 save_dir 会被拒绝。建议与 --transport http 搭配使用。 |
OPENPROJECT_MCP_MAX_DOWNLOAD_MB | 100 | 附件下载的大小上限,单位为 MiB。 |
OPENPROJECT_MCP_MAX_INLINE_MB | 10 | openproject://attachment 资源内联返回附件字节内容的大小上限,单位为 MiB(不会超过下载上限)。 |
OPENPROJECT_MCP_CACHE_TTL | 300 | 元数据缓存(状态、类型、优先级、架构)的生存时间,单位为秒。 |
OPENPROJECT_MCP_LOG_LEVEL | INFO | DEBUG、INFO、WARNING、ERROR 或 CRITICAL(不区分大小写)。 |
OPENPROJECT_MCP_LOG_FORMAT | text | text 或 json。日志始终写入 stderr(stdout 留给 stdio 传输)。 |
OPENPROJECT_MCP_LOG_BODIES | false | 记录请求/响应正文——仅在 DEBUG 级别下生效,并会隐藏凭据。仅用于开发。 |
OPENPROJECT_MCP_OTEL | false | 为 OpenTelemetry 跟踪预留。当前版本会接受此设置,但尚未将其接入任何功能;设置后不会生成跟踪数据。 |
OPENPROJECT_MCP_HTTP_HOST | 127.0.0.1 | --transport http 的绑定地址。 |
OPENPROJECT_MCP_HTTP_PORT | 8000 | --transport http 的端口。 |
OPENPROJECT_MCP_AUTH_TOKENS | 未设置 | --transport http 接受的 bearer token,以逗号分隔(例如,每个客户端一个)。每个请求都必须携带其中一个令牌,即 Authorization: Bearer <token>;其他情况均会返回 401。若未设置此项(且未设置 OPENPROJECT_MCP_INSECURE=1),HTTP 传输将拒绝启动。请参阅传输方式。 |
OPENPROJECT_MCP_CONNECT_TIMEOUT | 10 | 等待与 OpenProject 建立 TCP/TLS 连接的秒数。 |
OPENPROJECT_MCP_READ_TIMEOUT | 30 | 等待响应数据的秒数。 |
OPENPROJECT_MCP_WRITE_TIMEOUT | 60 | 发送请求数据(上传)时的等待秒数。 |
OPENPROJECT_MCP_POOL_TIMEOUT | 5 | 等待从连接池中获取空闲连接的秒数。 |
OPENPROJECT_MCP_MAX_CONNECTIONS | 10 | 连接到 OpenProject 的连接池大小。 |
OPENPROJECT_MCP_MAX_RETRIES | 3 | 幂等请求的重试次数上限。 |
机密信息(OPENPROJECT_API_KEY、OPENPROJECT_OAUTH_TOKEN、OPENPROJECT_MCP_AUTH_TOKENS)以 Pydantic SecretStr 值的形式保存在内存中,绝不会写入日志;每条日志记录中的 Authorization 标头都会被隐藏。 |
限制模型的操作
启动时,四项设置会缩减工具范围。此后,工具列表在进程的整个生命周期内保持固定,但有一个例外:enable_tool_group 可以恢复被 core 配置隐藏的工具组,且仅对调用它的会话生效。
OPENPROJECT_MCP_READ_ONLY=1仅提供 40 个读取工具。OPENPROJECT_MCP_ADMIN_TOOLS=1显示三个成员关系写入工具(create_membership、update_membership、delete_membership);这些工具默认隐藏。OPENPROJECT_MCP_DISABLE会移除整个工具组,以降低提示词开销,例如OPENPROJECT_MCP_DISABLE=meetings,news。有效的工具组标签包括:work_packages、wp_collaboration、attachments、git_activity、projects、queries、notifications、time_entries、versions、people、metadata、meetings、wiki、documents、budgets、news、reporting——与下方工具目录各节开头使用的标签相同——以及meetings的子标签meetings_recurring,它只会移除六个定期会议工具(meetings也会移除这些工具)。OPENPROJECT_MCP_PROFILE默认为core(自 0.4.0 起);它会隐藏由模块提供的工具组——meetings、news、documents、wiki、budgets、git_activity和reporting,以及两个报告提示词——让会话以较短的工具列表启动。设置为full可从一开始就列出所有工具组。模型需要其中某个工具组时,可调用enable_tool_group;该工具组只会为调用它的会话恢复。随后,服务会向该会话发送tools/list_changed,因此客户端必须遵循此通知并重新读取工具列表(如果客户端不支持,请设置为full)。会话规则在空闲 24 小时后过期。enable_tool_group不会解除READ_ONLY、管理员限制或OPENPROJECT_MCP_DISABLE的限制;它属于metadata工具组,因此禁用该组也会将其移除。
无论上述四项设置如何,所有破坏性工具(13 个永久删除工具)在执行操作前都必须显式传入 confirm=true 参数。
传输方式
-
stdio(默认)——Claude Code、Claude Desktop 和大多数本地 MCP 客户端使用此方式。 日志写入 stderr;stdout 仅承载协议内容。
-
Streamable HTTP——
openproject-mcp-server --transport http。默认绑定到127.0.0.1:8000;可通过--host/--port或OPENPROJECT_MCP_HTTP_HOST/OPENPROJECT_MCP_HTTP_PORT覆盖。未配置身份验证时,HTTP 传输拒绝启动:将OPENPROJECT_MCP_AUTH_TOKENS设置为以逗号分隔的 bearer token 列表,或者——仅限本地开发——设置OPENPROJECT_MCP_INSECURE=1。配置 token 后,发送到 MCP 端点的每个 HTTP 请求都必须携带
Authorization: Bearer <token>标头,且其中的 token 必须与某个已配置的值匹配(比较采用恒定时间);缺少 token、格式错误或 token 未知的请求都会被拒绝,并返回 401 和WWW-Authenticate标头。支持多个 token——例如为每个客户端配置一个,这样便可单独撤销。Token 必须为 ASCII 字符;端点不进行速率限制,因此请使用较长的随机值——例如python -c "import secrets; print(secrets.token_urlsafe(32))"。OPENPROJECT_MCP_INSECURE=1仍是仅供开发使用的应急选项,可让端点在不进行身份验证的情况下开放。服务不会终止 TLS,因此 token 否则会以明文形式通过网络传输:请保留默认的
127.0.0.1绑定;如果必须将 HTTP 传输暴露到 localhost 之外,请将其置于负责终止 TLS 的反向代理之后(例如 nginx 或 Caddy)。单一上游身份。 Bearer token 决定谁可以访问端点,而非他们在 OpenProject 中的身份:服务持有单个
OPENPROJECT_API_KEY(或 OAuth token),所有 HTTP 客户端都以该 OpenProject 用户的身份操作,并共用其元数据缓存。仅为你愿意让其使用该账户的客户端部署此服务,并为其创建专用且权限最小化的 OpenProject 用户。文件工具会操作服务所在机器的磁盘。
upload_attachment、create_work_package (attachment_paths)和download_attachment会读取和写入运行服务的机器上的路径。通过 HTTP 使用时,这些工具默认关闭,除非你限制其访问范围:upload_attachment和attachment_paths需要OPENPROJECT_MCP_UPLOAD_ROOT,download_attachment需要OPENPROJECT_MCP_DOWNLOAD_ROOT。在此之前,工具会被隐藏(并且attachment_paths会被拒绝),服务会在启动警告中指出缺少的变量。
工具
共 91 个工具:42 个读取工具、46 个写入工具和 3 个需管理员权限的写入工具。除非设置 OPENPROJECT_MCP_ADMIN_TOOLS=1,否则管理员工具会保持隐藏;此外,13 个破坏性工具每次调用还都需要 confirm=true。每个小节标题都会标明 OPENPROJECT_MCP_DISABLE 接受的组标签。
工作包(work_packages)
| 工具 | 类型 | 功能 |
|---|---|---|
search_work_packages | 读取 | 当你不知道工作包 ID 时,通过文本查找工作包。 |
list_work_packages | 读取 | 使用结构化筛选条件列出工作包——最常用的读取工具。 |
get_work_package | 读取 | 完整读取一个工作包:描述、日期、自定义字段、父级和进度。 |
create_work_package | 写入 | 创建工作包,首先通过 OpenProject 自身的表单端点进行验证。 |
update_work_package | 写入 | 更改工作包的任何可写字段,并使用乐观锁定。 |
bulk_update_work_packages | 写入 | 预览或应用最多 50 项更新,并提供每项的差异、验证和冲突结果。 |
delete_work_package | 写入(破坏性) | 永久删除工作包及其所有关联内容。 |
批量工作流:调用 bulk_update_work_packages(updates=[{"id": 4821, "changes": {"target_versions": [3, 4]}}]) 进行预览。检查返回的更改,
然后使用 dry_run=false 重复调用,并在 updates 中包含每项返回的
lock_version。任何预检错误都会阻止整个批次写入。之后发生的
冲突可能导致部分成功;请检查每项,且不要重放已成功的更新。unknown 表示响应丢失前写入可能已经提交。
评论、关联、关注者、提醒(wp_collaboration)
| 工具 | 类型 | 功能 |
|---|---|---|
list_work_package_comments | 读取 | 读取工作包的评论串和更改历史。 |
add_work_package_comment | 写入 | 在工作包上发表评论。 |
edit_work_package_comment | 写入 | 改写现有工作包评论的文本。 |
add_work_package_watcher | 写入 | 订阅用户接收工作包通知。 |
remove_work_package_watcher | 写入 | 取消订阅用户接收工作包通知。 |
create_work_package_relation | 写入 | 关联两个工作包(阻塞、后续、重复、相关等)。 |
update_work_package_relation | 写入 | 更改现有关联的类型、滞后时间或描述。 |
delete_work_package_relation | 写入(破坏性) | 移除两个工作包之间的关联。 |
toggle_comment_reaction | 写入 | 使用表情符号回应工作包评论,或撤回应。 |
set_work_package_reminder | 写入 | 设置、更改或清除你在工作包上的个人提醒。 |
list_reminders | 读取 | 列出你自己的近期工作包提醒。 |
execute_custom_action | 写入 | 对工作包运行实例定义的一键操作。 |
附件和文件链接(attachments)
| 工具 | 类型 | 功能 |
|---|---|---|
list_attachments | 读取 | 列出一个容器中附加的文件。 |
download_attachment | 读取 | 将附件字节下载到运行此服务的机器上的文件中。 |
upload_attachment | 写入 | 将本地文件附加到工作包、Wiki 页面、会议、文档、预算或评论。 |
delete_attachment | 写入(破坏性) | 从 OpenProject 永久删除一个附加文件。 |
list_file_links | 读取 | 列出链接到工作包的外部存储文件(Nextcloud、OneDrive/SharePoint)。 |
Git 和拉取请求(git_activity)
| 工具 | 类型 | 功能 |
|---|---|---|
get_work_package_git_activity | 读取 | 显示工作包背后的代码:提交、拉取/合并请求和 CI 状态。 |
get_github_pull_request | 读取 | 完整读取一个已关联的 GitHub 拉取请求,包括其 CI 检查运行。 |
项目(projects)
| 工具 | 类型 | 功能说明 |
|---|---|---|
list_projects | 读取 | 列出项目,服务器端筛选,一次返回一页。 |
get_project | 读取 | 完整读取一个项目。 |
create_project | 写入 | 创建项目,并先通过 OpenProject 自身的表单端点进行验证。 |
update_project | 写入 | 更改项目的名称、描述、可见性、父级、状态或归档状态。 |
delete_project | 写入(破坏性操作) | 安排永久删除项目及其所有内容。 |
copy_project | 写入 | 将项目复制到新项目中,包括其设置,并可选择是否复制工作包。 |
get_job_status | 读取 | 检查后台作业(项目复制或计划删除)是否已完成。 |
set_project_favorite | 写入 | 将项目添加到或移出已认证用户的收藏夹(OpenProject 17+)。 |
list_project_phase_definitions | 读取 | 列出实例级阶段目录(启动、规划等)及其开始/完成关卡(OpenProject 16.1+)。 |
get_project_phase | 读取 | 读取一个项目的阶段记录;其 ID 来自工作包的 project_phase 引用。 |
已保存的查询(queries)
| 工具 | 类型 | 功能说明 |
|---|---|---|
list_queries | 读取 | 列出该用户可以打开的已保存工作包视图(查询)。 |
run_query | 读取 | 运行已保存的视图,并获取其中当前的工作包。 |
save_query | 写入 | 将一组筛选条件保存为可供整个团队打开的 OpenProject 可复用视图。 |
通知(notifications)
| 工具 | 类型 | 功能说明 |
|---|---|---|
list_notifications | 读取 | 读取已认证用户的 OpenProject 收件箱。 |
mark_notifications | 写入 | 在一次批量请求中将指定通知标记为已读(或未读)。 |
mark_all_notifications_read | 写入 | 将符合筛选条件的所有通知标记为已读;默认标记整个收件箱。 |
时间跟踪(time_entries)
| 工具 | 类型 | 功能说明 |
|---|---|---|
list_time_entries | 读取 | 列出已记录的时间,在服务器端筛选,并可选择获取准确总计。 |
log_time | 写入 | 将时间记录到工作包或项目。 |
update_time_entry | 写入 | 更正现有时间记录。 |
delete_time_entry | 写入(破坏性操作) | 永久删除已记录的时间条目。 |
版本和冲刺(versions)
| 工具 | 类型 | 功能说明 |
|---|---|---|
list_versions | 读取 | 列出可分配工作包的版本(发布、里程碑、冲刺)。 |
list_sprints | 读取 | 列出可用于规划工作包的冲刺(Scrum 时间盒)。 |
get_sprint | 读取 | 完整读取一个冲刺:日期、工作区和生命周期状态。 |
create_version | 写入 | 在项目中创建版本(发布、里程碑或冲刺)。 |
update_version | 写入 | 更改版本的名称、日期、描述、状态或共享设置。 |
delete_version | 写入(破坏性操作) | 永久删除一个版本。 |
人员和成员资格(people)
| 工具 | 类型 | 功能说明 |
|---|---|---|
search_principals | 读取 | 查找用户、群组和占位用户,并获取其 ID。 |
get_user | 读取 | 读取一个用户的个人资料:姓名、登录名、电子邮件、管理员标记和状态。 |
list_memberships | 读取 | 列出谁可以访问哪些项目,以及拥有何种角色。 |
create_membership | 管理员写入 | 为主体授予项目中的一个或多个角色。 |
update_membership | 管理员写入 | 替换现有成员资格的角色。 |
delete_membership | 管理员写入(破坏性操作) | 撤销主体对项目的访问权限。 |
list_roles | 读取 | 列出此实例定义的角色及其 ID。 |
这三个成员资格写入工具要求设置 OPENPROJECT_MCP_ADMIN_TOOLS=1(并使用拥有 Manage members 权限的 OpenProject 账户)。
实例元数据和架构(metadata)
| 工具 | 类型 | 功能 |
|---|---|---|
get_instance_info | 读取 | 检查 OpenProject 连接,并报告此实例支持的功能。 |
get_project_metadata | 读取 | 列出此实例上实际有效的 ID 和名称(类型、状态、优先级等)。 |
get_work_package_schema | 读取 | 显示此项目中此类型的工作包接受哪些字段。 |
list_permissions | 读取 | 列出已认证用户获准执行的操作,可查看全局权限或某个项目的权限。 |
enable_tool_group | 读取 | 在当前会话中重新启用被 OPENPROJECT_MCP_PROFILE=core 隐藏的工具组;不会调用 OpenProject。 |
会议(meetings)
这 6 个定期会议工具也带有 meetings_recurring 标签,因此设置
OPENPROJECT_MCP_DISABLE=meetings_recurring 只会停用这些工具(它们需要 OpenProject 17.4+)。
| 工具 | 类型 | 功能 |
|---|---|---|
list_meetings | 读取 | 列出会议:即将召开的会议和已结束的会议。 |
get_meeting | 读取 | 完整读取一场会议:参与者、议程和已记录的结果。 |
create_meeting | 写入 | 在项目中安排会议,并可选择邀请参与者。 |
update_meeting | 写入 | 更改会议的标题、时间、地点或邀请名单,也可以更改会议的生命周期状态。 |
delete_meeting | 写入(破坏性) | 永久删除一场会议及其议程和已记录的结果。 |
add_meeting_agenda_item | 写入 | 向会议议程添加一个条目,也可选择将其关联到工作包。 |
update_meeting_agenda_item | 写入 | 编辑议程条目:修改标题、重写备注、调整时间、重新排序或更改关联项。 |
delete_meeting_agenda_item | 写入(破坏性) | 永久删除一个议程条目及其对应的任何已记录结果。 |
add_meeting_outcome | 写入 | 在某个议程条目下记录结果,例如决定、备注或后续工单。 |
update_meeting_outcome | 写入 | 更正已记录结果的类型、文本或关联的工作包。 |
delete_meeting_outcome | 写入(破坏性) | 从正在进行的会议纪要中永久删除一项已记录结果。 |
list_recurring_meetings | 读取 | 列出定期会议系列,即重复规则,而非单场会议。 |
get_recurring_meeting | 读取 | 完整读取一个定期会议系列:日程安排及其后续场次。 |
create_recurring_meeting | 写入 | 创建定期会议系列:包含日程安排和供后续场次复制的模板。 |
delete_recurring_meeting | 写入(破坏性) | 永久删除一个定期会议系列,包括模板、日程安排和所有场次。 |
init_recurring_meeting_occurrence | 写入 | 将系列中的一个场次实例化为真实会议,并从模板复制内容。 |
cancel_recurring_meeting_occurrence | 写入(破坏性) | 取消系列中的一个场次,跳过该时段而不更改日程安排。 |
Wiki(wiki)
| 工具 | 类型 | 功能 |
|---|---|---|
get_wiki_page | 读取 | 读取 Wiki 页面的标识信息和所属项目,不读取页面内容(API v3 不提供页面正文)。 |
文档(documents)
| 工具 | 类型 | 功能 |
|---|---|---|
list_documents | 读取 | 列出你在所有项目中可见的文档。 |
get_document | 读取 | 读取一份文档及其完整描述文本。 |
预算(budgets)
| 工具 | 类型 | 功能 |
|---|---|---|
list_budgets | 读取 | 列出项目预算及其 ID 和名称;这是 API v3 提供的全部信息。 |
新闻(news)
| 工具 | 类型 | 功能说明 |
|---|---|---|
list_news | 读取 | 列出项目新闻——团队在项目概览中发布的公告。 |
get_news | 读取 | 完整读取一条新闻,包括 Markdown 正文。 |
create_news | 写入 | 在项目中发布新闻公告。 |
update_news | 写入 | 更正或改写已发布的新闻。 |
delete_news | 写入(破坏性操作) | 永久删除一条新闻。 |
报告(reporting)
| 工具 | 类型 | 功能说明 |
|---|---|---|
get_project_report_data | 读取 | 汇总单个项目在指定日期范围内的状态报告:精确计数、可通过后续调用深入查看的抽样行,以及每个部分的状态。 |
提示词和资源
报告数据使用 closed_updated 表示在指定时间范围内更新的当前已关闭工作项。这取代了 v0.3.0 中原有的 closed 字段。它不能确定工作项何时完成;没有相应数据时,仍无法评估冲刺健康状况。
四个提示词模板会将实时 OpenProject 数据渲染为可直接使用的简报:
- weekly_report — 单个项目的每周状态报告:当前已关闭且已更新/进行中/计划中、工时和阻碍因素。
- daily_standup — 单个项目的今日站会内容:昨日进展、今日到期事项和受阻事项。
- triage_inbox — 按原因归类未读通知,并建议采取的行动。
- groom_backlog — 检查项目未完成的待办事项,找出未分配、长期未更新和未估算的工作。
三个资源模板通过稳定 URI 提供 OpenProject 对象:
openproject://work_package/{id}— 单个工作包的 JSON。openproject://project/{identifier}— 单个项目的 JSON(标识符别名或数字 ID)。openproject://attachment/{id}— 附件的字节数据及检测到的 MIME 类型,大小上限为OPENPROJECT_MCP_MAX_INLINE_MB。
支持的 OpenProject 版本
该服务面向 OpenProject 14 LTS 至 17.x。它不会假定 API 方言一致,而是在首次需要时延迟探测实例,并将结果缓存一小时。与版本有关的功能:
- 目标版本:所有受支持的实例都会在工作包详情中公开
target_versions。创建/更新操作接受版本 ID 列表([]表示清除);架构会在 17.8+ 上选择targetVersions,或使用单个旧版version。旧版version参数仍可作为单值别名;不要同时传入两者。读取时,如果分配了多个版本,该字段为 null。 - 内部(私有)评论需要 OpenProject >= 16。较旧的服务会静默忽略内部标记,因此在 16 以下,该服务会明确报错,而不是将你要求保密的评论公开发布。
- 表情回应(
toggle_comment_reaction)需要 OpenProject >= 16;该功能根据版本检测,并能容忍调用时返回 404。 - 项目收藏(
set_project_favorite)需要 OpenProject >= 17;同样能容忍相关情况。 - 时间条目筛选器:会探测工作包筛选器(使用
entityId,若不支持则回退到 15.x 之前的workPackage写法)。 - 权限上下文(
list_permissions):会探测上下文前缀(使用p{id},若不支持则回退到 17.2 引入的w{id}写法)。 - 会议时间筛选器:OpenProject 17.6 更改了线上的方言;
list_meetings会探测实例接受的写法并将其缓存。 - 故事点数需要启用 Backlogs 模块,且类型必须被 Backlogs 视为故事。17.x 在不满足条件时会拒绝
story_points;14.x 会接受写入但静默丢弃该值,因此结果会附带说明,指出该值未保存(批量预览会在写入前发出警告)。
依赖实例可选模块的功能(会议、新闻、文档、预算、维基、待办列表、GitHub/GitLab 集成、外部存储)在模块缺失时会如实降级:列表工具会返回空页面,并在页面内附上缺失模块的名称;详情工具会返回结构化错误,说明 404 可能表示的两种情况。
安全性
- API 密钥和 OAuth 令牌以
SecretStr保存,绝不会写入日志;每条日志记录中的Authorization和 Cookie 标头都会被隐藏。请求和响应正文仅在设置OPENPROJECT_MCP_LOG_BODIES=1时以 DEBUG 级别记录,供开发使用。 - 重定向离开 OpenProject 来源时,会移除
Authorization标头——附件下载会重定向到预签名的对象存储 URL,凭据不得传递到那里。 - 始终验证 TLS。支持通过
OPENPROJECT_MCP_CA_BUNDLE使用私有 CA;特意不提供禁用 TLS 验证的开关。 - 附件下载遵循 OpenProject 的病毒扫描器规则:绝不会获取已隔离的文件,并会产生结构化的
attachment_quarantined错误。下载大小受OPENPROJECT_MCP_MAX_DOWNLOAD_MB限制,文件以经过清理的文件名保存(目录分隔符和路径遍历序列会被处理),并报告文件字节的 SHA-256 值。 - 具有破坏性的工具需要
confirm=true,并带有注释,以便客户端事先征求用户确认。 - HTTP 传输在未配置
OPENPROJECT_MCP_AUTH_TOKENS时拒绝启动,并会在每个请求上验证Authorization: Bearer标头——缺失或无效的令牌会被拒绝并返回 401,且令牌比较采用恒定时间算法。服务器不会终止 TLS:请保留默认的127.0.0.1绑定;如果端口必须能够从其他位置访问,请在前面放置一个终止 TLS 的反向代理(参见传输)。所有 HTTP 客户端共用服务器的同一个 OpenProject 身份;请使用OPENPROJECT_MCP_UPLOAD_ROOT/OPENPROJECT_MCP_DOWNLOAD_ROOT限定文件工具的范围。 - 下载文件采用独占方式创建(即使并发下载同名文件,也绝不会覆盖现有文件);传输失败或取消时,只会删除本次创建的文件。
故障排除
| 症状 | 含义及处理方法 |
|---|---|
| 服务器退出并显示 "cannot start, configuration is incomplete" | 运行 openproject-mcp-server --check 并修复其列出的问题;变量说明请参见上文的配置部分。 |
| 401 authentication_failed | API 密钥错误、已撤销,或属于被封禁的账户。请在我的账户 → 访问令牌下生成新令牌。 |
| 403 permission_denied | 账户已通过身份验证,但缺少该项目的角色权限,或项目未启用相关模块。 |
| 列表为空,并提示缺少模块 | 该 OpenProject 模块(会议、新闻、文档……)未安装或未在项目中启用——空结果是准确的答复,并非错误。 |
| TLS 证书错误 | 你的实例使用私有 CA:请将 OPENPROJECT_MCP_CA_BUNDLE 指向其 PEM 文件包。没有禁用验证的选项。 |
--transport http 拒绝启动 | 设置 OPENPROJECT_MCP_AUTH_TOKENS(以逗号分隔的 Bearer 令牌),或仅在本地开发时设置 OPENPROJECT_MCP_INSECURE=1——参见传输。 |
| MCP HTTP 端点本身返回 401 | 请求缺少 Authorization: Bearer <token> 标头,或其值与任何已配置的 OPENPROJECT_MCP_AUTH_TOKENS 条目都不匹配。请检查客户端令牌是否有拼写错误;这与上文提到的上游 401 authentication_failed 不同,后者指的是 OpenProject API 密钥问题。 |
| 代理 | 底层 HTTP 客户端会遵循标准的 HTTPS_PROXY / ALL_PROXY / NO_PROXY 变量。 |
报告问题时,请提供你的 OpenProject 版本、openproject-mcp-server --version 的输出,以及 openproject-mcp-server --check 的输出。
开发
git clone https://github.com/kar-thik/openproject-mcp
cd openproject-mcp
uv sync --group dev
uv run pytest # entire suite runs offline (respx-mocked HTTP), no instance needed
uv run ruff check .
uv run ruff format --check .
uv run pyright # strict mode
默认测试套件保持离线。选择加入的兼容性检查会在兼容性工作流中,针对全新的官方 OpenProject 14.6、15.5、16.6 和 17.8 容器运行(包括 17.8 的单版本和多版本模式)。在本地运行其中一项检查(需运行 Docker):
uv run python scripts/live_smoke.py --image openproject/openproject:17.8.0
测试框架会创建一个私有项目、临时用户、自定义字段和版本;通过 MCP 进行测试,然后移除容器及其卷。不会使用现有实例和凭据。直接运行 pytest 时会跳过这些测试,除非提供 --live-openproject 和一个一次性测试夹具文件。
完整的技术规范见
SPEC.md。
发布流程见 CONTRIBUTING.md。
许可和商标
MIT — 详见 LICENSE。
这是一个社区项目,与 OpenProject GmbH 无关,也未获其认可或支持。“OpenProject”是 OpenProject GmbH 的商标,此处仅用于说明互操作性。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。