Content
# webmcp-bridge-mcp
An MCP server that allows tools from Antigravity CLI (and other MCP clients) to be invoked on WebMCP-enabled pages open in Chrome.
```
Antigravity CLI <--stdio(MCP)--> webmcp-bridge-mcp <--WebSocket--> webmcp-bridge-extension <--content/injected script--> Web Page
```
This server itself does not interact with the page's DOM; it merely acts as a bridge/registry/router between the Chrome Extension ([webmcp-bridge-extension](../webmcp-bridge-extension)) and other components. The extension must be installed and connected for tool invocation to work.
## Installation
```bash
bun install
```
## Development Startup
```bash
bun run dev
```
- The MCP server listens on **stdio** (expected to be launched from Antigravity CLI).
- A WebSocket server is started simultaneously on `ws://127.0.0.1:8787` (binding only to `127.0.0.1`, not accessible from outside).
- All logs are output to **stderr** (stdout is dedicated to MCP JSON-RPC communication).
The WebSocket port can be changed using the `WS_PORT` environment variable.
```bash
WS_PORT=9000 bun run dev
```
## Build / Production Startup
```bash
bun run build
bun run start
```
## Testing
```bash
bun test
```
`test/bridge.test.ts` launches the actual MCP server (`src/index.ts`) as a child process and connects a mock agent (scripting directly to call tools, simulating an LLM agent like Antigravity CLI) using the `@modelcontextprotocol/sdk` `Client`. The `FakeExtension` class connects using the same WebSocket protocol, allowing for verification of the bridge's logic without a browser: connection state, live queries for `tabs/list`, caching and forced refresh for `discover_tools`, concurrent tool invocation, and cleanup upon disconnection.
Verification of the extension itself (overlay display, tool execution with DOM manipulation) is performed using Playwright tests in [webmcp-bridge-extension](../webmcp-bridge-extension).
## Registration Example with Antigravity CLI
If published to npm, it can be launched directly with `bunx`/`npx` without prior installation or path specification (automatically downloaded and cached on the first run).
```json
{
"mcpServers": {
"webmcp-bridge": {
"command": "bunx",
"args": ["-y", "webmcp-bridge-mcp"]
}
}
}
```
It also works with `npx`.
```json
{
"mcpServers": {
"webmcp-bridge": {
"command": "npx",
"args": ["-y", "webmcp-bridge-mcp"]
}
}
}
```
To run directly from this repository (during development or unpublished), specify `cwd` as before.
```json
{
"mcpServers": {
"webmcp-bridge": {
"command": "bun",
"args": ["run", "dev"],
"cwd": "/absolute/path/to/webmcp-bridge-mcp"
}
}
}
```
### Preparation for npm Publication
A `bin` entry (`dist/index.js`, with a `#!/usr/bin/env node` shebang) is prepared in `package.json`, and `bun run build` builds with `--target node`, making it executable from both `node` and `bun`. Verification with `npm pack --dry-run` confirms that the contents are only `dist/index.js` and `README.md`. For actual publication, run `npm publish` (or `bun publish`).
## WebSocket URL
```
ws://127.0.0.1:8787
```
(can be changed with the `WS_PORT` environment variable). The Chrome Extension connects to this URL upon startup.
## Available MCP Tools
| Tool | Description |
| --- | --- |
| `webmcp_get_status` | Returns the extension's connection state, known tab count, and active tab ID. |
| `webmcp_list_tabs` | Returns a list of WebMCP-enabled tabs known to the extension (live query to the extension). |
| `webmcp_discover_tools` | Detects WebMCP tools in a specified tab (or active tab if omitted). Defaults to returning cached results; use `forceRefresh: true` for rescanning. |
| `webmcp_call_tool` | Executes a WebMCP tool in a specified tab with `toolId` and `args`. Timeout can be adjusted with `timeoutMs` (default 30 seconds). |
| `webmcp_ping` | Checks communication with the extension (measures latency) without performing page operations. |
### Example Input/Output
`webmcp_discover_tools`
```json
// input
{ "tabId": 123, "forceRefresh": true }
// output (content[0].text JSON)
{ "tabId": 123, "tools": [ { "id": "reserve_hotel", "name": "reserve_hotel", "source": "imperative", ... } ] }
```
`webmcp_call_tool`
```json
// input
{ "toolId": "reserve_hotel", "args": { "city": "Osaka" } }
// output
{ "ok": true, "result": { "ok": true, "city": "Osaka", "confirmationId": "RES-12345" } }
```
`source` adheres to the [WebMCP specification](https://webmachinelearning.github.io/webmcp/) for detection sources (`"imperative"` = `document.modelContext.registerTool()`, `"declarative"` = annotated `<form>`). See [webmcp-bridge-extension README](../webmcp-bridge-extension/README.md#webmcp-detection-specifications) for details.
If the extension is not connected, all tool invocations return an error (`ok: false` or an error message) without causing the server to crash or hang.
> **Note:** Tools with `requiresUserGesture: true` in `webmcp_discover_tools` results (declarative forms without `toolautosubmit`) might not respond until a human presses the submit button, depending on browser implementation. When calling such tools in automated execution contexts, set a sufficiently long `timeoutMs` or prompt a human for operation.
> **Note:** `result` is directly relayed from the tool's `execute()` return value. Verification with actual `document.modelContext.executeTool()` showed cases where the browser side converts page-side objects into JSON strings. This server passes `result` without modification, so MCP clients should determine if it's a string or structured data.
## Operation Verification (Checking Communication without Extension)
Using [MCP Inspector](https://github.com/modelcontextprotocol/inspector), you can verify communication with the server without the extension.
```bash
bunx @modelcontextprotocol/inspector bun run src/index.ts
```
Calling `webmcp_get_status` / `webmcp_ping` and receiving `extensionConnected: false` / `{"ok":false,"error":"Extension not connected."}` indicates normal operation.