operagx-connector-plus
# operagx-connector-plus
[](https://github.com/Zindaar/operagx-connector-plus/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/operagx-connector-plus)
[](https://www.npmjs.com/package/operagx-connector-plus)
[](./package.json)
[](./LICENSE)
[](https://github.com/Zindaar/operagx-connector-plus/issues)
An MCP server that adds real browser **interaction** — click, type, keyboard,
form-fill, drag, scroll, select — on top of the read-only OperaGX connector
(`go-to-page`, `list-tabs`, `tab-content`, `screenshot`, `close-tab`,
`history`). Run both MCP servers side by side; this one doesn't replace the
original, it fills the gap between "read the page" and "act on it."
## Why the Chrome DevTools Protocol, not OS-level input
Two ways exist to make an agent actually click/type in a browser:
1. **OS-level hardware events** (`SendInput` on Windows, `robotjs`,
`xdotool`) — simulate input at the operating system, blind to window
coordinates, steal the real mouse cursor, need the window focused and
on-screen, and need OS accessibility permissions.
2. **Chrome DevTools Protocol** (`Input.dispatchMouseEvent` /
`Input.dispatchKeyEvent`) — simulates input inside the browser's own input
pipeline. Indistinguishable from real hardware input to the page (unlike
`element.click()`/`dispatchEvent()` in JS, which skip native browser
behavior and are trivially detectable by sites), works in the background,
doesn't touch the real OS cursor, and needs no extra OS permissions.
Since Opera GX is Chromium-based, it already speaks CDP. This server uses
[`playwright-core`](https://www.npmjs.com/package/playwright-core) purely as
a typed CDP client (`chromium.connectOverCDP`) — **no Playwright-managed
browser is launched**; it attaches to your existing, already-running Opera GX.
## Install
```bash
npm install
npm run build
```
Requires Node.js 18+.
## Setup
1. **Launch Opera GX with a remote debugging port.** Add a flag to wherever
you launch it from:
```
--remote-debugging-port=9222
```
This applies to a shortcut's target, a `Run`-at-login entry, or any
launcher — see [`docs/enabling-cdp.md`](./docs/enabling-cdp.md) for exact
steps on Windows (taskbar pin, Start Menu shortcut, autostart registry
entry).
2. **Register the server** with your MCP client. For the Claude Code CLI, at
user scope (available in every project):
```bash
claude mcp add operagx-connector-plus -s user \
-e OPERAGX_CDP_URL=http://localhost:9222 \
-- node /absolute/path/to/operagx-connector-plus/dist/index.js
```
For other clients, the equivalent JSON config is:
```json
{
"mcpServers": {
"operagx-connector-plus": {
"command": "node",
"args": ["/absolute/path/to/operagx-connector-plus/dist/index.js"],
"env": { "OPERAGX_CDP_URL": "http://localhost:9222" }
}
}
}
```
3. **Also register the base OperaGX connector** (screenshot, tab-content,
go-to-page, ...) — this server is designed to complement it, not replace
it. See the section below for the recommended combined workflow.
## The interaction loop
This server pairs with the base connector's `screenshot` tool for visual
grounding ("set-of-marks" style):
1. `operagx_map_elements` — scans the DOM for clickable/fillable elements,
returns each with a small integer `id`, role, text, and coordinates, and
draws numbered badges on the live page.
2. Call the base connector's `screenshot` tool — the badges let you visually
confirm which numbered id is which element.
3. `operagx_click` / `operagx_type_text` / `operagx_fill_form` /
`operagx_select_option` / `operagx_drag_and_drop` / etc., addressed by
`elementId` (preferred), a raw CSS `selector`, or absolute `x`/`y`
coordinates.
4. `operagx_clear_annotations` when done, so badges don't linger in future
screenshots.
## Tools
| Tool | Does | Read-only | Idempotent |
|---|---|---|---|
| `operagx_list_tabs` | Enumerate tabs with a stable `tabId` usable by every other tool here | ✅ | ✅ |
| `operagx_map_elements` | Map clickable/fillable elements to numbered ids + coordinates, annotate the page | ✅ | — |
| `operagx_clear_annotations` | Remove the numbered overlay badges | — | ✅ |
| `operagx_click` | Real CDP mouse click (left/right/middle, single/double/triple) | — | — |
| `operagx_hover` | Move the mouse over an element/point | — | ✅ |
| `operagx_type_text` | Focus + type real per-character key events | — | — |
| `operagx_press_key` | Send a key or chord (`Enter`, `Control+A`, ...) | — | — |
| `operagx_fill_form` | Fill multiple fields in one call, optional submit key | — | — |
| `operagx_select_option` | Choose a `<select>` option by value/label/index | — | ✅ |
| `operagx_drag_and_drop` | Real mouse-down → move → mouse-up drag | — | — |
| `operagx_scroll` | Mouse-wheel scroll, or scroll an element into view | — | — |
| `operagx_wait_for` | Wait for a selector to reach a state (visible/hidden/attached/detached) | ✅ | ✅ |
Every tool accepts an optional tab selector (`tabId`, `tabIndex`, `matchUrl`,
`matchTitle`); omitting it defaults to the first open tab. Every tool also
declares MCP annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`,
`openWorldHint`) and a structured `outputSchema`, so clients that support
`structuredContent` get typed results, not just text.
## Evaluations
[`evaluations/eval.xml`](./evaluations/eval.xml) has 10 read-only, verifiable
QA pairs for testing whether an LLM can use this server effectively, following
the [MCP evaluation guidelines](https://modelcontextprotocol.io). Since this
server deliberately has no navigation tool (that's the base connector's job),
each question assumes both servers are available, exactly as described above.
## Security notes
- This server can act on whatever page is open — treat it like giving a
script mouse/keyboard access to the browser. Don't point an autonomous
agent at a tab with an authenticated session you don't want touched.
- There is no `execute-script`/arbitrary-JS tool by design, to keep the
attack surface to well-defined interaction primitives.
- CDP is unauthenticated by default on `localhost` — don't expose the
debugging port beyond localhost/a trusted network. This server binds
outbound to whatever `OPERAGX_CDP_URL` you configure; it does not open any
listening port itself.
- All inputs are validated with [Zod](https://zod.dev) `.strict()` schemas
before any tool executes.
## Development
```bash
npm run dev # tsc --watch
npm run build # one-shot build to dist/
npx @modelcontextprotocol/inspector node dist/index.js # interactive testing
```
## Contributing
See [`CONTRIBUTING.md`](./CONTRIBUTING.md).
## License
[MIT](./LICENSE)
TDQS
Scored across 12 tools
Each tool targets a distinct user interaction: typing, clicking, hovering, key presses, form filling, option selection, drag-and-drop, scrolling, waiting, and element mapping. Even the overlapping type_text and fill_form are clearly differentiated by scope (single field vs. multi-field with submit).
All tools share the 'operagx_' prefix and use clear snake_case verb-based names (type_text, list_tabs, clear_annotations, drag_and_drop). Single-word verbs like 'click' and 'scroll' are still consistent with the action-oriented pattern and do not cause confusion.
12 tools is a well-scoped set for a browser interaction extension. Each tool covers a distinct, commonly needed automation primitive without redundancy, fitting comfortably within the ideal 3-15 tool range.
The interaction surface is strong: click, type, hover, key press, form fill, select, drag-and-drop, scroll, wait, and element mapping. Minor gaps exist like file upload or iframe switching, but these are likely left to the base connector, so the extension's purpose is well covered.