MCP в браузерного AI-агента: полное руководство с кодом | AiManual
AiManual Logo Ai / Manual.
28 Апр 2026 Гайд

Как добавить поддержку MCP в браузерного AI-агента: полное руководство с кодом

Пошаговое руководство по интеграции Model Context Protocol в браузерного AI-агента n0x. Код, WebGPU, WASM, реальные примеры, ошибки и советы.

Браузерные AI-агенты — штука крутая, но до недавнего времени они были как рыба на велосипеде: вроде едет, но без контекста. Модель живёт в песочнице, не знает про твои файлы, базы данных, API. Выход есть — Model Context Protocol (MCP). И сегодня я покажу, как прикрутить MCP к браузерному агенту на примере open-source проекта n0x. Без туманных обещаний — только код, WebGPU, WASM и грязные хаки.

Если вы ещё не знаете, что такое MCP, советую сначала прочитать материал про MCP от Anthropic. Там база, без которой дальше будет тяжело.

Проблема: агент в браузере — глухой и слепой

Возьмём типичного браузерного агента: он открывает страницы, кликает, скроллит, может даже заполнять формы. Всё это работает через DOM API и иногда через WebGPU для инференса моделей. Но как только агенту нужно узнать курс доллара, посчитать что-то в Google Таблицах или отправить запрос в ваш внутренний API — начинается ад. Приходится костылить iframe, Service Workers, или вообще перетаскивать данные вручную.

Модель живёт изолированно, её контекст — это только то, что она видит на странице. MCP решает это за счёт стандартного протокола, который позволяет агенту подключать внешние инструменты, базы знаний и любые API, работающие через JSON-RPC.

💡
Идея простая: агент внутри браузера общается с MCP-сервером (который может быть запущен локально или на удалённой машине) по WebSocket или через HTTP SSE. Сервер предоставляет инструменты — от простого чтения файлов до сложных цепочек вызовов. Подробнее о концепции сабагентов и скиллов читайте в статье «Skills, MCP и сабагенты: как собрать AI-агента из LEGO в 2026 году».

Решение: n0x + MCP = агент, который умеет всё

Проект n0x (версия 2.4.0 на момент апреля 2026) — это фреймворк для построения AI-агентов, которые работают прямо в браузере. Он использует WebGPU для ускорения инференса моделей (через WASM + Vulkan/Metal) и поддерживает динамическую загрузку LLM через Hugging Face Transformers.js. Но главная фишка — плагинная система, в которую мы и воткнём MCP.

Вот что нам понадобится:

  • n0x SDK — сам агент, ставится через npm или CDN.
  • MCP-совместимый сервер — можно взять готовый (например, MCP-Manticore для SQL или Figma MCP-сервер для дизайна), либо написать свой на Python/Node.js.
  • MCP-клиент в браузере — библиотека @modelcontextprotocol/sdk уже умеет работать с WebSocket.

Звучит логично? Тогда поехали собирать.

Пошаговый план: от нуля до рабочего агента

1 Поднимаем MCP-сервер (можно локально)

В качестве примера возьмём сервер, который даёт агенту доступ к файловой системе и умеет выполнять Python-скрипты. Запускаем на Node.js:

mkdir mcp-server && cd mcp-server
npm init -y
npm install @modelcontextprotocol/sdk
# создаём index.js

В index.js определяем два инструмента: read_file и run_python. Код сервера (минимальный, но рабочий):

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new Server({
  name: "my-browser-helper",
  version: "1.0.0",
}, {
  capabilities: {
    tools: {}
  }
});

server.setRequestHandler("tools/list", async () => ({
  tools: [
    {
      name: "read_file",
      description: "Читает содержимое файла по пути",
      inputSchema: {
        type: "object",
        properties: {
          path: { type: "string" }
        },
        required: ["path"]
      }
    },
    {
      name: "run_python",
      description: "Выполняет Python-код и возвращает результат",
      inputSchema: {
        type: "object",
        properties: {
          code: { type: "string" }
        },
        required: ["code"]
      }
    }
  ]
}));

server.setRequestHandler("tools/call", async (request) => {
  const { name, arguments: args } = request.params;
  if (name === "read_file") {
    const fs = await import("fs/promises");
    const content = await fs.readFile(args.path, "utf-8");
    return { content: [{ type: "text", text: content }] };
  }
  if (name === "run_python") {
    const { execSync } = await import("child_process");
    try {
      const output = execSync(`python3 -c \`${args.code}\``, { encoding: "utf-8" });
      return { content: [{ type: "text", text: output }] };
    } catch (e) {
      return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
    }
  }
  throw new Error("Tool not found");
});

