Skip to main content
Glama
Zindaar

operagx-connector-plus

by Zindaar
README.md
# operagx-connector-plus

[![CI](https://github.com/Zindaar/operagx-connector-plus/actions/workflows/ci.yml/badge.svg)](https://github.com/Zindaar/operagx-connector-plus/actions/workflows/ci.yml)
[![npm version](https://img.shields.io/npm/v/operagx-connector-plus.svg)](https://www.npmjs.com/package/operagx-connector-plus)
[![npm downloads](https://img.shields.io/npm/dm/operagx-connector-plus.svg)](https://www.npmjs.com/package/operagx-connector-plus)
[![Node.js >=18](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](./package.json)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
[![Open issues](https://img.shields.io/github/issues/Zindaar/operagx-connector-plus.svg)](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

A4.5/5.0

Scored across 12 tools

Disambiguation5/5

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).

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivityStale
ResponsivenessNo issues