Skip to content

Commit 87af369

Browse files
authored
feat(mcp): add batch read tools — get_orders_batch, lookup_orders_batch, summarize_active_orders (#49)
Three new read tools that fan out parallel calls under the hood when the StatusPro server has no native batch endpoint, eliminating the per-item tool-call overhead for reconciliation flows. ### get_orders_batch(order_ids: list[int]) Fetch up to 50 orders by id in one tool call. Internally uses asyncio.gather over client.orders.get; transport-layer 429 retry handles rate-limit backoff. Returns a BatchOrderResponse with one BatchOrderResult per requested id, partitioned into found vs error (not_found, etc.) so the agent can act on partial-success batches. Live timing (this tenant): 10 ids in 0.68s, 50 ids ~3-5s with rate limiting. ### lookup_orders_batch(order_numbers: list[str]) Resolve up to 50 order numbers to orders in one tool call. Internally uses list_orders(search=number) per number with EXACT-MATCH disambiguation (search is fuzzy across order_number, name, customer name, and email — blindly taking the first match risks false positives). Marks ambiguous and not-found cases explicitly so callers can see why a number didn't resolve. Useful when an external system (e.g. Katana) hands you order numbers without ids. ### summarize_active_orders() One-shot dashboard. Returns counts of non-cancelled orders by: - workflow status_code (one count per defined status) - financial_status enum (paid, partially_paid, refunded, ...) - fulfillment_status enum (fulfilled, partial, ...) - "no status set" — active orders with no workflow code Internally issues ~12 list calls in parallel; cached at the response middleware (30s TTL). Replaces the manual paginate-per- status-and-count pattern. Live timing (this tenant, 475 active orders): 2.81s. ### Out of scope - bulk_add_order_comment / bulk_update_order_due_date — server has no native bulk endpoint AND add_order_comment is rate-limited to 5/min, so a "batch" wrapper would just be slower than serial fan-out. Filed as follow-up if a real need surfaces. - True batching at the StatusPro server level — that's #32 (id[] filter), still blocked on upstream feature request per #30 probes. ### Tests 11 new tests covering schema contracts (BatchOrderResult / Response, ActiveOrdersSummary) and the exact-match disambiguation predicate used by lookup_orders_batch (the non-trivial piece — verifies search fuzziness doesn't silently produce false positives). 247 total tests pass. Help resource updated with descriptions of all three. Tools added to _READ_ONLY_TOOLS for response caching.
1 parent f23fe4a commit 87af369

5 files changed

Lines changed: 761 additions & 4 deletions

File tree

statuspro_mcp_server/src/statuspro_mcp/resources/help.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
| `list_orders` | `GET /orders` | Paginated list with filters (search, status, tags, due-date range). Auto-paginates. `search` matches order number, name, or customer fields — use it to find an order from just an order number. |
1515
| `get_order` | `GET /orders/{id}` | Full detail for one order, with the most recent `history_limit` history entries (default 50). When `history_truncated` is true, use `get_order_history` for older entries. |
1616
| `get_order_history` | `GET /orders/{id}` (client-side paged) | Page through the full history timeline of one order. Use when `get_order` indicated truncation. |
17+
| `get_orders_batch` | `GET /orders/{id}` xN (parallel fan-out) | Fetch up to 50 orders by id in one tool call. Returns per-id found/not-found results. Useful when an external system hands you a list of ids. |
18+
| `lookup_orders_batch` | `GET /orders?search=` xN (parallel fan-out) | Resolve up to 50 order numbers to orders in one tool call. Marks ambiguous matches and not-founds explicitly. Use when you have order numbers but no ids. |
19+
| `summarize_active_orders` | Multiple `GET /orders` requests (parallel, capped at 10 concurrent, cached 30s) | One-shot dashboard: counts of non-cancelled orders by workflow status, financial_status, and fulfillment_status. Internal cost is variable — 1 totals + 1 status-catalog + 1 per workflow status code + 8 financial_status counts + 4 fulfillment_status counts. |
1720
| `get_viable_statuses` | `GET /orders/{id}/viable-statuses` | Valid status transitions for the order's current state. |
1821
| `update_order_status` | `POST /orders/{id}/status` | Change status. Two-step confirm. Preview self-validates against viable transitions (one extra read to `GET /orders/{id}/viable-statuses`, cached) — invalid `status_code` is surfaced before the write `POST` that would 422. |
1922
| `add_order_comment` | `POST /orders/{id}/comment` | Add a history comment. Two-step confirm. 5/min. |

statuspro_mcp_server/src/statuspro_mcp/server.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,9 @@ def _build_auth() -> "AuthProvider | None":
224224
"list_orders",
225225
"get_order",
226226
"get_order_history",
227+
"get_orders_batch",
228+
"lookup_orders_batch",
229+
"summarize_active_orders",
227230
"list_statuses",
228231
"get_viable_statuses",
229232
]

0 commit comments

Comments
 (0)