DEV Community

Cover image for I added WebMCP to a live Stripe checkout in ~40 lines
sms-florin
sms-florin

Posted on

I added WebMCP to a live Stripe checkout in ~40 lines

Most "an AI agent buys something on a website" demos are toy stores built for the demo. I wanted to know if WebMCP could go onto a product that already takes real money — without rebuilding the checkout and without opening a security hole.

So I put it on my eSIM store. It sells data plans, has live Stripe billing, and has paying customers. Here's what that took.

What WebMCP is, in one paragraph

A web page calls document.modelContext.registerTool() to hand a browsing AI agent named, callable actions — instead of the agent reading your HTML and guessing which button to click. It's a W3C Community Group standard; ChatGPT's in-app browser added support in August 2026. No .well-known file, no manifest, no separate server. It's client-side JS.

The two tools

  • list_esim_plans — returns the live plan catalog (country, data, duration, price).
  • buy_esim_plan — takes a plan slug, creates a real Stripe Checkout session, and returns the URL to the agent. No money moves until a human enters card details on Stripe's own page. The tool starts a purchase; it doesn't complete a charge.

An agent goes from "find me a 7-day UK data plan" to a fully-formed Stripe checkout in two calls, no DOM scraping.

The registration

One client component, mounted on the page. On mount it feature-detects document.modelContext and, if present, registers the two tools. If absent — every normal browser — it's a silent no-op, so it ships to production safely. The whole file is ~40 lines of registration plus two execute() functions that each do one fetch.

Full source: https://github.com/flovoice53-tech/sms-florin-webmcp-demo

The one design decision that mattered

Not the protocol — the protocol is tiny. The decision was: the agent path reuses the human path.

The human "Buy" button and the buy_esim_plan tool both call the same createCheckoutSession() function. Same pricing, same metadata, same Stripe config. There is no separate "agent checkout" that can drift out of sync with the real one. The tool's endpoint just returns the session URL as JSON instead of doing a server-side redirect.

Safety

  • Feature-detected: no effect on any non-WebMCP browser.
  • buy_esim_plan cannot move money — worst case is a created-but-unpaid Stripe session that expires on its own.
  • The backing endpoints (GET /api/v1/esim-catalog, POST /api/v1/esim-checkout) are unauthenticated — same guest-checkout model the human form already uses — but IP rate-limited.

Result

It's live at https://flo-voice1.com/esim right now. Integration code (MIT): https://github.com/flovoice53-tech/sms-florin-webmcp-demo . 2-minute walkthrough: https://youtu.be/yd-2FVXbW8s

If you're wrapping an existing product: don't fork your checkout for the agent. Make the agent call the same function your button does.

Top comments (0)