OpenProject CE MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| OPENPROJECT_URL | No | Instance root URL, e.g. https://openproject.example.com. A trailing /api/v3 is tolerated and stripped. | |
| OPENPROJECT_API_KEY | No | API key from My account → Access tokens. Sent as HTTP Basic apikey:<token>. | |
| OPENPROJECT_MCP_OTEL | No | Reserved for OpenTelemetry tracing. Accepted but not yet wired to anything in this release. | false |
| OPENPROJECT_MCP_DISABLE | No | Comma-separated group tags to remove whole tool groups at startup. | |
| OPENPROJECT_OAUTH_TOKEN | No | OAuth bearer token, as an alternative to the API key. | |
| OPENPROJECT_MCP_INSECURE | No | Allow --transport http to start without auth tokens. Local development only. | false |
| OPENPROJECT_MCP_CACHE_TTL | No | TTL in seconds for the metadata cache (statuses, types, priorities, schemas). | 300 |
| OPENPROJECT_MCP_CA_BUNDLE | No | Path to a CA bundle (PEM) for instances behind a private CA. TLS is always verified. | system trust store |
| OPENPROJECT_MCP_HTTP_HOST | No | Bind address for --transport http. | 127.0.0.1 |
| OPENPROJECT_MCP_HTTP_PORT | No | Port for --transport http. | 8000 |
| OPENPROJECT_MCP_LOG_LEVEL | No | DEBUG, INFO, WARNING, ERROR or CRITICAL (case-insensitive). | INFO |
| OPENPROJECT_MCP_READ_ONLY | No | Serve read tools only: every write, destructive and admin tool is removed at startup. | false |
| OPENPROJECT_MCP_LOG_BODIES | No | Log request/response bodies — only at DEBUG level, with credentials redacted. Development use only. | false |
| OPENPROJECT_MCP_LOG_FORMAT | No | text or json. Logs always go to stderr. | text |
| OPENPROJECT_MCP_ADMIN_TOOLS | No | Expose the three admin-gated membership write tools (hidden by default). | false |
| OPENPROJECT_MCP_AUTH_TOKENS | No | Comma-separated bearer tokens accepted by --transport http. Every request must carry Authorization: Bearer <token>. | |
| OPENPROJECT_MCP_MAX_RETRIES | No | Retry budget for idempotent requests. | 3 |
| OPENPROJECT_MCP_DOWNLOAD_DIR | No | Directory where download_attachment writes files (created if missing; default is relative to the server's working directory). | ./openproject-downloads |
| OPENPROJECT_MCP_POOL_TIMEOUT | No | Seconds to wait for a free connection from the pool. | 5 |
| OPENPROJECT_MCP_READ_TIMEOUT | No | Seconds to wait for response data. | 30 |
| OPENPROJECT_MCP_WRITE_TIMEOUT | No | Seconds to wait while sending request data (uploads). | 60 |
| OPENPROJECT_MCP_ACCEPT_LANGUAGE | No | Sent as the Accept-Language header; OpenProject localizes validation messages accordingly. | |
| OPENPROJECT_MCP_CONNECT_TIMEOUT | No | Seconds to wait for a TCP/TLS connection to OpenProject. | 10 |
| OPENPROJECT_MCP_MAX_CONNECTIONS | No | Connection pool size toward OpenProject. | 10 |
| OPENPROJECT_MCP_MAX_DOWNLOAD_MB | No | Size cap for attachment downloads, in MiB. | 100 |
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": true
} |
| logging | {} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| extensions | {
"io.modelcontextprotocol/ui": {}
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| search_work_packagesA | Find work packages by text when you do not know their ids. Use this first whenever a user names a ticket instead of numbering it, then feed the
returned Returns the standard list envelope: compact rows (id, subject, type, status, priority,
assignee, project, dates, progress) plus Pitfalls: search filters, it does not rank, so a broad query returns a lot — narrow it
with For structured filtering use |
| list_work_packagesA | List work packages with structured filters — the workhorse read tool. Use it for every "what is assigned to me", "what is overdue", "what is in this sprint"
question. Convenience queries are parameters here, not separate tools: overdue →
Returns the standard list envelope: compact rows plus Pitfalls: this returns open work packages only unless you pass For text lookups use |
| get_work_packageA | Read one work package in full: description, dates, custom fields, parent and progress. This is the tool to call once a search or list has given you an id, and the only way to
read a work package's description text. The Returns every core field, Pitfalls: includes are capped at 20 — a truncated For the comment thread use |
| create_work_packageA | Create a work package, validated through OpenProject's own form endpoint first. Use it for new tasks, bugs, subtasks ( Returns the created work package in full detail, including its new Pitfalls: To change it afterwards use |
| update_work_packageA | Change any writable field of a work package, with optimistic locking done properly. Use it to assign or unassign, move a status forward, re-schedule, re-parent, set progress or write custom fields. Every convenience the old tooling spread across a dozen tools is a parameter here. Returns the updated work package in full detail, including the new Pitfalls: omitted parameters are left alone, while passing null clears a field
(assignee, responsible, version, parent, dates, description). A 409 error means somebody
else changed the work package first — the error carries the fresh Ids come from |
| delete_work_packageA | Permanently delete a work package and everything attached to it. Use only on explicit user instruction. Deletion removes the work package with its comments, attachments, time entries and relations, and OpenProject offers no API-side undo. Returns a small confirmation object once OpenProject accepts the deletion. Pitfalls: children are not deleted with the parent, so check
|
| list_work_package_commentsA | Read the comment thread and change history of a work package. Use this whenever the question is "what did people say about this
ticket" or "what changed on it": it returns the full activity journal —
comment entries (author, markdown text, internal flag, timestamps) and
field-change entries whose details are parsed into
Returns the standard list envelope: Pitfalls. OpenProject's activities endpoint is unpaginated — this
tool fetches the entire journal on every call and pages it here, so
Cross-references: post a comment with |
| add_work_package_commentA | Post a comment on a work package. Use this to reply in a ticket's thread, record a decision, or leave a
handover note. Returns the created journal entry (activity id, author,
markdown text, internal flag, timestamps) — the same shape
Pitfalls. Every call creates a new comment; it is not idempotent, so do
not retry blindly after a timeout — read the thread first.
Cross-references: read the thread with |
| edit_work_package_commentA | Rewrite the text of an existing work-package comment. Use this to fix a typo, correct a wrong statement, or extend a note you
just posted. Returns the updated journal entry (activity id, author,
markdown text, internal flag, timestamps) in the same shape
Pitfalls. Only comment entries are editable: the journal also holds field-change entries ("Status changed from New to In progress"), which OpenProject records automatically and refuses to alter — this tool rejects those locally, before any write. Editing needs the edit-work-package-comments permission (or edit-own for your own comments); a 403 means the account may read the thread but not rewrite it. The edit replaces the text entirely and OpenProject keeps no API-visible history of the previous version, so do not use it to "undo" — post a correcting comment when the record matters. Editing does not notify anyone. Cross-references: read the thread and get activity ids with
|
| add_work_package_watcherA | Subscribe a user to a work package's notifications. Use this when someone should be kept in the loop on a ticket without being assigned to it. Watchers receive OpenProject's notifications for comments and changes. Returns the watcher (user id and name), the watch state after the call, and whether this call actually changed anything. Pitfalls. The user must already be able to see the work package;
OpenProject answers 422 with a violation on Cross-references: |
| remove_work_package_watcherA | Unsubscribe a user from a work package's notifications. Use this to stop notifying someone who no longer needs the updates. Returns the user, the watch state after the call (always not watching) and a confirmation message. Pitfalls. OpenProject answers the same 204 whether or not the user was
watching, so Cross-references: |
| create_work_package_relationA | Link two work packages (blocks, follows, duplicates, relates, ...). Use this to record a dependency the schedule or the reader needs to know about: "ship the client layer follows design sign-off", "this duplicates #4321". Returns the created relation with its id, type, reverse_type, both work packages, lag and description. Pitfalls. OpenProject stores one canonical direction per pair, so the
passive spellings are rewritten on save: creating Cross-references: |
| update_work_package_relationA | Change an existing relation's type, lag or description. Use it to widen the gap between a predecessor and its successor, to correct a link that was created with the wrong type, or to explain why two work packages are connected. Returns the updated relation. Pitfalls. At least one of type, lag or description must be given.
Relations carry no lock version, so this is a plain overwrite with no
conflict detection — a concurrent edit is silently replaced; re-read the
relation if that matters. The two work packages cannot be changed here:
delete the relation and create a new one instead. Raising the lag on a
Cross-references: |
| delete_work_package_relationA | Remove the link between two work packages. Use it when a dependency no longer holds. Neither work package is touched, only the relation between them. Returns a small confirmation object. Pitfalls. Deleting a Cross-references: |
| toggle_comment_reactionA | React to a work-package comment with an emoji, or take your reaction back. Use this for the lightweight acknowledgement a comment does not deserve:
👍 on a decision, 👀 to say you are looking at it, 🎉 when something
shipped. Returns the comment's full reaction state afterwards — every
emoji on it with the people who picked it — plus Pitfalls. This is a toggle, not an add: calling it twice with the
same reaction leaves the comment exactly as it started, so it is not safe
to retry blindly after a timeout — read Cross-references: |
| set_work_package_reminderA | Set, change or clear your personal reminder on a work package. Use this when something should resurface later: "remind me about this on
Monday", "ping me an hour before the release". Reminders are private —
only you see yours, and only you are notified. The tool upserts: it looks
for your active reminder on the work package and creates one if there is
none, updates it if there is. Returns Passing Pitfalls. OpenProject allows exactly one active reminder per work package
per person, so a second "create" becomes an update of the first — there
is no way to stack two. Cross-references: |
| list_remindersA | List your own upcoming work-package reminders. Use this to answer "what have I asked to be reminded about", to check
whether a reminder is already set before creating another one, or to find
the work packages you deferred. Returns the standard list envelope:
Pitfalls. Reminders are personal — this only ever shows the ones the
authenticated account created, never a colleague's, and there is no way
to list someone else's. It only shows reminders that are still
upcoming: once one has fired (or was completed) OpenProject drops it
from this collection, so an empty result does not mean nothing was ever
scheduled. The work package each reminder points at is in
Cross-references: |
| execute_custom_actionA | Run an instance-defined one-click action on a work package. Custom actions are shortcuts an administrator configured — "Accept and
assign to me", "Reject", "Move to review" — that apply several field
changes at once, sometimes under conditions (role, status, project).
Use one when Pitfalls. The action decides what changes; this tool cannot influence it,
and OpenProject does not report which fields it touched — compare the
returned row with what you read before, or call Cross-references: |
| list_attachmentsA | List the files attached to one container. Containers are work packages, wiki pages, meetings, documents, budgets and comments. Use this to discover attachment ids before calling download_attachment, or to check what a work package already carries. The upstream collection is not paginated, so it is fetched in full: the envelope always reports has_more=false and a total equal to the row count. Returns the standard list envelope; each row has id, file_name, size_bytes, content_type, description, author, created_at and status. status is the virus-scan state — 'uploaded' and 'scanned' are downloadable, 'quarantined' files are not, and anything else is still being scanned and is readable only by its uploader. Pitfalls: container_id identifies the container, not the file. A 404 means the container does not exist or the module providing it (meetings, budgets, documents) is not enabled on this instance. Forum posts are a valid API container but have no discovery path here. Related: download_attachment fetches the bytes for one row, upload_attachment adds a file to the same containers, and get_work_package(include=['attachments']) returns these rows inline for a single work package. |
| download_attachmentA | Download an attachment's bytes to a file on the machine running this server. Use it once list_attachments (or get_work_package(include=['attachments'])) has given you an attachment_id. Metadata is read first, then the bytes are streamed to disk in chunks with progress notifications, so a large file neither stalls the call nor buffers in memory. Returns path, file_name, size_bytes, content_type and the SHA-256 of the bytes (use it to verify or de-duplicate). With return_image=true an image of at most 1 MB comes back as an inline image block as well. Pitfalls: the file is written on the server's machine, which is the user's machine only in a local (stdio) deployment — tell the user the returned path rather than assuming they can see it. Quarantined attachments fail with attachment_quarantined and are never fetched. An attachment whose virus scan is unfinished answers 401 for everyone except its uploader. Transfers above OPENPROJECT_MCP_MAX_DOWNLOAD_MB (default 100) are refused up front and aborted mid-stream, leaving no partial file. A name collision in the target directory saves as 'name (2).ext' and says so in notes. Related: list_attachments produces attachment_id; upload_attachment is the reverse direction. |
| upload_attachmentA | Attach a local file to a work package, wiki page, meeting, document, budget or comment. Use it when a file that already exists on the server's machine should be added to an existing container. The file's existence and its size against this instance's maximumAttachmentFileSize are checked locally first, so an oversized file fails instantly instead of after the transfer. Returns the created attachment row (id, file_name, size_bytes, content_type, description, author, created_at, status) — the id feeds download_attachment. Pitfalls: uploading to a container needs edit permission on that container, so to give a brand-new work package its files use create_work_package(attachment_paths=[...]) instead, which uploads the files unattached and claims them on create. Instances may restrict extensions; a rejected type comes back as validation_failed with the allowlist hint and nothing is stored. The stored name comes from file_name (or the path's basename), never from the multipart part. Related: list_attachments shows what a container already holds; download_attachment is the reverse direction. |
| delete_attachmentA | Permanently delete one attached file from OpenProject. Use it only on explicit user instruction, for example to remove a file uploaded to the wrong work package or a superseded document. The attachment's metadata is read first so the result names the file and the container it was attached to, and so an unknown id fails before anything is removed. Returns the attachment id, the file name, its container and a confirmation message. Pitfalls: this deletes the file itself, not a link to it — every work package, wiki page or comment that embedded it loses the image or download. Deleting needs edit permission on the container (or authorship for a file that has no container yet), so a 403 can follow a successful read. A 404 means the id is unknown or already deleted; a second call on the same id answers 404 rather than succeeding. Removing a file does not remove the comment or work package that referenced it. Related: list_attachments shows the ids and file names of everything a container holds; upload_attachment adds a replacement; download_attachment saves a copy first if the bytes are still wanted. |
| list_file_linksA | List the external-storage files (Nextcloud, OneDrive/SharePoint) linked to a work package. File links are OpenProject's other kind of file: instead of living inside OpenProject like an attachment, the document stays in a connected storage and the work package points at it. Use this to answer "which documents belong to this ticket" — and pair it with list_attachments, because the two lists are disjoint and neither implies the other. Returns the standard list envelope, fetched in full (has_more is always false). Each row carries file_name, the storage it lives on, the file's origin_id inside that storage, mime_type, the creator and — the useful part — open_url and download_url. Those are absolute OpenProject URLs that redirect to the storage once OpenProject has resolved the link, so hand them to the user: they need the user's own OpenProject login, this server cannot fetch the bytes, and download_attachment does not work on them. Pitfalls: this needs the storages module and a storage connected to the project. When it is missing (404) or this account may not read the links (403) the call still succeeds with an EMPTY list and a note explaining which — read notes before saying a ticket has no documents. An empty list is never proof either: an account lacking the 'view file links' permission gets an empty 200 rather than a 403, which is exactly what that note says. permission carries the storage's own wording — 'View allowed' means the URLs will work, 'View not allowed', 'Not found' and 'Error' mean they will not, and null means the storage said nothing. Creating and deleting file links, and browsing the remote storage, are out of scope for this server — do them in the OpenProject UI. Related: list_attachments covers files stored inside OpenProject, download_attachment fetches those bytes, and get_work_package gives the ticket the links belong to. |
| get_work_package_git_activityA | Show the code behind a work package: commits, pull/merge requests and CI status. Use this for "is this ticket implemented", "what shipped for it", "did CI pass",
"which branch/PR is this in". It returns, in one call:
Pitfalls. Every pull/merge request carries two numbers: Nothing appears here by magic. Links are created by text, not by the API: a commit message must mention the work package ('refs #123', or 'fixes #123' / 'closes #123' to also close it), and a pull or merge request must mention 'OP#123' or the full work-package URL in its description or a comment. OpenProject cannot browse repositories, list branches or diffs, or create these links through the API. Cross-references: full pull-request detail (body, diff counts, all check runs) via
|
| get_github_pull_requestA | Read one linked GitHub pull request in full, including its CI check runs. Use it after Pitfalls. A pull request appears in OpenProject only when its description or a comment mentions 'OP#123' or the full work-package URL; commits link separately via 'refs #123' in the commit message. Neither link can be created through the API. Cross-references: find the id with |
| list_projectsA | List projects, filtered server-side, one page at a time. Use this to turn a project name into the id or identifier that every other tool
consumes, to enumerate the sub-projects of a parent, or to review which projects are
off track. It is the id-producing path for every Returns the standard list envelope: Pitfalls: For a single project's description and status explanation use |
| get_projectA | Read one project in full. Use it after Returns Pitfalls: For the ids valid inside this project (types, versions, categories, time-entry
activities) call |
| create_projectA | Create a project, validated through OpenProject's own form endpoint first. Use it for a new workspace or, with Returns the created project: Pitfalls: creating projects usually requires the 'create project' permission or
admin rights, so a 403 here is about the account, not the payload. The new project
starts with the instance's default modules and types enabled — check
Cross-references: |
| update_projectA | Change a project's name, description, visibility, parent, status or archived state. Use it to record a status change with its explanation ("at_risk because the vendor
slipped"), to rename or re-parent a project, to publish it, or to archive it with
Only the parameters you pass are sent — omitted fields are never rewritten, so two
agents editing different fields do not clobber each other. Projects carry no
Returns the updated project in the same shape as Pitfalls: Cross-references: |
| delete_projectA | Schedule the permanent deletion of a project and everything inside it. Use only on an explicit, specific instruction. Deletion CASCADES: every subproject,
work package, comment, attachment, time entry, version, wiki page and membership of
this project goes with it, and OpenProject offers no API-side undo. If the goal is
only to get the project out of the way, Deletion is ASYNCHRONOUS upstream: OpenProject accepts the request and runs it as a
background job. This tool therefore returns Pitfalls: deleting normally requires admin rights (403 otherwise). A 404 means the
id or identifier is wrong, or the project was already deleted. Because the work runs
in the background, a later failure inside the job is not visible here; confirm with
Cross-references: |
| copy_projectA | Copy a project — its settings, and optionally its work packages — into a new one. Use it to spin a new engagement or release off a template project, which is the only
way to reproduce a project's members, versions, categories and enabled modules in one
call. The request goes through Copying is ASYNCHRONOUS: OpenProject queues a job and answers immediately. This tool
therefore returns Pitfalls: only Cross-references: |
| get_job_statusA | Check whether a background job (a project copy, a scheduled deletion) has finished. OpenProject runs copies, deletions and exports asynchronously and hands back a job id.
This is the only way to learn what happened to one: call it after Returns Pitfalls: a 200 does not mean the job worked — read Cross-references: |
| set_project_favoriteA | Add or remove a project from the authenticated user's favorites (OpenProject 17+). Favorites are per user, not per project: this changes what the account behind OPENPROJECT_API_KEY sees starred on its own overview page, and nothing about the project itself or about anybody else's view. Use it when the user asks to pin, star or favorite a project they work in. Returns Pitfalls: this endpoint only exists from OpenProject 17. When the instance reports a version older than that the call is REFUSED before anything is sent, with the detected version in the message, because there is no downgrade that would achieve the same thing — favorite the project in the web UI instead. When it reports no version at all the request IS sent, since an unreported version says nothing about the endpoint. A 404 is ambiguous on purpose in the hint: it means either the project does not exist for this account or the endpoint is missing. This is not project 'status' and not a work-package watcher. Cross-references: |
| list_project_phase_definitionsA | List the instance-global phase definitions — the vocabulary of the project life cycle. Use it to learn which phases (Initiating, Planning, …) and gates this instance
defines, and to get the definition id or name that Returns the standard list envelope of Pitfalls: definitions are the instance-wide catalog, not any project's actual
phases — a project may deactivate phases or set no dates. Phase dates are not
exposed by the API at all. Requires OpenProject 16.1+ and the
Cross-references: |
| get_project_phaseA | Read one project's phase record: name, active flag and its definition. Use it after Returns Pitfalls: the API has no phases index — ids only come from work packages'
Cross-references: |
| list_queriesA | List the saved work-package views (queries) this user can open. Use it to discover what a team already tracks — "Sprint board", "My open bugs",
"Overdue in Platform" — before hand-building filters: running someone's saved view
with Returns the standard list envelope: rows of Pitfalls. Query ids are instance-wide, not per project — never guess one, take it from here. This lists definitions only; it never runs them, so nothing here says how many work packages a query returns. Cross-references: run one with |
| run_queryA | Run a saved view and get its work packages — the fastest way to answer with a team's own definition of "the sprint" or "our bugs". OpenProject queries run on read: this returns the rows as they are right now, in the
stored order and grouping. The result is the standard list envelope — Pitfalls. Cross-references: find query ids with |
| save_queryA | Save a filter set as a reusable OpenProject view the whole team can open. Use it when a filter combination is worth keeping — "Overdue in Platform", "My open
bugs" — instead of rebuilding it every session: the saved view shows up in the
OpenProject UI as well, and The call runs Pitfalls. Filter values are ids, not names — 'Grace Hopper' is not a value, Cross-references: |
| list_notificationsA | Read the authenticated user's OpenProject inbox. Use this to answer "what needs my attention?", "was I mentioned anywhere?" or "what changed on the things I watch?" — it is the only tool that sees notifications, and it always reports the inbox of the token owner, never another user's. Returns the standard list envelope: Pitfalls. Several changes to the same work package are aggregated into
one notification, so the count is not a count of events. Reading a
notification here does not mark it read — that is
Cross-references: mark specific rows read with |
| mark_notificationsA | Mark specific notifications read (or unread) in one bulk request. Use it after you have actually handled what a notification was about, so
the user's inbox reflects reality. It is the id-consuming counterpart of
Returns Pitfalls. Marking is idempotent, so a retry after a timeout is safe. Pass
the notification id, not Cross-references: get the ids from |
| mark_all_notifications_readA | Mark everything matching the filters as read — the whole inbox by default. Use it for "clear my notifications" or "I have dealt with everything in
project X". Called with no arguments it marks every unread notification
of the token owner as read, across all projects; Returns This tool only ever marks read. There is deliberately no
"mark everything unread" twin: that is a mistake with no upside, and the
reverse direction stays available per-id through
Cross-references: preview or page the inbox with |
| list_time_entriesA | List logged time, filtered server-side, with an optional accurate total. Use it to answer "how much time went into this ticket?", "what did I
book last week?" or "how much did the team spend on project X in June?".
Filters combine with AND, so Returns the standard list envelope: Pitfalls. Visibility is permission-bound: without the
view-all-time-entries permission you see only your own entries, and a
small total may mean "not allowed to see" rather than "nobody booked
time". Cross-references: book time with |
| log_timeA | Book time against a work package or a project. Use it when the user says "log 2 hours on #1234" or "book half a day to project X". The call is validated through OpenProject's own form endpoint first, so an activity this project does not allow, a missing permission or a closed cost-reporting period comes back as a typed error listing what would be accepted — nothing half-written is left behind. Returns the created entry: Pitfalls. This is not idempotent — calling it twice books the time
twice, so never blind-retry after a timeout; list the day's entries
first. The time is always booked for the token owner; you cannot log
time on someone else's behalf through this tool. Logging time does not
change the work package's status, estimate or progress — those are
separate fields, and on instances that derive progress from work the
percentage is read-only anyway. The work package's Cross-references: the activities and ids this project accepts come from
|
| update_time_entryA | Correct an existing time entry. Use it for the everyday fixes: wrong duration, wrong day, wrong activity, a comment that needs to say what actually happened. Only the parameters you pass are written; everything else is left exactly as it is. Returns the updated entry in the same shape Pitfalls. What can be moved between entries is limited: the work package
and the project a time entry belongs to are not editable here —
delete the entry and log it again where it belongs. Some instances
report a Cross-references: find the id with |
| delete_time_entryA | Permanently delete a logged time entry. Use only on explicit user instruction, and only for genuinely wrong entries. Deletion removes the booked hours from every cost report and from the work package's aggregated spent time, with no API-side undo. Returns a small confirmation object once OpenProject accepts the deletion. Pitfalls. If the entry is merely on the wrong day, has the wrong
duration or the wrong activity, Cross-references: find the id with |
| list_versionsA | List versions (releases, milestones, sprints) you can assign work packages to. Use it to turn "Sprint 12" or "release 2.1" into the version id that
Returns the standard list envelope: Pitfalls: Cross-references: |
| create_versionA | Create a version (release, milestone or sprint) inside a project. Use it to open a new sprint or plan a release before assigning work packages to it.
The call goes through Returns the created version Pitfalls: Cross-references: |
| update_versionA | Change a version's name, dates, description, status or sharing. Use it to move a sprint's dates, to close a finished release ( Only the parameters you pass are sent, so concurrent edits to other fields survive.
Versions carry no Returns the updated version in the same shape as Pitfalls: Cross-references: |
| delete_versionA | Permanently delete a version. Use it only for a version created by mistake. For a finished release or sprint,
Returns a small confirmation once OpenProject accepts the deletion. Work packages are NOT deleted — they simply lose their version — but that only happens on instances that allow the deletion at all. Pitfalls: OpenProject refuses (422) to delete a version that work packages still reference; the error hint explains how to find them. Deleting a shared version affects every project that used it. The 'manage versions' permission is required, so a 403 is about the account. Cross-references: |
| search_principalsA | Find users, groups and placeholder users, and get their ids. This is the id-producing tool for every principal parameter in this
server: Use it to answer "who is Grace Hopper's account", "which groups exist",
"who is a member of the demo project". Returns the standard list
envelope: Pitfalls. Cross-references: |
| get_userA | Read one user's profile: name, login, email, admin flag and status. Use it after Returns Pitfalls. Cross-references: |
| list_membershipsA | List who has access to which project, and with which roles. Use it before granting or revoking access ("does she already have a role here?"), to audit a project's member list, or to see which projects a principal can reach. Called with no arguments it pages through every membership the authenticated account may see, which on a large instance is a lot — filter. Returns the standard list envelope: Pitfalls. The Cross-references: |
| list_rolesA | List the roles this instance defines, with their ids. This is the id-producing tool for Returns the standard list envelope with Pitfalls. Role names are configurable per instance, so do not assume
'Member' exists — read the list. Some roles are not assignable to a
project membership (global and work-package roles live in the same
collection); the membership form rejects those with the assignable set
listed. Not every OpenProject version exposes permission arrays on this
endpoint: when Cross-references: |
| get_instance_infoA | Check the OpenProject connection and report what this instance supports. Call this first when anything fails in an unexplained way, when the user asks "am I connected / who am I", or before using a version-gated parameter. It is the server's connection test: it authenticates on every call rather than answering from cache. Returns the core version and instance name, the attachment size ceiling
( Pitfalls: For per-project ids (types, statuses, priorities, versions, categories, activities)
use |
| get_project_metadataA | List the ids and names that are actually valid on this instance. This is the one-call answer to "what do I pass for type / status / priority / version / category / activity". Call it before any create or update, before filtering by ids, and whenever a write fails with an allowed-values error. Nothing here is hardcoded — priority ids and activity ids differ per instance. Without Pitfalls: results are cached (default 300 s) — pass For the writable fields and custom fields of one project+type combination use
|
| get_work_package_schemaA | Show which fields a work package of this type accepts in this project. Call it before Returns Pitfalls: Ids for both parameters come from |
| list_permissionsA | List what the authenticated user is allowed to do, globally or in one project. Use it before attempting a write that might 403, to explain to a user why an action failed, or to pick between tools ("can I add a member here, or should I ask an admin?"). It reads the real capabilities API for the current user — it does not return a user profile and it never guesses from the admin flag. Returns the standard list envelope whose CAVEAT, straight from the API: OpenProject exposes only a SUBSET of its permissions as capabilities. An action missing from this list is not proof that the user lacks the permission — it may simply not be modelled. Treat a hit as reliable and a miss as "unknown, try it and read the 403". Pitfalls: the capabilities API has no Cross-references: |
| list_meetingsA | List meetings — the schedule side of a project: what is coming up, what already ran. Use it to answer "when do we next meet", "what meetings does this project have", or to
find the meeting id that Returns the standard list envelope: rows of Pitfalls. Cancelled meetings and recurring-series templates are excluded upstream, so an
absent meeting may exist in another state. Cross-references: |
| get_meetingA | Read one meeting in full: participants, the agenda, and any recorded outcomes. This is the "what was discussed / what was decided" call. It returns the meeting fields
( Pitfalls. A work-package agenda item carries an empty Cross-references: |
| create_meetingA | Schedule a meeting in a project and optionally invite participants. Use it for "book a review on Thursday" style requests. The call goes through
Returns the created meeting in the same shape as Pitfalls. Check Cross-references: |
| update_meetingA | Change a meeting's title, time, place or invite list — or move its lifecycle state. Use it to reschedule ("move Thursday's review to 15:00"), to publish a draft
( Returns the updated meeting in the same shape as Pitfalls. Cross-references: |
| delete_meetingA | Permanently delete a meeting, together with its agenda and recorded outcomes. Use only on explicit user instruction. The meeting, its agenda items, their outcomes
and its attachments all go with it, and OpenProject offers no API-side undo. If the
meeting merely did not happen, Returns a small confirmation object once OpenProject accepts the deletion. Pitfalls. This needs the 'delete meetings' permission, so a 403 is about the account, not the id. A 404 means the id is wrong, the meeting was already deleted, or — on OpenProject before 17.4 — the meetings write API does not exist at all; the hint names all readings. Cross-references: |
| add_meeting_agenda_itemA | Add one item to a meeting's agenda, optionally pinned to a work package. Use it to build or extend an agenda: "add 'Release readiness' with 15 minutes", or "put #1234 on Thursday's agenda". Linking a work package is also how a ticket learns it was discussed — the link shows up on the work package's Meetings tab. Returns the created item: Pitfalls. This needs the 'manage agendas' permission, so a 403 is about the account, not
the payload. A 422 usually means the work package is not visible to this account or the
meeting is already closed — Cross-references: |
| update_meeting_agenda_itemA | Edit one agenda item: retitle it, rewrite its notes, retime, reorder or re-link it. Use it for "give that item 20 minutes", "move it to the top" ( Returns the updated item in the same shape as Pitfalls. Once the meeting is CLOSED its agenda is frozen — every write answers a
validation error until the meeting is reopened with Cross-references: |
| delete_meeting_agenda_itemA | Permanently delete one agenda item, with any outcomes recorded against it. Use only on explicit user instruction. The item and its recorded outcomes disappear from the agenda for good; the items after it move up. The meeting itself is untouched. Returns a small confirmation object once OpenProject accepts the deletion. Pitfalls. A CLOSED meeting's agenda is frozen: the delete answers a validation error,
not a 403, until the meeting is reopened with Cross-references: |
| add_meeting_outcomeA | Record an outcome — a decision, a note, a follow-up ticket — against an agenda item. This is how minutes are written through the API: "decision: ship on Friday" becomes
Returns the created outcome: Pitfalls — the timing rule matters most. Outcomes can only be written while the
meeting state is exactly 'in_progress': before that, and again once it is closed,
every outcome write answers a validation error. Start the meeting with
Cross-references: |
| update_meeting_outcomeA | Correct a recorded outcome's kind, text or linked work package. Use it while the meeting still runs: fix a typo in the minutes, upgrade an information note to a decision, or attach the follow-up ticket that was created after the fact. Only the parameters you pass are sent. Returns the updated outcome in the same shape as Pitfalls. The same timing rule as every outcome write: this only works while the
meeting state is exactly 'in_progress' — once it is closed, the minutes are what they
are, and the write answers a validation error. Outcomes carry no Cross-references: |
| delete_meeting_outcomeA | Permanently delete a recorded outcome from a running meeting's minutes. Use only on explicit user instruction, for an outcome recorded by mistake or against
the wrong item. If the text is merely wrong, Returns a small confirmation object once OpenProject accepts the deletion. Pitfalls. The outcome timing rule applies to deletion too: it only works while the meeting state is exactly 'in_progress' — a closed meeting's minutes are frozen, and the delete answers a validation error, not a 403. This needs the 'manage outcomes' permission. A 404 means the id is wrong, the outcome is already gone — or, on OpenProject before 17.6, that there is no outcomes API at all. Cross-references: |
| get_wiki_pageA | Read a wiki page's identity and project — NOT its content. Two limits define this tool, and both must be passed on to the user rather than worked
around. First, So: use it to confirm which page a URL points at, to get the project a page belongs to, and as the step before fetching its files. To read the text, ask the user to paste it or open the page in the browser. Pitfalls. A 404 means the id is wrong, the page was deleted, or the wiki is disabled in that project — it does not mean the wiki is empty. Sub-pages, revisions, page history and wiki-page↔work-package links are not exposed either. Creating or editing wiki pages is not supported by this server. Cross-references: |
| list_documentsA | List the documents visible to you, across every project. Documents are OpenProject's filing cabinet: a title, a description, and attached files.
Use this to find a document id for Returns the standard list envelope: rows of Pitfalls. This is instance-wide: the endpoint takes no project parameter here, so filter
by reading Cross-references: |
| get_documentA | Read one document with its full description text. Use it after Pitfalls. The attached files are not part of this result — list them with
Cross-references: |
| list_budgetsA | List a project's budgets — their ids and names, which is all API v3 exposes. Use it to see whether a project tracks budgets at all and to get a budget id, which is
what Returns the standard list envelope with rows of Pitfalls — read before answering a money question. API v3's budget representer carries
no amounts: planned costs, spent costs, labor/material breakdowns and the assigned
work packages are simply not there. Do not infer them and do not present a budget row as
financial data; point the user at the budget in the UI, or use
Cross-references: |
| list_recurring_meetingsA | List recurring meeting series — the repetition rules, not the individual meetings. Use it to answer "what regular meetings do we have" and to find the series id that
Returns the standard list envelope: rows of Pitfalls. The listing is instance-wide — the endpoint takes no project filter, so
scope by reading Cross-references: |
| get_recurring_meetingA | Read one recurring series in full: the schedule plus its next occurrences. This is the step before touching any occurrence: the Returns the series fields (schedule, Pitfalls. Cross-references: |
| create_recurring_meetingA | Create a recurring meeting series: a schedule plus a template the occurrences copy. Use it for "set up a weekly sync Mondays at 9" style requests. The frequency and end_after combinations are validated locally BEFORE anything is sent — OpenProject's own "infer the monthly fields" defaults never apply to API creates, so a bad combination is rejected here with the allowed matrix spelled out. Returns the created series in the same shape as Pitfalls — two upstream quirks are handled but must be understood. First, the
template meeting is created as a DRAFT: Cross-references: |
| delete_recurring_meetingA | Permanently delete a recurring series: template, schedule, and EVERY occurrence. Use only on explicit user instruction, and make sure the user means the whole series:
every instantiated meeting of the series — past minutes included — is destroyed with
the template, and when the series has Returns a small confirmation object once OpenProject accepts the deletion. Pitfalls. This needs the 'delete meetings' permission, so a 403 is about the account, not the id. A 404 means the id is wrong, the series was already deleted — or OpenProject before 17.4, which has no recurring-meetings API at all; the hint names all readings. Cross-references: |
| init_recurring_meeting_occurrenceA | Materialize one occurrence of a series as a real meeting, copied from the template. Use it when a specific slot needs its own agenda, minutes or attachments before the day: the occurrence becomes a normal meeting (template agenda and attachments copied) that every meeting tool can work on. Called on a cancelled occurrence it RESTORES it to 'open'; called where an open meeting already exists it idempotently returns that meeting. Returns the instantiated meeting in the same shape as Pitfalls — the instant is trusted, not validated. OpenProject matches Cross-references: |
| cancel_recurring_meeting_occurrenceA | Cancel one occurrence of a series — skip a slot without touching the schedule. Use it for "no sync next Monday": the slot stays in the occurrences list as
'cancelled' (backed by a cancelled stub meeting) while the series keeps
running. A cancelled occurrence is recoverable —
Returns a small confirmation object carrying the normalized instant. Pitfalls. The instant is matched exactly and never validated against the schedule:
cancelling at a wrong time succeeds (204) by creating a cancelled phantom stub while
the real occurrence lives on — always copy Cross-references: |
| list_newsA | List project news — the announcements a team publishes on its project overview. Use it to answer "what was announced recently", to find the id of an entry before reading, editing or deleting it, or to check whether a report was already published. Results come back newest first (sorted by creation date descending). Returns the standard list envelope: Pitfalls: news is only visible where the project has the news module enabled and this
account holds the 'view news' permission, and neither absence is an error — an empty
page carries a Cross-references: |
| get_newsA | Read one news entry in full, including the markdown body. Use it after Returns Pitfalls: a 404 here means "no such entry, or you may not read news in its project" — the news module is enabled per project, so a missing entry is not always a wrong id. Comments people left on the announcement are not exposed by API v3 and are not included. Cross-references: |
| create_newsA | Publish a news announcement in a project. Use it for release notes, a weekly report, a maintenance window — anything the whole project should see on its overview page. The author is the authenticated account and is set by the server; project members watching the project are notified. Returns the created entry Pitfalls: this needs the 'manage news' permission in that project, which exists only
while the project has the news module enabled — a 403 is about the account or the
module, never about the text. Cross-references: |
| update_newsA | Correct or rewrite a published news entry. Use it to fix a headline, refresh a weekly report in place, or clear a stale teaser. Only the parameters you pass are sent, so a concurrent edit to another field survives. Returns the updated entry in the same shape as Pitfalls: Cross-references: |
| delete_newsA | Permanently delete a news entry. Use it for an announcement published by mistake or in the wrong project. For an
outdated but real announcement, Returns a small confirmation once OpenProject accepts the deletion. Pitfalls: the entry and every comment left on it are removed for good — API v3 offers no undo and no trash. The 'manage news' permission is required, so a 403 is about the account or a disabled news module; a 404 means the id is wrong or its news is not visible to you. Cross-references: |
| get_project_report_dataA | Aggregate everything a status report needs about one project and one date window. Use it for weekly reports, sprint reviews, standups and "what happened in June" —
one call replaces a dozen filtered listings. It returns, for the window: Done/in-progress classification is safe here: every row carries Pitfalls. Counts and row lists are different things: Cross-references: rendered reports are the |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| weekly_report | Render the 8-section Agile/Scrum weekly report for one project, with live data. The server does the reading: work packages created, changed and completed in the window, the server-side open-by-status counts, logged hours per activity and per person, the membership roster, and the blocking relations on open work. Done is decided by each status's own `isClosed` flag, so the report is correct on translated and renamed workflows; the rest split into Planned (raised in the window and untouched since) and In progress. |
| daily_standup | Render today's standup for one project: yesterday's movement, what is due today, and what is blocked. The window is yesterday on the server's clock. Completed items are the ones whose status carries the instance's `isClosed` flag, never a status name; "due today" is an open-status query on today's date; blockers are the `blocks`/`blocked` relations visible on the open work packages that moved. |
| triage_inbox | Group the current user's unread OpenProject notifications by reason and suggest what to do with each group. Reads the unread inbox server-side and renders one section per reason (mentioned, assigned, watched, …) with the work packages behind it, so triage is a single pass instead of one notification at a time. |
| groom_backlog | Sweep a project's open backlog for the three things that rot it: work with no assignee, work with no estimate, and work nobody has touched in weeks. The open set is read oldest-changed first and classified here, because "has no estimate" is not expressible as an OpenProject filter. Counts always come from the server, so a capped scan understates the lists but never the backlog. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/kar-thik/openproject-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server