Tutu MCP
Enables searching for buses and trains, and when direct routes are unavailable, it provides the underlying data needed to assemble multi-leg itineraries with transfers.
README
Туда, куда не ищется
Собираем поездку через пересадку, когда прямого билета нет.
Поиск любого сервиса отвечает на вопрос «есть ли билет из А в Б». Если прямого сообщения нет, выдача пустая — и человек уходит. Хотя доехать можно, и оба нужных билета продаются там же.
Живой пример. Запрос «Москва → Углич» на 20 августа 2026 в MCP Туту:
search_multitransport → 0 вариантов
search_bus → 0 вариантов
search_rail → 0 вариантов
Наш ответ на тот же запрос:
Москва → Ярославль автобус 09:00 → 13:00 863 ₽
пересадка в Ярославле — 40 минут
Ярославль → Углич автобус 13:40 → 16:25 616 ₽
итого 1 479 ₽, на месте в 16:25
Оба билета продаёт Туту. Их поиск этого маршрута не покажет никогда.
Как это работает
запрос «Москва → Плёс»
↓
MCP Туту: прямой поиск → 0 вариантов, регион «Ивановская область»
↓
узлы-кандидаты: справочник «регион → центр» + предложения агента
↓
для каждого узла: сначала плечо «узел → цель», затем «откуда → узел»
↓
код сводит стыковки: отбрасывает рейсы, на которые не успеть, считает запас и сумму
↓
карточки маршрутов
Поиском управляет агент: он сам решает, какие города и даты проверять, и человек видит ход его работы лентой на экране. Но стыковки, цены и ранжирование считает код — модель к арифметике не допущена, именно там агенты ошибаются. Тяжёлые ответы Туту через модель не проходят: она получает идентификаторы найденных плеч и короткие сводки, а полные данные уходят прямо в интерфейс.
Если уехать в выбранный день нельзя, бэкенд досылает агента за гостиницами: ищется ближайший день отъезда и подбирается ночлег ровно на столько ночей, сколько ждать.
Если агент недоступен или упёрся в лимит, интерфейс молча переключается на детерминированный поиск — экран показывает результат в любом случае.
Запуск
npm install
cp .env.example .env # вписать OPENROUTER_API_KEY (необязательно)
npm run db:up # Postgres в Docker
npm run migrate # схема базы
npm run warm # прогрев кэша реальными ответами Туту
npm run dev # http://localhost:3100
OPENROUTER_API_KEY опционален: без него подсказка городов отключается,
поиск работает на справочнике регионов.
Команды
| Команда | Что делает |
|---|---|
npm run dev |
приложение на http://localhost:3100 |
npm run route -- Москва Углич 2026-08-20 |
сборка маршрута в консоли |
npm run warm |
прогрев кэша из src/modules/tutu/fixtures/ |
npm run cache |
что сейчас в кэше |
npm run smoke |
проверка живой связки с MCP Туту |
npm run db:up / db:down |
Postgres в Docker |
npm run migrate |
миграции Prisma |
npm run lint |
ESLint |
Структура
Весь код в src/, в корне только конфигурация. Интерфейс собран одной папкой,
логика разложена по модулям — по смыслу, а не по типу файла:
src/
app/ роутинг Next: страница и три API — тонкие, только вызовы модулей
api/agent/ агентный поиск потоком
api/route/ детерминированный поиск (страховка)
api/stay/ гостиницы
frontend/ всё, что видно в браузере
components/route/ форма, календарь, подсказки, лента, карточки, гостиницы
hooks/ чтение потока агента, определение города
design.ts палитра и подписи из макета
format.ts, geo.ts форматирование и расстояния
config.ts константы интерфейса
modules/ логика, зависимости однонаправленные: agent → routing → tutu
tutu/ клиент MCP, кэш, типы, прокси, снятые ответы (fixtures)
routing/ сборка маршрутов, справочники регионов и городов
agent/ цикл, инструменты, промпт, ошибки, ретраи, состояние
lib/ клиент Prisma
Почему внутри модулей нет слоёв domain/, infra/, api/. Такая нарезка
оправдана на десятках тысяч строк и полутора десятках доменов. Здесь один
сценарий: слои дали бы папки по одному файлу и пустой contract/. Когда модуль
перерастёт тысячу строк, они появятся вокруг существующих файлов.
Работа с MCP Туту
Подключение: https://mcp.tutu.ru/mcp, streamable HTTP, авторизация не нужна.
Два инженерных решения, без которых это не работает:
Ответы весят ~26 КБ. Инструменты обёрнуты так, что полный JSON уходит в
интерфейс и рисуется карточками, а в языковую модель — сжатая выжимка через
toModelOutput. Замер на реальном поиске: 26 305 → 1 971 символ, экономия 93 %.
У сервера жёсткий rate limit. Около полусотни запросов подряд закрыли нам
доступ ко всему домену на уровне TCP на несколько часов. Поэтому: view: 'compact',
кэш ответов в Postgres, не больше двух узлов на поиск, а перед демо — прогрев
кэша из fixtures/ командой npm run warm. Если сервер недоступен, экран
показывает то, что есть в кэше, и не падает.
Стек
Next.js 16 (App Router) · TypeScript · @ai-sdk/mcp · Prisma 7 + Postgres 18 ·
Tailwind 4 + shadcn/ui · OpenRouter (опционально)
Документы
SPECIFICATION.md— продукт целиком: проблема, доказательства, техника, регламентSCREEN-SPEC.md— спецификация экрана для вёрсткиUSER-GUIDE.md— руководство пользователяfixtures/README.md— что за сохранённые ответы и зачем
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。