Skip to main content
Glama

ffmcp

Расширения для Firefox и Chrome + MCP-сервер, дающие агентам полный доступ к твоим настоящим браузерам. Транспорт целиком локальный: stdio и Unix-сокет, ни одного HTTP-запроса и ни одного открытого порта.

Как устроено

                                 ┌─ Unix-сокет ~/.ffmcp/firefox.sock ─▶ ffmcp-host.js ─▶ расширение Firefox
MCP-агент ──stdio JSON-RPC──▶ ffmcp-mcp.js
                                 └─ Unix-сокет ~/.ffmcp/chrome.sock ──▶ ffmcp-host.js ─▶ расширение Chrome

У каждого браузера свой native-хост и свой сокет (права 0600). Хост поднимается самим браузером при старте расширения и работает как брокер: к нему подключаются MCP-серверы. Поэтому несколько агентов одновременно работают с одним браузером, а внешне не открыт ни один сетевой порт.

Один MCP-сервер обслуживает оба браузера сразу — какой именно использовать, агент решает вызовом browser_use либо аргументом browser у любого инструмента.

Ответы больше ~700 КБ (скриншоты, дампы DOM) автоматически режутся на чанки и собираются обратно в хосте — ограничение native messaging на размер сообщения обходится прозрачно.

Related MCP server: mcp-browser-kit

Установка

cd ~/Projects/ffmcp
./install.sh

Скрипт кладёт манифесты native-хоста в каталоги Firefox и всех найденных браузеров на Chromium и создаёт лаунчеры с абсолютным путём к node (браузер из Finder не видит /opt/homebrew/bin).

Затем ставим расширения — нужно хотя бы одно.

Firefox:

  1. about:debugging#/runtime/this-firefox

  2. Загрузить временное дополнение… → выбрать extension/manifest.json

Временное дополнение живёт до перезапуска Firefox. Чтобы поставить навсегда, нужен Firefox Developer Edition / Nightly / ESR с xpinstall.signatures.required = false в about:config — тогда собери .xpi (npm run build-xpi) и установи через about:addonsУстановить дополнение из файла. В обычном релизном Firefox неподписанные расширения навсегда поставить нельзя — это ограничение Mozilla.

Chrome:

  1. chrome://extensions → включить Режим разработчика

  2. Загрузить распакованное расширение → выбрать каталог extension-chrome

  3. ID должен получиться mifolcjccjkcdfdoebmkgklimogoemng — он зашит полем key в манифесте, и именно его разрешает манифест native-хоста

  4. Желательно: в карточке расширения включить Разрешить пользовательские скрипты

Последний пункт нужен для browser_eval на сайтах со строгим CSP — подробности ниже. Распакованное расширение переживает перезапуск Chrome, но требует включённого режима разработчика.

Проверка обоих браузеров сразу:

./bin/ffmcp.js doctor
./bin/ffmcp.js browsers

Подключение к агентам

Claude Code:

claude mcp add browser -- node ~/Projects/ffmcp/bin/ffmcp-mcp.js

Любой другой MCP-клиент (mcp.json, Cursor, Zed):

{
  "mcpServers": {
    "browser": {
      "command": "node",
      "args": ["/абсолютный/путь/к/ffmcp/bin/ffmcp-mcp.js"]
    }
  }
}

Если хочется жёстко привязать сервер к одному браузеру — добавь --browser firefox или --browser chrome (то же самое делает переменная FFMCP_BROWSER). Тогда browser_use не понадобится, а вызовы в другой браузер уходить не будут.

Выбор браузера

browser_list                      # кто доступен и кто выбран сейчас
browser_use {"browser": "chrome"} # закрепить Chrome для всех следующих вызовов
browser_use {}                    # показать текущий выбор
browser_use {"release": true}     # вернуться к автоопределению
browser_tabs {"browser": "firefox"}  # разовый вызов мимо закрепления

Без закрепления браузер выбирается сам: единственный запущенный, иначе последний удачно использованный, иначе Firefox. Аргумент browser у конкретного вызова всегда сильнее закрепления.

Инструменты

39 инструментов. Основные:

Группа

Инструменты

Браузер

browser_list, browser_use, browser_status

Рабочее окно

browser_use_window, browser_new_window

Вкладки и окна

browser_tabs, browser_open, browser_navigate, browser_close_tab, browser_activate_tab, browser_reload, browser_back, browser_forward, browser_windows

Страница

browser_snapshot, browser_read, browser_html, browser_eval, browser_click, browser_fill, browser_press, browser_wait_for, browser_screenshot

Отладка

browser_console, browser_network

Профиль

browser_cookies, browser_cookie_set, browser_cookie_remove, browser_history, browser_bookmarks, browser_downloads, browser_storage, browser_containers, browser_recent_closed

Всё остальное

browser_api, browser_api_describe

Старые имена вида firefox_tabs продолжают работать (и заодно задают браузер), но в списке инструментов их больше нет.

