Skip to content

feat(sprints): native sprint & backlog management tools (clean implementation) #16

Description

@AndreaV-Lsi

Problem / motivation

The server has no tools for sprints or the product backlog. Agile project
management — the core agentic-PM use case — needs to see what's in the current
sprint, what's sitting in the backlog, and (for planning) to move work between them.
OpenProject 17.3+ exposes sprints in the API v3, so we can support this natively.

Background — verified against a live instance (not assumptions)

Spiked on ephemeral openproject/openproject:17 (coreVersion 17.5.1):

  • GET /api/v3/sprints200 (HAL collection, empty on a fresh instance).
  • GET /api/v3/projects/{id}/sprints200.
  • Sprint resource fields: id, name, status (in_planning | active |
    completed), startDate, finishDate, description{raw},
    _links.definingWorkspace (the project).
  • The endpoint answered without enabling Backlogs, but per the API docs it is
    gated by a "view sprints"/backlogs permission, so tools must degrade gracefully
    when a project has no sprints / the module is off.

Proposed tools (clean implementation — NOT a port)

Read-only first (highest value, lowest risk):

Tool Description
list_sprints List sprints, optionally by project_id and status
get_sprint One sprint's details by ID
list_sprint_work_packages Work packages in a sprint (with story-point total)
list_backlog_work_packages Work packages not in any sprint (product backlog)

Optional write path (separate, only if verified):

  • sprint_id and story_points on create_work_package / update_work_package
    (+ remove_from_sprint to send a WP back to the backlog).

Design

  • New src/tools/sprints.py; client methods get_sprints(project_id, filters, offset, page_size) and get_sprint(sprint_id) in src/client.py; register in
    src/server.py. Follow existing tool conventions (Pydantic where inputs are
    structured, format_*, try/except → format_error, full docstrings).
  • Reuse the existing get_work_packages(project_id, filters, ...) for the two
    WP-listing tools rather than adding bespoke client code.

Open questions to resolve DURING implementation (verify live, don't assume)

  1. WP query filter for sprint. Is a work package filtered by sprint via a
    sprint filter identifier, a version-based filter, or something else? (Recall
    the time-entries entity_id surprise — verify the exact identifier and the
    "no sprint" / backlog operator against the instance.)
  2. Story points field. Confirm the WP attribute name (storyPoints) and whether
    it is readable/writable via the API on a stock instance.
  3. Sprint assignment write path (only if we build the write tools): how a WP is
    assigned to a sprint in the payload (_links.sprint? a version link?), and
    whether it needs the Backlogs module active.
  4. How to create a sprint for the integration test (likely a rails helper, since
    the API is read-only for sprints).

Acceptance criteria

  • The 4 read-only tools register and return sensible output (and a clear empty-state
    message when a project has no sprints / backlog).
  • Live smoke on ephemeral OpenProject 17.5.1: create a sprint + assign a WP (via a
    rails helper), then list_sprints, get_sprint, list_sprint_work_packages
    (shows the WP + story points), and list_backlog_work_packages (shows an
    unassigned WP) all return correct data.
  • Network-free unit tests for formatting + filter construction, in the existing style.
  • Any WP write params (sprint_id/story_points) are proven to round-trip before merge,
    or dropped.

Out of scope

Prior art / attribution

Independent, clean implementation. Upstream PR
AndyEverything/openproject-mcp-server#25 (@MacherelR) and issue AndyEverything#20 surfaced the
17.3+ sprint API and are acknowledged as inspiration; no code is ported from them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions