Skip to main content
Glama

list_work_packages

Read-onlyIdempotent

Retrieve and filter OpenProject work packages by project, status, assignee, priority, version, or date range, with sorting, grouping, and sum totals—no free-text query needed.

Instructions

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:

  • created_on/updated_on/due_on: exact date match

  • created_between/updated_between/due_between: inclusive date range [start, end] Cannot specify both _on and _between for the same field.

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).

Input Schema

NameRequiredDescriptionDefault
typeNo
limitNoPage size, capped at OPENPROJECT_MAX_PAGE_SIZE.
due_onNo
offsetNo1-based page number; pass the previous result's next_offset.
selectNoFields to return; a requested unset field comes back as null. Allowed: assignee, author, category, created_at, custom_comments, custom_comments_truncated, custom_fields, custom_fields_truncated, derived_due_date, derived_estimated_time, derived_percentage_done, derived_remaining_time, derived_start_date, description, description_length, description_truncated, display_id, due_date, duration, estimated_time, has_description, has_project_attributes, id, ignore_non_working_days, parent_display_id, parent_id, percentage_done, priority, project, project_phase, readonly, remaining_time, responsible, schedule_manually, spent_time, sprint, start_date, status, subject, target_versions, type, updated_at, version.
statusNo
projectNoProject identifier, id, or name; a unique part of a name or identifier also matches.
sort_byNoSort criteria as "field:direction" or "field-direction" (e.g. ["status:desc", "priority-asc"]); the direction defaults to asc. Fields: assigned_to, assignee, author, backlog_bucket, category, created_at, done_ratio, due_date, duration, estimated_hours, estimated_time, id, observed_in_versions, percentage_done, position, priority, project, project_phase, remaining_hours, remaining_time, responsible, sprint, start_date, status, story_points, subject, target_versions, type, updated_at, version, or a custom field's cf_<id>. Newer columns need an OpenProject release: project_phase 16.1+, sprint 17.4+, backlog_bucket 17.6+, target_versions 17.8+, observed_in_versions 17.9+; target_versions is version under its newer name. sprint and backlog_bucket also need the Backlogs module in a project where you may view sprints.
versionNo
assigneeNo
group_byNoOne field to group the results by: assigned_to, assignee, author, backlog_bucket, category, done_ratio, observed_in_versions, percentage_done, priority, project, project_phase, responsible, sprint, status, target_versions, type, version, or a custom field's cf_<id>. Newer columns need an OpenProject release: project_phase 16.1+, sprint 17.4+, backlog_bucket 17.6+, target_versions 17.8+, observed_in_versions 17.9+; target_versions is version under its newer name. sprint and backlog_bucket also need the Backlogs module in a project where you may view sprints.
priorityNo
open_onlyNo
created_onNo
updated_onNo
assignee_meNo
due_betweenNo
include_sumsNo
overdue_onlyNo
version_statusNo
created_betweenNo
due_within_daysNo
updated_betweenNo
custom_field_filtersNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Addedv0.4.4
  2. Removedv0.4.0
  3. Changed1 schema field changedv0.3.7
    • addedInput schema / additionalProperties
      Added value: +false
  4. Addedv0.3.3
  5. Removedv0.3.0
  6. Changed14 schema fields changedv0.2.3
    • addedInput schema / properties / assignee
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Assignee"
      +}
    • addedInput schema / properties / created_between
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Created Between"
      +}
    • addedInput schema / properties / created_on
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Created On"
      +}
    • addedInput schema / properties / due_between
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Due Between"
      +}
    • addedInput schema / properties / due_on
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Due On"
      +}
    • addedInput schema / properties / group_by
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Group By"
      +}
    • removedInput schema / properties / has_description
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "boolean"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "title": "Has Description"
      -}
    • addedInput schema / properties / priority
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Priority"
      +}
    • addedInput schema / properties / select
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Select"
      +}
    • addedInput schema / properties / sort_by
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Sort By"
      +}
    • addedInput schema / properties / status
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Status"
      +}
    • addedInput schema / properties / updated_between
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Updated Between"
      +}
    • addedInput schema / properties / updated_on
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "title": "Updated On"
      +}
    • changedOutput schema / (root)
      Previous value: -{
      -  "$defs": {
      -    "WorkPackageSummary": {
      -      "properties": {
      -        "assignee": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Assignee"
      -        },
      -        "description": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Description"
      -        },
      -        "display_id": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Display Id"
      -        },
      -        "due_date": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Due Date"
      -        },
      -        "has_description": {
      -          "title": "Has Description",
      -          "type": "boolean"
      -        },
      -        "id": {
      -          "title": "Id",
      -          "type": "integer"
      -        },
      -        "percentage_complete": {
      -          "anyOf": [
      -            {
      -              "type": "integer"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Percentage Complete"
      -        },
      -        "priority": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Priority"
      -        },
      -        "project": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Project"
      -        },
      -        "project_phase": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Project Phase"
      -        },
      -        "responsible": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Responsible"
      -        },
      -        "start_date": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Start Date"
      -        },
      -        "status": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Status"
      -        },
      -        "subject": {
      -          "title": "Subject",
      -          "type": "string"
      -        },
      -        "type": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Type"
      -        },
      -        "url": {
      -          "title": "Url",
      -          "type": "string"
      -        },
      -        "version": {
      -          "anyOf": [
      -            {
      -              "type": "string"
      -            },
      -            {
      -              "type": "null"
      -            }
      -          ],
      -          "title": "Version"
      -        }
      -      },
      -      "required": [
      -        "id",
      -        "display_id",
      -        "subject",
      -        "type",
      -        "status",
      -        "priority",
      -        "project_phase",
      -        "assignee",
      -        "responsible",
      -        "project",
      -        "version",
      -        "start_date",
      -        "due_date",
      -        "percentage_complete",
      -        "description",
      -        "has_description",
      -        "url"
      -      ],
      -      "title": "WorkPackageSummary",
      -      "type": "object"
      -    }
      -  },
      -  "properties": {
      -    "count": {
      -      "title": "Count",
      -      "type": "integer"
      -    },
      -    "limit": {
      -      "title": "Limit",
      -      "type": "integer"
      -    },
      -    "next_offset": {
      -      "anyOf": [
      -        {
      -          "type": "integer"
      -        },
      -        {
      -          "type": "null"
      -        }
      -      ],
      -      "title": "Next Offset"
      -    },
      -    "offset": {
      -      "title": "Offset",
      -      "type": "integer"
      -    },
      -    "results": {
      -      "items": {
      -        "$ref": "#/$defs/WorkPackageSummary"
      -      },
      -      "title": "Results",
      -      "type": "array"
      -    },
      -    "total": {
      -      "title": "Total",
      -      "type": "integer"
      -    },
      -    "truncated": {
      -      "title": "Truncated",
      -      "type": "boolean"
      -    }
      -  },
      -  "required": [
      -    "offset",
      -    "limit",
      -    "total",
      -    "count",
      -    "next_offset",
      -    "truncated",
      -    "results"
      -  ],
      -  "title": "WorkPackageListResult",
      -  "type": "object"
      -}New value: +null
  7. First observedv0.2.2

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only/idempotent, so the bar is behavioral detail beyond that — and the description supplies a great deal: total/next_offset fallback semantics under OPENPROJECT_READ_PROJECTS scoping (including the counterintuitive total=0 with non-null next_offset case), include_sums shape and null conditions, custom_fields normalization and 50-entry/255-char caps, ~250 KB worst case, local ValueError validation, per-call query limits, and version-gated columns.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with purpose and the project parameter caveat, but the body sprawls across many dense paragraphs and repeats material already present in the schema (the sort_by/group_by field lists and release requirements). It also defers key rules to an external 'docs/filters.md' the agent may not have access to, which weakens structure.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 24-parameter, no-output-schema, high-complexity list tool, the description covers nearly everything an agent needs — filtering semantics, pagination, aggregation, custom-field handling, and failure modes. The main shortfall is reliance on external documentation references for the custom-field operator matrix and the global-filtering constraint.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 25% across 24 parameters, so the description must compensate, and it does: it clarifies project accepts name/id/slug (not project_id), status/priority accept exact names or IDs but not meta-values, date format and inclusivity, overdue_only's composed predicate, sort_by/group_by validity checking against real columns, select field behavior, and the full custom_field_filters key/operator/limit contract.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List work packages') and immediately delimits scope with 'structured filters and no free-text query requirement', which distinguishes it from the search_work_packages sibling. An agent can identify the tool's role without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'no free-text query requirement' phrasing implies the alternative is a text-search tool and gives clear context for structured filtering, and conflict rules (due_on vs due_between vs overdue_only, assignee_me precedence) tell the agent how to compose a call. However, it never names search_work_packages or list_my_open_work_packages as alternatives with explicit when-to-use conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools