Skip to main content
Glama

To Where Search Can't Reach

We put together a trip with a connection when there's no direct ticket.

Any service's search answers the question "is there a ticket from A to B." If there's no direct connection, the results are empty — and the person leaves. Even though you can get there, and both needed tickets are sold right there.

Live example. Query "Moscow → Uglich" for August 20, 2026 in MCP Туту:

search_multitransport → 0 вариантов
search_bus            → 0 вариантов
search_rail           → 0 вариантов

Our response to the same query:

Москва → Ярославль   автобус 09:00 → 13:00    863 ₽
пересадка в Ярославле — 40 минут
Ярославль → Углич    автобус 13:40 → 16:25    616 ₽
                                       итого  1 479 ₽, на месте в 16:25

Tutu sells both tickets. Their search will never show this route.

How it works

запрос «Москва → Плёс»
   ↓
MCP Туту: прямой поиск → 0 вариантов, регион «Ивановская область»
   ↓
узлы-кандидаты: справочник «регион → центр» + предложения агента
   ↓
для каждого узла: сначала плечо «узел → цель», затем «откуда → узел»
   ↓
код сводит стыковки: отбрасывает рейсы, на которые не успеть, считает запас и сумму
   ↓
карточки маршрутов

The search is driven by an agent: it decides which cities and dates to check, and the user sees its progress as a feed on screen. But connections, prices, and ranking are computed by code — the model isn't allowed near the arithmetic, since that's exactly where agents make mistakes. Heavy Tutu responses don't go through the model: it receives identifiers of found legs and short summaries, while the full data goes straight to the interface.

If you can't leave on the selected day, the backend sends the agent out for hotels: it finds the nearest departure date and picks lodging for exactly as many nights as the wait.

If the agent is unavailable or hits a limit, the interface silently switches to deterministic search — the screen shows a result either way.

Related MCP server: mcp-sbb-transport

Running

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 is optional: without it, city suggestions are disabled and search works off the region directory.

Commands

Command

What it does

npm run dev

app at http://localhost:3100

npm run route -- Москва Углич 2026-08-20

build a route in the console

npm run warm

warm the cache from src/modules/tutu/fixtures/

npm run cache

what's currently in the cache

npm run smoke

check the live connection with MCP Туту

npm run db:up / db:down

Postgres in Docker

npm run migrate

Prisma migrations

npm run lint

ESLint

Structure

All code is in src/, the root only has configuration. The interface is built as a single folder, the logic is split into modules — by meaning, not by file type:

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

Why there are no domain/, infra/, api/ layers inside modules. Such slicing is justified at tens of thousands of lines and a dozen and a half domains. Here there's a single scenario: layers would produce one-file folders and an empty contract/. When a module outgrows a thousand lines, they'll appear around the existing files.

Working with MCP Туту

Connection: https://mcp.tutu.ru/mcp, streamable HTTP, no authorization needed.

Two engineering decisions without which this doesn't work:

Responses weigh ~26 KB. The tools are wrapped so that the full JSON goes to the interface and is rendered as cards, while the language model gets a compressed digest via toModelOutput. Measured on a real search: 26,305 → 1,971 characters, 93% savings.

The server has a strict rate limit. Around fifty consecutive requests got us blocked from the entire domain at the TCP level for several hours. Therefore: view: 'compact', response cache in Postgres, no more than two legs per search, and before a demo — warm the cache from fixtures/ with the npm run warm command. If the server is unavailable, the screen shows what's in the cache and doesn't crash.

Stack

Next.js 16 (App Router) · TypeScript · @ai-sdk/mcp · Prisma 7 + Postgres 18 · Tailwind 4 + shadcn/ui · OpenRouter (optional)

Documents

  • SPECIFICATION.md — the entire product: problem, evidence, tech, procedures

  • SCREEN-SPEC.md — screen spec for layout

  • USER-GUIDE.md — user guide

  • fixtures/README.md — what the saved responses are and why

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables multi-modal travel planning for India, aggregating flights, trains, buses, cabs, and personal vehicles across 117 cities with multi-leg routing and weighted scoring.
    2
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Live intercity bus-trip search across Ukraine and Europe — real-time prices, seats, carriers, cheapest-day-of-month calendar, and trip details with passenger discounts. Read-only, no API key; also available as a hosted remote endpoint at https://mcp.soloway.com.ua/mcp.
    MIT

View all related MCP servers

Related MCP Connectors

  • Real-time transit stops, routes, arrivals, vehicle positions, and schedules via OneBusAway APIs.

  • Transitland MCP — global GTFS aggregator

  • Plan door-to-door trips across French trains, buses, transit and flights.

View all MCP Connectors

Latest Blog Posts

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/nyxandro/tutu-hackathon'

If you have feedback or need assistance with the MCP directory API, please join our Discord server