Connect with WebMCP

View as Markdown

The WebMCP connection is a Run-scoped MCP server. It lets an AI agent discover and call tools exposed by the active webpage, such as search, add_to_cart, or book_appointment.

BCTRL returns a credentialed webMcpUrl when the browser Runtime starts. Pass that URL to any MCP client that supports Streamable HTTP.

Complete example

Install the BCTRL SDK and the official TypeScript MCP SDK:

$pnpm add @bctrl/sdk @modelcontextprotocol/sdk

This example creates a browser Runtime, opens a WebMCP-enabled store, connects an MCP client, discovers the page tools, and calls search_catalog.

Replace the example URL, tool name, and arguments with those exposed by the site you want to automate.

1import { Bctrl } from "@bctrl/sdk";
2import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4
5const bctrl = new Bctrl({
6 apiKey: process.env.BCTRL_API_KEY,
7});
8
9// 1. Create and start a browser Runtime.
10const runtime = await bctrl.runtimes.create({
11 type: "browser",
12 name: "shopping-agent",
13});
14
15let mcp: Client | undefined;
16
17try {
18 const connection = runtime.connection;
19 if (!connection?.webMcpUrl) {
20 throw new Error("This browser host does not offer WebMCP");
21 }
22
23 // 2. Open a page that exposes WebMCP tools.
24 const openCall = await bctrl.tools.start("browser.pages.open", {
25 url: "https://your-webmcp-site.example/products",
26 }, { runtimeId: runtime.id });
27
28 await bctrl.toolCalls.result(openCall.id, {
29 waitSeconds: 30,
30 });
31
32 // 3. Connect a standard MCP client to the active browser Run.
33 mcp = new Client({
34 name: "shopping-agent",
35 version: "1.0.0",
36 });
37
38 await mcp.connect(
39 new StreamableHTTPClientTransport(
40 new URL(connection.webMcpUrl),
41 ),
42 );
43
44 // 4. Discover the tools declared by the webpage.
45 const { tools } = await mcp.listTools();
46 console.log("Page tools:", tools.map((tool) => tool.name));
47
48 const searchTool = tools.find(
49 (tool) => tool.name === "search_catalog",
50 );
51
52 if (!searchTool) {
53 throw new Error("The page does not expose search_catalog");
54 }
55
56 // 5. Call a page tool through WebMCP.
57 const result = await mcp.callTool({
58 name: searchTool.name,
59 arguments: {
60 query: "camera",
61 },
62 });
63
64 console.log("Search result:", result.content);
65} finally {
66 // 6. Close the MCP connection and browser Runtime.
67 await mcp?.close();
68 await bctrl.runtimes.stop(runtime.id);
69}

The MCP client can access only the tools declared by the active webpage. It does not receive CDP access or general control of the browser.

Get the WebMCP URL

An ephemeral Runtime starts during creation:

1const runtime = await bctrl.runtimes.create({
2 name: "shopping-agent",
3});
4
5const connection = runtime.connection;
6if (!connection?.webMcpUrl) {
7 throw new Error("This browser host does not offer WebMCP");
8}
9
10const { webMcpUrl, runId } = connection;

For a reusable profile-backed Runtime, start it when you need a new session:

1const runtime = await bctrl.runtimes.create({
2 name: "shopping-agent",
3 profile: true,
4});
5
6const started = await bctrl.runtimes.start(runtime.id);
7const { webMcpUrl, runId } = { ...started.connection, runId: started.runId };
8
9if (!webMcpUrl) {
10 throw new Error("This browser host does not offer WebMCP");
11}

The connection fields are:

FieldTypeAlways presentMeaning
connection.webMcpUrlstringNoRun-scoped MCP endpoint. Omitted when unavailable.
connection.cdpUrlstringYesCDP endpoint for the same browser.
connection.webDriverUrlstringYesWebDriver endpoint for the same browser Run.
runIdstringYesRun that owns the connections.
connection.recording{ enabled: boolean }YesWhether Run recording is enabled.

The URL remains stable while the Run is active and stops working when the Run ends. Treat it as a credential: do not log it, persist it, or expose it to page code.

Open a WebMCP-enabled page

WebMCP exposes tools from the current webpage. Navigate the browser to a site that supports WebMCP before listing tools.

You can use a hosted browser Tool:

1const call = await bctrl.tools.start("browser.pages.open", {
2 url: "https://your-webmcp-site.example",
3}, { runtimeId: runtime.id });
4
5await bctrl.toolCalls.result(call.id, {
6 waitSeconds: 30,
7});

You can also navigate with CDP, WebDriver, or a hosted Agent.

Connect an MCP client

Connect using the Runtime’s webMcpUrl:

1import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
4const client = new Client({
5 name: "shopping-agent",
6 version: "1.0.0",
7});
8
9const transport = new StreamableHTTPClientTransport(
10 new URL(webMcpUrl),
11);
12
13await client.connect(transport);

List and call page tools

List the tools exposed by the active page:

1const { tools } = await client.listTools();
2
3for (const tool of tools) {
4 console.log(tool.name, tool.description);
5}

Call a tool by name with the arguments defined by its input schema:

1const result = await client.callTool({
2 name: "search_catalog",
3 arguments: {
4 query: "camera",
5 },
6});
7
8console.log(result.content);

Tool names and arguments are defined by the website. If the active page does not expose WebMCP tools, tools/list returns an empty list. Navigating to another page can change the available tools, so list them again after navigation.

Close the connection

Close the MCP client when the agent is finished, then stop the Runtime:

1await client.close();
2await bctrl.runtimes.stop(runtime.id);

Stopping the Runtime ends the active Run and invalidates its WebMCP URL. Use runId with Runs to inspect the recording, trace, events, usage, and files from the session.

Page requirements and safety

The active page must register tools with the browser’s native WebMCP API. During the browser rollout, a site may also need to meet Chromium’s feature-availability or origin-trial requirements.

Tool descriptions, schemas, and results come from the webpage. Treat them as untrusted input and keep approval checks for tools that purchase items, submit forms, or change account state.

The WebMCP URL grants access only to page-declared tools. It does not grant raw CDP or WebDriver access.

Next