Guide
Operating the tools from an agent
Give an agent access to the Yichus engine, call a tool, and replay the result on the command line. Choose the Node server or the browser connection; both expose the same tool catalog.
Both packages are built from a checkout of this repository. Neither is published to npm. The measured walkthrough below links the recorded experiment and shows calls from its harness log.
Words used below. MCP is the Model Context Protocol, the interface an agent calls tools through. A stdio server is a local process the agent's client starts and talks to over its standard input and output. WebMCP is the browser interface that lets an open page register tools on navigator.modelContext; a relay is the local process that carries those page tools to an MCP client. Sources are the program's Bosatsu files, passed to every tool as a JSON array of {fileName, source}.
1. Connect over stdio: the Node server
@yichus/api-mcp runs the engine compiled to JavaScript inside a Node 20+ process. Build it from the checkout, confirm it starts, then add it to your MCP client's server configuration with the absolute path of your checkout.
git clone https://github.com/snoble/yichus && cd yichus
pnpm install
pnpm run yichus-api-mcp:build
node packages/yichus-api-mcp/dist/cli.js --help
{
"mcpServers": {
"yichus-api": {
"command": "node",
"args": ["/absolute/path/to/yichus/packages/yichus-api-mcp/dist/cli.js"]
}
}
}
Restart the client. The connection works when the server's tool list includes api_guide, api_verify, and api_why, and api_guide returns its guide. The connect reference carries the recovery steps for a server that does not appear.
2. Connect over WebMCP: the page and the relay
The WebMCP workbench opened with ?webmcp=1 registers the same catalog on navigator.modelContext and embeds the relay endpoint. The relay, @yichus/mcp, is built from the checkout and runs as the stdio server your client starts; it carries the page's tools to the agent and the agent's calls to the page.
pnpm run yichus-mcp:build
node packages/yichus-mcp/dist/cli.js
With the relay running and the page open, the client's tool list shows the relay's own tools (webmcp_list_sources, webmcp_list_tools, webmcp_call_tool, webmcp_open_page) and, through webmcp_list_tools, the page's catalog. The page also registers application tools that run a generated app in an iframe (yichus_app_open and its siblings); the connect reference lists them. Analysis runs in the page; source arguments and results pass through the relay to the client, so the relay and the client are the privacy boundary.
3. Call one tool: api_why
api_why evaluates one binding of the program on inputs you give, in a fresh in-memory world seeded with the rows you give, and reports the output, the facts that hold for every input, the facts observed on this run, the run in sentences (narrative), and the experiments the run's facts make discriminating (proposals, each a complete request; none is run unasked). Its arguments, from the catalog:
| argument | required | meaning |
|---|---|---|
sources | yes | the program's files, a JSON array of {fileName, source} |
binding | yes | the binding to evaluate, as Pkg/Name::binding |
inputs | no | a JSON object of provided inputs; a missing one is filled from the seed, not from a default |
rows | no | a JSON object {table: [row, ...]} seeding the world for a handler run |
seed, variations, observe | no | the run seed (the whole run replays from it), variations per axis, and whether to run the differentials at all |
The same call from a shell, through the WebMCP evaluation harness this repository keeps for measuring the surface (the harness serves the built site, starts the relay, and opens pages in a headless browser; its --file flag builds the sources string from files so no source is pasted):
node scripts/webmcp-eval/harness.mjs serve
node scripts/webmcp-eval/webmcp.mjs open /api-mcp.html
node scripts/webmcp-eval/webmcp.mjs call api_why '{"binding": "Demo/Forum::read_thread", "inputs": {"p": {"user_id": "carol", "roles": []}, "req": {"thread_id": "t1"}}, "seed": 7, "variations": 3}' --file sources=demos/service/forum.bosatsu
Reading the result. Show narrative verbatim to a reader who will not read JSON; the reviewer page reads one aloud. Treat soundFacts and observed as disjoint: an observed-constant result is never independence. A real client has no --file: the agent pastes the sources into the argument, and the parameter's declared type says it is an array.
4. The measured walkthrough: one agent's calls, from the harness log
The WebMCP cell of 2026-09-10 ran sixteen fresh agents over this connection and the command line, one task each, and the harness logged every call an agent made with its tag, the tool, the milliseconds, and the size of its arguments. Below, the rows of one agent asked to verify a program and read its conventions and routes: it opened the page, listed the tools, and made four calls. These are whole-call timings; the log does not isolate compilation time from analysis or relay overhead.
Verbatim from docs/agent-era/webmcp-cell/w1-harness-log.json; a test holds this page to that file. Lines elided are marked ....
{
"at": "2026-09-10T03:16:12.309Z",
"event": "open-by",
"path": "/api-mcp.html",
"agent": "A-T2-s1"
},
...
{
"at": "2026-09-10T03:16:16.028Z",
"event": "list",
"ms": 0.42077,
"agent": "A-T2-s1"
},
...
{
"at": "2026-09-10T03:16:22.125Z",
"event": "call",
"name": "api_guide",
"ms": 13.858102,
"agent": "A-T2-s1",
"argChars": 2,
"isError": false
},
...
{
"at": "2026-09-10T03:16:36.583Z",
"event": "call",
"name": "api_verify",
"ms": 10671.764459,
"agent": "A-T2-s1",
"argChars": 26924,
"isError": false
},
...
{
"at": "2026-09-10T03:16:41.538Z",
"event": "call",
"name": "api_organize",
"ms": 349.747888,
"agent": "A-T2-s1",
"argChars": 26931,
"isError": false
},
...
{
"at": "2026-09-10T03:16:54.320Z",
"event": "call",
"name": "api_permissions",
"ms": 114.190715,
"agent": "A-T2-s1",
"argChars": 26910,
"isError": false
},
...
How to read a row. event is what the harness saw (open-by: the agent opened a page; list: it asked for the tools; call: it called one). ms is the round trip through the relay and the page; argChars is the size of the arguments, which for a call over the forum's source is the source itself. isError is the tool's own verdict on the call.
The cell's record scores this agent's run in one row of its results table:
Verbatim from docs/agent-era/2026-09-08-webmcp-cell.md; a test holds this page to that file. Lines elided are marked ....
| A-T2-s1 | sonnet | yes | no | 6 relay rows (open, list, guide, verify, conventions, permissions) + close | 75,570 | verify 10.7, conventions 0.35, permissions 0.11 | none |
...
What the cell found. The connection passed its pre-registered gate (every agent finished, none fell back to another surface, tokens within 1.15 of the command-line arm). Two findings are the operator's to know: an omitted api_why input is filled from the seed, not left at a default, which tripped both command-line agents on one task once; and the catalog's api_organize has no diff lens, so an agent reads family membership from the conventions page. The record, its samples, and the whole log are under docs/agent-era/.
5. Replay the run on the command line
Every api_why response echoes its request and names its sources by hash; the matching command-line call, yichus why, is checked for parity with the tool at the same engine version, and --record writes it with every source's content as a self-contained record. The page's Copy as yichus why button prints the command that reproduces a page run; the page's Open record button runs a record the command line wrote. To check a record anywhere the jar runs:
sbt assembly
java -jar target/scala-3.8.2/yichus.jar why --replay docs/forum-demo/records/read_thread-as-carol.json
The command compiles the record's embedded sources, re-runs the recorded request, and prints replay: identical or the keys that differ, then the response. The forum's ten records are under docs/forum-demo/records/; the builder page shows the command that wrote one.
Where to go next
- Connect: both routes in full, with recovery steps, and the page tools.
- The tool reference: every catalog tool with its parameters, generated from the catalog.
- The agent tooling guide: which lens or tool answers which question, for an agent that reads the repository.
Dig deeper: where the surfaces are implemented
The catalog is src/main/resources/yichus/mcp.bosatsu, one value both surfaces read. The stdio server is packages/yichus-api-mcp/src/server.ts over the engine's JavaScript build; the page is web/api-mcp.html with web/webmcp-register.js registering its tools; the relay is packages/yichus-mcp/. The harness and its CLI are scripts/webmcp-eval/. Command-line and tool JSON are pinned equal by ArtifactParityTest; each tool's surfaces are listed by ToolSurface.scala.
Where this fits
What this is about: How the pieces fit