Bygge en MCP-server for WooCommerce: en praktisk guide
Model Context Protocol gir en KI-agent en typet, introspekterbar flate å handle mot butikken på. WooCommerce har allerede et REST API under /wp-json/wc/v3/. Setter du MCP foran det, blir denne flaten noe en LLM kan kalle uten å gjette parameternavn. Det er arkitekturen jeg ruller ut for kunder som vil ha katalogen og ordreintensjonen tilgjengelig fra Claude, ChatGPT eller sin egen agent-runtime.
Artikkelen hører til tjenesten utvikling av MCP-servere og søylen Universal Commerce Protocol.
TL;DR
- MCP ligger foran WooCommerce REST som en typet JSON-RPC-flate.
- Tre verktøy dekker det meste agenten trenger:
catalogue.list,product.detail,order.intent. - Zod-skjemaer definerer hver inn- og utdata og kjører ved hvert kall.
- Map WooCommerce-felter til
schema.orgProduct og Offer, slik at agentens svar blir konsistente på tvers av flater. - Cloudflare Workers er mitt standardvalg for utrulling av MCP-servere som domineres av lesing.
Hva MCP egentlig er
Anthropic lanserte Model Context Protocol 25. november 2024 (anthropic.com/news/model-context-protocol). Det er en åpen protokoll basert på JSON-RPC 2.0 som lar en klient (en LLM-vert som Claude Desktop, en IDE eller din egen agent-runtime) snakke med en server (din MCP-implementasjon) over stdio eller HTTP med Server-Sent Events.
Tre primitiver:
- Tools. Kallbare funksjoner med typet inn- og utdata. Agenten velger én og kaller den.
- Resources. Lesbare referanser til dokumenter eller poster som agenten kan hente inn i konteksten.
- Prompts. Promptmaler levert av serveren, som verten kan kalle.
For en WooCommerce-butikk er det tools som bærer hovedtyngden. Å bla i katalogen er et verktøykall. Produktdetaljer er et verktøykall. Å foreslå en ordre er et verktøykall. Resources er nyttige når agenten trenger hele teksten i returvilkårene eller en lang produktbeskrivelse; prompts er nyttige når du vil levere ferdige interaksjoner (“foreslå tre produkter for denne kundeprofilen”).
Hvilke MCP-verktøy en WooCommerce-butikk trenger
Før jeg skriver en eneste kodelinje, lister jeg opp intensjonene agenten skal kunne uttrykke overfor butikken. For en typisk WooCommerce-butikk er listen kort:
- Bla i katalogen med filtre (
catalogue.list). - Fullstendige detaljer om ett produkt (
product.detail). - Foreslå en ordre på vegne av kunden, returnert som et utkast som et menneske bekrefter (
order.intent). - Sjekke statusen til en eksisterende ordre ut fra ordrenummer og e-postadresse (
order.status). - Spørre etter lagerbeholdning for en SKU (
inventory.check).
Hver intensjon tilsvarer nøyaktig ett verktøy. Motstå fristelsen til å eksponere wc.products.get, wc.products.list, wc.orders.create som én-til-én-innpakning av REST. Agenten har ingen nytte av REST-verb; den har nytte av intensjonsverb.
Slik definerer du MCP-verktøy i Zod
TypeScript-SDK-en i @modelcontextprotocol/sdk bruker Zod (zod.dev) til inn- og utdataskjemaer. Slik ser kontrakten for catalogue.list ut:
import { z } from "zod";
export const catalogueListInput = z.object({
query: z.string().min(2).max(200).optional(),
category: z.string().optional(),
in_stock: z.boolean().optional(),
price_min: z.number().nonnegative().optional(),
price_max: z.number().nonnegative().optional(),
page: z.number().int().min(1).max(100).default(1),
per_page: z.number().int().min(1).max(50).default(12),
});
export const catalogueListOutput = z.object({
results: z.array(
z.object({
sku: z.string(),
name: z.string(),
url: z.string().url(),
price: z.object({
amount: z.number().nonnegative(),
currency: z.string().length(3),
}),
availability: z.enum(["InStock", "OutOfStock", "PreOrder"]),
image: z.string().url().optional(),
})
),
total: z.number().int().nonnegative(),
page: z.number().int(),
});To ting er viktige her. For det første bruker utdataene schema.org-vokabularet (InStock, OutOfStock, PreOrder er verdier rett fra ItemAvailability). For det andre avviser inndataene søppel ved protokollgrensen; handleren ser aldri query: "" eller en negativ price_min.
Hvert verktøy deklarerer jeg etter samme mønster: inndataskjema, utdataskjema, handler. Handleren er en tynn adapter over /wp-json/wc/v3/. Zod kjører to ganger per kall: én gang på inndata, én gang på utdata. Sjekken av utdata fanger handlerfeil som ellers ville lekket til agenten som misdannede data.
Slik kobler du MCP-serveren til WooCommerce REST API
Handleren for catalogue.list leser fra /wp-json/wc/v3/products:
async function handleCatalogueList(input: z.infer<typeof catalogueListInput>) {
const params = new URLSearchParams();
if (input.query) params.set("search", input.query);
if (input.category) params.set("category", input.category);
if (input.in_stock) params.set("stock_status", "instock");
if (input.price_min !== undefined) params.set("min_price", String(input.price_min));
if (input.price_max !== undefined) params.set("max_price", String(input.price_max));
params.set("page", String(input.page));
params.set("per_page", String(input.per_page));
const response = await fetch(
`${WC_BASE}/wp-json/wc/v3/products?${params.toString()}`,
{ headers: { Authorization: `Basic ${WC_AUTH}` } }
);
const products = await response.json();
const total = Number(response.headers.get("X-WP-Total") ?? 0);
return catalogueListOutput.parse({
results: products.map(mapWooProductToSchemaOrg),
total,
page: input.page,
});
}Hjelpefunksjonen mapWooProductToSchemaOrg oversetter WooCommerce-feltnavn (stock_status, regular_price, permalink) til den schema.org-kompatible formen fra utdatadeklarasjonen. Feltmappingen ligger på ett sted, kalles fra ett verktøy, som kalles fra én handler. Avvik mellom WooCommerce-oppdateringer og agentkontrakten fanges av parse-kallet på utdata, ikke av produksjon.
I order.intent kaller jeg aldri WooCommerce sine skrivende endepunkter fra handleren. Verktøyet returnerer et ordreutkast som verten viser brukeren, brukeren bekrefter, og først da kaller en separat, autentisert vei POST /wp-json/wc/v3/orders. Å skrive i blinde på grunnlag av en LLM er en dårlig standard. Det passer også med GDPR art. 25 (innebygd personvern); utkastet lar deg tilpasse kjøpsknappen og markedsføringssamtykkene før operasjonen utføres.
Slik mapper du WooCommerce-felter til schema.org
To grunner til å holde verktøyenes utdata i schema.org-vokabularet:
Agenter bruker de samme ordene på tvers av kilder. Når en agent svarer på “er dette produktet tilgjengelig?”, syr den sammen en Product-entitet fra MCP-serveren din, en Offer med availability og eventuelt en Review. Hvis MCP-serveren din returnerer { "stock": "ja" } og en annen kilde availability: "https://schema.org/InStock", må agenten forene to vokabularer. Med schema.org-samsvar på din side slipper den det.
Butikkens strukturerte data snakker uansett schema.org. Din /wp-content/themes/<theme>/single-product.php (eller den headless-ekvivalenten) sender ut JSON-LD av typen Product. Holder du MCP-utdataene i samme form, serverer den samme produktsiden de samme dataene til Googles crawler, til OpenAIs crawler via URL og til agenten som kaller MCP-verktøyet ditt direkte.
Mappingen av et typisk WooCommerce-produkt ser slik ut:
| WooCommerce-felt | schema.org-felt |
|---|---|
sku | sku |
name | name |
permalink | url |
regular_price + currency | offers.price + priceCurrency |
stock_status: "instock" | availability: InStock |
stock_status: "outofstock" | availability: OutOfStock |
images[0].src | image |
description | description |
Varianter krever et ekstra lag (en hasVariant-liste av typen Product), men grunnformen er den samme.
Slik gjør du ordrer idempotente i MCP-serveren
Leseverktøyene (catalogue.list, product.detail, inventory.check, order.status) er naturlig idempotente. Tre kall gir samme svar.
order.intent er fellen. Agenten kan kalle to ganger hvis nettverket mellom svaret og verten hikker. Kontrakten jeg ruller ut:
order.intenttar imot en valgfriidempotency_key(UUID levert av verten).- Handleren lagrer nøkkelen i Workers KV med TTL på 24 timer, sammen med ID-en til ordreutkastet som ble opprettet.
- Et nytt kall med samme nøkkel returnerer det samme utkastet i stedet for å lage et nytt.
Mønsteret tilsvarer Stripes idempotens på POST /v1/charges. Det er godt forstått; agenter og mennesker har like stor nytte av det.
Slik ruller du ut MCP-serveren på Cloudflare Workers
TypeScript-SDK-en for MCP eksporterer klassen Server pluss transportadaptere. For Workers bruker jeg strømmende HTTP-transport. Inngangen til Workeren ser slik ut:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.method !== "POST") {
return new Response("Method not allowed", { status: 405 });
}
const auth = request.headers.get("Authorization");
if (!isValidAgentToken(auth, env)) {
return new Response("Unauthorized", { status: 401 });
}
const server = createWooCommerceMcpServer(env);
const transport = new StreamableHTTPServerTransport(request);
return server.connect(transport);
},
};isValidAgentToken sjekker avgrensede tokens i Workers KV. Skrivebeskyttede verktøy slipper gjennom med et token med lavere rettigheter; order.intent krever et token med scope orders:write. Autentiseringsstrategien er ett av to mønstre for MCP-autentisering.
wrangler.toml deklarerer origin-URL-en til WordPress, forbrukernøkkelen og hemmeligheten for WooCommerce (som Worker-hemmeligheter, aldri i koden) og et KV-navnerom for idempotens. Utrulling skjer med wrangler deploy. Workeren holder seg liten (godt under grensen på 1 MB komprimert bundle), fordi den bare er JSON-RPC-ruting pluss REST-adaptere.
Slik logger og overvåker du MCP-verktøykall
Hvert verktøykall logger jeg med:
- Navnet på verktøyet.
- En SHA-256-hash av inndataene (ikke selve inndataene; risiko for personopplysninger etter GDPR art. 32).
- Forsinkelse.
- Om valideringen av utdata gikk gjennom eller ikke.
- Scopet til agentens token.
Loggene går via Cloudflare Logpush til langtidslagring. To driftsvaner dette gjør mulig:
Innstramming av skjemaer. Seks uker etter lansering går jeg gjennom valideringsfeilene. Hver utdatafeil er en handlerfeil eller et WooCommerce-felt som ikke er mappet. Hver inndatafeil er enten en agent med en svakhet eller et for strengt skjema. Begge deler havner i neste utgivelse.
Kostnadsfordeling. Verktøykall er målbar belastning på WooCommerce-origin. Loggen viser hvilket agenttoken som skaper belastningen, og med hvilket verktøy. En enkelt agent som oppfører seg dårlig og går i loop på catalogue.list, er én loggspørring unna å bli identifisert.
Andre guider om MCP og WooCommerce
Denne artikkelen viser selve implementeringen. En feiltolerant arkitektur for ERP-synkronisering, Redis-køer og databasetransaksjoner er beskrevet i vår guide til arkitektur for integrasjon mellom WooCommerce og ERP 2026. Tjenestesiden er utvikling av MCP-servere. Den bredere strategien finner du i Universal Commerce Protocol.
Prisen er individuell, fordi omfanget avhenger av hvor mange verktøy du trenger, hvor komplekse WooCommerce-utvidelsene er og hvilke agent-runtimes du vil støtte.







