Add project board tools (projects, columns, cards) #13
Labels
No labels
status/paused
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jbr870/forgejo-mcp-server#13
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The MCP server lets agents manage issues, comments, labels, and wiki pages on a Forgejo repo, but it has no coverage for Forgejo's project boards. As a result, an agent can create and label an issue but cannot place it on a board, move it across columns as work progresses, or set up the board itself. Anyone using boards to coordinate work has to drop out of chat and into the Forgejo web UI to do anything board-related, which breaks the "fully agentic repo workflow" story.
It is now feasible to close this gap: upstream Forgejo recently landed a complete project-board REST API (forgejo/forgejo PR #9384) covering CRUD for projects, columns, and cards including reordering. Source: Forgejo issue #13.
Users:
Current state: All board operations (creating projects, adding/renaming/recoloring columns, placing issues on boards, moving cards) happen exclusively in the Forgejo web UI. The agent has no way to observe or modify board state.
Proposed Solution
Add MCP tools that wrap the Forgejo project-board REST API end-to-end. The tools live in a new
src/tools/projects.pymodule alongside the existing tool families and follow the same plumbing already proven byissue-10-label-management:ForgejoClientfor HTTP,_resolve_token_and_instancefor per-user auth,_validate_owner_repofor input hardening, and the standard{"error": "..."}shape forForgejoConnectionError/ForgejoAPIError.The surface covers three resources:
/api/v1/repos/{owner}/{repo}/projects) and org-scoped (/api/v1/orgs/{org}/projects). Repo and org scopes are exposed as separate, explicitly-named tools (list_repo_projectsvslist_org_projects,create_repo_projectvscreate_org_project, etc.) so each tool's parameters are unambiguous. This continues the explicit-naming precedent fromissue-11.add_issue_to_project(lands in the project's default column),remove_issue_from_project,move_card(column + position; this is the only "assign to column" primitive in the underlying API),list_column_cards. The two primitives are kept separate; their tool descriptions explicitly document the two-step "add then move" pattern so agents can sequence them without us hiding a non-atomic composite.Scope: Full — all three resources, both scopes for projects, no functionality deferred to a follow-up. Each individual tool is a thin wrapper over a single Forgejo endpoint, which matches the
issue-10pattern that landed cleanly in one feature.User Stories
Acceptance Criteria
list_repo_projects, then the response contains every project on the repo with at leastid,title,description, andstate.list_org_projects, then the response contains every project on the org with the same fields.create_*_projecttool, then the project is created on the correct scope and the response contains the created project with its assigned id.list_project_columns, then the response contains every column withid,title,color, and a flag indicating which column is the default.create_column/update_column/delete_column, then the column is created / partially updated / removed and subsequent list calls reflect the change.set_default_column, then that column becomes the project's default and a subsequent project / column listing reflects the new default.add_issue_to_project, then a card representing that issue appears on the board in the project's default column.move_cardwith a targetcolumn_idandposition, then the card moves to that column at that position and a subsequentlist_column_cardsreflects the move.remove_issue_from_project, then the card is removed from the board and a subsequentlist_column_cardsdoes not include it.list_column_cards, then the response contains every card in that column with at least the linked issue's index/id and the card's position.{"error": "Forgejo API error <code>: <detail>"}shape.{"error": "Cannot connect to Forgejo: ..."}shape.ForgejoAPIError(no custom version-probe layer).Out of Scope
add_issue_to_projectandmove_cardas distinct primitives mirrors the underlying API; tool descriptions document the two-step pattern. A composite would hide a non-atomic two-step.issue-10-label-management.Dependencies
ForgejoClientinsrc/forgejo_client.py— will be extended with project / column / card methods._resolve_token_and_instanceand_validate_owner_repohelpers insrc/tools/_resolve.py.src/tools/projects.pymodule with aregister_project_toolsentry point, wired intosrc/tools/__init__.py:register_toolsalongside the existing fourregister_*_toolscalls.Notes
issue-10-label-managementprecedent.list_repo_projects/list_org_projects, etc. — each tool's parameters are unambiguous, continuing the explicit-naming precedent fromissue-11-standardize-param-names.add_issue_to_project+move_cardstay as primitives; tool descriptions document the two-step pattern.get_project/update_project/delete_project(whether they're scope-prefixed or use the global project id), the precisemove_cardpayload shape, default-column toggling semantics, and which Forgejo version pins as the minimum — are deferred to/technical-plan.Status: paused (2026-04-24)
Pause reason — upstream API not merged
The PREQ's premise (referenced in the issue description) is that Forgejo has a complete project-board REST API ready to wrap. Research during
/technical-planshows this is not yet the case:Direct inspection of
https://code.forgejo.org/swagger.v1.jsonconfirms: no paths under/projects,/columns, or/cardsexist in the shipping OpenAPI spec as of 2026-04-24.Building the MCP tools against the closed PRs' draft shape would ship 13 agent-facing tools that return
404on every real Forgejo instance. Unit tests (mocked) would pass; every live invocation would fail. Not a useful shipping state.SREQ — summary
Full technical plan lives on branch
feature/issue-13-project-board-toolsatdevwork/backlog/issue-13-project-board-tools/SREQ.md. Key decisions captured so the work can resume without starting from scratch:src/tools/projects.pywithregister_project_tools, organised into three comment-separated sections (projects / columns / cards). Mirrors theissue-10-label-managementprecedent./api/v1/repos/{owner}/{repo}/projects[/:id]and/api/v1/orgs/{org}/projects[/:id]./api/v1/projects/{project_id}/columns[/:column_id]— globally keyed on project id./api/v1/columns/{column_id}/cards,POST /api/v1/cards/{card_id}/movewith{"column_id": <int>, "position": <int>},DELETE /api/v1/cards/{card_id}— globally keyed on column / card id.add_issue_to_projectis a two-step: resolve project default column, thenPOST /columns/{column_id}/cards. Tool returns the resolvedcolumn_idfor auditability (TOCTOU is possible if default column changes between calls).remove_issue_from_projectis a three-step composite: list columns → list cards per column →DELETE /cards/{card_id}. Non-atomic, O(columns × cards). Tool returnsdeleted_card_idfor idempotent retry on partial failure. Alternative primitive (remove_card_by_id) explicitly rejected — PREQ names the tool by issue, not card.list_repo_projects/list_org_projects, etc.), perissue-11precedent._validate_org+_validate_positive_inthelpers insrc/tools/_resolve.py, both built on the same character-test helper as_validate_owner_repo(no re-implementation — the/simplifydrift noted in CLAUDE.md was the reason for unifying).Total tool surface on resume: 13 tools across three resources. 21 acceptance criteria (19 from PREQ + 2 from expert review: integer-ID bounds, shared-validator parity).
Resume trigger
Unpause when a Forgejo release ships REST handlers under the paths above. On resume:
devwork/backlog/todevwork/in-development/./develop.Tracked upstream: