update_order
Update order metadata: email, tags, note, or custom attributes. Tags and custom attributes are fully replaced—read current values first to merge. Use for fixing email typos, adding fulfillment notes, or attaching internal tags.
Instructions
Update an existing order's metadata: email, tags, internal note, or custom attributes. Most order fields are immutable post-creation in Shopify (line items, totals, customer-of-record can't be changed via the Admin API after the fact) — for those, use refund_order or cancel_order to back out, then create a corrected order. Tags and customAttributes are full replacements: read the current values first if you want to merge rather than replace. Use when fixing a typo'd email, adding a fulfillment-team note, or attaching internal segmentation tags.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Order GID or numeric ID to update. Most order fields are immutable post-creation; only the metadata fields below can be edited via this tool. | |
| No | New customer email. Pass to update or fix the contact email. | ||
| tags | No | New tag set. REPLACES the existing tags entirely. Read current tags first if you want to merge rather than replace. | |
| note | No | New internal staff note. Replaces any prior note. | |
| customAttributes | No | Custom attributes (cart attributes / order notes). Replaces the entire set if provided. |
Implementation Reference
- src/tools/orders.ts:216-243 (schema)Schema definition for the update_order tool's input parameters: id (required), email, tags, note, and customAttributes (all optional).
const updateOrderSchema = { id: z .string() .describe( "Order GID or numeric ID to update. Most order fields are immutable post-creation; only the metadata fields below can be edited via this tool.", ), email: z .string() .email() .optional() .describe("New customer email. Pass to update or fix the contact email."), tags: z .array(z.string()) .optional() .describe( "New tag set. REPLACES the existing tags entirely. Read current tags first if you want to merge rather than replace.", ), note: z .string() .optional() .describe("New internal staff note. Replaces any prior note."), customAttributes: z .array(z.object({ key: z.string(), value: z.string() })) .optional() .describe( "Custom attributes (cart attributes / order notes). Replaces the entire set if provided.", ), }; - src/tools/orders.ts:434-467 (handler)Handler function for update_order that builds the input object, calls the ORDER_UPDATE_MUTATION GraphQL mutation, and returns a success message with the order name and ID.
async (args) => { const input: Record<string, unknown> = { id: toGid(args.id, "Order") }; if (args.email !== undefined) input.email = args.email; if (args.tags !== undefined) input.tags = args.tags; if (args.note !== undefined) input.note = args.note; if (args.customAttributes !== undefined) { input.customAttributes = args.customAttributes; } const data = await client.graphql<{ orderUpdate: { order: { id: string; name: string; email?: string | null; tags?: string[] | null; note?: string | null } | null; userErrors: ShopifyUserError[]; }; }>(ORDER_UPDATE_MUTATION, { input }); throwIfUserErrors(data.orderUpdate.userErrors, "orderUpdate"); const o = data.orderUpdate.order; if (!o) { return { content: [ { type: "text" as const, text: "orderUpdate returned no order." }, ], }; } return { content: [ { type: "text" as const, text: `Updated order ${o.name} — ${o.id}`, }, ], }; }, ); - src/tools/orders.ts:59-72 (helper)GraphQL mutation ORDER_UPDATE_MUTATION that sends OrderInput to Shopify's orderUpdate endpoint, returning id, name, email, tags, note, and userErrors.
const ORDER_UPDATE_MUTATION = /* GraphQL */ ` mutation OrderUpdate($input: OrderInput!) { orderUpdate(input: $input) { order { id name email tags note } userErrors { field message } } } `; - src/tools/orders.ts:430-467 (registration)Registration of the 'update_order' tool on the MCP server via server.tool() with its name, description, schema, and handler function.
server.tool( "update_order", "Update an existing order's metadata: email, tags, internal note, or custom attributes. Most order fields are immutable post-creation in Shopify (line items, totals, customer-of-record can't be changed via the Admin API after the fact) — for those, use refund_order or cancel_order to back out, then create a corrected order. Tags and customAttributes are full replacements: read the current values first if you want to merge rather than replace. Use when fixing a typo'd email, adding a fulfillment-team note, or attaching internal segmentation tags.", updateOrderSchema, async (args) => { const input: Record<string, unknown> = { id: toGid(args.id, "Order") }; if (args.email !== undefined) input.email = args.email; if (args.tags !== undefined) input.tags = args.tags; if (args.note !== undefined) input.note = args.note; if (args.customAttributes !== undefined) { input.customAttributes = args.customAttributes; } const data = await client.graphql<{ orderUpdate: { order: { id: string; name: string; email?: string | null; tags?: string[] | null; note?: string | null } | null; userErrors: ShopifyUserError[]; }; }>(ORDER_UPDATE_MUTATION, { input }); throwIfUserErrors(data.orderUpdate.userErrors, "orderUpdate"); const o = data.orderUpdate.order; if (!o) { return { content: [ { type: "text" as const, text: "orderUpdate returned no order." }, ], }; } return { content: [ { type: "text" as const, text: `Updated order ${o.name} — ${o.id}`, }, ], }; }, ); - src/server.ts:58-58 (registration)Top-level call to registerOrderTools which registers all order tools including update_order on the MCP server.
registerOrderTools(s, shopify);