browser_api — это и есть «полный доступ». Он вызывает любой метод WebExtension API напрямую, так что агент не ограничен готовым списком:

{ "path": "tabs.query", "args": [{ "audible": true }] }
{ "path": "browsingData.removeCache", "args": [{}] }
{ "path": "proxy.settings.set", "args": [{ "value": { "proxyType": "none" } }] }

browser_api_describe показывает, что вообще доступно ({"path": "cookies"} → список методов). Наборы API у Firefox и Chrome разные, так что спрашивать стоит у того браузера, в котором собираешься работать.

Рабочее окно

По умолчанию операции без явного tabId идут в активную вкладку текущего окна — то есть туда, где сейчас работаешь ты. Чтобы агент не мешал, закрепи за ним окно:

browser_new_window {"url": "https://example.com"}   # своё окно, сразу закреплено
browser_use_window {"windowId": 3}                  # закрепить существующее
browser_use_window {}                               # показать текущее закрепление
browser_use_window {"release": true}                # снять

После закрепления в это окно уходят все операции без tabId, туда же открываются новые вкладки, а browser_tabs показывает только его вкладки (allWindows: true — все). В browser_windows закреплённое окно помечено target: true, а в попапе расширения видно строкой «Рабочее окно». Закрепление живёт отдельно в каждом браузере и снимается само, если окно закрыть. Из CLI — ffmcp use-window <id> и ffmcp new-window [url].

Работа со страницей

browser_snapshot возвращает интерактивные элементы с короткими uid — это дешевле скриншота и точнее селекторов:

{ "uid": "e12", "tag": "input", "type": "email", "text": "Email address", "rect": {...} }

Далее browser_fill {uid: "e12", value: "..."} и browser_click {uid: "e15"}. browser_fill выставляет значение через нативный сеттер прототипа и шлёт input/change, поэтому корректно работает с React, Vue и Svelte.

browser_eval выполняет код в контексте страницы — это тело async-функции, доступны await и return:

return [...document.querySelectorAll("h2")].map(h => h.innerText)

Логи консоли и необработанные исключения собираются автоматически на каждой загруженной странице (буфер на 2000 записей), сетевые запросы — через webRequest. Читать через browser_console и browser_network. Вывод console.* из самого browser_eval тоже попадает в буфер.

Чем Chrome отличается от Firefox

Расширение для Chrome — Manifest V3, и часть вещей там устроена иначе. Набор операций одинаковый, отличается поведение:

Firefox

Chrome

Фон

постоянная фоновая страница

service worker, который браузер усыпляет

Произвольный JS

tabs.executeScript со строкой

мир страницы + new Function, при отказе CSP — мир пользовательских скриптов

Скриншот всей страницы

одним вызовом

прокрутка и сшивка кусков (медленнее, до 25 экранов)

Скриншот неактивной вкладки

как есть

вкладку приходится на миг активировать

Контейнеры

browser_containers работает

аналога нет, вызов честно падает

Что из этого важно на практике:

  • browser_eval и CSP. Код выполняется в мире страницы, а там действует её Content-Security-Policy. На сайтах со строгим script-src (например GitHub) eval запрещён. Обход — включить в карточке расширения «Разрешить пользовательские скрипты»: тогда ffmcp выполнит код в отдельном мире, где CSP страницы не действует. Без этого на таких сайтах придёт понятная ошибка с этой же подсказкой. Инструменты browser_click, browser_fill, browser_snapshot и остальные структурные операции CSP не касается вообще — они внедряются готовыми функциями, а не строками.

  • Буферы логов и сон воркера. Service worker MV3 живёт от события до события. Расширение держит его будильником и переподключается автоматически, но если Chrome всё же усыпит воркер, накопленные browser_console и browser_network обнулятся. Закрепление рабочего окна переживает это — оно лежит в storage.session.

  • Служебные страницы. chrome://*, Chrome Web Store и PDF расширениям недоступны — там любая операция со страницей вернёт ошибку. В Firefox то же самое с about:* и addons.mozilla.org.

CLI

Тот же мост доступен вручную, без агента:

./bin/ffmcp.js doctor                      # диагностика обоих браузеров
./bin/ffmcp.js browsers                    # кто сейчас на связи
./bin/ffmcp.js status                      # версия браузера, число вкладок
./bin/ffmcp.js tabs                        # список вкладок
./bin/ffmcp.js open https://example.com
./bin/ffmcp.js snapshot 12                 # элементы вкладки 12
./bin/ffmcp.js eval 'return document.title'
./bin/ffmcp.js api tabs.query '[{"pinned":true}]'
./bin/ffmcp.js call page.text '{"tabId":12}'

Браузер выбирается флагом --browser=chrome (или -b chrome), переменной FFMCP_BROWSER, иначе автоматически:

./bin/ffmcp.js -b chrome tabs
FFMCP_BROWSER=chrome ./bin/ffmcp.js status

Тесты

./tests/run.sh

