WebMCP
WebMCP lets a page offer tools to an agent in the browser. Sutram sits on top of it: WebMCP is how the tools reach the agent, and Sutram decides what they are. Every part of the app registers its commands in one registry, and the same commands work in the console for people and through Sutram.call() where WebMCP is not there yet. See Why not just WebMCP?.
connectWebMCP(), or loading dist/sutram.js, registers every command as a tool in browsers that support it, and keeps the list in step with the registry.
import { connectWebMCP, findModelContext } from "@d34dman/sutram/webmcp";
connectWebMCP(registry, findModelContext());What agents get
- One tool per command. The name is the command name with underscores:
cart addbecomescart_add. - The input schema, and the annotations as hints:
readOnlyHint,consequentialHint,untrustedContentHint. - A description that says what the command does, what it returns (from the output schema), whether it leaves the page, and what any app-defined formats mean.
sutram_status, which runs every<provider> statusat once and returns{ code: 0, data: { providers: [{ provider, code, text?, data? }] } }. Agents should call it first. Later,{ providers: ["form", "page"] }asks only those, so the agent does not read the whole page again.sutram_batch, which runs several tools as one change:{ calls: [{ tool: "cart_add", input: { sku: "V60" } }, …] }. Withquiet: trueit leaves out the results of the calls that worked and returns{ code, completed, total }, plus the failing call's result asfailed. It always hasuntrustedContentHint, assutram_statusdoes: it returns its calls' results as they are, page text included. When the page asks the person about a batch, the question includes each consequential command's own question, such as an order's price.
When commands are added or removed, the tools follow. If you change a definition in place, register it again (registry.register(def)) so the tool's hints follow too; otherwise the tool is refreshed at its next call. A tool the browser refuses is skipped with a warning; the others still register.
An agent's input is checked strictly: its JSON arrives typed, so "off" for a boolean or "2" for an integer is a usage error, not converted as text typed in the console would be.
Approval
WebMCP decides which sites' tools an agent may see, not whether a call may change the user's page. So every call goes through the page's policy first. When a call needs approval, the approval dialog (<sutram-approval>) shows what the agent wants to run and asks the person. A page can set its own asker instead; with neither, the browser's confirm() asks. That includes sutram_status: its commands are read-only, but a page may mark one consequential. When the agent's host cancels a call while the person is deciding, the question is withdrawn and nothing runs.
Without WebMCP
Browsers without WebMCP still have every tool: Sutram.tools() and Sutram.call() for agents that run JavaScript in the page (see Test with Playwright), and the console for agents that type. agentPrompt() hands a task to any of them.