5 Of 14 Vendor Portals Became MCP Clients In 3 Weeks

Abstract tech illustration: 5 Of 14 Vendor Portals Became MCP Clients In 3 Weeks

Google I/O 2026 sold WebMCP as a developer-experience upgrade. For the invoice pipeline I run for a small-business accounting client, it was a forced migration in three weeks — and it exposed which of the three headline updates actually touches a production scraping stack this quarter.

Here's the baseline so the numbers mean something. The pipeline pulls invoices from 14 vendor portals, roughly 340 documents a week, feeds them through OCR and line-item extraction, and hands the output to an SMB accounting product. Playwright drives the scraping, Claude Haiku plus a local model handles classification, and n8n stitches the orchestration together. That's what I measured Google I/O 2026 against — not a demo repo, a stack a real client depends on every Monday morning.

WebMCP forced a rewrite on 5 of 14 vendors in 3 weeks

WebMCP lets a website expose structured tool endpoints that AI agents call directly instead of scraping the DOM. Within three weeks of the keynote, five of my 14 vendor portals shipped MCP endpoints. That is not a slow migration — that is a forced one, because once a portal exposes structured tools, the DOM starts drifting, selectors break, and the polite path forward is to switch clients.

I rewrote the scraper for those five. The Playwright code was 840 lines: login flows, pagination, table parsing, PDF download, retry logic. The MCP client version is 312 lines. Extraction accuracy on those five portals went from 94.1% to 99.6%, because I stopped parsing rendered HTML and started calling a tool that returns typed invoice objects.

# Before: Playwright selector-driven extraction
async def extract_invoice_rows(page):
    await page.wait_for_selector("table.invoice-lines tbody tr", timeout=15000)
    rows = await page.query_selector_all("table.invoice-lines tbody tr")
    out = []
    for r in rows:
        cells = await r.query_selector_all("td")
        out.append({
            "sku":  (await cells[0].inner_text()).strip(),
            "desc": (await cells[1].inner_text()).strip(),
            "qty":  float((await cells[2].inner_text()).replace(",", ".")),
            "net":  float((await cells[3].inner_text()).replace(",", ".")),
        })
    return out
# After: MCP tool call, typed response
async def extract_invoice_rows(mcp, invoice_id: str):
    result = await mcp.call_tool(
        "get_invoice_lines",
        {"invoice_id": invoice_id}
    )
    return result.lines  # already typed: sku, desc, qty, net, tax_code

One caveat. The other nine portals have not moved, and probably won't for a year. The real production state is a hybrid pipeline — half MCP client, half Playwright — and the orchestration layer now has to route per vendor.

What actually changed on those five portals

  • Line count: 840 → 312 (-62.9%)
  • Accuracy: 94.1% → 99.6%
  • Retry logic: gone (typed errors instead of selector timeouts)
  • PDF download: still Playwright — MCP tools return metadata, not the binary

Gemini Nano in Chrome killed a $23/mo classification call

The Nano runtime shipped into Chrome got demoed as a summarization toy. The useful angle for a small-business pipeline is client-side line-item classification. Previously, every extracted invoice line ran through a Claude Haiku call to tag it as materials, service, tax, or discount. Cheap per call — but 340 invoices a week × ~11 lines each = roughly $23/month in API spend, plus round-trip latency.

I moved that call into a headless Chrome worker on the same box. The entire external API hop is gone.

Metric Claude Haiku (before) Gemini Nano in Chrome (after)
Cost/month ~$23 $0
Latency per line 380–520 ms 40–70 ms
Classification accuracy 97.2% 95.8%
Failure mode rate limit / timeout none observed in 3 wks

Accuracy dropped 1.4 points, which sits inside my tolerance because a human reviews flagged lines anyway. Twenty-three dollars a month is not a headline. But it's a recurring cost off the books, and the latency drop matters when a customer is watching a progress bar refresh on the invoice-review screen.

If you don't already run a Chrome worker, spinning one up just for Nano is not worth it — you'll spend more on the container than you save.

Skills in Chrome: not production ready, revisit in 6 months

Google positioned Skills as reusable agent capabilities the browser can invoke. I tested it against the operator dashboard the accounting team uses — the one where a human clicks through flagged invoices and corrects them. The idea was to let a Skill handle the correction workflow end to end.

It's not production ready.

  • The Skills API throws permission prompts on every meaningful action. Fine for a personal agent, useless for an operator processing 60 flagged lines an hour.
  • The audit trail is thin. For an accounting workflow you need "who changed this field, when, from what value, to what value." Skills logs "action invoked."
  • It can't reliably persist state between sessions the way an n8n workflow can. Halfway through a batch, session dies, state is gone.

I kept the existing n8n flow. Revisit in six months. If you're running any workflow where an auditor could eventually ask "prove this," don't put it behind Skills yet.

Honest scorecard against a live 340-invoice-a-week pipeline

One of the three updates is a real, measurable win today, and it's the one that also happens to shrink the codebase. One is a small cost cut worth doing if you already run Chrome workers. One is six months out.

Update Codebase impact $ impact Accuracy impact Ship this quarter?
WebMCP -528 lines on 5/14 vendors ~$0 direct (Playwright infra stays) +5.5pts on migrated vendors Yes, if your vendors moved
Nano in Chrome ~40 lines added -$23/mo -1.4pts Only if you already run Chrome workers
Skills in Chrome 0 0 n/a No — 6 months out

