ffmcp
Provides tools for controlling Firefox browser, managing tabs, pages, cookies, history, bookmarks, and executing arbitrary WebExtension API calls, enabling full browser automation.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ffmcpopen a new tab to example.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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:
about:debugging#/runtime/this-firefoxЗагрузить временное дополнение… → выбрать
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:
chrome://extensions→ включить Режим разработчикаЗагрузить распакованное расширение → выбрать каталог
extension-chromeID должен получиться
mifolcjccjkcdfdoebmkgklimogoemng— он зашит полемkeyв манифесте, и именно его разрешает манифест native-хостаЖелательно: в карточке расширения включить Разрешить пользовательские скрипты
Последний пункт нужен для 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 инструментов. Основные:
Группа | Инструменты |
Браузер |
|
Рабочее окно |
|
Вкладки и окна |
|
Страница |
|
Отладка |
|
Профиль |
|
Всё остальное |
|
Старые имена вида 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 |
| мир страницы + |
Скриншот всей страницы | одним вызовом | прокрутка и сшивка кусков (медленнее, до 25 экранов) |
Скриншот неактивной вкладки | как есть | вкладку приходится на миг активировать |
Контейнеры |
| аналога нет, вызов честно падает |
Что из этого важно на практике:
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.
Диагностика
Симптом | Причина |
| браузер не запущен либо расширение не загружено; |
| хост поднялся, но расширение отвалилось — жми «Переподключить» в попапе |
Значок расширения показывает | native-хост не запускается; смотри |
В Chrome ID расширения не | загружен каталог без поля |
| включи «Разрешить пользовательские скрипты» в карточке расширения Chrome |
| это внутренняя страница ( |
Вызовы висят, значок показывает | ждёт твоего подтверждения — открой popup ffmcp и выбери область доступа |
| никто не нажал подтверждение за отведённое время; повтори вызов и подтверди в popup |
Агент переспрашивает доступ каждый раз | одобрено «на подключение»; выбери «на сессию» или «навсегда» |
В Chrome пропали логи консоли | service worker уснул и буферы обнулились — логи копятся заново с этого момента |
This server cannot be installed
Maintenance
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
- Alicense-qualityDmaintenanceAn MCP server paired with a Firefox extension that enables LLM clients to control the user's browser, supporting tab management, history search, and content reading.Last updated31307MIT
- Alicense-qualityBmaintenanceAn MCP Server that enables AI assistants to interact with your local browsers.Last updated2,67454MIT
- Alicense-qualityDmaintenanceAn MCP server that exposes Firefox browser automation capabilities through the Model Context Protocol, enabling AI assistants to control web browsers for navigation, interaction, and data collection tasks.Last updated4BSD 3-Clause
- AlicenseBqualityCmaintenanceBrowser MCP server that connects to your existing browser, preserving sessions, passwords, and extensions, enabling AI agents to interact with web pages without bot detection.Last updated31201MIT
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…
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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