angeo / module-mcp-checkout
Guest cart and checkout MCP tools for Magento 2. Adds create_cart, add_to_cart, get_cart, get_shipping_methods, set_shipping_information and place_order to the Angeo MCP Server, letting AI agents (Claude and other MCP clients) complete a full discovery-to-order flow with hard server-side guardrails
Package info
github.com/angeo-dev/module-mcp-checkout
Type:magento2-module
pkg:composer/angeo/module-mcp-checkout
Requires
- php: ~8.1.0||~8.2.0||~8.3.0||~8.4.0
- angeo/module-mcp-server: ^2.2
- magento/framework: >=103.0.6 <104
- magento/module-catalog: >=104.0.6 <105
- magento/module-checkout: >=100.4.6 <101
- magento/module-configurable-product: >=100.4.6 <101
- magento/module-directory: >=100.4.6 <101
- magento/module-grouped-product: >=100.4.6 <101
- magento/module-offline-payments: >=100.4.6 <101
- magento/module-offline-shipping: >=100.4.6 <101
- magento/module-payment: >=100.4.6 <101
- magento/module-quote: >=101.2.6 <102
- magento/module-sales: >=103.0.6 <104
- magento/module-store: >=101.1.6 <102
Requires (Dev)
- phpunit/phpunit: ^9.6
Suggests
- angeo/module-aeo-audit: Score whether the store is actually visible to AI shopping agents
- angeo/module-llms-txt: Generate llms.txt discovery files that point agents at the MCP endpoint
- angeo/module-ucp: Publish a /.well-known/ucp profile so UCP-compliant agents discover the checkout binding
Provides
None
Conflicts
None
Replaces
None
README
MCP Checkout for Magento 2 — AI Agent Cart & Order Tools
Six MCP tools that let an AI agent go from a product search to a placed order in a real Magento store — with every guardrail enforced server-side, at the order choke point.
angeo/module-mcp-checkout extends angeo/module-mcp-server v1.1+ with guest cart and checkout tools, so Claude or any MCP client can complete a full discovery → cart → checkout flow against Magento 2 / Adobe Commerce. No browser automation, no scraping, no headless driver that breaks on the next theme deploy.
Watch it happen: Claude places a real order in Magento 2 via MCP — full tool sequence and a real
order_numberfrom a live store.
📖 Module page: angeo.dev/modules/mcp-checkout · End-user docs: angeo.dev/docs/mcp-checkout
⚠️ This module lets an AI agent place real orders. It is disabled by default. Read the security model and set every limit deliberately before enabling it on a store with real payment methods.
Contents
- Tools
- Tool annotations
- How it plugs into module-mcp-server
- Security model
- Requirements
- Installation
- Store prerequisites
- Pay by Link
- GDPR notes
- Connecting Claude
- Design decisions
- FAQ
- Changelog
- The Angeo agentic stack
Tools
| Tool | Purpose |
|---|---|
create_cart |
Create an empty guest cart, returns cart_id |
add_to_cart |
Add a product by SKU — simple, virtual, and configurable (variant SKU, or parent SKU + options); enforces qty / item-count / order-total caps |
get_cart |
Line items and totals |
get_shipping_methods |
Estimate shipping for a destination; enforces country whitelist |
set_shipping_information |
Address + email + shipping method; returns allowed payment methods and final totals |
place_order |
Places the order; pre-flights every cap for a clear agent-facing message, then the guardrail plugin re-verifies and reserves the rate-limit slot; tags and audit-logs the order; returns a PSP payment_url when pay-by-link is in use, and replays the original order if the call is retried |
Canonical agent flow:
search_products → add_to_cart → get_shipping_methods
→ set_shipping_information → user confirms total → place_order
The SKU returned by the server's search_products / get_product feeds straight into add_to_cart.
Tool annotations
Every tool declares MCP ToolAnnotations, including a human-readable title, and they match runtime behaviour — which is what a Connectors Directory reviewer verifies:
| Tool | title | readOnly | destructive | idempotent | openWorld |
|---|---|---|---|---|---|
create_cart |
Create cart | false | false | false | false |
add_to_cart |
Add item to cart | false | false | false | false |
get_cart |
Get cart contents | true | false | true | false |
get_shipping_methods |
Get shipping methods | true | false | true | false |
set_shipping_information |
Set shipping information | false | false | true | false |
place_order |
Place order | false | true | false | true |
place_order is the only destructive tool, and the only one with openWorldHint: true — placing the order can call out to a payment provider to mint the pay-by-link. Its idempotentHint is deliberately false: a retry against the same cart is safe and returns the original order, but the same arguments against a new cart are a second, intended order, and the hint is about arguments rather than carts.
Per the MCP spec, annotations are hints for clients, not security boundaries. The security model below is what actually enforces behaviour. The matrix above is pinned by a unit test, so it cannot drift from the code without the build failing.
How it plugs into module-mcp-server
Tools implement Angeo\McpServer\Api\ToolInterface (verified against v1.0.0):
- Availability gating —
isAvailable()returns the admin enable flag, so when checkout is disabled the tools vanish fromtools/listentirely. They never appear to agents, rather than failing at call time. - Error model — business errors are thrown as
\InvalidArgumentException, which the server maps to anisErrortool result (structured, agent-readable) rather than a protocol error, exactly as the server contract requires. Internal errors are logged in full and returned as a generic actionable message; no paths or SQL ever reach the agent. - Registration —
etc/di.xmlinjects all six tools intoAngeo\McpServer\Model\Tool\ToolRegistryvia itstoolsarray argument.
No changes to module-mcp-server are required.
Security model
Disabled by default. A limit written into a system prompt is advisory; a limit enforced in PHP before the order is placed is not.
Where enforcement lives
Since 1.1.0 the guardrails are applied in Plugin\AgentOrderGuardrails, on Magento\Quote\Model\CartManagementInterface::placeOrder() — the single point every route to a placed order passes through. The checks inside the MCP tools remain as a fast pre-flight so the agent gets a specific, recoverable message, but they are not the boundary.
This matters more than it sounds. The masked cart_id handed to an agent is also a valid credential for Magento's own anonymous guest-cart REST endpoints:
POST /rest/V1/guest-carts/{cartId}/items
POST /rest/V1/guest-carts/{cartId}/shipping-information
PUT /rest/V1/guest-carts/{cartId}/order
In 1.0.x every cap lived in the tool layer, so anything holding a cart_id — a compromised agent, a leaked transcript, a verbose log — could add 500 units, ship anywhere, pick any enabled payment method and place the order outside every limit and outside the audit log. Carts created via create_cart are now flagged in angeo_mcp_agent_quote, and the plugin applies the full guardrail set to them wherever the order request originates. Carts that were not created by an agent are untouched.
Treat cart_id as a bearer token. The caps are what bound the damage if it leaks; they are no longer avoidable by changing entry point.
The guardrails
- Guest checkout only — enforced, not assumed. Carts carrying a
customer_idare rejected, as are carts belonging to another store view and carts already ordered. The blast radius of a compromised agent session is one guest cart. - Payment method whitelist, default
checkmo(offline). Online methods must be explicitly allowed. Verified atplace_orderand again at the choke point. - Order total cap (default 100, base currency) — enforced at
add_to_cartwith rollback of the offending item, and re-verified against final totals including shipping and tax when the order is placed. - Qty / cart-size caps (default 5 per item, 10 line items). The quantity cap applies to the resulting quantity, so repeated additions of the same SKU cannot stack past it, and both are re-verified at order time.
- Country whitelist for shipping (default
NL), checked at estimation, at address save, and again at order time. Independent of Magento's own allowed-countries setting — both must permit the destination. - Rate limits — global orders/hour (default 10) and per-IP orders/hour (default 10), counted per store. Slots are reserved before the order and released if it fails, so concurrent calls cannot overshoot the cap and a failing payment method cannot drain the budget. Backed by a DB table (
angeo_mcp_order_log),open_basedir-safe, doubling as an audit trail. Important: the server already rate-limits requests per client key (REMOTE_ADDR|sha256(token)), and cloud MCP clients like Claude connect from a small pool of provider egress IPs — so the global cap is the real safety valve; the per-IP cap is a best-effort secondary brake, and behind a proxy it is only as trustworthy as your forwarded-header configuration. - Safe retries — MCP clients retry tool calls on transport errors. The quote is deactivated once ordered and
CartResolverrefuses an inactive cart for mutation, so a retry cannot produce a second order; the audit row letsplace_orderresolve and return the original order withalready_placed: trueinstead of an unhelpful error. - Order tagging — every agent order gets a status-history comment identifying it as agent-placed. The client IP is kept in
angeo_mcp_order_logunder a seven-day retention rather than in the order history, which is retained indefinitely. - Demo hygiene cron — off by default. When enabled it cancels unpaid agent orders older than 24h. Offline methods such as
checkmoleave legitimate orders in exactly that state, so enable it on demo and staging only.
Known limits of the model
- Guardrails bind to carts created through
create_cart. A cart created by other means and then driven through the MCP tools is subject to the in-tool checks but is not flagged for the plugin. - The per-IP cap is advisory in any deployment behind a CDN or load balancer. Rely on the global cap.
module-mcp-serverowns bearer-token validation and per-client-key rate limiting. This module's fail-safe depends onangeo_mcp/general/require_token.
Found a vulnerability? See SECURITY.md — please do not open a public issue.
Requirements
- Magento Open Source / Adobe Commerce 2.4.6+
- PHP 8.1 – 8.4 (matches
module-mcp-server) angeo/module-mcp-server^1.1 — forToolAnnotationsInterfaceand annotation serialisation intools/list- No PSP SDKs: the pay-by-link adapters call Stripe, Mollie and Adyen REST APIs directly
Installation
composer require angeo/module-mcp-checkout bin/magento module:enable Angeo_McpCheckout bin/magento setup:upgrade bin/magento setup:di:compile bin/magento cache:flush
Configure and enable at Stores → Configuration → Angeo → MCP Checkout (AI Agents). Review every limit before enabling on a store with real payment methods.
Store prerequisites (easy to miss)
angeo/module-mcp-serverenabled (angeo_mcp/general/enabled = 1) and reachable over HTTPS.- Guest checkout on — Stores → Configuration → Sales → Checkout → Allow Guest Checkout = Yes. This module is guest-only.
- A whitelisted payment method enabled — Sales → Payment Methods → Check / Money Order (
checkmo) for demos, or Pay by secure payment link (angeo_mcp_paylink) for real money. If none is enabled,set_shipping_informationreports "no payment methods". - A shipping method + carrier enabled (e.g. Flat Rate) that serves your allowed countries.
- Cron running, for the cleanup job.
- Salable products in a supported type — simple, virtual and configurable are supported. Grouped products return actionable guidance to add the components individually; bundle and downloadable are out of scope for this release.
Pay by Link (Stripe / Mollie / Adyen)
The structural problem with agentic payments is simple: no card number may ever appear in a chat transcript — not for PCI DSS, not for GDPR, not for basic sanity. Pay by Link splits the flow:
- The agent places the order with the
angeo_mcp_paylinkpayment method; the order lands in pending payment. - The module calls the configured PSP and gets back an opaque, hosted payment link, returned by
place_orderaspayment_urlwithpayment_link_expires_at. - The agent shows the link to the customer, who pays on the PSP's own page. Magento, the MCP transport and the conversation never see payment credentials.
- The PSP webhook confirms payment and the module flips the order to processing — signature-verified, idempotent, and gated to paylink orders sitting in pending state.
- If the link is never paid the order stays pending; enable the demo cleanup cron on staging if you want those cancelled automatically, and align its age with the link validity.
Link generation is fail-soft: a PSP outage never fails an order that has already been placed. The agent is told the store will follow up, and the failure is recorded in the order comments.
Setup:
- Enable Pay by secure payment link (Sales → Payment Methods) and add
angeo_mcp_paylinkto Allowed Payment Method Codes. - In Pay by Link config, pick a provider and paste its API credentials — stored encrypted.
- Register the webhook with the PSP:
- Stripe — endpoint
https://<store>/angeo-mcp-checkout/webhook/stripe, eventcheckout.session.completed; paste the signing secret into config. - Mollie — nothing to register; the webhook URL is attached to every link automatically.
- Adyen — standard webhook to
https://<store>/angeo-mcp-checkout/webhook/adyenwith an HMAC key; paste the key (hex) into config.
- Stripe — endpoint
- Test with the PSP's test credentials first. Adyen live mode additionally needs the live URL prefix.
Scope: the webhook marks orders paid. Invoices, captures and refunds are deliberately out of scope — pair with the PSP's official Magento integration if you need the full payment lifecycle. Zero-decimal currencies (JPY, KRW, …) are rejected fail-closed rather than mischarged 100×.
Extensibility: add a PSP from any module by implementing Angeo\McpCheckout\Api\PaymentLinkProviderInterface and registering the adapter in ProviderPool via di.xml — the same pattern as the MCP tool registry.
GDPR notes
- What the PSP receives: amount, currency, and the order increment id as reference. The customer email is forwarded only on explicit merchant opt-in, for the PSP's receipt flow (Mollie payment links take no email at all). Name, address and cart contents are never sent.
- What the chat sees: the opaque payment URL and the order number. No payment credentials, ever. The tool description instructs the agent to refuse card data in conversation.
- Roles: the merchant is the controller; Stripe/Mollie/Adyen act per their own DPAs — link those from your privacy policy.
- Audit log:
angeo_mcp_order_logstores the client IP for rate limiting and fraud prevention (legitimate interest, Art. 6(1)(f)); rows are pruned after 7 days by cron, independently of the demo cleanup switch. For cloud-hosted agents the IP identifies the AI provider's egress pool, not the person. - Order status history carries no client IP — deliberately, since order comments are retained for the life of the order.
This is engineering documentation, not legal advice.
Connecting Claude
module-mcp-server exposes POST /mcp (Streamable HTTP, single request/response — no SSE, which keeps Varnish and shared-hosting compatibility trivial). Two connection paths:
Public demo (no auth) — leave angeo_mcp/general/require_token = No. In Claude: Settings → Connectors → Add custom connector → URL https://demo.angeo.dev/mcp → Add, then enable it per conversation via the "+" menu. This is the frictionless "try it yourself" path for the demo store.
Authenticated (recommended for real stores) — set require_token = Yes. Create a Magento Integration (System → Extensions → Integrations) granting only the Angeo_McpServer::agent_access resource, activate it, and use its Access Token as a Bearer token. Revoking the integration instantly cuts agent access.
Note: the claude.ai custom-connector UI negotiates OAuth, not static bearer tokens. For static-token testing use the MCP Inspector or Claude Code:
claude mcp add --transport http my-store https://your-store.example/mcp \
-H "Authorization: Bearer <token>"
For current connector steps see https://support.claude.com.
Deployment note: the server sets Cache-Control: no-store on /mcp, but add a Varnish VCL bypass for the route — full-page cache in front of /mcp is the number one Magento-specific pitfall.
Example prompt:
"I need a gift — a ceramic vase under €60, neutral colours, shipped to the Netherlands. Find options, compare them, and place the order to [address]."
Design decisions
- Magento service contracts, not HTTP self-calls —
GuestCartManagementInterface,GuestCartItemRepositoryInterface,GuestShipmentEstimationInterface,GuestShippingInformationManagementInterface,GuestPaymentInformationManagementInterface. Same code paths as core REST, no extra hop, compatible with checkout extensions built on those contracts. - Compact tool outputs with a
next_stephint on each — verbose payloads measurably degrade agent decisions and waste context. - Fail-closed everywhere — missing config, an empty payment whitelist, or a breached cap blocks the order rather than falling back to something permissive.
FAQ
Can an AI agent really place a live order? Yes — that is what the six tools do, and there is a recorded demo with a real order number. Which is precisely why every guardrail is enforced in Magento rather than requested in a prompt, and why the module ships disabled.
What stops an agent buying a thousand units?
Server-side caps: order total, quantity per item, line-item count, and orders per hour (global and per IP). All of them are re-verified inside CartManagementInterface::placeOrder(), not only when the item is added — so they hold even if the order request never goes through the place_order tool. The quantity cap applies to the resulting line quantity, so repeated small additions cannot stack past it.
Is this the same as ACP Instant Checkout?
No. ACP Instant Checkout is OpenAI's purchase flow inside ChatGPT and requires merchant approval — see module-openai-instant-checkout. MCP checkout is an open tool surface any MCP client can drive, with no approval process. Different clients, different gatekeeping, both worth having.
Why guest checkout only? So there are no stored credentials for an agent session to compromise, and no customer account to take over. It also keeps the module out of any flow that touches saved payment data.
Can I use it with online payment methods?
Technically yes — the whitelist is configurable. Do it only after you have exercised the flow on staging and reviewed the caps, and review it against your own PCI scope. The default is offline (checkmo) for a reason.
Does it support configurable or bundle products?
Configurable, yes — either by the exact variant SKU or by the parent SKU plus an options map; an incomplete selection comes back with every required attribute and its available values, so the agent can correct itself in one more call. Grouped products return the component SKUs to add individually. Bundle and downloadable are still out of scope.
How does the agent pay without handling card data?
It doesn't handle card data at all. With pay-by-link enabled, place_order returns a payment_url to a page hosted by Stripe, Mollie or Adyen, and the customer pays there. Card tokenisation needs a PCI-compliant browser form, so the agent flow stays outside PCI scope entirely.
What happens if the agent retries place_order?
It gets the order that was already placed, with already_placed: true — not a duplicate and not an error. The cart is deactivated at order time, so a second order from the same cart is impossible regardless of how the retry arrives.
Do I need this to appear in ChatGPT or Claude? No. Discovery and transaction are separate problems. This closes the transaction loop once agents can already find you — start with an AEO audit to see whether they can.
The Angeo agentic stack
MIT-licensed, no paid tier, no licence key.
| Layer | Module |
|---|---|
| Crawler access | module-robots-txt-aeo |
| Discovery files | module-llms-txt |
| Structured data | module-rich-data |
| ChatGPT Shopping feed | module-openai-product-feed |
| Live agent access | module-mcp-server |
| Agent checkout | module-mcp-checkout ← you are here |
| UCP profile | module-ucp · module-ucp-catalog |
| Measurement | module-aeo-audit |
All thirteen modules: https://angeo.dev/modules/
Support
Issues and feature requests: GitHub Issues. Security reports: SECURITY.md — not a public issue. Implementation and audits: info@angeo.dev
License
MIT — see LICENSE.