Живой браузер не нужен — браузеры и расширения заменяются заглушками. Проверяются: сборка JSON-RPC и все схемы инструментов, проход вызова MCP → сокет → хост → расширение, выбор браузера и маршрутизация между двумя хостами, сборка чанкованных ответов, очистка сокета, отсутствие синхронных циклов при загрузке фона (отдельно для фоновой страницы Firefox и для service worker Chrome) и, отдельно, устойчивость обоих перехватчиков консоли к зацикливанию.

Последний тест не декоративный. В первой версии обмен со страницей шёл через window.postMessage, а его видит и сама страница: если её код логирует полученные сообщения (частый паттерн у виджетов и аналитики), возникала петля console.log → postMessage → обработчик страницы → console.log. Каждая итерация уходила в фон отдельным runtime.sendMessage, забивая главный поток родительского процесса браузера, и он переставал реагировать на ввод. Сейчас обмен идёт приватным CustomEvent, стоят защита от реентрантности, лимит 100 сообщений в секунду со страницы, батчинг раз в 250 мс и общий потолок 500 записей в секунду в фоне.

Безопасность

Это по построению очень мощный доступ: агент видит твои cookies, историю и авторизованные сессии и может действовать от твоего имени на любом сайте.

Подтверждение подключения

Каждое новое подключение MCP-клиента к сокету пользователь подтверждает вручную. Пока не подтверждено — все вызовы (кроме health-check ping и __status) висят, а хост показывает нотификацию браузера. Клик по ней открывает popup расширения, где для запроса предлагается выбор области:

  • это подключение — доступ только для текущего живого соединения; переподключился клиент — спросят снова;

  • на эту сессию — до перезапуска браузера (запоминается токен клиента в памяти хоста);

  • навсегда — токен клиента сохраняется в ~/.ffmcp/allowed-<браузер>.json (0600) и переживает перезапуск.

Одобрение действует в пределах одного браузера: разрешив агенту Firefox, ты не разрешил ему заодно и Chrome — там он спросит отдельно.

Клиент идентифицируется стабильным токеном из ~/.ffmcp/client-token (0600); MCP-сервер и CLI используют один и тот же токен, поэтому одобрение «навсегда» покрывает оба. Если пользователь не реагирует за FFMCP_APPROVAL_TIMEOUT_MS (по умолчанию 120000 мс), доступ отклоняется (fail-closed). Полностью выключить гейт — FFMCP_APPROVAL=0 (для headless/CI).

Ограничение платформы: кнопок в нотификациях Firefox нет, поэтому подтверждать нужно именно в popup (нотификация только сигналит и открывает его).

  • Сокеты лежат в ~/.ffmcp с правами 0600 — доступны только твоему пользователю, никакой сети, ни локальной, ни внешней.

  • Буферы browser_console и browser_network пишутся постоянно, со всех вкладок, и в них оседает то, что страницы логируют сами. На практике это бывают почта, идентификаторы аккаунта, тариф и прочие персональные данные — например, claude.ai печатает в консоль полный набор трейтов аналитики. Любой подключённый агент прочитает это одним вызовом. Чистить буфер: browser_console {"clear": true}.

  • Манифест хоста ограничивает подключение конкретным расширением: allowed_extensions с ffmcp@local у Firefox, allowed_origins с chrome-extension://mifolcjccjkcdfdoebmkgklimogoemng/ у Chrome.

  • Чтобы временно всё отключить — выгрузи расширение (about:debugging / chrome://extensions) или закрой браузер: сокет исчезает вместе с хостом.

  • Логи хостов: ~/.ffmcp/firefox.log и ~/.ffmcp/chrome.log.

Диагностика

Симптом

Причина

сокет не найден

браузер не запущен либо расширение не загружено; ffmcp browsers покажет, кто на связи

расширение ffmcp не подключено к хосту

хост поднялся, но расширение отвалилось — жми «Переподключить» в попапе

Значок расширения показывает off

native-хост не запускается; смотри ~/.ffmcp/<браузер>.log и проверь путь к node в лаунчере

В Chrome ID расширения не mifolcjccjkcdfdoebmkgklimogoemng

загружен каталог без поля key в манифесте — переустанови из extension-chrome

страница запрещает выполнение кода своей CSP

включи «Разрешить пользовательские скрипты» в карточке расширения Chrome

скрипт не вернул результат

это внутренняя страница (about:, chrome://, магазин расширений) — там расширения работать не могут

Вызовы висят, значок показывает !

ждёт твоего подтверждения — открой popup ffmcp и выбери область доступа

доступ к … не подтверждён (таймаут)

никто не нажал подтверждение за отведённое время; повтори вызов и подтверди в popup

Агент переспрашивает доступ каждый раз

одобрено «на подключение»; выбери «на сессию» или «навсегда»

В Chrome пропали логи консоли

service worker уснул и буферы обнулились — логи копятся заново с этого момента

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Live browser debugging for AI assistants — DOM, console, network via MCP.

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ruslankolmakov/ffmcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server