Inspiration
What it does## Inspiration
Everyone who opens an Arduino kit hits the same wall in the first hour. The LED doesn't light. The wire is one hole off, or the resistor is in the wrong row, and the PDF that came with the kit can't tell you which. You take a photo, paste it into a chat, and the answer is a guess about a blurry picture.
I wanted the agent to stop guessing. If the page that draws the breadboard already knows where every lead is, the agent should read that, not the pixels. WebMCP is exactly the missing piece: the page hands the agent a small set of tools, in the page's own vocabulary, and the agent works on the same build you're looking at.
What it does
PilotCircuits is a guided Arduino workbench for beginners. Six chapters, each adding one idea: a breathing lamp, a traffic light, a motion night-light, a plant guardian, a touchless soap dispenser, and a pre-built parking barrier as the capstone. You wire each one by hand on a simulated bench, dragging real-looking parts off a kit shelf into breadboard holes and header pins.
An agent connected through WebMCP sees the same bench. On the workbench it can:
explain_project— say what the chapter is for and what each part doesinspect_build— compare your wiring against the sketch and list what's offshow_correction— pan the camera to the lead at faultpoint_at— frame any part, pin or hole you ask about, without touching anythingattach_lead— the one tool that changes the build: seat a lead, or pull it looseverify_current_step,navigate_build_step,run_functional_test— walk the steps and run the chapter's own checks
Two things on screen tell you what the agent is doing. A ring on the bench shows where it is working, and a small LED-shaped coach in the corner shows what: reading, thinking, pointing, testing, and a happy face when the test passes.
What's new here is the division of labour. You build. The agent checks the build against the plan, shows you the mistake on the board itself, and if you say "fix it", it moves the lead through the same code path your own drag would take. You can undo its move. Neither side is watching a screenshot of the other.
It works as a normal web app without a WebMCP host, and it's fully localised in English and Turkish, tool descriptions and refusal messages included.
How I built it
Next.js 16, React 19, TypeScript, Tailwind. The breadboard, Uno and component artwork is ported from Wokwi Elements (MIT). Deployed on Vercel at https://pilotcircuits.com.
The WebMCP layer lives in src/lib/agent/webmcp.ts and a React hook around it. Tools are registered with navigator.modelContext inside an effect, per route, and torn down when the route changes: the library registers the search and open tools, the workbench registers the nine above, and nothing is offered on a page that can't act on it. When the build or the language changes, every tool re-registers with the new descriptions. Thirteen tool names in total.
Every tool call goes through the same queue as the buttons in the UI, so an agent's attach_lead and a person's drag are literally the same operation, with one activity log and one undo stack. Every handler validates its own input and returns refusals as data the model can act on ("no finding has that id, the ids come from inspect_build"), not as thrown errors. The AbortSignal the host passes is honoured, so a cancelled call doesn't keep moving the bench after the agent walked away.
The "Connected via WebMCP" badge only lights up when registerTool actually resolved, not when the API merely exists.
971 unit tests across 28 files cover the circuit model, the tool handlers, the step verification and the copy.
Challenges I ran into
For most of the build, no browser shipped WebMCP. The whole layer was written against the spec and a fake host. The first time it ran in a real host (Chrome with the WebMCP flags, driven by Playwright) was one day before the deadline, and that run changed things. Chrome passed my MCP-style result envelope straight to the model as text: 6,618 characters for 2,425 characters of payload, with isError reaching nobody. I switched every tool to return bare JSON. Chrome also doesn't validate arguments against inputSchema, so the handlers had to.
ChatGPT's in-app browser is a split pane. Below 1120 px the bench has no room for a canvas, so a narrow window registers only the five tools that make sense without one. I couldn't measure the pane itself, so the README says it out loud.
The bench itself was the other half of the work: pointer capture on drags, the view panning under a lead mid-carry, a cable router that turned hairpins on every stub. And the first draft of the mascot looked too much like someone else's mascot. It went in the bin, and the lamp took its place.
Accomplishments that I'm proud of
Watching ChatGPT desktop, connected over WebMCP, take a jumper I'd plugged in wrong on purpose, find both bad ends, move the cable, then build the remaining 18 connections of the traffic light off the shelf and pass the functional test. That's the demo video, and none of it is scripted on the page's side.
Also: tool descriptions that tell the truth. attach_lead's description says what it costs, because that string is the only channel that reaches the model.
What I learned
Measure against the real host. My reading of the spec was reasonable and wrong in three places, and each one was visible within minutes of running Chrome with the flag.
A face that mirrors a 300 ms tool call is invisible. The coach holds each mood for at least 1.2 seconds, because it's a presentation for the person, not a debugger for the agent.
And the description field of a tool is documentation for a reader who can't open the source. Write it like that.
What's next for PilotCircuits
A real board beside the simulated one, so the last step of a chapter is flashing the sketch to the Uno on your desk. More chapters past the capstone. And a way for the agent to write a chapter: given a parts list, produce the steps, the sketch and the checks in the same format the six existing ones use.
Built With
- arduino
- chatgpt
- cloudflare
- javascript
- motion
- next.js
- node.js
- playwright
- react
- svg
- tailwindcss
- typescript
- vercel
- vitest
- webmcp
- wokwi
Log in or sign up for Devpost to join the conversation.