Skip to content

fix(mcp): make move_task/bulk_move_tasks match the task-positions API - #631

Closed
DreamchaserLG wants to merge 2 commits into
Paca-AI:masterfrom
DreamchaserLG:contribution/issue-610-1792776668
Closed

DreamchaserLG wants to merge 2 commits into
Paca-AI:masterfrom
DreamchaserLG:contribution/issue-610-1792776668

Conversation

@DreamchaserLG

Copy link
Copy Markdown

Summary

move_task and bulk_move_tasks sent target_view_id / target_status_id / target_position — none of which the task-positions API recognizes (MoveTaskRequest binds only position + group_key). Every call bound as position: 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

  • Other — bug fix: align the two MCP tools' input schemas, routes, and descriptions with the task-positions API.

Root cause & changes

  • PacaAPIViewsClient.bulkMoveTasks hit the single-task route (PUT .../task-positions/{taskId}) with fields the API's MoveTaskRequest doesn't know; bulk_move_tasks also called the single-task route instead of the bulk route (PUT .../task-positions with { items }).
  • Added moveTaskPosition(projectId, viewId, taskId, position, groupKey?) with the correct body; bulk_move_tasks now maps items: [{ taskId, position, groupKey? }] through the existing bulkMoveViewTaskPositions bulk-route helper.
  • Tool schemas/descriptions updated to reorder-only semantics ("does not change a task's view, sprint, or status — use update_task for that"); success replies now state what actually changed.
  • Types: replaced the phantom BulkMoveTasksInput / MoveTaskInput with MoveTaskPositionItem, mirroring the backend's BulkMoveTaskItem DTO.
  • Docs: fixed the mcp-server-setup example claiming bulk_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 / targetPosition are removed, position is required, and bulk_move_tasks takes items. As noted in #610, callers passing targetViewId were already getting a silent no-op (position reset to 0), so there is no working behavior to preserve.

Testing

  • biome lint and tsc --noEmit (deps aligned to bun.lock): clean.
  • vitest run: 635 passed (baseline 630; +5 covering client route/body shapes — including omitted vs explicit-null group_key — tool argument mapping, empty-items and missing-position rejection, and reply wording).
  • Coverage on the touched files: views-client.ts 92.3→92.52% stmts / 73.91→74.64% branch; view-tools.ts 100% stmts.
  • apps/e2e, apps/web, services/agent-runner have 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

  • The change is focused and scoped.
  • Related documentation is updated.
  • New structure or direction is explained clearly.
  • I avoided unnecessary detail or premature abstraction.

DreamchaserLG and others added 2 commits October 24, 2026 01:39
…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>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues — verified the new request/response contracts against the backend DTOs; two minor cleanups below.

Reviewed changes

  • move_task reorder-only fix — PacaAPIViewsClient.moveTaskPosition now hits PUT .../task-positions/:taskId with { position, group_key? }, matching MoveTaskRequest; it includes group_key only when !== undefined, so an explicit null clears grouping while omission preserves it.
  • bulk_move_tasks now uses the bulk route — the handler maps items into bulkMoveViewTaskPositions (PUT .../task-positions with { items }), mirroring backend BulkMoveTaskItem/BulkMoveTasksRequest.
  • Schemas/descriptions realigned — items: [{ taskId, position, groupKey? }] (.min(1)) and required position; descriptions and success replies now say reorder-only and never claim a view/sprint/status change.
  • Types — phantom BulkMoveTasksInput/MoveTaskInput replaced with MoveTaskPositionItem.
  • Docs — mcp-server-setup.md sprint example corrected from bulk_move_tasks to update_task.
  • Tests — added client route/body coverage (incl. omitted vs explicit-null group_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?

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

CreateCustomFieldInput,
CreateViewInput,
CustomFieldDefinition,
MoveTaskPositionItem,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] MCP: move_task and bulk_move_tasks send fields the task-positions API ignores

1 participant