OpenProject CE MCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| OPENPROJECT_TIMEOUT | No | Request timeout in seconds | 12 |
| OPENPROJECT_BASE_URL | Yes | Base URL of your OpenProject instance, e.g. https://op.example.com | |
| OPENPROJECT_API_TOKEN | Yes | Personal API token | |
| OPENPROJECT_LOG_LEVEL | No | CRITICAL, ERROR, WARNING, or INFO | WARNING |
| OPENPROJECT_TEXT_LIMIT | No | Character cap for description previews in list results (max 50000) | 500 |
| OPENPROJECT_VERIFY_SSL | No | Verify TLS certificates | true |
| OPENPROJECT_MAX_RESULTS | No | Hard cap on total results returned by a tool | 100 |
| OPENPROJECT_MAX_PAGE_SIZE | No | Hard cap on results per request | 50 |
| OPENPROJECT_READ_PROJECTS | No | Readable projects; comma-separated identifiers, names, or glob patterns; * allows all visible projects; empty denies all project-scoped reads | |
| OPENPROJECT_WRITE_PROJECTS | No | Writable projects; same syntax; empty disables all project-scoped writes; always intersected with OPENPROJECT_READ_PROJECTS | |
| OPENPROJECT_ATTACHMENT_ROOT | No | Absolute directory local attachment uploads are confined to; empty disables uploads | |
| OPENPROJECT_DEFAULT_PAGE_SIZE | No | Default results per page | 10 |
| OPENPROJECT_ENABLE_ADMIN_READ | No | Instance-wide users, groups, principals and storage connections (admin) | false |
| OPENPROJECT_ENABLE_BOARD_READ | No | Boards | true |
| OPENPROJECT_ENABLE_ADMIN_WRITE | No | User, group and storage connection management (admin); explicit opt-in only | false |
| OPENPROJECT_ENABLE_BOARD_WRITE | No | Board create/update/delete. Has no effect without a non-empty OPENPROJECT_WRITE_PROJECTS. | true |
| OPENPROJECT_HIDE_CUSTOM_FIELDS | No | Custom field names or keys to omit; * wildcards supported | |
| OPENPROJECT_ENABLE_MEETING_READ | No | Meetings, agenda items, sections, outcomes, recurring meetings | true |
| OPENPROJECT_ENABLE_PROJECT_READ | No | Projects, documents, phases, project storages | true |
| OPENPROJECT_ENABLE_VERSION_READ | No | Versions | true |
| OPENPROJECT_ENABLE_EXTENDED_READ | No | Rarely used metadata tools (query schemas, render_text, help texts, working days) | false |
| OPENPROJECT_ENABLE_MEETING_WRITE | No | Meeting, agenda item, section, outcome and recurring meeting create/update/delete. Has no effect without a non-empty OPENPROJECT_WRITE_PROJECTS. | true |
| OPENPROJECT_ENABLE_PERSONAL_READ | No | Your own preferences and notifications | false |
| OPENPROJECT_ENABLE_PROJECT_WRITE | No | Project create/update/delete, news, documents, grids. Has no effect without a non-empty OPENPROJECT_WRITE_PROJECTS. | true |
| OPENPROJECT_ENABLE_VERSION_WRITE | No | Version create/update/delete. Has no effect without a non-empty OPENPROJECT_WRITE_PROJECTS. | true |
| OPENPROJECT_ENABLE_PERSONAL_WRITE | No | Update your own preferences, mark notifications read; requires OPENPROJECT_ENABLE_PERSONAL_READ | false |
| OPENPROJECT_ENABLE_MEMBERSHIP_READ | No | Memberships, roles, current user, actions, capabilities | true |
| OPENPROJECT_ENABLE_MEMBERSHIP_WRITE | No | Project membership create/update/delete. Has no effect without a non-empty OPENPROJECT_WRITE_PROJECTS. | true |
| OPENPROJECT_ENABLE_WORK_PACKAGE_READ | No | Work packages, search, relations, attachments, watchers, sprints | true |
| OPENPROJECT_ENABLE_USER_SCHEDULE_READ | No | Per-user non-working times and working hours (OpenProject 17.3+) | false |
| OPENPROJECT_ENABLE_WORK_PACKAGE_WRITE | No | Work package create/update/delete, comments, relations, attachments, time entries. Has no effect without a non-empty OPENPROJECT_WRITE_PROJECTS. | true |
| OPENPROJECT_ENABLE_USER_SCHEDULE_WRITE | No | Create/update/delete user non-working times and working hours; requires OPENPROJECT_ENABLE_USER_SCHEDULE_READ | false |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| list_projectsA | List visible projects with optional name or identifier search. Under a restrictive OPENPROJECT_READ_PROJECTS, total reflects only the allowed projects already scanned to fill this page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| get_projectA | Get a project by id, identifier or name, including its ancestor chain. description/status_explanation are returned in full by default (single projects
are not truncated). Pass |
| get_project_admin_contextC | Return project admin metadata such as lifecycle statuses, parent options, and writable fields. |
| get_project_configurationA | Return a project's configuration: get_instance_configuration's fields plus enabled_internal_comments. |
| list_sprintsA | List Backlogs sprints, optionally filtered by name search. Omit project to list every sprint visible to the current token across all projects; pass it to list only sprints for that project. Requires the OpenProject Backlogs module and OpenProject 17.3 or newer; unavailable instances return a clear not-found message. total is only the count of allowed sprints returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| get_sprintB | Get a Backlogs sprint by id. Requires OpenProject 17.3 or newer. |
| list_backlog_bucketsA | List Backlogs backlog buckets, optionally filtered by name search. Omit project to list every backlog bucket visible to the current token across all projects; pass it to list only backlog buckets for that project. Requires the OpenProject Backlogs module and OpenProject 17.6 or newer; unavailable instances return a clear not-found message. total is only the count of allowed backlog buckets returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| get_backlog_bucketB | Get a Backlogs backlog bucket by id. Requires OpenProject 17.6 or newer. |
| list_documentsA | List documents, optionally filtered to a single project or by title search. total is only the count of allowed documents returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. text_limit caps each document's description at that many characters (default: the server's configured OPENPROJECT_TEXT_LIMIT, NOT unlimited -- unlike get_document's single-item default). When text is cut, description_truncated is true and description_length reports the real length. |
| get_documentA | Get a single document by id. The description is returned in full by default (single documents are not
truncated). Pass |
| list_project_storagesA | List a project's links to configured external file storages, optionally filtered to one project. Read-only in OpenProject's API -- no create/update/delete endpoint exists for this resource; manage the underlying connection with the storages tools instead. |
| get_project_storageB | Get a single project's link to a configured external file storage by id. |
| list_newsA | List news entries, optionally filtered by project or title/summary search. total is only the count of allowed news entries returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. text_limit caps each entry's summary/description at that many characters (default: the server's configured OPENPROJECT_TEXT_LIMIT, NOT unlimited -- unlike get_news's single-item default). When text is cut, description_truncated is true and description_length reports the real length. |
| get_newsA | Get a single news entry by id. The description is returned in full by default (single news entries are
not truncated). Pass |
| get_wiki_pageA | Get a single wiki page's metadata (id, title, project) by id. OpenProject's REST API v3 does not expose a wiki page's body text at all -- GET /api/v3/wiki_pages/{id} returns only id/title/project, and there is no other route that returns the page content. This tool therefore cannot return wiki page text; use the OpenProject web UI to read a page's content. |
| get_postA | Get a single forum post by id. OpenProject's API exposes exactly one route for posts: GET /api/v3/posts/{id}. There is no collection/list endpoint for posts or forums at all in OpenProject's REST API -- a post's id must therefore come from elsewhere (e.g. a work package's activity/journal referencing a forum post, or a link copied from the OpenProject web UI). This MCP does not and cannot provide a list_posts or list_forums tool. |
| list_viewsA | List saved OpenProject views, optionally filtered by project, view subtype, or name search. total is only the count of allowed views returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| get_viewC | Get a single OpenProject view by id. |
| list_gridsA | List dashboard grids, optionally filtered by scope (page path). total is only the count of allowed grids returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| get_gridC | Get a single dashboard grid by id. |
| list_categoriesA | List work-package categories configured for a project. |
| get_categoryA | Get a single category by id. project is optional: when given, it's cross-checked against the category's real project and a mismatch raises a not-found error, rather than being the sole source of authorization. |
| list_project_phase_definitionsA | List available project lifecycle phase definitions exposed by OpenProject. |
| get_project_phase_definitionB | Get a single project lifecycle phase definition by id. |
| get_project_phaseC | Get a single project lifecycle phase by id. |
| get_my_project_accessB | Return the current user's membership and inferred access hints for a project. |
| get_project_work_package_contextB | Return project metadata and, optionally, the writable work-package schema for a given type. |
| get_instance_configurationA | Return instance-level OpenProject configuration and active feature flags. |
| get_job_statusB | Get the current status of a background job such as project copy. |
| list_work_packagesA | List work packages with structured filters and no free-text query requirement. project accepts a numeric ID, exact identifier/slug, or project name; the parameter is named project, not project_id. There is no generic filters=[...] parameter; each filter is its own named argument (version, status, assignee, the date filters, etc.), listed below. version_status filters by the status of a work package's assigned version: one of 'open', 'closed', or 'locked'. It requires OpenProject 16.4 or newer. A work package with several target versions matches version and version_status when any one of them matches. assignee filters by any user (username, id, or "me"). assignee_me takes precedence. status/priority filter by exact OpenProject status/priority name or numeric ID (case-insensitive), not meta-values like 'open'/'closed'; set open_only=true to restrict results to not-closed work packages instead. Date filters accept YYYY-MM-DD format:
overdue_only=true restricts results to work packages with due_date before today that are not closed (OpenProject's own overdue? predicate; there is no dedicated overdue API filter, this composes a relative date filter with the open-status meta-filter). due_within_days=N restricts to due_date in [today, today+N days]. Neither can be combined with each other or with due_on/due_between (all four constrain the same field). sort_by and group_by are checked against OpenProject's real sortable and groupable work-package columns (the parameters list them with the release each newer column needs); an unknown field raises a ValueError listing the valid set instead of only failing once OpenProject itself rejects the request. A column the instance's release lacks is rejected by OpenProject and the error names the release it needs. Dates, hours, subject, id and the other columns without a value per group sort fine but cannot be grouped by. select restricts each result row to the given fields (e.g. ["id", "subject", "status"]); an invalid name returns the allowed set. Common fields: id, display_id, subject, type, status, priority, assignee, project, version, parent_id, parent_display_id, start_date, due_date, estimated_time, spent_time, created_at, updated_at, author, category, description, schedule_manually, derived_start_date, derived_due_date, percentage_done, derived_percentage_done, readonly, has_project_attributes, ignore_non_working_days, custom_fields, custom_fields_truncated, custom_comments, custom_comments_truncated. custom_fields/custom_comments are selectable/hideable only as a whole field, not by individual custom-field key (per-key filtering is OPENPROJECT_HIDE_CUSTOM_FIELDS' concern, not select's). parent_display_id is only populated on OpenProject 17.5+ (semantic mode); it stays null on older/classic instances even when parent_id is set. total is the real matching count only when the query is provably restricted to OPENPROJECT_READ_PROJECTS server-side: scope is unrestricted, an explicit project was given, or (no project, restricted scope) a server-side filter for the resolved allowed project IDs was sent. Otherwise total falls back to this page's item count, and next_offset/truncated are based on whether this page came back full rather than the server's own total, so nothing here ever reveals how many matches exist in projects you can't see. Because of this, total can read 0 while next_offset is still non-null (a restrictive scope filtered out every match on this page, but the raw server page was full); that is not an inconsistency, keep paging via next_offset rather than stopping on a low/zero total. Page until next_offset is null either way. include_sums=true adds server-computed aggregates instead of requiring client-side pagination and summation: groups (one entry per group_by value, with count and a sums dict of OpenProject's fixed summable fields: estimated_time, story_points, percentage_done, remaining_time, overall_costs, labor_costs, material_costs, plus any custom fields, as raw server-formatted values, e.g. ISO 8601 durations and currency strings) and total_sums (the same shape, across all matches). groups is only populated when group_by is also set; total_sums is populated either way (a sum over the whole filtered result set even without grouping). Same scope-safety rule as total above: groups/total_sums come back null whenever the query cannot be proven restricted to OPENPROJECT_READ_PROJECTS server-side. A group named after a version, sprint or backlog bucket defined in a project that OPENPROJECT_READ_PROJECTS does not cover keeps its count and sums under the label [outside read scope]. Version rollup recipe: group_by="status", version="", include_sums=true returns per-status progress/time sums for one version's work packages, replacing manual pagination + client-side summation. custom_fields is a dict keyed by the RAW OpenProject key (e.g. "customField12") -- never a friendly name -- with values normalized by shape: plain scalars pass through; link-typed values (list/user/version format) become title-only strings (or a list of titles for a multi-value field), matching every other link field in this response; multi- paragraph "text"-format values are capped like description (this call's effective text_limit); a scalar string/link/date-format value is independently capped at ~255 characters. custom_fields_truncated is true when the dict was capped at 50 entries and/or any individual entry's value was itself capped. custom_comments (keyed the same way, holding a field's freeform comment text) and custom_comments_truncated follow the identical shape and caps, independently -- in practice custom_comments is always empty/null for work packages on OpenProject's stock CE behavior: only Projects opt into per-custom-field comments, work packages do not, so this field is present for forward compatibility only. Combined worst case is roughly 250 KB for custom_fields per work package, always finite regardless of how many custom fields exist or how large their values are. get_work_packages (batch) and list_my_open_work_packages return the same custom_fields/custom_comments shape and caps, since they reuse this same normalization. OPENPROJECT_HIDE_CUSTOM_FIELDS hides individual custom_fields entries by matching ONLY the raw key/wildcard (e.g. "customField12", "customField*") -- unlike the write path, which also accepts the custom field's friendly name, a read-side hide pattern written as a friendly name has no effect. custom_field_filters filters results by custom field value(s) -- a dict keyed by "cf_" or "customField" (both forms accepted transparently and always normalized to "cf_" on the wire; "cf_" is CustomField#column_name, the actual OpenProject filter key, distinct from "customField" which is the JSON/PATCH key used by custom_fields above -- do not confuse the two). Each entry's value is {"operator": "", "values": [...]}, e.g. {"cf_12": {"operator": "=", "values": ["42"]}}. Learn a field's cf_ id from any prior get_work_package call's custom_fields dict keys (strip the "customField" prefix). Only raw cf_/customField keys are accepted -- friendly-name resolution is not supported (a list/search call has no single project+type context to resolve a name against safely; a friendly name is only meaningful for the write path's per-call project+type schema probe). At most 20 custom-field filters per call, at most 100 values per filter, each value at most 1000 characters. Legal operators depend on the field's format on this instance -- see docs/filters.md's "Custom-Field Filters" section for the full format-to-operator matrix, verified against OpenProject CE source. This tool validates the key shape and the operator symbol locally (a recognized custom-field operator, not necessarily legal for this specific field's format) and rejects hidden fields (OPENPROJECT_HIDE_CUSTOM_FIELDS) before any network call; an operator/value that is syntactically valid but illegal for the field's actual format is rejected by OpenProject itself with a clear error (surfaced as a ValueError here, not a raw HTTP passthrough) rather than validated client-side against a live schema -- this keeps list/search calls at their existing single-request cost (no per-call schema probe). user/version-format custom-field filters additionally require project to be set (OpenProject only considers project-scoped custom fields of these two formats filterable at all; this is not checked locally -- a global, no-project user/version CF filter fails server-side with an unhelpful "filter not available" error, see docs/filters.md's "Global (no-project) filtering constraint" section). |
| search_work_packagesA | Search work packages by free text, optionally scoped to a project. search matches only the work package subject and numeric ID (OpenProject's native subject_or_id full-text filter); it does NOT match version, category, description, or other linked-resource fields. To filter by version, use list_work_packages(version=..., project=...) instead. In parallel with that text/id search, a search shaped like a work package reference (a numeric id or a display id like "PROJ-42", but not a date such as 2026-10-15) is also resolved directly the same way get_work_package does; other text is never looked up as an id. When that resolves to a work package that also satisfies every other filter given here (project/status/assignee/dates/ custom fields/etc.), it's returned separately as exact_match; never folded into results, and never counted toward total/count/pagination, since a single extra item can't be paginated consistently. Absent (not present in the response at all) when nothing resolves, when the resolved item fails a filter, or when it's already present in results via the text match. select applies to exact_match the same way it applies to each results row. Without project, the search runs globally across every project readable under OPENPROJECT_READ_PROJECTS, not just one project; pass project explicitly to scope results to it. Set status to restrict results to an exact OpenProject status name or numeric ID, not a meta-value like 'open'/'closed'. Set open_only=true to return only open (not-closed) work packages. Set assignee_me=true to return only work packages assigned to the current user. assignee filters by any user (username, id, or "me"). assignee_me takes precedence. priority filters by priority name or numeric ID (case-insensitive). Date filters, overdue_only/due_within_days, select, pagination (offset/limit/total), include_sums, and each result's custom_fields/custom_comments (raw-key custom-field values/comments, capped and hide-matched exactly as documented) all work exactly as documented on list_work_packages; see that tool's docstring for the full field lists and semantics. sort_by and group_by take the same fields and are described by their own parameters. One difference: total is the real matching count only when scope is unrestricted or an explicit project was given (list_work_packages's server-side allowed-project filter for the no-project+restricted-scope case does not apply here); otherwise total/groups/total_sums fall back to this page's data, same safety guarantee either way. custom_field_filters filters by custom field value(s); see list_work_packages's docstring for the full parameter documentation (identical shape and semantics on both tools). |
| get_work_packageA | Get a work package by id, including its full description. The description is returned in full by default (single work packages are not
truncated). Pass select restricts the response to the given fields (e.g. ["id", "subject", "status"]); an invalid name returns the allowed set. |
| get_work_packagesA | Get several work packages by id in one batch call. Fetches work packages in parallel and returns per-item results. Failed fetches are reported individually without stopping the batch. Maximum 100 IDs per batch. ids: internal ids (e.g., 952) or display_ids (e.g., "PROJ-51"), not UI display numbers. Duplicate IDs are automatically deduplicated. select restricts each result's work_package to the given fields (e.g. ["id", "subject", "status"]); an invalid name returns the allowed set. The id/success/error fields on each result are always included regardless of select, so you can still tell which items succeeded; listing success or error in select is accepted and changes nothing, while id doubles as a selectable work_package field. For batches with many full-detail items, set text_limit and/or select proactively; an unbounded batch of large work packages can exceed the tool-result size limit and get redirected to a file. Each item's work_package carries the same custom_fields/custom_comments shape and caps as get_work_package; see list_work_packages's docstring for the full details (raw-key values, per-field caps, and the OPENPROJECT_HIDE_CUSTOM_FIELDS key-only hide-matching asymmetry). With many items, an unbounded custom_fields/custom_comments per item adds to the same size-limit risk text_limit/select address above. |
| list_my_open_work_packagesA | List the current user's open assigned work packages. This query has no project scope of its own, so total is the real matching count only when OPENPROJECT_READ_PROJECTS is unrestricted ("*"); under a restricted scope, total always falls back to this page's item count, and next_offset/truncated are based on whether this page came back full rather than the server's own total, so nothing here ever reveals how many matches exist in projects you can't see. Page until next_offset is null either way. Each result row also carries custom_fields/custom_comments, selectable or hideable only as a whole field like every other field, with the same shape, caps, and OPENPROJECT_HIDE_CUSTOM_FIELDS key-only hide-matching as list_work_packages -- see that tool's docstring for the full details. |
| get_work_package_activitiesA | Get the activity log for a work package, most recent first. Comments are returned in full by default (this is one work package's own
history, not an open-ended multi-row list; same rationale as
get_work_package). Pass When OPENPROJECT_READ_PROJECTS is not |
| list_work_package_reactionsA | List emoji reactions across a work package's comment activities. One row per comment and reaction, without the activity id, so a reaction can repeat. |
| list_remindersA | List the current user's active reminders across all work packages. Requires OpenProject 16.1+. |
| get_work_package_relationsA | Get the relations of one work package (blocks, relates to, duplicates, etc.). type/from_id/to_id reflect how OpenProject actually stored the relation, which does not depend on which work package's relations you query, but can differ from how it was originally requested, since OpenProject canonicalizes some relation types at creation time (e.g. a relation requested as 'precedes' is stored as 'follows' with from_id/to_id swapped; see create_work_package_relation). Use from_id/to_id together with type, not the request you expect to have made, to determine the actual direction. Each result additionally carries queried_perspective, a caller-relative reading of the same relation from work_package_id's own side; never a replacement for type/from_id/to_id, which stay unchanged. queried_perspective.direction is "from" or "to" (which raw id equals work_package_id); queried_perspective.effective_type is the type as read FROM work_package_id's side (e.g. a stored "blocks" relation reads as effective_type="blocked" when work_package_id is the to_id side, "blocks" when it's the from_id side). queried_perspective.predecessor_id/successor_id are populated only for the precedes/follows type pair (OpenProject's own scheduling-relevant relation types); both stay null for every other type, since no other type has an equivalent first/second concept. total is only the count of allowed relations returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| list_work_package_attachmentsA | List attachments on a work package. include_total_size=true sums file_size_bytes across every attachment (independent of limit/offset); OpenProject's attachments endpoint always returns the full list in one response, so this costs no extra request in the common case. Null if file_size_bytes is hidden by server configuration, rather than leaking it indirectly through a sum. include_images=true also reads the listed PNG/JPEG/GIF/WebP attachments
and returns them as images the model can see, appended after the list.
One shared byte budget covers the whole call
(OPENPROJECT_ATTACHMENT_CONTENT_MAX_BYTES, 5 MB by default), taken in
listing order; every attachment that was not inlined is reported in
|
| get_attachmentC | Get a single attachment by id. |
| get_attachment_contentA | Read an attachment's actual content, not just its metadata. Returns a JSON block describing the outcome, followed by the content itself as a native block when it can be inlined:
max_bytes may only LOWER the server's configured limit (OPENPROJECT_ATTACHMENT_CONTENT_MAX_BYTES, 5 MB by default), never raise it. size_bytes is the size of the returned content block, and is null if file_size_bytes is hidden by server configuration, rather than leaking it indirectly under another name. Nothing is written to disk. Use get_attachment for metadata alone. |
| list_work_package_file_linksA | List Nextcloud file links attached to a work package (Community Edition). For files uploaded to OpenProject itself, use list_work_package_attachments. |
| list_work_package_watchersC | List watchers of a work package. |
| list_statusesA | List all available work package statuses. Read-only: statuses cannot be created or modified via the OpenProject API (Community Edition); configure them in the web admin UI. |
| get_statusC | Get a single work package status by id. |
| list_prioritiesB | List all available work package priorities. |
| get_priorityB | Get a single work package priority by id. |
| list_typesA | List all available work package types, optionally filtered by project. Read-only: types cannot be created or modified via the OpenProject API (Community Edition); configure them in the web admin UI. |
| get_typeA | Get a single work package type by id. |
| list_time_entry_activitiesB | List available time entry activities. |
| list_time_entriesA | List time entries with optional project, work package, user, and date filters. total is only the count of allowed time entries returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. include_total_hours=true sums |
| get_time_entryA | Get a single time entry by id, including its full comment. The comment is returned in full by default (single time entries are not
truncated). Pass |
| get_cost_entryB | Get a single cost entry by id. Cost entries are entirely read-only in OpenProject's API (Community Edition) -- there is no create/update/delete endpoint for this resource. |
| list_work_package_cost_entriesA | List all cost entries recorded against a work package. Returns every cost entry for the work package in one call -- this endpoint is unpaginated on OpenProject's side (no offset/limit parameters exist). |
| get_work_package_costs_by_typeA | Get a work package's costs aggregated by cost type. count is the number of distinct cost types with recorded spend on this work package, not a monetary total. Each result's spent_units is a quantity in that cost type's own unit (see get_cost_type for the unit name) -- there is no currency conversion or grand total computed here or by OpenProject's own API. |
| get_cost_typeA | Get a cost type by id. Cost types are entirely read-only in OpenProject's API (Community Edition) -- there is no create/update/delete endpoint, and no collection GET either (no list_cost_types tool exists because the endpoint does not exist upstream). |
| get_github_pull_requestA | Get a single GitHub pull request by its own id. GitHub pull requests are read-only mirror rows synced by OpenProject's own GitHub App integration -- never creatable via this API. An empty or 404 result can mean either the pull request doesn't exist, or the GitHub App integration isn't configured on this instance; OpenProject's API does not distinguish these cases. Unlike work-package-scoped lookups in this domain, this global lookup relies on OpenProject's own visibility check (whether the linked work package is visible to the API token), not on this MCP's OPENPROJECT_READ_PROJECTS allowlist -- the pull request payload carries no project link for this MCP to check against. |
| list_work_package_github_pull_requestsA | List all GitHub pull requests linked to a work package. Returns every linked pull request in one call -- this endpoint is unpaginated on OpenProject's side (no offset/limit parameters exist). An empty result can mean either no pull requests are linked, or the GitHub App integration isn't configured on this instance; OpenProject's API does not distinguish these cases. |
| list_work_package_gitlab_issuesA | List all GitLab issues linked to a work package. Returns every linked issue in one call -- this endpoint is unpaginated on OpenProject's side (no offset/limit parameters exist). An empty result can mean either no issues are linked, or the GitLab integration isn't configured on this instance; OpenProject's API does not distinguish these cases. No single-item get_gitlab_issue tool exists because no such endpoint exists upstream -- only this work-package-scoped list. |
| list_work_package_gitlab_merge_requestsA | List all GitLab merge requests linked to a work package. Returns every linked merge request in one call -- this endpoint is unpaginated on OpenProject's side (no offset/limit parameters exist). An empty result can mean either no merge requests are linked, or the GitLab integration isn't configured on this instance; OpenProject's API does not distinguish these cases. No single-item get_gitlab_merge_request tool exists because no such endpoint exists upstream -- only this work-package-scoped list. |
| list_relationsA | List all relations across the instance, optionally filtered by type (e.g. 'blocks', 'follows'). type/from_id/to_id reflect how OpenProject actually stored the relation (it does not change depending on which work package's relations you're viewing), which can differ from how it was originally requested; OpenProject canonicalizes some relation types at creation time (e.g. a relation requested as 'precedes' is stored as 'follows' with from_id/to_id swapped; see create_work_package_relation). Filtering by relation_type matches the stored (canonical) type, not necessarily the type a caller originally requested when creating it. Each result's queried_perspective field is always null here; a caller-relative reading needs one anchor work package to read the relation FROM, and this instance-wide listing has none. Use get_work_package_relations instead when you need queried_perspective populated. total is only the count of allowed relations returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| list_work_package_wiki_linksA | List wiki pages linked to a work package. Requires OpenProject 17.5+; on an older server this returns a [not_found] naming the required version. Known OpenProject server bug (17.5 to at least 17.9.1): this call returns a [server_error] when none of the work package's links resolves to a wiki page the user can see, and on 17.5/17.6 also when the work package has no links. A link to the internal wiki resolves when its identifier is the page's numeric id. Only the work package is checked against OPENPROJECT_READ_PROJECTS: a link carries no project, so a link to a page in another project is listed. It shows the identifier, provider and author, never the page's title or text. |
| execute_queryA | Execute a saved OpenProject query by id and return its resolved work packages. query_id: the query's own numeric id; obtain it from get_view/list_views's query_id field, or from list_boards/get_board (a board's id IS its underlying query id, since OpenProject Boards are Query resources). Runs the query server-side (OpenProject resolves its stored filters/sort/ group_by and returns real work packages, not just the query's definition); no client-side filter translation happens here. Results are still filtered against this MCP's own OPENPROJECT_READ_PROJECTS allowlist before being returned, since the query itself executes with the API token's full server-side permissions. |
| list_project_membershipsB | List memberships for a project, including principal and role names. |
| get_membershipA | Get one project membership by id: the user or group, the project and the role names. To list a project's members use list_project_memberships. |
| list_rolesB | List OpenProject roles visible to the current user. |
| get_current_userA | Return the currently authenticated user's profile. |
| list_actionsA | List the action ids OpenProject's API defines, e.g. "work_packages/create". This is the vocabulary only; which user or group may perform an action in which project comes from list_capabilities. |
| list_capabilitiesA | List API capabilities exposed by OpenProject. At least one of project or capability_id is required; there is no unfiltered global listing, since one would bypass the project read allowlist. |
| list_versionsA | List versions globally or for a specific project, optionally filtered by a case-insensitive name substring. Without project, total is only the count of allowed versions returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| get_versionA | Get a version by id, including its full description. The description is returned in full by default (single versions are not
truncated). Pass |
| list_boardsA | List saved OpenProject boards/queries, optionally scoped to a project. With project, search, or a restrictive OPENPROJECT_READ_PROJECTS, total is only the count of allowed boards returned on THIS page, not a full count of all matches; the search stops as soon as it has enough, so an exact total would need an extra full walk. Page until next_offset is null. |
| get_boardC | Get a saved OpenProject board/query by id. |
| list_meetingsA | List OpenProject meetings, optionally scoped to a project. Requires OpenProject 17.4+; the meetings module's agenda/section/ participant shape used here does not exist on 16.6, which only exposes an incompatible legacy "meeting contents" representation. Omit project to list across all readable projects. |
| get_meetingA | Get a single OpenProject meeting by id: schedule, state, participants and its lock_version. Requires OpenProject 17.4+. Its agenda comes from list_meeting_sections and list_meeting_agenda_items. |
| list_meeting_agenda_itemsA | List the agenda items of one meeting. Requires OpenProject 17.4+. This list is unpaginated server-side (OpenProject returns every agenda item of the meeting in one response); offset/limit are applied client-side by this MCP. text_limit caps each item's notes at that many characters (default: the server's configured OPENPROJECT_TEXT_LIMIT, NOT unlimited). When text is cut, notes_truncated is true and notes_length reports the real length. |
| list_work_package_meeting_agenda_itemsA | List the agenda items, across all meetings, that link a work package. Requires OpenProject 17.7+. Items of meetings in projects outside OPENPROJECT_READ_PROJECTS are left out. This list is unpaginated server-side; offset/limit are applied client-side by this MCP. text_limit caps each item's notes at that many characters (default: the server's configured OPENPROJECT_TEXT_LIMIT, NOT unlimited). When text is cut, notes_truncated is true and notes_length reports the real length. |
| get_meeting_agenda_itemA | Get a single meeting agenda item by id. Requires OpenProject 17.6+. |
| list_meeting_outcomesA | List outcomes of a meeting agenda item. Requires OpenProject 17.6+; the meeting_outcomes endpoint does not exist on 17.4/17.5. This list is unpaginated server-side; offset/limit are applied client-side by this MCP. text_limit caps each outcome's notes at that many characters (default: the server's configured OPENPROJECT_TEXT_LIMIT, NOT unlimited). When text is cut, notes_truncated is true and notes_length reports the real length. |
| get_meeting_outcomeB | Get a single meeting outcome by id. Requires OpenProject 17.6+. |
| list_meeting_sectionsA | List sections of an OpenProject meeting. Requires OpenProject 17.4+. This list is unpaginated server-side; offset/limit are applied client-side by this MCP. |
| get_meeting_sectionA | Get a single meeting section by id: title, position and whether it is the backlog. Requires OpenProject 17.6+. Its agenda items come from list_meeting_agenda_items. |
| list_recurring_meetingsA | List OpenProject recurring meeting series, optionally scoped to a project. Requires OpenProject 17.4+. Omit project to list across all readable projects. |
| get_recurring_meetingA | Get a single OpenProject recurring meeting series by id. Requires OpenProject 17.4+. |
| list_recurring_meeting_occurrencesA | List virtual occurrences of a recurring meeting. Requires OpenProject 17.4+. filter: one of "upcoming", "past", "cancelled", "open". Occurrences are virtual (synthesized from the recurrence rule) except where a real Meeting has already been materialized via init_recurring_meeting_occurrence; this list has no offset/pagination, unlike list_meetings/list_recurring_meetings. |
| create_projectA | Create a project. Omitted optional fields are not sent, so OpenProject's defaults apply.
A rejected validation preview is not a tool error; inspect |
| update_projectA | Update a project. Omitted fields stay unchanged.
A rejected validation preview is not a tool error; inspect |
| delete_projectA | Delete a project and its subprojects (admin operation). OpenProject archives them at once and deletes them in a background job, with their work packages, memberships, versions, time entries, news, wiki, forums, meetings, documents and storage links; this cannot be undone. OpenProject also tries to delete storage project folders managed automatically, with their files. Unless the project is already archived, rejected while work packages of other projects use one of their versions. |
| copy_projectA | Copy an existing project into a new project. name, identifier and the optional fields describe the new project. A confirmed
copy starts a background job; poll get_job_status with the returned job_status_id.
A rejected validation preview is not a tool error; inspect |
| set_project_favoriteA | Mark or unmark a project as a favorite. Requires OpenProject 17.0 or later. |
| create_newsC | Create a news entry inside a project. |
| update_newsA | Update a news entry. Omitted fields stay unchanged. |
| delete_newsA | Delete a news entry with its comments and attachments; this cannot be undone. |
| update_documentB | Update a document. Omitted fields stay unchanged. |
| create_gridA | Create a dashboard grid on a page. A grid is the widget layout of My Page, a project overview or a board. The grid starts with OpenProject's default widgets for that page; other widgets are added in OpenProject. A board's saved work package queries are created with create_board. |
| update_gridA | Rename or resize a dashboard grid; omitted fields stay unchanged. The widgets stay as they are; a size that would leave a widget outside the grid is rejected. |
| delete_gridA | Delete a board grid; My Page and project overview grids cannot be deleted. 17.0+: its column queries are deleted too, as far as you may delete them. This cannot be undone. |
| create_work_packageA | Create a work package. The tool validates the payload first.
assignee: 'me' or numeric user id (e.g., 42). Call list_users to find ids. parent: internal id (e.g., 952) or display_id (e.g., "PROJ-51"), not UI display number to nest the new work package under a parent.
estimated_time, remaining_time, duration accept ISO8601 duration strings (e.g., 'PT8H' for 8 hours, 'PT1H30M' for 1.5 hours, 'P1D' for 1 day, 'P2W' for 2 weeks).
target_versions accepts a list of version names/ids to assign multiple target versions at once
(OpenProject's multi-version feature); omit it, or pass [], to create with no target version
assigned. target_versions and version write the same underlying data and cannot be used together
in one call.
due_date falling on a non-working day (e.g. a weekend) can be silently moved forward to the
next working day by OpenProject; compare the request and the returned |
| create_subtaskA | Create a subtask under an existing work package. The tool validates the payload first. Concurrent calls to this tool (or create_work_package) do not preserve call order in the resulting IDs; use bulk_create_work_packages when order across several new items matters. target_versions accepts a list of version names/ids to assign multiple target versions at once (OpenProject's multi-version feature). target_versions and version write the same underlying data and cannot be used together in one call. |
| update_work_packageA | Update a work package. The tool validates the patch first. assignee: 'me' or numeric user id (e.g., 42). Call list_users to find ids. parent re-parents the work package (numeric id or a PROJ-123 reference); pass 'none' to remove the parent and make it top-level. version accepts a version name/id, or 'none' to unassign the version. sprint accepts a Backlogs sprint name/id (requires the Backlogs module and OpenProject 17.3+), or 'none' to unassign it. Pass 'none' to assignee, responsible, category or project_phase to unassign that field. Omitted fields stay unchanged. target_versions accepts a list of version names/ids to assign multiple target versions at once (OpenProject's multi-version feature); pass [] to clear all. target_versions and version write the same underlying data and cannot be used together in one call. If this work package already has more than one target version, version alone is rejected; use target_versions instead. A change of version, target_versions, sprint or a version custom field is refused while the work package holds such an assignment in a project OPENPROJECT_READ_PROJECTS does not cover, because the change would remove it. estimated_time, remaining_time, duration accept ISO8601 duration strings (e.g., 'PT8H' for 8 hours, 'PT1H30M' for 1.5 hours, 'P1D' for 1 day); omit to leave unchanged, or pass 'none' to clear the field. percentage_done is an integer 0-100. Setting status to a closed status auto-fills percentage_done=100 and remaining_time=PT0H when you don't supply them explicitly and OpenProject's schema reports those fields as writable (on instances using status-based progress calculation, OpenProject already derives them itself and this is skipped). On such an instance, explicitly passing percentage_done together with a closing status is rejected with a hard validation error (percentageDone is not writable there) rather than silently ignored; omit percentage_done and let OpenProject derive it instead. due_date's non-working-day shift and the confirm/preview contract work exactly as documented on create_work_package. |
| bulk_create_work_packagesA | Create multiple work packages in one call. New items have no identifier field to set (unlike Each item in A rejected item's validation is not a tool error; inspect each item's select restricts each item's nested result to the given fields (e.g.
["ready", "work_package_id"]); an invalid name returns the allowed set.
These are write-result fields (work_package_id, ready, state, ...), not work
package fields: A per-item timeout is reported as that item's failure and does not stop the loop. If this call is cancelled outright (e.g. the host cancels the request), items already created beforehand remain on the server; items not yet attempted are not created. No result summary is returned in that case (the call ends via cancellation, not a normal return); use list_work_packages/get_work_package afterward to determine what was actually written. This operation is not atomic; OpenProject CE has no batch/transaction endpoint. Items are processed strictly sequentially in list order, and each result's index reflects that order; use this tool instead of parallel create_work_package/create_subtask calls whenever the relative order of a batch matters. |
| bulk_update_work_packagesA | Update multiple work packages in one call. Each item's identifier field is Each item in due_date's non-working-day shift, the confirm/preview contract, select's item-trimming
behavior, and cancellation/atomicity semantics all work exactly as documented on
bulk_create_work_packages; only the affected result field differs
( |
| delete_work_packageA | Delete a work package with its time and cost entries, relations, attachments and history. This cannot be undone. Up to 17.6 all its descendants are deleted too; 17.7+ only those you may delete, the others lose their parent. |
| add_work_package_commentB | Add a comment to a work package. notify=false avoids change emails by default.
The result never includes |
| toggle_activity_emoji_reactionA | Toggle an emoji reaction on a work package comment activity. Adds the reaction if absent, removes it if already present. |
| create_work_package_reminderA | Create a reminder on a work package.
|
| update_reminderA | Update a reminder's time or note; at least one is required, an omitted one stays unchanged. Requires OpenProject 16.1+. |
| delete_reminderA | Delete a pending reminder so it never fires; this cannot be undone. Its unread notifications are marked read. Only its creator can; requires OpenProject 16.1+. |
| create_work_package_relationA | Create a relation between work packages. relation_type: relates, duplicates, duplicated, blocks, blocked, precedes, follows, includes, partof, requires, required. work_package_id becomes from_id and related_to_work_package_id becomes to_id, but OpenProject stores only one canonical type per pair and silently rewrites the other: creating with relation_type='precedes' (or 'blocked', 'duplicated', 'partof', 'required') is stored as the paired canonical type ('follows', 'blocks', 'duplicates', 'includes', 'requires' respectively) with from_id/to_id SWAPPED relative to work_package_id/related_to_work_package_id. The canonical types themselves ('follows', 'blocks', 'duplicates', 'includes', 'requires', and non-directional 'relates') are stored exactly as given, with from_id/to_id unswapped. This happens once at creation and does not depend on which work package's relations you later query; always read the actual type/from_id/to_id from the response rather than assuming they match what you requested. |
| delete_relationA | Delete a relation between work packages; this cannot be undone. Removing a follows/precedes relation reschedules the former successor. |
| delete_attachmentB | Delete an attachment; this cannot be undone. |
| set_work_package_watcherA | Add/remove a watcher on a work package. watching=true adds the watcher; watching=false removes it. The two previews are NOT symmetric: watching=true's preview looks up and returns the user's summary (result is populated; whether the user already watches is not checked); watching=false's preview makes no extra lookup and always returns result=null. |
| create_time_entryA | Create a time entry. hours accepts an ISO8601 duration string (e.g., 'PT8H' for 8 hours, 'P1D' for 1 day). start_time is an ISO 8601 date-time and requires the instance setting "allow tracking of start and end times"; ignored otherwise. No end_time parameter -- OpenProject derives it read-only from start_time + hours. Use create_time_entry_until to specify an end time instead of hours directly. |
| update_time_entryA | Update a time entry. hours accepts an ISO8601 duration string (e.g., 'PT8H' for 8 hours, 'P1D' for 1 day). start_time is an ISO 8601 date-time. No end_time parameter -- OpenProject derives it read-only from start_time + hours. Use update_time_entry_until to specify an end time instead of hours directly. |
| create_time_entry_untilA | Create a time entry by start/end time instead of a duration. Computes hours = end_time - start_time locally; only hours and start_time are sent to OpenProject (end_time itself is never accepted by the server, see create_time_entry's docstring). end_time must be strictly after start_time. There is no ongoing parameter here -- a time entry with a known end time is complete, not still running; use create_time_entry for an ongoing entry. |
| update_time_entry_untilA | Update a time entry by start/end time instead of a duration. Computes hours = end_time - start_time locally; only hours and start_time are sent to OpenProject (end_time itself is never accepted by the server, see update_time_entry's docstring). end_time must be strictly after start_time. Always sets ongoing=False, since a completed time span with a known end time cannot still be running. |
| delete_time_entryB | Delete a time entry; this cannot be undone. |
| update_relationA | Update the type or description of a relation. relation_type is subject to the same write-time canonicalization as create_work_package_relation: setting it to a "reverse" pair member (precedes, blocked, duplicated, partof, required) rewrites the stored relation to the paired canonical type (follows, blocks, duplicates, includes, requires) with from_id/to_id swapped relative to the relation's existing from/to. Read the actual type/from_id/to_id back afterward rather than assuming they match what was requested. |
| delete_file_linkA | Delete a file link; this cannot be undone, but the file itself stays in the external storage. |
| create_work_package_wiki_linkA | Create a link from a work package to a wiki page. Requires OpenProject 17.7+; on an older server this returns a [not_found] naming the required version. identifier: the target wiki page's identifier at its provider; for the internal wiki, the page's numeric id (the wiki_page_id of get_wiki_page). OpenProject accepts any string, but list_work_package_wiki_links fails while none of a work package's links resolves to a page. provider: the wiki provider's universal identifier (e.g. "internal" for OpenProject's built-in wiki). |
| delete_work_package_wiki_linkA | Delete a work package's wiki page link; this cannot be undone. Requires OpenProject 17.6+. On 17.4 or older this returns a [not_found] naming 17.6; on 17.5 the link check below usually fails first with a [server_error]. This tool lists the work package's links first to verify that link_id belongs to work_package_id (an authorization check), so it fails with a [server_error] whenever list_work_package_wiki_links does (see there). Only relation links (link_type "relation") can be deleted. An inline link comes from a wiki link in the work package's description or from a wiki page that mentions the work package; this tool rejects it with a [validation_error], and the link goes away only when that text changes. Deleting needs the "Manage wiki page links" permission in the work package's project; without it OpenProject answers 404, which the tool reports as a [not_found] naming 17.6, not as [permission_denied]. work_package_id must be the work package the link belongs to; OpenProject has no single GET for a link, so the delete is authorized against that work package's project. link_id: the wiki page link's own id, from list_work_package_wiki_links. |
| create_membershipA | Create a project membership. The preview is validated by OpenProject; problems come back in validation_errors. |
| update_membershipA | Update a project membership's roles. The preview is validated by OpenProject; problems come back in validation_errors. |
| delete_membershipA | Delete a project membership; this cannot be undone. Roles inherited from a group stay: if some roles come from a group, only the direct ones are removed; if all do, the call is rejected. |
| create_versionB | Create a version for a project. A rejected validation preview is not a tool error; inspect |
| update_versionA | Update a version. Omitted fields stay unchanged.
A rejected validation preview is not a tool error; inspect |
| delete_versionA | Delete a version; this cannot be undone. Rejected while any work package, in any project, uses it (17.8+: also as its "found in" version). |
| create_boardA | Create a saved OpenProject board/query. This saves a work package query (filters, columns, sorting, grouping); a board grid that shows queries as columns is created with create_grid. |
| update_boardB | Update a saved OpenProject board/query. Omitted fields stay unchanged; a given list replaces the stored one. |
| delete_boardA | Delete one saved work package query; this cannot be undone. A board grid that shows it as a column keeps a column pointing to the deleted query; board grids themselves are deleted with delete_grid. |
| create_meetingA | Create an OpenProject meeting. Requires OpenProject 17.4+. duration: an ISO 8601 duration like "PT1H30M" (hours/minutes only). state and notify cannot be set on create: OpenProject starts a new meeting as a draft with notifications off, so passing either is rejected; set them afterwards with update_meeting. |
| update_meetingA | Update one meeting's details; omitted fields stay unchanged. Requires OpenProject 17.4+. The meeting's agenda is changed with the agenda item and section tools, and a recurring series' schedule with update_recurring_meeting; for an occurrence of a series this changes only that occurrence. With notifications on, a change of title, time, duration or location emails the invited participants (not for a closed or cancelled meeting). From 17.8, an update that takes a one-time meeting out of draft or turns notifications on also sends the invitations; 17.4 to 17.7 send no invitations on update. Changing participants is not supported: participant_user_refs is rejected. |
| delete_meetingA | Delete a meeting with its agenda, outcomes, attachments and the time entries logged on it. Requires OpenProject 17.4+. Deleting a one-time meeting cannot be undone. An occurrence of a series is only cancelled; init_recurring_meeting_occurrence restores it, reset to the series template. Invited participants get a cancellation email when the meeting's notifications are on. The template meeting of a recurring series is rejected, because deleting it would break the series. To delete the series with all its occurrences use delete_recurring_meeting. |
| create_meeting_agenda_itemA | Add an item to a meeting's agenda. Requires OpenProject 17.6+. Rejected while the meeting is closed. For a work package, its project must be inside OPENPROJECT_WRITE_PROJECTS. To record a result of a discussed item use create_meeting_outcome. |
| update_meeting_agenda_itemA | Update one agenda item of a meeting; omitted fields stay unchanged. Requires OpenProject 17.6+. Rejected while the meeting is closed. Each confirmed update also updates the meeting's own timestamp. Outcomes of the item are changed with update_meeting_outcome. |
| delete_meeting_agenda_itemA | Delete a meeting agenda item with its outcomes. Requires OpenProject 17.6+. Rejected while the meeting is closed. This cannot be undone. |
| create_meeting_outcomeA | Create a meeting outcome on an agenda item. Requires OpenProject 17.6+. kind must be one of "information", "decision", "work_package" (OpenProject's real enum values, not e.g. "info" or "action", which OpenProject rejects with an internal server error rather than a clean validation error). "information"-kind outcomes require notes; "work_package"-kind outcomes require work_package_id. |
| update_meeting_outcomeB | Update a meeting outcome. Requires OpenProject 17.6+. kind, if given, must be one of "information", "decision", "work_package" (OpenProject's real enum values, not e.g. "info" or "action", which OpenProject rejects with an internal server error rather than a clean validation error). |
| delete_meeting_outcomeB | Delete a meeting outcome; this cannot be undone. Requires OpenProject 17.6+. |
| create_meeting_sectionA | Create a meeting section. Requires OpenProject 17.6+. backlog cannot be changed after creation via update_meeting_section; pass it only here, on create. |
| update_meeting_sectionA | Rename or move a meeting section; omitted fields stay unchanged. Requires OpenProject 17.6+. Rejected while the meeting is closed, and for the backlog section. Its agenda items stay in it. backlog cannot be changed after creation; this tool does not accept it. |
| delete_meeting_sectionA | Delete a meeting section with its agenda items and their outcomes (they are not moved). Requires OpenProject 17.6+. Rejected while the meeting is closed, and for the backlog section. This cannot be undone. |
| create_recurring_meetingA | Create a recurring meeting series; its template meeting starts as a draft. Requires OpenProject 17.4+. For a single meeting use create_meeting. Occurrences are virtual until init_recurring_meeting_occurrence creates one; the series is changed with update_recurring_meeting. |
| update_recurring_meetingA | Update an OpenProject recurring meeting series. Requires OpenProject 17.4+. Already created future occurrences move and are renamed with the series. A schedule change other than the time of day can delete cancelled occurrences; on 17.4 to 17.8 a time-of-day change also rewrites the slot times of past occurrences. When the schedule changes, invited participants get an update email if notifications are on. |
| delete_recurring_meetingA | Delete a recurring meeting series with all its occurrences, past and future. Requires OpenProject 17.4+. Each occurrence goes with its agenda, outcomes, attachments and time entries; this cannot be undone. Invited participants get a cancellation email when notifications are on. |
| init_recurring_meeting_occurrenceA | Materialize a virtual recurring-meeting occurrence into a real, standalone Meeting. Requires OpenProject 17.4+. start_time: the occurrence's exact start time (ISO 8601, matching a start_time value from list_recurring_meeting_occurrences); occurrences have no numeric id, they are addressed by this timestamp. On success, result is a full Meeting (use its id with get_meeting/ update_meeting/delete_meeting), not an occurrence. A cancelled occurrence is restored and its content reset to the template. If the series template is still a draft, this first sets it to open, which stays even if the init fails; on 17.6 and later OpenProject creates further occurrences automatically only once the template is open. On OpenProject 17.4 and 17.5, initializing an occurrence that already exists fails with a server error instead of returning it; 17.6 and later return the existing occurrence. |
| cancel_recurring_meeting_occurrenceA | Cancel a virtual (not-yet-materialized) recurring-meeting occurrence. Requires OpenProject 17.4+. start_time: the occurrence's exact start time (ISO 8601), matching init_recurring_meeting_occurrence's addressing scheme. If the occurrence has already been materialized into a real Meeting and is not itself cancelled, this fails with an error (delete_meeting the materialized meeting directly instead). If NOT yet materialized, OpenProject records the cancellation as a cancelled Meeting (init_recurring_meeting_occurrence restores it, a later schedule change of the series other than the time of day can delete it); this call's result does not report that new meeting's id; list_meetings/ list_recurring_meeting_occurrences(filter="cancelled") can be used to find it afterward if needed. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 147 tools
Descriptions are unusually detailed and explicitly cross-reference each other, which rescues many boundaries. However, there is genuine overlap in the work-package listing family (list_work_packages, search_work_packages, list_my_open_work_packages, execute_query, get_work_packages) and in paired tools like create_time_entry vs create_time_entry_until and list_work_package_relations vs list_relations. An agent can usually pick correctly after reading, but misselection is easy without the docstrings.
Names overwhelmingly follow a snake_case verb_noun pattern (list_/get_/create_/update_/delete_ + resource), consistently across projects, work packages, meetings, memberships, etc. A few outliers exist (execute_query, toggle_activity_emoji_reaction, get_project_work_package_context, bulk_* prefixes), but they are readable and follow their own sub-convention.
147 tools is far beyond any reasonable surface for an agent-facing MCP server; the rules mark 50+ as an extreme mismatch. While the domain (a full project-management suite) is broad, this count imposes heavy context cost and makes tool selection error-prone even with excellent descriptions.
Coverage is very broad: full CRUD for projects, work packages, relations, time entries, versions, memberships, meetings/series/agenda/outcomes, boards, grids, news, and many read-only integrations, with upstream limitations (wiki body text, posts, cost entries, statuses/types) clearly explained. Minor gaps remain—notably no create/delete for documents, and write operations for sprints/backlog buckets are absent—but they are narrow.