
# WebMCP

[WebMCP](https://webmachinelearning.github.io/webmcp/) is a page telling the browser what it can do:
`document.modelContext.registerTool(...)`, so an agent living in the browser — a sidebar, an
extension, whatever the reader already has — can call it. `webmcp` is the bridge from codelet's own
tool registry to that: whatever anything in the workbench registered with `vscode.lm.registerTool`
is published, and nothing else.

```ts
import { Workbench, FileSystem } from "codelet/workbench";
import { webmcp } from "codelet/extensions/webmcp";
import { workspaceTools } from "codelet/extensions/workspace-tools";
import { typescript } from "codelet/extensions/lsp/typescript";

new Workbench({
  parent: document.getElementById("app")!,
  fs: new FileSystem({ "/index.ts": "export const hello = 1;\n" }),
  extensions: [workspaceTools(), typescript(), webmcp()],
});
```

::note
It publishes a registry, so mount something that fills one. On its own it publishes nothing — that's
an empty registry, not a bug. [`workspace-tools`](/extensions/workspace-tools) is the workspace's
files, [`lsp`](/extensions/lsp) is what the language servers know, and any extension of your own
that registers a tool is published the same way.
::

## Options

```ts
webmcp({
  // Install a `document.modelContext` where the browser has none. On by default, and behind a
  // dynamic import — a browser with the real thing never fetches it.
  polyfill: true,
  // Which registered tools to publish. Everything, by default.
  tools: (tool) => !tool.tags.includes("workspace_write"),
});
```

`tools` is the one decision codelet can't make for you: a page agent isn't the reader, and a
workbench published on the open web may want the reading half of its tools offered and not the
writing half.

## The reader is still asked

A call from the browser goes through the same path an extension's would: the input is checked
against the tool's declared schema, and a tool that asks for confirmation raises it over the
workbench before it runs. So an agent driving the page reaches exactly what an extension in the page
reaches, under the same questions — it doesn't get a way around them.

Tools are exposed to this window only. A workbench framed by someone else's page hands that page
nothing.

## The polyfill

No shipping browser has `document.modelContext` without a flag, so the extension installs one unless
the browser beat it to it. It's the shape everybody's page agents were written against — the same
`window.__webmcp_registered_tools` registry and the same `getTools()` / `executeTool()` pair — with
results serialized to JSON the way the spec says, so a client can't tell it from native.

## Seeing what's published

**WebMCP: Republish Tools** in the command palette writes the list to an output channel and opens it.
Useful when a tool arrived late — a language server's tools land when the server answers, not when
the page loads — though the extension republishes on its own whenever the registry moves.
