Skip to content

feat(mcp): bulk_update_order_status returns per-order outcomes #34

@dougborg

Description

@dougborg

Problem

Today bulk_update_order_status returns:

```python
{
"confirmed": True,
"success": is_success(response), # 202 Accepted = True
"status_code": 202,
"note": "Bulk updates are queued and processed asynchronously.",
}
```

A reconciliation run that bulk-updates 50 orders has no way to know which 47 actually moved to the new status vs which 3 hit a viable-status check or rate-limit and silently failed. This makes the tool useless for any real "fire 50 updates and report results" workflow — the agent has to follow up with 50 individual get_order calls to verify each, defeating the bulk path.

Two implementation paths (choice depends on #30 / F3)

Path A — server returns a job_id

If the server's 202 response includes a job_id and there's a GET /jobs/{id} or similar endpoint:

  • Expose job_id in the bulk return type
  • Add a new MCP tool get_bulk_status_job(job_id) that polls the job and returns per-order outcomes
  • Optionally: bulk_update_order_status could synchronously poll until the job completes (with a timeout) and return the per-order outcomes inline — agent ergonomics > async ceremony

Path B — per-order results inline

If the server returns per-order results in the 202 response body:

  • Reshape the OpenAPI BulkStatusUpdateResponse schema to include the array
  • Reshape the MCP tool's return type to a typed BulkUpdateOutcome per order

Acceptance

  • Tool return type includes per-order pass/fail breakdown
  • Prefab UI shows a results table (one row per order: id, name, target status, outcome, error if any) — reuse the find/view/decide/mutate cluster from feat(mcp): render Prefab UI for the find/view/decide/mutate cluster #20
  • At least one integration test simulating partial failure (e.g., 1 invalid status_code among 5)
  • Help resource updated to reflect the new return shape

Breaking change

The current return shape changes. Callers reading result["success"] will see a different semantic — "request was accepted" no longer implies "all 50 moved." Callable as feat(mcp)!.

Depends on

Tracking

Part of epic #31, Tier 1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/clientTouches statuspro_public_api_client/area/mcpTouches statuspro_mcp_server/ onlyarea/specTouches docs/statuspro-openapi.yamlpriority/p0Blocks reconciliation workflow todaytheme/tool-surface-redesignMCP tool surface redesign initiativetype/breakingBreaking change for an MCP/client consumer

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions