AeionClaw + WebMCP — Browser-Native AI Under User RBAC.
Most AI assistants face a security tradeoff: either give the LLM a service-account API key (security disaster) or build a brittle Chrome extension (UX disaster). WebMCP solves both. AeionClaw skills execute inside the user's authenticated browser session via `navigator.modelContext`. The LLM never sees a service-account key. Every tool call runs under the user's JWT + RBAC. Same security model as your admin UI.
The Architecture
WebMCP is the bridge between AeionClaw and the user's browser. Tools execute on the client, scoped to the calling user.
useAeionTool Hook — Dynamic Context-Aware Tools
React components register browser tools that the AI assistant can invoke. Tools are context-aware — they capture closure variables from the component.
What WebMCP Solves
No server-side API key exposed to LLM
tools run under user auth, never the platform's auth
Granular per-page tool registration
the AI only sees tools relevant to the current page
Closure-captured context
tools capture component-local data (contactId, projectId, etc.)
Per-user RBAC enforced
user can only invoke tools the user has permission for
Audit log per tool call
every WebMCP invocation logs to the same audit stream
Rate limiting per user
sessionStorage-backed per-user rate limits prevent abuse
Approval workflow per tool
high-risk tools require explicit user approval before execution
W3C MCP API standard
built on `navigator.modelContext` for cross-browser compatibility
Enterprise Governance — Every Tool Call Goes Through the Same Gate
useAeionTool isn't just a registration hook — every invocation is routed through a governance layer that enforces, in order: does the user have permission to call this tool, is the user rate-limited, does this tool require approval (and if so, has the user approved it), and does the tenant have AI budget headroom (for tools that consume AI tokens). Only after all four checks pass does the tool execute — and both the attempt and the outcome are written to the same audit log as every other AeionClaw action.
Frequently Asked Questions
The LLM doesn't call the tool — it *requests* a tool call. That request goes to the server-side AI gateway, which returns the tool-call intent to the browser. The `aeionToolRegistry` then executes the tool client-side, and the `aeionFetch` inside `invoke` carries the user's own session JWT. The provider only ever sees the request and the returned result, never a credential. That's why there's no service-account key to leak.
Every invocation passes through the governance gate before it fires, in order: permission check, per-user rate limit, approval requirement, and AI-budget headroom. A tool call that fails any check never executes. Because the actual work happens through the normal REST API under the user's JWT, the 3-stage RBAC engine also applies at the data layer — the same enforcement that protects the admin UI.
Context. The `useAeionTool` hook lets a React component register tools that capture its local state via closure — a `merge_duplicate_contacts` tool that already knows the `contactId` you're viewing, or a tool that only exists when a record's status is `active`. The assistant sees exactly the tools relevant to where the user is, which keeps the tool surface small, precise, and safe rather than exposing every possible action everywhere.
Server-side function calling needs a service-account key so the backend can act on the model's behalf — a single over-permissive credential the LLM effectively drives. WebMCP inverts that: tools execute inside the already-authenticated browser session, so the ceiling on what the AI can do is exactly the ceiling on what the signed-in user can do. No shared privileged key, no separate permission model to keep in sync.
No. WebMCP is built on the W3C `navigator.modelContext` API surface, which lives in the page itself — no extension to install, no per-browser engineering, no separate update channel. Tools are registered by the same admin UI the user is already running, which is why the assistant feels native: it is running inside the app, not bolted onto the browser around it.