If you were watching the keynote wondering which announcement to actually integrate this quarter, WebMCP is the only one that pays back inside 90 days, and only if your vendors are moving. Check your top three data sources. If any of them shipped an MCP endpoint, the migration is straightforward and the accuracy gain is real. If none of them have, sit tight and don't rewrite anything.

The governance shift nobody put in the keynote slides

WebMCP was sold as a developer-experience upgrade. For anyone running scraping or OCR against third-party portals it's a governance shift. Vendors now decide what your agent sees, and the ones that ship MCP first will quietly deprecate the scrapable version of their site. That's fine when you're a small builder wiring up five clean endpoints. It becomes a problem the first time a vendor changes the shape of a returned object and every downstream pipeline breaks at once.

Build the abstraction layer now. Don't wire MCP tool calls directly into business logic.

# vendor_adapter.py — one interface, two backends
class VendorAdapter(Protocol):
    async def list_invoices(self, since: date) -> list[InvoiceRef]: ...
    async def fetch_invoice(self, ref: InvoiceRef) -> Invoice: ...

class MCPVendorAdapter:
    def __init__(self, mcp_client, vendor_id): ...
    async def fetch_invoice(self, ref):
        raw = await self.mcp.call_tool("get_invoice", {"id": ref.id})
        return normalize_invoice(raw, source=self.vendor_id)

class PlaywrightVendorAdapter:
    def __init__(self, browser, vendor_id): ...
    async def fetch_invoice(self, ref):
        raw = await scrape_invoice(self.browser, ref)
        return normalize_invoice(raw, source=self.vendor_id)

# Business logic never sees which backend ran
adapter = registry.get(vendor_id)  # MCP or Playwright, doesn't matter
invoice = await adapter.fetch_invoice(ref)

The normalize_invoice step is where you eat vendor schema drift. When a vendor version-bumps their MCP tool from net_amount to amount_net, one file changes. When another vendor still on Playwright renames a table column, one file changes. Business logic downstream doesn't know or care.

This is also where you version-pin. MCP tools are just as capable of shipping a breaking change as an HTML DOM was — the difference is the change is now silent (typed field renamed) instead of loud (selector 404). Pin the tool schema you validated against, and fail loudly on drift.

Why bizflowai.io helps with this

The hybrid-vendor problem — some sources on MCP, some on scraping, some on APIs, all feeding one accounting or ops workflow — is exactly the shape of pipeline we build for SMB clients at bizflowai.io. The abstraction layer, per-vendor routing, and human-in-the-loop review queue for flagged extractions are the parts that take longest to get right and the parts a small business shouldn't be maintaining in-house. If your invoice or document pipeline is stitched together with brittle selectors and you're staring at a keynote wondering what to migrate first, that's the conversation.


Want more like this?

I publish practical AI automation, GenAI engineering, and faceless content workflows on YouTube every week.

Subscribe to bizflowai.io on YouTube — never miss a new tutorial.

Planning an AI automation project or need a second opinion on your architecture?

Connect with me on LinkedIn — Lazar Milicevic, GenAI Engineer & bizflowai.io Founder.

Visit bizflowai.io for our services, case studies, and AI consulting.

Frequently asked questions

What is WebMCP and why does it matter for web scraping pipelines?

WebMCP lets websites expose structured tool endpoints that AI agents call directly, instead of scraping the DOM. For scraping pipelines, it's a governance shift: vendors decide what agents see, and once a portal ships MCP, its DOM starts drifting and selectors break. In one production pipeline, migrating five Serbian vendor portals to MCP cut scraper code from 840 to 312 lines and raised extraction accuracy from 94.1% to 99.6%.

How do I decide whether to migrate a Playwright scraper to a WebMCP client?

Check your top three data sources. If any vendor has shipped an MCP endpoint, migrate those specifically, because the DOM will drift and selectors will break anyway. Expect roughly a 60% code reduction and meaningful accuracy gains from receiving typed objects instead of parsing HTML. If none of your vendors have shipped MCP endpoints, don't rewrite anything yet. A hybrid pipeline routing per vendor is the realistic outcome.

Why move line-item classification to Chrome's built-in Gemini Nano instead of Claude Haiku?

Running Gemini Nano client-side in a headless Chrome worker eliminates per-call API costs and latency. For a pipeline processing 340 invoices per week at about eleven lines each, moving classification off Claude Haiku saved roughly twenty-three dollars a month and removed network latency from a customer-facing progress bar. Accuracy dropped from 97.2% to 95.8%, which is acceptable when a human already reviews flagged lines.

Is Chrome Skills ready for production agent workflows?

No. Chrome Skills is not production ready as of Google I/O 2026. The API triggers permission prompts on every meaningful action, the audit trail is thin, and it cannot reliably persist state between sessions the way an n8n workflow can. For existing operator dashboards and correction workflows, keeping n8n orchestration is the better choice. Revisit Skills in about six months.

When should I use MCP clients vs Playwright for vendor portal scraping?

Use an MCP client whenever a vendor exposes structured tool endpoints, because you get typed objects, less code, and higher extraction accuracy. Keep Playwright for portals that haven't shipped MCP, since DOM scraping remains the only option. Most real pipelines will be hybrid for at least a year, with an orchestration layer routing per vendor based on which interface each portal supports.