webmcp (EXPERIMENTAL)
The WebMCP standard (document.modelContext — navigator.modelContext is
deprecated as of Chrome 150, and this adapter still probes it) lets a
page expose typed, callable tools to browser agents — but every existing
integration hand-writes those tools. tosijs doesn't have to: the agent surface
already knows the app's state roots, wiring, and actions, so the tool set is
generated, not authored.
import { enableAgentInterface, webmcpAdapter } from 'tosijs'
const agent = enableAgentInterface()
const mcp = webmcpAdapter(agent) // detect, generate, register
// …
mcp?.unregister()
Two layers, split like schematicSVG:
webmcpTools(agent)— pure: returns the tool definitions ({ name, description, inputSchema, execute }) derived fromdescribe(). Test it, print it, hand it to any MCP-shaped host — no browser API needed.webmcpAdapter(agent, options)— feature-detects the runtime (document.modelContextfirst, thennavigator.modelContext, or an injectedoptions.modelContext), registers the tools through whichever registration shape the host offers (registerToolper tool, orprovideContext({ tools })as a batch), and returns{ tools, unregister }— orundefinedwhen no host API exists (callers feature-detect by result).
The generated set:
| tool | does |
|---|---|
tosi_describe |
the live affordance map — start here |
tosi_surface |
what this surface IS: version + capabilities |
tosi_read |
serializable value at a path — scoped surfaces only |
tosi_changes |
turn drain: final-value-per-path since your cursor — scoped surfaces only |
tosi_act_<path> |
one named tool per discovered/declared action |
tosi_write |
direct state writes — dev-gated (see below) |
tosi_write registers only with an explicit allowWrites: true: an
unvalidated write tool is an RPC endpoint with good documentation.
tosi_read and tosi_changes register only once the surface says what it
exposes — expose: { roots: [...] } or expose: 'all' — or with an
explicit allowReads: true. The no-options default is read-only over the
whole registry, and a browser agent is a different principal: an
unscoped read of everything shouldn't be published to the page's tool
registry as a side effect of one unargumented call. The introspection tools
still register: they report the DOM an agent can already see, and the map is
the point.
Tool names are global to the page. Where another script (or a second
surface) already owns tosi_*, pass a distinct prefix — the adapter
reports any generated tool the host did not take as a console.error,
because a name you didn't get is a name an agent will reach someone else
through.
EXPERIMENTAL. The WebMCP spec is churning; the adapter is deliberately tolerant of both registration shapes and takes an injected host for tests.