create_fulfillment
Mark items as shipped by creating a fulfillment record for one or more fulfillment orders. Specify per-line item quantities for partial shipments, attach tracking info, and optionally notify the customer with a shipment confirmation email.
Instructions
Mark items as shipped — creates a fulfillment record covering one or more fulfillment orders. For each fulfillment order in the request, you can either fulfill everything still remaining (omit fulfillmentOrderLineItems) or specify per-line {id, quantity} pairs for partial shipments. Optionally attach tracking info (carrier + number; URL is auto-derived for major carriers like USPS/UPS/FedEx/DHL) and set notifyCustomer=true to send the shipment-confirmation email. The fulfillmentOrderLineItem IDs come from list_fulfillment_orders. Side effects: customer-facing email if notifyCustomer is true; webhook fires; remaining quantities decrement.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| lineItemsByFulfillmentOrder | Yes | One entry per fulfillment order being fulfilled in this shipment. | |
| trackingInfo | No | Tracking info. Company+number is enough; Shopify auto-derives URL for known carriers. | |
| notifyCustomer | No | Send the customer a shipment notification email. |
Implementation Reference
- src/tools/fulfillment.ts:385-427 (handler)The handler function for the create_fulfillment tool. Calls the Shopify GraphQL fulfillmentCreate mutation with lineItemsByFulfillmentOrder, trackingInfo, and notifyCustomer. Returns the created fulfillment details.
async (args) => { const fulfillment: Record<string, unknown> = { lineItemsByFulfillmentOrder: args.lineItemsByFulfillmentOrder, }; if (args.trackingInfo) fulfillment.trackingInfo = args.trackingInfo; if (args.notifyCustomer !== undefined) { fulfillment.notifyCustomer = args.notifyCustomer; } const data = await client.graphql<{ fulfillmentCreate: { fulfillment: FulfillmentNode | null; userErrors: ShopifyUserError[]; }; }>(FULFILLMENT_CREATE_MUTATION, { fulfillment }); throwIfUserErrors(data.fulfillmentCreate.userErrors, "fulfillmentCreate"); const f = data.fulfillmentCreate.fulfillment; if (!f) { return { content: [ { type: "text" as const, text: "fulfillmentCreate returned no fulfillment." }, ], }; } const tracking = f.trackingInfo .map((t) => [t.company, t.number, t.url].filter(Boolean).join(" | ")) .filter(Boolean) .join("; "); return { content: [ { type: "text" as const, text: [ `Created fulfillment ${f.name} [${f.status}] — ${f.id}`, f.order ? ` Order: ${f.order.name} (${f.order.id})` : "", tracking ? ` Tracking: ${tracking}` : "", ] .filter(Boolean) .join("\n"), }, ], }; }, - src/tools/fulfillment.ts:212-222 (schema)Zod schema defining the input parameters for create_fulfillment: lineItemsByFulfillmentOrder (array of fulfillment order line items with optional per-item quantities), trackingInfo (optional carrier details), and notifyCustomer (optional boolean).
const createFulfillmentSchema = { lineItemsByFulfillmentOrder: z .array(lineItemByFulfillmentOrderSchema) .min(1) .describe("One entry per fulfillment order being fulfilled in this shipment."), trackingInfo: trackingInfoSchema.optional(), notifyCustomer: z .boolean() .optional() .describe("Send the customer a shipment notification email."), }; - src/tools/fulfillment.ts:381-428 (registration)Registration of the create_fulfillment tool on the MCP server via server.tool(), with name, description, schema, and handler.
server.tool( "create_fulfillment", "Mark items as shipped — creates a fulfillment record covering one or more fulfillment orders. For each fulfillment order in the request, you can either fulfill everything still remaining (omit `fulfillmentOrderLineItems`) or specify per-line {id, quantity} pairs for partial shipments. Optionally attach tracking info (carrier + number; URL is auto-derived for major carriers like USPS/UPS/FedEx/DHL) and set notifyCustomer=true to send the shipment-confirmation email. The fulfillmentOrderLineItem IDs come from list_fulfillment_orders. Side effects: customer-facing email if notifyCustomer is true; webhook fires; remaining quantities decrement.", createFulfillmentSchema, async (args) => { const fulfillment: Record<string, unknown> = { lineItemsByFulfillmentOrder: args.lineItemsByFulfillmentOrder, }; if (args.trackingInfo) fulfillment.trackingInfo = args.trackingInfo; if (args.notifyCustomer !== undefined) { fulfillment.notifyCustomer = args.notifyCustomer; } const data = await client.graphql<{ fulfillmentCreate: { fulfillment: FulfillmentNode | null; userErrors: ShopifyUserError[]; }; }>(FULFILLMENT_CREATE_MUTATION, { fulfillment }); throwIfUserErrors(data.fulfillmentCreate.userErrors, "fulfillmentCreate"); const f = data.fulfillmentCreate.fulfillment; if (!f) { return { content: [ { type: "text" as const, text: "fulfillmentCreate returned no fulfillment." }, ], }; } const tracking = f.trackingInfo .map((t) => [t.company, t.number, t.url].filter(Boolean).join(" | ")) .filter(Boolean) .join("; "); return { content: [ { type: "text" as const, text: [ `Created fulfillment ${f.name} [${f.status}] — ${f.id}`, f.order ? ` Order: ${f.order.name} (${f.order.id})` : "", tracking ? ` Tracking: ${tracking}` : "", ] .filter(Boolean) .join("\n"), }, ], }; }, ); - src/shopify/client.ts:25-54 (helper)The ShopifyClient.graphql() method used by the handler to execute the GraphQL fulfillmentCreate mutation against the Shopify Admin API.
async graphql<T>( query: string, variables?: Record<string, unknown>, ): Promise<T> { const res = await fetch(this.endpoint, { method: "POST", headers: { "Content-Type": "application/json", "X-Shopify-Access-Token": this.accessToken, }, body: JSON.stringify({ query, variables }), }); if (!res.ok) { throw new Error( `Shopify API ${res.status}: ${await res.text()}`, ); } const body = (await res.json()) as GraphQLResponse<T>; if (body.errors?.length) { throw new Error( `Shopify GraphQL errors: ${body.errors.map((e) => e.message).join("; ")}`, ); } if (!body.data) { throw new Error("Shopify returned no data"); } return body.data; } - src/tools/fulfillment.ts:123-137 (helper)The GraphQL mutation string used by the create_fulfillment handler.
const FULFILLMENT_CREATE_MUTATION = /* GraphQL */ ` mutation FulfillmentCreate($fulfillment: FulfillmentInput!) { fulfillmentCreate(fulfillment: $fulfillment) { fulfillment { id status name createdAt trackingInfo { company number url } order { id name } } userErrors { field message } } } `;