const transport = new StdioServerTransport();
await server.connect(transport);

Запускаем: node index.js. Сервер готов слушать. Но для браузера нужен WebSocket. Переключаем транспорт:

import { WebSocketServerTransport } from "@modelcontextprotocol/sdk/server/websocket.js";

const transport = new WebSocketServerTransport({ port: 3001 });
await server.connect(transport);
console.log("MCP server running on ws://localhost:3001");

Важно: Если вы используете HTTPS (а в продакшне иначе нельзя), WebSocket должен быть защищённым — wss://. Для локальной разработки подойдёт ws://, но браузер может блокировать смешанный контент, если страница открыта по HTTP. Учитывайте.

2 Инициализируем n0x агента с MCP-клиентом

Ставим n0x через CDN (или npm, если используете сборщик):


<script type="module">
import { Agent } from "https://cdn.n0x.ai/v2.4/agent.js";
import { Client } from "https://cdn.jsdelivr.net/npm/@modelcontextprotocol/sdk@1.7.0/client/wasm/index.js";

// ...
</script>

Создаём агента, загружаем модель (например, Qwen2.5-7B-Instruct quantized для WebGPU) и подключаем MCP-клиент:

const agent = new Agent({
  model: "nomic-ai/Qwen2.5-7B-Instruct-q4f16",
  backend: "webgpu", // используем WebGPU
  maxContextLength: 4096,
});

// Ждём загрузки модели
await agent.init();

// Подключаем MCP
const mcpClient = new Client({
  name: "n0x-mcp-client",
  version: "1.0.0",
});

await mcpClient.connect({
  transport: new WebSocketClientTransport(new WebSocket("ws://localhost:3001"))
});

// Регистрируем инструменты MCP как функции агента
const tools = await mcpClient.listTools();
for (const tool of tools) {
  agent.registerTool({
    name: tool.name,
    description: tool.description,
    handler: async (args) => {
      const result = await mcpClient.callTool(tool.name, args);
      return result.content[0].text;
    }
  });
}

Теперь агент может вызывать read_file и run_python прямо из своего контекста. Например, если пользователь скажет: «Прочитай файл config.json и запусти скрипт, который выведет его размер», агент сам решит, какие инструменты и в каком порядке запустить.

3 Заставляем агента использовать MCP в диалоге

Самое смешное, что просто зарегистрировать инструменты мало. Нужно ещё научить LLM их применять. В n0x это делается через системный промпт. Добавляем описание инструментов в начало контекста:

const systemPrompt = `Ты — полезный AI-агент, работающий в браузере.
У тебя есть доступ к следующим инструментам:
- read_file (аргумент: path) — читает файл
- run_python (аргумент: code) — выполняет Python код
Чтобы использовать инструмент, напиши JSON вида:
{"tool": "название", "args": {...}}
После получения результата проанализируй его и дай ответ пользователю.`;

await agent.setSystemPrompt(systemPrompt);

Затем в цикле диалога парсим ответ агента. Если он содержит вызов инструмента — выполняем, результат подставляем обратно в контекст и просим модель продолжить. Это стандартная схема ReAct (Reasoning + Acting).

async function chat(userMessage) {
  const response = await agent.generate(userMessage);
  const toolCall = extractToolCall(response.text);
  if (toolCall) {
    const result = await agent.executeTool(toolCall.name, toolCall.args);
    const finalResponse = await agent.generate(
      `Результат выполнения ${toolCall.name}: ${result}\n\nДай ответ пользователю.`
    );
    return finalResponse.text;
  }
  return response.text;
}

function extractToolCall(text) {
  const match = text.match(/\{"tool":\s*"(\w+)",\s*"args":\s*(\{[^}]+\})\}/);
  if (match) {
    return { name: match[1], args: JSON.parse(match[2]) };
  }
  return null;
}

Готово. Запускаем — и видим, как агент читает файлы и выполняет Python прямо из браузера. Магия.

Нюансы и грабли, на которые я наступил

В теории всё красиво, на практике — вот что может пойти не так.

