Как я добавил в браузерного AI-агента поддержку MCP за вечер

"Эта статья о том, как я n0x из просто болталки сделал агента который научился открывать браузер, делать скриншоты и выполнять команды

Как я добавил в браузерного AI-агента поддержку MCP за вечер

Канал с гайдами и контентом по claude code, выкладываем новости (когда режут лимиты в 10 раз) и какие инструменты через claude реализуем для проектов, канал: https://t.me/claudedevolper

Вы когда-нибудь разговаривали с AI, и он в ответ на просьбу «открой Яндекс» писал вам: «Вот ссылка: https://yandex.ru»?

Я — да. И каждый раз мне хотелось сказать: «Спасибо, капитан Очевидность, я и сам это знаю».

Проблема в том, что большинство LLM-приложений — это просто болталки. Они генерируют текст, но не могут сделать что то полезное. А что, если бы AI мог управлять браузером? Открывать страницы, делать скриншоты, выполнять JavaScript?

В этой статье я расскажу, как добавил в проект n0x поддержку MCP (Model Context Protocol) — и научил AI-агента открывать сайты по команде «открой …».

Что такое n0x и зачем ему MCP

n0x — это open-source AI-воркстейшн, который работает полностью в браузере. LLM, RAG, Python-песочница, генерация изображений. Всё это крутится на WebGPU и WASM. Нет сервера, нет API-ключей, ваши данные не покидают ваш компьютер.

Проект уже умеет многое, но есть нюанс: агент мог только болтать. Он вызывает свои внутренние тулы (поиск, Python, память), но не может взаимодействовать с внешним миром.

А мне хотелось, чтобы на фразу «открой Хабр» он мог реально открыть вкладку с habr.com.

Так я решил добавить MCP.

Что такое MCP (Model Context Protocol)

MCP — это протокол, который позволяет LLM-приложениям вызывать внешние инструменты через стандартизированный интерфейс. Придуман он был в Anthropic (создатели Claude), но стал стандартом по всей экосистеме.

Выглядит это так:

[Пользователь] → [LLM] → [MCP Client] → [MCP Server] → [Инструмент] ↓ Результат выполнения

MCP Server — это отдельный процесс, который предоставляет набор тулов. Например, chrome-devtools-mcp даёт возможность управлять браузером: открывать URL, делать скриншоты, выполнять JS.

LLM в ответе пишет что-то на подобии:

{"tool": "chrome_devtools_navigate", "args": {"url": "https://habr.com"}}

MCP клиент перехватывает объект, вызывает сервер, получает результат и отдаёт обратно LLM для генерации финального ответа.

как я встроил MCP в n0x

В n0x используется React + Zustand + Web Workers. MCP-клиент работает в отдельном воркере, чтобы не блокировать UI.

Вот схема:

┌─────────────────────────────────────────────────────────────┐ │ UI (React) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ ChatInput │ │ AgentTrace │ │ McpToolDrawer │ │ │ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │ └─────────┼────────────────┼────────────────────┼────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Zustand Store │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ useAgent.ts │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │ │ │ │ │ parseToolCall│ │ executeTool │ │ buildPrompt │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬──────┘ │ │ │ └─────────┼──────────────────┼──────────────────┼────────┘ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ useMCP.ts │ │ │ │ (Zustand store + Worker communication) │ │ │ └─────────────────────────┬──────────────────────────────┘ │ └────────────────────────────┼────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Web Worker │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ mcp.worker.ts │ │ │ │ • Client (StreamableHTTPClientTransport) │ │ │ │ • Tool registration & state management │ │ │ └─────────────────────────┬──────────────────────────────┘ │ └────────────────────────────┼────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ MCP Server │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ chrome-devtools-mcp + supergateway │ │ │ │ (отдельный процесс на localhost:8080/mcp) │ │ │ └────────────────────────────────────────────────────────┘ │

Каждый уровень отвечает за своё:

  • UI — отображает панель управления тулами (McpToolDrawer)
  • useAgent.ts — парсит ответы LLM и вызывает тулы
  • useMCP.ts — Zustand-хранилище и коммуникация с воркером
  • mcp.worker.ts — реальные HTTP-запросы к MCP-серверу
  • MCP Server — внешний процесс (chrome-devtools-mcp)

Ключевые компоненты кода

1. Подключение к MCP-серверу (mcp.worker.ts)

