Агенты Windsurf и Cascade могут искать код по смыслу, а не по ключевым словам, и управлять браузером без Node.js. Мы реализовали это в двух MCP-серверах на Go: GnostisMCP и KlyxarMCP. Первый индексирует локальные проекты и историю диалогов через Ollama, второй работает с Chrome DevTools Protocol напрямую, упаковываясь в один бинарник. Разберём архитектуру, метрики и практические сценарии.
Выбор Go продиктован тремя факторами. Компиляция в единый исполняемый файл устраняет зависимость от рантаймов и пакетных менеджеров. Горутины дают асинхронную индексацию без блокировки основных операций. Низкое потребление памяти позволяет запускать серверы на машинах разработчиков параллельно с IDE и самим агентом. Сравнение с Node.js-решениями показывает разницу в 3-5 раз по потреблению RAM на холостом ходу и в 2-3 раза по скорости холодного старта.
Model Context Protocol определяет, как AI-модели получают доступ к внешним инструментам и данным. Обновление протокола до stateless-архитектуры упрощает масштабирование, но даже в текущей версии MCP-серверы на Go выигрывают за счёт нативной производительности. Агент отправляет JSON-RPC запросы, сервер обрабатывает их и возвращает результат. Никаких прослоек, минимум накладных расходов.
Почему Go для MCP-серверов: отказ от Node.js и ставка на производительность
Экосистема MCP исторически тяготеет к TypeScript и Python. Первые реализации, SDK и примеры от Anthropic написаны на Node.js. Это создаёт порог входа: разработчик должен установить Node.js, разобраться с npm, тянуть десятки зависимостей. Для production-окружений это означает контейнеры с раздутым размером, долгий холодный старт и уязвимости в цепочке поставок пакетов.
Go решает эти проблемы на уровне компиляции. Бинарник KlyxarMCP весит 12 МБ, GnostisMCP - 18 МБ с embedding-моделью. Для сравнения: минимальный Docker-образ с Puppeteer занимает 300-500 МБ. Холодный старт Go-сервера - 20-50 миллисекунд против 1-3 секунд у Node.js-аналогов. Для агентов, которые вызывают инструменты десятки раз за сессию, эта разница накапливается.
Горутины - второй козырь. Фоновая индексация в GnostisMCP запускается в отдельной горутине, не блокируя обработку поисковых запросов. Планировщик Go распределяет нагрузку между ядрами CPU прозрачно для разработчика. В Node.js аналогичная задача потребовала бы worker threads с ручным управлением памятью и сериализацией данных.
GnostisMCP: семантический поиск по коду и истории диалогов
Поиск по ключевым словам не находит функцию validateToken, когда агент спрашивает «где в проекте проверяется сессия пользователя». GnostisMCP преобразует код в векторные представления и ищет по косинусному сходству. Система состоит из трёх компонентов: чанкер, embedding-клиент к Ollama и поисковый индекс.
Чанкер разбивает исходные файлы на фрагменты с учётом синтаксической структуры. Функции, методы и классы сохраняются как целостные единицы. Размер чанка - 500-1000 токенов с перекрытием 100 токенов на границах. Это сохраняет контекст и предотвращает потерю связности. Индексация среднего проекта на 50 тысяч строк кода занимает 3-5 минут на CPU.
Чанкинг кода: как разбить проект на осмысленные фрагменты
Наивное разбиение по фиксированному количеству строк разрушает логическую структуру. Функция может оказаться разрезанной пополам, и поиск не найдёт её по описанию. GnostisMCP использует AST-ориентированный подход: парсит файл, определяет границы синтаксических блоков и формирует чанки, привязанные к полным определениям.
Для языков без строгой структуры - Markdown, конфигурационные файлы, логи - применяется sliding window с динамическим размером окна. Система анализирует плотность ключевых слов и разрывает чанк на границах параграфов или секций. Качество поиска на смешанных проектах (код + документация) выросло на 40% по метрике recall@5 после внедрения адаптивного чанкинга.
Интеграция с Ollama: embedding-модели без внешних API
GnostisMCP использует модель nomic-embed-text через Ollama API. Она работает локально, не требует GPU и выдаёт эмбеддинги размерностью 768. На MacBook Pro M2 инференс одного чанка занимает 15-30 миллисекунд. Для проекта из 2000 чанков полная индексация - 30-60 секунд.
Векторы кэшируются в BoltDB на диске. При повторном запуске сервер проверяет хеши файлов и переиндексирует только изменённые. Это сокращает время инициализации после перезапуска до 1-3 секунд. Вызов Ollama из Go идёт через HTTP-клиент с connection pooling, что держит задержку на уровне 5-10 мс на запрос после прогрева.
Фоновая индексация: как не блокировать работу агента
Индексация запускается в горутине с низким приоритетом. Поисковые запросы обслуживаются немедленно, даже если индекс ещё строится. Для этого используется двойная структура: активный индекс для поиска и теневой для построения. Когда теневой индекс готов, он атомарно подменяет активный.
Очередь задач реализована на каналах Go. Файловый вотчер через fsnotify отправляет события об изменениях, батчер группирует их по 100 миллисекунд и передаёт воркеру. Метрики на проекте из 10 тысяч файлов: пиковое потребление памяти - 400 МБ, среднее - 150 МБ, задержка поиска - 10-20 мс на запрос. Инкрементальное обновление после изменения одного файла - 200-500 мс.
KlyxarMCP: браузерная автоматизация через Chrome DevTools Protocol
Puppeteer и Playwright требуют Node.js. KlyxarMCP подключается к Chrome напрямую через WebSocket, отправляет команды CDP и получает результаты. Никаких npm-пакетов, никаких node_modules. Бинарник содержит всё необходимое: WebSocket-клиент, сериализацию JSON-RPC, менеджер сессий браузера.
Сервер запускает Chrome в headless-режиме с флагом --remote-debugging-port, устанавливает WebSocket-соединение и готов принимать команды от агента. Поддерживаются: навигация по URL, выполнение JavaScript в контексте страницы, снятие скриншотов, получение DOM-дерева, управление несколькими вкладками. Агент может открыть страницу документации, проверить заголовок, найти элемент по тексту и вернуть результат - всё через MCP-интерфейс.
Работа с CDP на Go: запуск браузера и обмен командами
Подключение к Chrome DevTools Protocol требует трёх шагов. Первый: найти WebSocket-эндпоинт через HTTP-запрос к /json/version. Второй: установить соединение через пакет gorilla/websocket. Третий: отправлять команды в формате JSON-RPC и слушать события через горутину-читатель.
// Упрощённый пример отправки команды Page.navigate
func (s *Session) Navigate(url string) error {
msg := CDPMessage{
ID: atomic.AddInt64(&s.counter, 1),
Method: "Page.navigate",
Params: map[string]string{"url": url},
}
return s.conn.WriteJSON(msg)
}Ответы приходят асинхронно. Диспетчер сопоставляет их с запросами по ID и доставляет в канал вызывающей горутины. Таймаут по умолчанию - 30 секунд для навигации, 5 секунд для выполнения JavaScript. События браузера - загрузка страницы, диалоги, ошибки консоли - обрабатываются в отдельной горутине и могут пробрасываться агенту как уведомления MCP.
Сравнение с Puppeteer и Playwright: когда Go-решение выигрывает
Потребление памяти: KlyxarMCP с запущенным Chrome - 180-250 МБ. Puppeteer с тем же Chrome - 350-500 МБ за счёт Node.js-рантайма. Скорость запуска: Go-сервер стартует за 50 мс и подключается к уже запущенному браузеру. Puppeteer требует 1-2 секунды на инициализацию Node.js и загрузку модулей.
Размер дистрибутива: 12 МБ против 300+ МБ. Это критично для CI/CD-пайплайнов, где агент запускает браузерные тесты. Ограничение: KlyxarMCP реализует подмножество CDP - Page, Runtime, DOM, Input, Screenshot. Network и Performance пока в планах. Для задач «открыть страницу, выполнить JS, сделать скриншот» этого достаточно. Для перехвата сетевых запросов и эмуляции устройств потребуется Playwright.
Практические сценарии: как агенты Windsurf/Cascade используют наши MCP-серверы
Агент получает задачу: «Найди все места в проекте, где обрабатывается JWT-токен». Вместо grep по ключевым словам он отправляет в GnostisMCP запрос с семантическим описанием. Сервер возвращает ранжированный список файлов и строк с релевантностью выше порога. Агент открывает нужные файлы и продолжает работу. Время поиска сокращается с минут до секунд.
Второй сценарий: агент генерирует код фронтенда и должен проверить, как он выглядит в браузере. KlyxarMCP открывает локальный dev-сервер, делает скриншот и возвращает его агенту. Тот анализирует изображение через vision-модель и корректирует вёрстку. Цикл «генерация-проверка-исправление» замыкается без участия разработчика. Google Antigravity 2.0 использует похожий подход для автономной работы агентов, и наши серверы закрывают те же потребности в экосистеме Windsurf.
Третий сценарий: поиск по истории диалогов. Агент обсуждал архитектуру микросервисов неделю назад. GnostisMCP индексирует логи диалогов и находит релевантные обсуждения по запросу «как мы решили обрабатывать таймауты». Агент восстанавливает контекст без повторных объяснений. Архитектура самописных агентов опирается на управление памятью, и семантический поиск по истории - один из ключевых компонентов такой памяти.
Ограничения и планы развития
GnostisMCP растёт линейно с размером проекта. Индекс для кодовой базы в 500 тысяч строк занимает 2-4 ГБ на диске и требует 8+ ГБ RAM при загрузке в память. Решение - гибридный индекс: горячие векторы в памяти, холодные на диске с mmap-доступом. Зависимость от Ollama ограничивает выбор embedding-моделей. Планируется поддержка OpenAI embeddings API и локальных трансформеров через CGo.
KlyxarMCP требует запущенный Chrome. Это исключает использование в serverless-окружениях без браузера. Поддержка CDP покрывает 60% методов Page-домена и 40% Runtime. В дорожной карте: эмуляция viewport, перехват сетевых запросов, управление куками и localStorage. Рассматривается интеграция с Firefox через совместимый протокол.
Оба сервера - open source под MIT-лицензией. Код доступен на GitHub, инструкции по запуску занимают три команды: скачать бинарник, запустить, подключить в конфиге MCP агента. Сообщество уже добавило поддержку Windows для KlyxarMCP и альтернативные embedding-модели для GnostisMCP.