weboperator-mcp 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +51 -0
- package/SKILL.md +115 -0
- package/agent-client.js +56 -0
- package/bridge.js +716 -0
- package/hermes-config.json +14 -0
- package/install.sh +61 -0
- package/mcp-server.js +608 -0
- package/native-host-template.json +10 -0
- package/native-host.sh +9 -0
- package/openclaw-tools.json +23 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Artem KK
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# weboperator-mcp
|
|
2
|
+
|
|
3
|
+
MCP server that hands your **live Chrome tab** to any agent client — Claude Desktop, Cursor, Hermes, OpenClaw, OpenHands. Speaks MCP over stdio.
|
|
4
|
+
|
|
5
|
+
It drives the browser you are already signed into, so your sessions, cookies, and extensions come along. Nothing is launched headless and nothing leaves the machine.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
`browser_snapshot` · `browser_navigate` · `browser_click` · `browser_type` · `browser_press` · `browser_scroll` · `browser_screenshot` · `browser_extract` · `browser_solve_captcha` · `weboperator_execute_goal`
|
|
10
|
+
|
|
11
|
+
`browser_snapshot` returns an accessibility tree with numbered interactive elements; the action tools take those numbers, so an agent never guesses at CSS selectors.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
The server talks to Chrome through the [WebOperator extension](https://github.com/KazKozDev/WebOperator) and a Native Messaging host, so install the extension first, then register the host:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx -p weboperator-mcp weboperator-bridge-install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then point your client at the server:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"weboperator": {
|
|
27
|
+
"command": "npx",
|
|
28
|
+
"args": ["-y", "weboperator-mcp"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Reload the extension in `chrome://extensions` after registering the host.
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
| Variable | Default | What it does |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `WEBOPERATOR_BRIDGE_PORT` | `8765` | Port of the local bridge HTTP API |
|
|
41
|
+
| `WEBOPERATOR_BRIDGE_HOST` | `127.0.0.1` | Bridge bind address |
|
|
42
|
+
| `WEBOPERATOR_AGENT_SOCKET` | `/tmp/weboperator-bridge.sock` | Unix socket the bridge listens on |
|
|
43
|
+
| `WEBOPERATOR_API_TOKEN` | _(unset)_ | Shared token, required when unauthenticated bridge access is disabled |
|
|
44
|
+
|
|
45
|
+
macOS and Linux. Chrome, Chromium, Brave, Edge, and Arc are all registered by the installer.
|
|
46
|
+
|
|
47
|
+
## Security
|
|
48
|
+
|
|
49
|
+
Page content is treated as data, never as instructions — the extension's prompt-injection fixtures live in [`evals/fixtures/`](https://github.com/KazKozDev/WebOperator/tree/main/evals/fixtures). `browser_solve_captcha` pauses for you rather than defeating a challenge, and login flows stop for a human instead of typing credentials.
|
|
50
|
+
|
|
51
|
+
MIT © Artem KK · [full documentation](https://github.com/KazKozDev/WebOperator)
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: weboperator
|
|
3
|
+
description: "Control and automate the live browser (Brave, Chrome) via the WebOperator MCP server. Navigate websites, search, click, type, scroll, take screenshots, extract data, or run autonomous goals directly in the user's active browser."
|
|
4
|
+
version: 1.4.0
|
|
5
|
+
author: WebOperator
|
|
6
|
+
license: MIT
|
|
7
|
+
platforms: [macos, linux, windows]
|
|
8
|
+
metadata:
|
|
9
|
+
hermes:
|
|
10
|
+
tags: [Browser-Automation, WebOperator, MCP, Chrome, Brave, Web-Navigation, Live-Browser]
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# WebOperator Browser Automation Skill
|
|
14
|
+
|
|
15
|
+
WebOperator connects Hermes directly to the user's live browser (Brave Browser, Google Chrome) via MCP.
|
|
16
|
+
|
|
17
|
+
> [!IMPORTANT]
|
|
18
|
+
> When the user asks to open a site, search in the browser, scroll, click, or mentions "вебоператор" / "WebOperator", **ALWAYS** use the `mcp__weboperator__*` tools.
|
|
19
|
+
> **DO NOT** use Firecrawl or built-in `web_search`/`web_extract` when the user refers to WebOperator or wants browser automation.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Available MCP Tools
|
|
24
|
+
|
|
25
|
+
All tools are prefixed with `mcp__weboperator__`:
|
|
26
|
+
|
|
27
|
+
### 1. `mcp__weboperator__browser_navigate`
|
|
28
|
+
Navigate the active tab to a specific URL.
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"url": "https://www.google.com"
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. `mcp__weboperator__browser_snapshot`
|
|
36
|
+
Capture the interactive accessibility tree with numbered element IDs (`@1`, `@2`, etc.) from the active tab.
|
|
37
|
+
```json
|
|
38
|
+
{}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. `mcp__weboperator__browser_click`
|
|
42
|
+
Click an interactive element by its index from `browser_snapshot` or CSS selector.
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"index": 2
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 4. `mcp__weboperator__browser_type`
|
|
50
|
+
Type text into an input field.
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"index": 1,
|
|
54
|
+
"text": "auriculares baratos",
|
|
55
|
+
"clear": true
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 5. `mcp__weboperator__browser_press`
|
|
60
|
+
Press a keyboard key (e.g. Enter, Tab, Escape).
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"key": "Enter"
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 6. `mcp__weboperator__browser_scroll`
|
|
68
|
+
Scroll the active webpage up or down.
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"direction": "down",
|
|
72
|
+
"amount": 500
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 7. `mcp__weboperator__browser_screenshot`
|
|
77
|
+
Capture a visual PNG screenshot of the active browser viewport.
|
|
78
|
+
```json
|
|
79
|
+
{}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 8. `mcp__weboperator__browser_extract`
|
|
83
|
+
Extract structured text content or answers from the active page.
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"instruction": "Extract list of top 5 products with prices"
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 9. `mcp__weboperator__browser_solve_captcha`
|
|
91
|
+
Attempt to detect and automatically pass or click Cloudflare Turnstile, reCAPTCHA, or hCaptcha verification challenges on the active page.
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"type": "auto"
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 10. `mcp__weboperator__weboperator_execute_goal`
|
|
99
|
+
Run a high-level autonomous goal in the browser end-to-end using WebOperator's planner.
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"goal": "Find headphones under 30 euros on amazon.es and summarize top 3 options",
|
|
103
|
+
"timeoutMs": 120000
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Typical Workflow
|
|
110
|
+
|
|
111
|
+
1. **Open a site**: Call `mcp__weboperator__browser_navigate` with `url`.
|
|
112
|
+
2. **Inspect page**: Call `mcp__weboperator__browser_snapshot` to see element numbers and text.
|
|
113
|
+
3. **Interact**: Call `mcp__weboperator__browser_type` or `mcp__weboperator__browser_click` using the element indices.
|
|
114
|
+
4. **Scroll / Read**: Call `mcp__weboperator__browser_scroll` or `mcp__weboperator__browser_extract`.
|
|
115
|
+
5. **Or run autonomous goal**: Call `mcp__weboperator__weboperator_execute_goal` with the full prompt.
|
package/agent-client.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// WebOperator framed JSON client for agents.
|
|
3
|
+
const net = require('net');
|
|
4
|
+
const { randomUUID } = require('crypto');
|
|
5
|
+
|
|
6
|
+
const socketPath = process.env.WEBOPERATOR_AGENT_SOCKET || '/tmp/weboperator-bridge.sock';
|
|
7
|
+
const token = process.env.WEBOPERATOR_API_TOKEN || '';
|
|
8
|
+
const input = process.argv[2] ? JSON.parse(process.argv[2]) : { type: 'bridge.health' };
|
|
9
|
+
const message = {
|
|
10
|
+
id: input.id || randomUUID(),
|
|
11
|
+
type: input.type || 'bridge.health',
|
|
12
|
+
payload: input.payload || {},
|
|
13
|
+
timeoutMs: input.timeoutMs,
|
|
14
|
+
...(token ? { token } : {}),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
let buffer = Buffer.alloc(0);
|
|
18
|
+
let nextFrameLength = null;
|
|
19
|
+
const socket = net.createConnection(socketPath, () => sendFrame(socket, message));
|
|
20
|
+
|
|
21
|
+
socket.on('data', (chunk) => {
|
|
22
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
23
|
+
readFrames();
|
|
24
|
+
});
|
|
25
|
+
socket.on('error', (err) => {
|
|
26
|
+
console.error(err.message);
|
|
27
|
+
process.exitCode = 1;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function readFrames() {
|
|
31
|
+
while (true) {
|
|
32
|
+
if (nextFrameLength === null) {
|
|
33
|
+
if (buffer.length < 4) return;
|
|
34
|
+
nextFrameLength = buffer.readUInt32LE(0);
|
|
35
|
+
buffer = buffer.slice(4);
|
|
36
|
+
}
|
|
37
|
+
if (buffer.length < nextFrameLength) return;
|
|
38
|
+
const payload = buffer.slice(0, nextFrameLength).toString('utf8');
|
|
39
|
+
buffer = buffer.slice(nextFrameLength);
|
|
40
|
+
nextFrameLength = null;
|
|
41
|
+
const msg = JSON.parse(payload);
|
|
42
|
+
if (msg.kind === 'event') {
|
|
43
|
+
console.error(JSON.stringify(msg));
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
console.log(JSON.stringify(msg, null, 2));
|
|
47
|
+
socket.end();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function sendFrame(sock, obj) {
|
|
52
|
+
const body = Buffer.from(JSON.stringify(obj), 'utf8');
|
|
53
|
+
const header = Buffer.alloc(4);
|
|
54
|
+
header.writeUInt32LE(body.length, 0);
|
|
55
|
+
sock.write(Buffer.concat([header, body]));
|
|
56
|
+
}
|