async function connectToServer(url: string) { const serverUrl = new URL(url); const transport = new StreamableHTTPClientTransport(serverUrl); const client = new Client({ name: "n0x-mcp-client", version: "1.0.0" }); await client.connect(transport); const { tools } = await client.listTools(); return { client, tools };}

Ничего сложного — создаём транспорт, подключаем клиент, получаем список тулов.

2. Парсинг навигационных команд (useAgent.ts)

Самое интересное для меня было — научить LLM понимать естественный язык:

function parseToolCall(text: string) { // Паттерны для распознавания команд навигации const navPatterns = [ /(?:открой|open|goto|перейди|загрузи)\s+(?:https?:\/\/)?([a-zA-Z0-9][a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(?::\d+)?(?:\/[\w\-./?%&=]*)?)/i, /^(?:открой|open)\s+([\w\-]+(?:\.[\w\-]+)+)/i, ]; for (const pattern of navPatterns) { const match = text.match(pattern); if (match) { let url = match[1]; if (!url.startsWith('http')) url = 'https://' + url; return { thought: "", tool: "mcp_navigate", // имя тула из MCP args: { url } }; } } // ... остальной парсинг JSON}

Благодаря этой конструкции, фраза «открой яндекс» агент возвращает структурированный вызов тула, а не просто текст.

3. Алиасы для удобства (useChat.ts)

Когда MCP-тулы загружаются, я на всякий случай добавил короткие алиасы:

for (const tool of server.tools) { if (tool.isEnabled) { toolkit[tool.name] = async (args) => { return await mcpState.callTool(server.url, tool.name, args); }; // Алиасы для удобства пользователей if (tool.name.includes('navigate')) { toolkit['open'] = toolkit[tool.name]; toolkit['goto'] = toolkit[tool.name]; } }}

После этого стало можно писать «open google.com» вместо длинного chrome_devtools_navigate.

4. Системный промпт с инструкциями

Чтобы LLM понимала, когда надо вызывать тулы, я добавил в системный промпт секцию:

BROWSER CONTROL TOOLS: • http___localhost_8080_mcp_navigate — OPEN ANY URL IN BROWSER. CRITICAL INSTRUCTIONS: - When user asks to "open", "go to", "visit", "открой", "перейди" — use navigate tool IMMEDIATELY. - Do NOT respond with just a text link. - ALWAYS add https:// if not specified.

Как это выглядит со стороны пользователя

  1. Пользователь пишет: «открой хабр»
  2. Агент распознаёт команду и вызывает MCP-тул navigate
  3. Chrome открывает новую вкладку с habr.com
  4. Агент отвечает: «✓ Открыл https://habr.com»

Всё происходит достаточно быстро. Никаких лишних кликов.

Подключение

Есть два процесса, которые вместе создают мост между n0x и браузером Chrome:

n0x (браузер) → supergateway (прокси) → chrome-devtools-mcp → Chrome (с отладкой)

Для начала надо запустить Chrome с remote debugging

chromium --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile

Проверить, что Chrome запущен правильно:

В отдельном терминалеcurl http://localhost:9222/json/version

Дальше надо запустить supergateway с chrome-devtools-mcp

npx supergateway --stdio "npx chrome-devtools-mcp@latest --browser-url=http://127.0.0.1:9222" \ --port 8080 --outputTransport streamableHttp

И указать путь в MCP Tools http://localhost:8080/mcp

Вот и все.

Что дальше?

Сейчас я добавил только открытие URL. Но MCP открывает огромные возможности:

  • Скриншоты — «сделай скриншот текущей страницы»
  • Выполнение JS — «найди на странице все заголовки h1»
  • Взаимодействие с DOM — «кликни на кнопку “Войти”»
  • Заполнение форм — «заполни поле поиска словом “MCP”»

В планах сделать полноценного AI-ассистента, который реально работает в браузере, а не просто общение.

Итог

За один вечер я добавил в n0x поддержку MCP. Мне понавилось то, на сколько это просто сделать агента, который может управлять браузером. Главное что я понял: MCP — это мост между LLM и реальным миром. И он уже существует прямо в браузере. Если захотите повторить — все исходники открыты в репозитории n0x.

Канал с гайдами и контентом по claude code, выкладываем новости (когда режут лимиты в 10 раз) и какие инструменты через claude реализуем для проектов, канал: https://t.me/claudedevolper

Как я добавил в браузерного AI-агента поддержку MCP за вечер