list_fulfillment_orders
View fulfillment orders for a Shopify order, revealing per-location line item quantities, locations, and destinations to identify which items to fulfill.
Instructions
List the fulfillment orders attached to a Shopify order. A fulfillment order groups line items by the location that will ship them — a single order can have multiple fulfillment orders if items split across warehouses. Each one tracks per-line remaining quantity (totalQuantity minus what's already shipped/cancelled). Returns the assigned location, destination address, and line-item progress for each. This is the primary read tool you'll call before create_fulfillment to figure out which fulfillmentOrderLineItem IDs and quantities to mark as shipped.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| orderId | Yes | Order GID to list fulfillment orders for (e.g. gid://shopify/Order/123). |
Implementation Reference
- src/tools/fulfillment.ts:262-306 (registration)Tool registration via server.tool() — registers 'list_fulfillment_orders' on the McpServer with its schema and handler callback.
server.tool( "list_fulfillment_orders", "List the fulfillment orders attached to a Shopify order. A fulfillment order groups line items by the location that will ship them — a single order can have multiple fulfillment orders if items split across warehouses. Each one tracks per-line remaining quantity (totalQuantity minus what's already shipped/cancelled). Returns the assigned location, destination address, and line-item progress for each. This is the primary read tool you'll call before create_fulfillment to figure out which fulfillmentOrderLineItem IDs and quantities to mark as shipped.", listFulfillmentOrdersSchema, async (args) => { const data = await client.graphql<{ order: | { id: string; name: string; fulfillmentOrders: { edges: Array<{ node: FulfillmentOrderNode }>; }; } | null; }>(LIST_FULFILLMENT_ORDERS_QUERY, { orderId: args.orderId }); if (!data.order) { return { content: [ { type: "text" as const, text: `Order not found: ${args.orderId}` }, ], }; } const fos = data.order.fulfillmentOrders.edges; if (fos.length === 0) { return { content: [ { type: "text" as const, text: `Order ${data.order.name} has no fulfillment orders.`, }, ], }; } const lines: string[] = [ `Order ${data.order.name} has ${fos.length} fulfillment order(s):`, ]; for (const { node } of fos) { lines.push(...summarizeFulfillmentOrder(node)); } return { content: [{ type: "text" as const, text: lines.join("\n") }], }; }, ); - src/tools/fulfillment.ts:266-305 (handler)Handler function (async callback) that executes the tool logic: queries Shopify GraphQL API for fulfillment orders of a given orderId, processes the response, and returns formatted text content.
async (args) => { const data = await client.graphql<{ order: | { id: string; name: string; fulfillmentOrders: { edges: Array<{ node: FulfillmentOrderNode }>; }; } | null; }>(LIST_FULFILLMENT_ORDERS_QUERY, { orderId: args.orderId }); if (!data.order) { return { content: [ { type: "text" as const, text: `Order not found: ${args.orderId}` }, ], }; } const fos = data.order.fulfillmentOrders.edges; if (fos.length === 0) { return { content: [ { type: "text" as const, text: `Order ${data.order.name} has no fulfillment orders.`, }, ], }; } const lines: string[] = [ `Order ${data.order.name} has ${fos.length} fulfillment order(s):`, ]; for (const { node } of fos) { lines.push(...summarizeFulfillmentOrder(node)); } return { content: [{ type: "text" as const, text: lines.join("\n") }], }; }, - src/tools/fulfillment.ts:198-202 (schema)Input schema (Zod) for the tool — defines 'orderId' as a required string described as the order GID.
const listFulfillmentOrdersSchema = { orderId: z .string() .describe("Order GID to list fulfillment orders for (e.g. gid://shopify/Order/123)."), }; - src/tools/fulfillment.ts:52-82 (helper)GraphQL query string LIST_FULFILLMENT_ORDERS_QUERY used by the handler to fetch fulfillment orders from Shopify.
const LIST_FULFILLMENT_ORDERS_QUERY = /* GraphQL */ ` query ListFulfillmentOrders($orderId: ID!) { order(id: $orderId) { id name fulfillmentOrders(first: 50) { edges { node { id status requestStatus assignedLocation { name location { id } } destination { address1 city countryCode zip } lineItems(first: 50) { edges { node { id totalQuantity remainingQuantity lineItem { id title sku } } } pageInfo { hasNextPage } } createdAt } } } } } `; - src/tools/fulfillment.ts:236-256 (helper)Helper function summarizeFulfillmentOrder used to format a FulfillmentOrderNode into human-readable text lines for the response.
function summarizeFulfillmentOrder(fo: FulfillmentOrderNode): string[] { const lines: string[] = [ ` ${fo.id} [${fo.status}/${fo.requestStatus}] at ${fo.assignedLocation.name}`, ]; if (fo.destination) { const d = fo.destination; lines.push( ` ship to: ${[d.address1, d.city, d.zip, d.countryCode].filter(Boolean).join(", ") || "(no address)"}`, ); } for (const edge of fo.lineItems.edges) { const li = edge.node; lines.push( ` - ${li.lineItem.title}${li.lineItem.sku ? ` (SKU ${li.lineItem.sku})` : ""} — ${li.remainingQuantity}/${li.totalQuantity} remaining — ${li.id}`, ); } if (fo.lineItems.pageInfo.hasNextPage) { lines.push(" (more line items available)"); } return lines; } - src/server.ts:65-65 (registration)Top-level registration call: registerFulfillmentTools(s, shopify) invoked in buildContext() to wire all fulfillment tools onto the server.
registerFulfillmentTools(s, shopify);