Inspiration
Deep brain stimulation programming has no standard method — patients average 6.9 clinic visits in the first year alone just to get their settings right, for a device that stays implanted for a decade or more. The research trying to fix that is real and published, but it's scattered: an image-guided algorithm out of Berlin, sweet-spot mapping out of Bern, sensor-guided approaches, a foundational protocol from Toronto that's still the baseline everyone measures against. Nobody had put it in one place a researcher could actually search. That gap, and the WebMCP Challenge's push toward tools that agents can use as first-class citizens instead of scraping a UI, was the whole starting point.
What it does
Triangulate is a workbench, not a chatbot. A researcher — or their AI agent, through the exact same tools — can search a curated set of 14 verified DBS programming studies, compare methods side by side, ask for a research plan built from a question and a set of studies, save that plan, and export it as a cited brief. A sixth tool reaches live into Europe PMC for anything the curated set doesn't cover, clearly marked unreviewed so it's never confused with the vetted evidence. Six document.modelContext.registerTool() calls, all wired to the same functions the on-page buttons call.
That's the actual fit with WebMCP: a generic chatbot answering "find me DBS studies" gives back unstructured prose that's gone once the chat scrolls. Triangulate instead exposes real, schema-constrained tools, so results stay structured and persistent in a shared workspace instead of trapped in a transcript, and tools chain reliably — search_studies into compare_protocols into build_research_plan — because each one's output is real data, not re-parsed guesses. That's also what's newly possible: because each tool's output is exactly the input the next one expects — a study id from search_studies is exactly what compare_protocols and build_research_plan take — an agent can chain a request like 'compare the Bayesian and sweet-spot studies, then draft a plan for tremor patients' into real, structured tool calls instead of hallucinating a summary of research it never structurally engaged with. I verified every tool individually, end to end, including the exact chain of ids each one expects from the last.
How I built it
React, TypeScript, and Vite, in a GitHub Codespace. I started with a five-study placeholder just to prove document.modelContext.registerTool() actually worked end to end, then went and pulled real citations — Charité Berlin's StimFit trial, Bern's ARTORG sweet-spot papers, the original Toronto Western algorithms, an industry-sponsored adaptive DBS trial — and built the dataset out to 14, each with a real, checkable link. The tools were built one at a time and tested in the WebMCP Inspector before moving to the next: search first, then compare, then the plan builder, then persistence, then the brief, then live search once we confirmed Europe PMC allows direct browser requests with no backend needed. The UI went through more than one real redesign once it became clear a wall of scrolling cards wasn't going to cut it for a 3-minute demo.
Challenges I ran into
The biggest one: document.modelContext.registerTool() throwing InvalidStateError: Duplicate tool name under React's StrictMode double-invoke in dev. Fixing it properly meant switching every registration to the current WebMCP draft's AbortSignal-based cleanup instead of trying to manually unregister — unregisterTool() was actually dropped from the spec in April 2026 in favor of that pattern. Separately, I hit a real crash: two research plans saved to localStorage before a schema change didn't have a field the newer code expected, and reading .length on undefined took the whole page down. The fix was a small normalizePlan() function that backfills missing fields on load, which is now just standard practice for anything read back out of storage. I also had a longer stretch of the research-question text not actually influencing the plan output — it was stored but not used — which I caught by testing the same three studies with two different questions and noticing the output didn't change.
Accomplishments that I'm proud of
Fourteen real, independently checkable citations, not filler. Six tools that all survived direct testing, not just a demo run. A working live literature search against Europe PMC with zero backend, confirmed via a real CORS test rather than assumed. And a research-plan builder that actually reads the question — mentioning "tremor" in a question the selected studies don't cover surfaces that gap by name, first, before the generic ones.
What I learned
The most useful distinction I learned: document.modelContext is the production registration API; navigator.modelContextTesting is a separate, narrower API that only debugging tools like the WebMCP Inspector depend on. A tool can be fully registered and working for a real agent while a specific inspector extension still shows zero — which is exactly what happened to me, and cost real time to pin down with actual console checks instead of assumptions. I also came away with a firm rule for anything touching browser storage: never trust that old saved data matches your current schema, normalize on read.
What's next for Triangulate
Letting a researcher promote a live, unreviewed search result into the curated tier with one click after actually reading it — a lightweight path to growing the dataset without needing accounts or moderation infrastructure. Accounts themselves, so a saved workspace follows a researcher across devices instead of living in one browser's local storage. And growing the curated set past 14 as the literature does.
Built With
- abortcontroller
- chrome
- css3
- europe-pmc-api
- git
- github-codespaces
- html5
- javascript
- json-schema
- localstorage
- markdown
- mermaid
- model-context-protocol
- netlify
- react
- rest-api
- typescript
- vite
- webmcp
Log in or sign up for Devpost to join the conversation.