Inspiration

Most permission UIs assume a human is clicking Revoke. Agents change that. Once a model can call tools on a live page, the hard question is no longer "can the agent help?" It is "what is the agent allowed to do, and can I see that?"

Tenscore came from that gap. I wanted a consent workspace where an agent can inspect and plan, but apply stays locked until a person approves in the UI. WebMCP's dynamic tool registration made that enforceable.

The product pitch and the safety model are the same idea: consent is visible, and the apply tool does not exist until you unlock it.

What it does

Tenscore is an interactive simulation of connected apps and grants. You pick a demo profile (Power User, Forgotten Accounts, or Minimalist), then explore a score, findings list, and consent map of who can see what.

A browser agent can call typed site tools to inspect access, trace data flows, simulate cleanup, and stage a plan. The human reviews the plan in the UI and clicks Approve. Only then does apply_approved_changes register. After apply, the page shows a permission diff and a consent receipt.

How we built it

Stack: Next.js App Router, React, TypeScript, Tailwind, Zustand, Zod, Vitest, Playwright. Deployed on Vercel.

Domain logic lives in pure functions under src/domain/: scoring, findings, simulation, approvals, mutations, graph projection, policy, receipts, replay. The UI and WebMCP tools call the same mutation path through the store, so agent actions and button clicks stay in sync.

Tools register with document.modelContext.registerTool and clean up via AbortController. Registration is phase-based (no_plan, staged, approved, applied), so apply is absent until UI approval binds a plan hash, profile version, and expiry.

We TDD'd the domain first, then added scripted agent evals, catalog tests, and a Playwright judge journey. Stretch work includes privacy budget planning, timeline scrubbing synced to the map, snapshot import/export, redacted reports, and manual service creation.

Challenges we ran into

Keeping one truth for UI and tools. Early on it was easy to let the agent mutate state the panels did not show. Sharing domain functions and flushing UI updates before tool results return fixed that.

Making the approval gate structural. A disabled button is weak proof. We needed apply to be unregistered until approve, then disappear after use, with fail-closed errors when the agent tries early.

Accomplishments that we're proud of

The apply gate is visible in product UI, not only in a README. The capability contract lists available vs denied tools per phase. A blocked apply shows a banner with the human next step.

We shipped a full typed tool surface with Zod schemas, annotations (readOnlyHint, untrustedContentHint), deterministic evals, and Playwright coverage for the human path.

Consent receipts and agent policy make the demo feel closer to how real agent permissions should work: constrain, approve, apply, audit.

What we learned

WebMCP is most interesting when tools change with state. A static tool list is a thin API. A phase-gated list is a permission model.

Human-agent collaboration needs a shared surface. If the agent acts off screen, humans cannot verify anything. Map pulses, plan diffs, and the tool inspector matter as much as the execute functions.

What's next for Tenscore

Connect real grant sources behind the same stage/approve/apply path, with adapters that never let the agent skip UI approval.

Ship a portable capability contract component other WebMCP apps can reuse: phase, available tools, denied tools, human next step.

Add stronger live-agent eval harnesses (not only scripted chains) and keep the fail-closed apply path as the default for any write tool.

Built With

Share this project:

Updates

Submission history