Memention

Borrowing a browser

Curiosity killed the cat, but imagine if it had had access to Claude.

It started with WCAG, the accessibility rules, the things keyboard and screen-reader people bump into on a page that the rest of us never notice. I had been reading a little about them and wondered if I could get Claude to build me a small site checker. Nothing serious, just to see how far I would get.

Those rules are a lot, hundreds of them, and the last thing a lazy hobbyist should do is reimplement them by hand. So I didn’t. There is a really good engine for it already, axe-core from Deque. My tool is not clever about accessibility at all, it opens a page, injects axe-core, and gets out of the way. The browser holds the door, axe-core walks in and does the reading.

How hard can it be? On the laptop, not hard. Puppeteer launches a headless Chrome, you call axe.run(), you get a report. Said and done.

But I wanted it on the Pi, the little lab in the closet that runs my agents, and a Raspberry Pi in a closet really does not want a whole Chrome bolted onto it. So how do you run a browser checker with no browser? You borrow one. The macmini in the house already runs a headless Chrome behind a little Puppeteer MCP server, so the checker ships with no Chrome at all and just drives the Mac’s browser over MCP. The Pi orchestrates, the Mac renders.

The setup: a web frontend in the cloud proxying to the always-on Pi at home, which drives a headless browser on another box and builds the report

That sounds clean written down. It was not. There is one borrowed browser, and not much machine behind it, so the runs cannot all barge in at once. They have to queue, and a run takes its time, so you cannot just hold a connection open and wait for the answer. It has to be asynchronous. Fire the job, let it find its place in the line, and come back for the result later.

In practice that meant I stopped asking for the answer and started leaving notes on the page instead. Kick off the run, stash the result on window, and walk away:

window.axe.run(document, opts)
  .then(r => { window.__wcagRes = r; window.__wcagDone = true; });

then knock once a second and ask “are you done yet?” until the note appears. Not elegant. Works.

The funny part is what MCP is for. It is meant for an AI agent to reach its tools, and here there is no model in the loop at all, just a plain Node program speaking the protocol with a straight face. I did not set out to use it backwards. It was just the door that happened to be open.

The report I had fun with too. Instead of a wall of JSON it hands back an HTML “inspection certificate”, violations grouped by severity, and for the contrast failures little live swatches with the two colors side by side so you can see why it failed.

The HTML inspection certificate, severity ledger up top

If you want to try it on a page of your own, it is running here: ai.memention.net/wcag_checker. Paste a URL, wait a moment, and you get a certificate back.

So the closet Pi has another little job now. I keep meaning to actually fix the problems it finds, instead of just admiring the certificate…

· · ·