Skip to content

Without native WebMCP ​

Most of this project does not need the browser API. Supply your own tool source and ship today.

document.modelContext needs a flag. Your users will not start their browser with a flag. That does not block you, because only one of the four layers inside the package touches the browser API.

LayerNeeds document.modelContext
coreNo
agentNo
widgetNo
webmcpYes

The seam is the source option. createAssistant builds a native source only when you leave source empty. Pass one, and no code reads document.modelContext at all.

Write a source ​

A ToolSource is four methods.

source.ts
import type { ToolSource } from 'actionwire';

export function createLocalSource(): ToolSource {
  return {
    async discover() {
      return {
        revision: 1,
        tools: [
          {
            id: 'createProject',
            name: 'createProject',
            description: 'Create a project.',
            inputSchema: {
              type: 'object',
              additionalProperties: false,
              properties: { name: { type: 'string' } },
              required: ['name'],
            },
          },
        ],
      };
    },
    async execute(call) {
      const project = projects.create(String(call.arguments.name));
      return { callId: call.id, ok: true, text: `Created ${project.name}` };
    },
    subscribe() {
      return () => {};
    },
    dispose() {},
  };
}

Then mount as usual:

assistant.ts
createAssistant({
  model: openAICompatible({ endpoint: '/api/assistant' }),
  source: createLocalSource(),
}).mount();

Everything else is unchanged. The same widget, the same tool cards, the same confirmation prompts, the same error messages.

What you keep and what you give up ​

You keep the transcript, the confirmation flow, the stale-approval check, the schema validation, the timeouts, the round limit, the accessibility work, and the error copy.

You give up automatic discovery. You list the tools yourself, and you raise revision and call your subscriber when the list changes, so approvals given against the old list expire correctly.

A working example ​

packages/actionwire/e2e/main.ts in this repository drives the whole product from a hand-written source with static tools, including the destructive-delete confirmation. It runs in unmodified Chromium, with no flags, as part of the test suite.

Moving to the native API later ​

When the browser ships WebMCP, delete your source and the source option. The widget then builds createWebMCPSource() on its own. No other code changes.

TIP

You can decide at runtime. Try createWebMCPSource(), call discover(), and fall back to your own source if it throws UNSUPPORTED_WEBMCP. Do this once, at startup, and pass the winner to createAssistant.

Read moreToolSource reference

Released under the MIT License.