Inspiration
Everyone repeats the same warning — "don't paste your bank statement into a chatbot" — and yet AI is genuinely good at exactly that kind of analysis. The blocker was never capability; it's that every normal path (upload the file, paste the rows, sync to a server) copies your raw records out of your hands before any analysis happens. WebMCP hinted at a different shape entirely: what if the agent could call tools that run inside the page and receive only the answers? I wanted to find out whether a hosted AI could analyse something as sensitive as a year of personal spending — or a payslip — without ever receiving it.
What it does
Airlock is a private, in-browser data workbench. You load a CSV with date, description, category and amount columns and it's parsed and analysed entirely inside your browser tab. The page registers seven WebMCP tools — describe_dataset, sum_by_category, filter_rows, monthly_trend, find_anomalies, top_expenses, clear_highlights — and an agent (ChatGPT's in-app browser, or Chrome with WebMCP enabled) calls them and gets back only aggregates. Ask "what am I spending most on?" or "is anything unusual?" and it answers with real numbers, while the rows it's reasoning about are highlighted in your own table for you to read. On the bundled synthetic year of spending — 965 transactions across 12 categories — it isolates the four genuinely unusual charges by per-category z-score. Open DevTools during the conversation and the network panel stays empty.
How I built it
Plain TypeScript and Vite, papaparse for CSV, no backend — a backend would undercut the whole premise. Tools are registered with document.modelContext.registerTool, each reading from a module-level store so handlers never close over stale state. The load-bearing design decision is privacy mode: it ships on by default, so the row-returning tools answer with counts, totals and category names instead of row contents, describe_dataset even withholds the file name, and only the human can lower the gate — no tool is registered to change it, because a consent gate the agent can open by itself isn't one. It also re-arms to on every time a new file is loaded, so a fresh, more sensitive file never inherits a previous "off."
Challenges I ran into
The sharpest one was a flaw in my own premise, caught mid-build: "the file stays in the tab" only rules out an upload — anything a tool returns reaches the model anyway. That redesigned the entire project around drawing the privacy boundary at the answer, not the file. Others: proving it to a real external agent rather than self-invocation, which I did by driving the live tools through Chrome's experimental WebMCP CDP domain, the same path a real MCP client takes; a WebMCP quirk where a thrown error reaches the agent as a generic failure, so I return errors as values to keep the recovery hints; and a consent footgun where turning privacy off then loading a new file left it exposed — fixed by the re-arm-on-load behaviour above.
What I learned
WebMCP's real novelty isn't "tools on a web page" — it's that computation happens where the data lives, which is what makes it possible to keep the raw data and still get the analysis. I also learned that privacy is about control, not lockout: a default-safe, human-controlled, reversible gate is a far better model than all-or-nothing. And that a WebMCP project is only truly proven when an external agent drives it — so the boundary is enforced in the tool layer and unit-tested directly (27 tests), not just asserted in the UI.
What's next for Airlock
Tightening the consent model further: auto-reverting privacy after a single disclosed answer, scoping disclosure to only the highlighted rows, and a k-anonymity guard on the aggregate tools to close query-composition reconstruction by an adversarial agent. And input breadth — PDF and image ingestion via pdf.js and in-browser WASM OCR, kept strictly client-side so the guarantee that nothing leaves the tab still holds.
Built With
- css3
- html5
- javascript
- netlify
- node.js
- papaparse
- typescript
- vite
- webmcp
Log in or sign up for Devpost to join the conversation.