An MCP server for controlling Yandex Browser. You can connect it to Claude Desktop (or any MCP-capable host) to manage tabs, windows, and navigation.
Note: macOS only. This extension relies on AppleScript and the Yandex Browser AppleScript dictionary, which are available on macOS.
To use as an npm package:
npm install @avavilov/yandex-browser-controlOr use as a Claude Desktop MCP server:
- If distributed via the Claude Desktop Extensions catalog: open Claude Desktop → Extensions and install "Yandex Browser Control" (when available).
- For local development today: add it as a custom MCP server in Claude Desktop.
- Build or run from source (see Development below).
- In Claude Desktop, go to Settings → Extensions → Model Context Protocol → Add server (Command), and point it to either:
- Dev: run command
npm run devin this repository directory - Prod: run command
node dist/index.jsin this repository directory
- Dev: run command
Once connected, you can control Yandex Browser directly through Claude Desktop.
You can choose which macOS app bundle to control using a setting exposed in Claude Desktop:
- Setting name: app_id
- Default:
ru.yandex.desktop.yandex-browser - Where it’s used: passed to the server as environment variable
APP_ID.
This is useful if you want to target Yandex Browser Beta/Canary or a custom Chromium-based browser that supports the same AppleScript dictionary. Set the bundle identifier accordingly (for example, ru.yandex.desktop.yandex-browser.beta if applicable).
For local development or manual runs, you can also set the environment variable directly:
APP_ID="ru.yandex.desktop.yandex-browser" npm run dev
- All logs are emitted to stderr only (never stdout) to comply with MCP over stdio.
- In addition, logs are duplicated to a temp file. The absolute path to this file is printed to stderr on startup, for example:
logging to file: /var/folders/…/yandex-browser-control.log.12345
You can control verbosity with the LOG_LEVEL env variable (default: info).
AppleScript executions have a unified timeout applied at the runner level. This prevents scattered per-call overrides and keeps both AppleScript and controller layers consistent.
Environment variable:
| Variable | Default | Meaning |
|---|---|---|
APPLE_RUNNER_TIMEOUT_MS |
60000 |
Global timeout (milliseconds) for AppleScript execution (converted internally to seconds) and the Node.js controller watchdog. |
Behavior & precedence (from the underlying @avavilov/apple-script library):
- Per-run override (
apple.run(op, input, { timeoutSec })) timeoutByKind(if set on runner config)defaultTimeoutSec(derived fromAPPLE_RUNNER_TIMEOUT_MSinsrc/runtime/apple-runner.ts)- Library fallback
We intentionally rely on (3) so ordinary calls do not need explicit options. Increase the timeout if you experience timeouts on large tab counts or heavy system load:
APPLE_RUNNER_TIMEOUT_MS=90000 npm run devTests now fail (not skip) on timeout to surface real instability early. If you hit genuine timeouts, adjust the env var rather than reintroducing skip logic.
See CONTRIBUTING.md for development, build, and code quality instructions.
We separate fast unit tests from slower AppleScript-driven integration tests by naming convention:
- Integration test names are prefixed with
[int](see*.integration.spec.ts). - To run only unit tests (skipping integration by name):
npm run test:unit
This invokes Node's test runner with --test-skip-pattern '^\[int\]' before the --test glob so integration test definitions are filtered by name without adding custom environment flags.
Run integration tests explicitly:
npm run test:int
Or everything (unit first, then integration):
npm test
Rationale: --test-skip-pattern filters test names, not files. We keep a dedicated test:int script so integration specs are still discoverable and runnable in isolation.
src/— TypeScript source code for the server.dist/— Compiled JavaScript output (generated on build).src/tools/— MCP tools, one directory per tool with anindex.tsthat exports metadata, input schema (when needed), handler, and types.
- Each tool lives in
src/tools/<tool-name>/index.tsand should export:nameanddescription(strings / const assertions)argsSchema(a Zod schema; usez.object({})for no-arg tools)handler(receives already-validated args) returning MCPCallToolResultArgstype (e.g.export type Args = z.infer<typeof argsSchema>) for consumers- (Optional)
annotations
- Register all tools in
src/tools/index.tsviaregisterTools(server), which is invoked fromsrc/index.ts.
See detailed per-tool documentation in src/tools/TOOLS.md.
MIT