Repository navigation
fix(mcp): make move_task/bulk_move_tasks match the task-positions API - #631
DreamchaserLG wants to merge 2 commits into
Conversation
…closes Paca-AI#610) move_task and bulk_move_tasks sent target_view_id/target_status_id/ target_position, which the API's MoveTaskRequest (position, group_key) ignores entirely — so the endpoint upserted position 0 in the source view and the tools reported 'Task moved successfully' without anything moving (see Paca-AI#610). Align both tools with the task-positions API (reorder-only, as agreed in the issue): move_task takes {viewId, taskId, position, groupKey?}, bulk_move_tasks takes an items array and calls the bulk route. Cross- view/sprint/status moves now point to update_task. Tool descriptions and the mcp-server-setup guide example updated accordingly. Co-authored-by: ZCode Scout <noreply@zcode.local>
There was a problem hiding this comment.
ℹ️ No critical issues — verified the new request/response contracts against the backend DTOs; two minor cleanups below.
Reviewed changes
move_taskreorder-only fix —PacaAPIViewsClient.moveTaskPositionnow hitsPUT .../task-positions/:taskIdwith{ position, group_key? }, matchingMoveTaskRequest; it includesgroup_keyonly when!== undefined, so an explicitnullclears grouping while omission preserves it.bulk_move_tasksnow uses the bulk route — the handler mapsitemsintobulkMoveViewTaskPositions(PUT .../task-positionswith{ items }), mirroring backendBulkMoveTaskItem/BulkMoveTasksRequest.- Schemas/descriptions realigned —
items: [{ taskId, position, groupKey? }](.min(1)) and requiredposition; descriptions and success replies now say reorder-only and never claim a view/sprint/status change. - Types — phantom
BulkMoveTasksInput/MoveTaskInputreplaced withMoveTaskPositionItem. - Docs —
mcp-server-setup.mdsprint example corrected frombulk_move_taskstoupdate_task. - Tests — added client route/body coverage (incl. omitted vs explicit-
nullgroup_key) and tool-level mapping/rejection/reply assertions.
I confirmed the bodies match services/api/internal/transport/http/dto/view_dto.go:167-183 and the handler at services/api/internal/transport/http/handler/view_handler.go:343-397, so the silent no-op this PR targets is genuinely closed.
ℹ️ Old one-line tool summaries left in README.md and ALL_TOOLS.md
Two hand-maintained lists still describe the tools the way the pre-fix semantics implied, while the in-code descriptions and mcp-server-setup.md were updated. Low impact (both still scope the action to "in a view"), but worth aligning since this PR's whole point is that "move" was ambiguous.
Technical details
# Stale tool summaries after the reorder-only semantic change
## Affected sites
- `apps/mcp/README.md:328-329` — "`bulk_move_tasks` - Bulk move tasks in a view" / "`move_task` - Move a task within a view"
- `apps/mcp/ALL_TOOLS.md:75-76` — same two lines
## Required outcome
- The summaries reflect that the tools only reorder task positions within one view and cannot change a task's view/sprint/status.
## Suggested approach (optional)
- Mirror the new in-code descriptions, e.g. "`bulk_move_tasks` - Set the manual order of multiple tasks within a view (reorder only)".
- If either file is auto-generated from `getViewTools()`, regenerate instead of editing by hand.
## Open questions for the human (optional)
- Are `README.md` / `ALL_TOOLS.md` generated or hand-maintained?deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
| CreateCustomFieldInput, | ||
| CreateViewInput, | ||
| CustomFieldDefinition, | ||
| MoveTaskPositionItem, |
There was a problem hiding this comment.
MoveTaskPositionItem is imported here but never referenced anywhere in the file, so biome lint reports lint/correctness/noUnusedImports (it exits 0, so CI is not blocked, but the warning stands). It looks like the intent was to type bulkMoveViewTaskPositions's parameter: replace that method's inline Array<{ task_id; position; group_key? }> with MoveTaskPositionItem[] and the import is used; otherwise drop the import.

Summary
move_taskandbulk_move_taskssenttarget_view_id/target_status_id/target_position— none of which the task-positions API recognizes (MoveTaskRequestbinds onlyposition+group_key). Every call bound asposition: 0, upserted position 0 in the source view, returned 200, and the tools reported "Task moved successfully" while the task never moved.This PR implements option 1 (reorder-only) as agreed in #610. Closes #610.
Type of Change
Root cause & changes
PacaAPIViewsClient.bulkMoveTaskshit the single-task route (PUT .../task-positions/{taskId}) with fields the API'sMoveTaskRequestdoesn't know;bulk_move_tasksalso called the single-task route instead of the bulk route (PUT .../task-positionswith{ items }).moveTaskPosition(projectId, viewId, taskId, position, groupKey?)with the correct body;bulk_move_tasksnow mapsitems: [{ taskId, position, groupKey? }]through the existingbulkMoveViewTaskPositionsbulk-route helper.update_taskfor that"); success replies now state what actually changed.BulkMoveTasksInput/MoveTaskInputwithMoveTaskPositionItem, mirroring the backend'sBulkMoveTaskItemDTO.mcp-server-setupexample claimingbulk_move_tasks"Moves all tasks to the new sprint" — the exact misconception reported in the issue.Breaking change
Both tools' input schemas change:
targetViewId/targetStatusId/targetPositionare removed,positionis required, andbulk_move_taskstakesitems. As noted in #610, callers passingtargetViewIdwere already getting a silent no-op (position reset to 0), so there is no working behavior to preserve.Testing
biome lintandtsc --noEmit(deps aligned tobun.lock): clean.vitest run: 635 passed (baseline 630; +5 covering client route/body shapes — including omitted vs explicit-nullgroup_key— tool argument mapping, empty-itemsand missing-positionrejection, and reply wording).views-client.ts92.3→92.52% stmts / 73.91→74.64% branch;view-tools.ts100% stmts.apps/e2e,apps/web,services/agent-runnerhave zero references to the old schema; audited all 67 MCP client endpoints against the Go route table — no remaining route/field mismatches after this fix.Checklist