Проблема Причина Решение
WebSocket не соединяется CORS или смешанный контент Настройте сервер с Access-Control-Allow-Origin: * и используйте wss:// на продакшне
Модель не вызывает инструменты Слабый системный промпт или маленький контекст Увеличьте контекст до 8k токенов, добавьте примеры вызовов в промпт
WebGPU падает с ошибкой Несовместимость драйвера или устаревший браузер Обновите Chrome 125+, включите флаг WebGPU, попробуйте backend: "wasm" как fallback
Сервер отказывается выполнять Python Безопасность: exec может быть запрещён Используйте Docker для изоляции или перепишите на безопасный executor (например, Pyodide)

Отдельно хочу предупредить про безопасность. Если ваш MCP-сервер запущен на локальной машине, и вы подключаетесь к нему из браузера — любой скрипт на странице может вызывать инструменты. Используйте ограничение по происхождению (origin) или токен аутентификации. В примере выше сервер не проверяет, кто к нему подключился. Для продакшна добавьте проверку заголовка Sec-WebSocket-Protocol или используйте JWT.

Ещё один важный момент: не пытайтесь загрузить модель через WebGPU на машинах без дискретной видеокарты. Интегрированная графика Intel или старые AMD часто не поддерживают FP16 вычисления, и инференс будет в 10 раз медленнее, чем на CPU. Для продакшна лучше запускать модель на сервере, а браузеру оставить только лёгкий MCP-клиент. Почитайте про LM Studio MCP — там показано, как запустить агента локально без GPU.

Как не надо делать: типичные ошибки

Вот кусок кода, который я написал на первой итерации. Он упал с ошибкой, но объяснит, почему нельзя тупо копировать:

// НЕПРАВИЛЬНО: асинхронный вызов без await
const tools = mcpClient.listTools();  // вернёт Promise, а не массив
agent.registerTool(tools[0]);         // tools[0] undefined

Ошибка начинающих — забыть await. Но ещё хуже: регистрировать инструменты до того, как агент инициализирован. В n0x agent.init() загружает модель и выделяет память, и только после этого можно добавлять кастомные обработчики. Порядок важен.

Вторая ошибка — парсить вызов инструмента регуляркой. Если модель сгенерирует JSON с лишними пробелами или в markdown-коде — всё сломается. Лучше попросить модель выводить только JSON (без пояснений) и парсить через JSON.parse, обернув в try-catch. Или использовать structured output — у n0x есть поддержка response_format: { type: "json_object" }.

Что дальше: превращаем агента в мультиинструментальную платформу

После того как базовая связка работает, можно расширять.

  • Подключить несколько MCP-серверов одновременно — агент сам выберет нужный по описанию инструмента.
  • Добавить сабагентов (о чём я писал в статье про LEGO-агентов) — каждый сабагент имеет свой MCP-контекст, а главный агент координирует их.
  • Использовать MCP-сервер для доступа к WordPress: почитайте как автономно писать и публиковать посты через MCP.
  • Интегрировать с IntelliJ IDEA через MCP-сервер для IDE — тогда браузерный агент сможет управлять средой разработки.

Есть и более экзотические варианты: подключить финансовую онтологию через FIBO MCP-сервер или добавить голосовой ввод/вывод через Lemon Slice. Возможности ограничены только фантазией и временем.

Лично я сейчас экспериментирую с тем, чтобы агент сам мог создавать новые MCP-инструменты на лету — генерировать код, деплоить его на сервер и тут же его использовать. Это уже похоже на AGI, но пока что это просто цепочка вызовов. Если хотите посмотреть, как я это реализовал — загляните в мой пост про BlueMouse. Там есть кусок про динамическую регистрацию инструментов.

И последнее: не забывайте про лицензии. Многие MCP-серверы распространяются под MIT, но некоторые (например, для коммерческих баз данных) требуют покупки лицензии. Если строите продукт — проверьте.

Совет напоследок: если хотите запустить всё это без боли, используйте готовый VPS с предустановленным n0x и MCP-сервером. За 15 минут получите рабочую песочницу. А для инференса на CPU берите GGUF-хостинг — дёшево и сердито.

Когда-нибудь все браузерные агенты будут по умолчанию уметь подключать MCP. Но уже сейчас вы можете сделать это сами. Вопрос только в том, какой следующий инструмент вы дадите своему агенту. Если придумаете что-то безумное — пишите, мне интересно.

Подписаться на канал