Skip to main content
Glama

Zaezd

A trip engine that starts with a reason. A person doesn't know where to go, they know why: they want to attend a conference on their topic. Zaezd finds the nearest offline event, calculates the round trip, a hotel near the venue, and the full participation price, and shows up to three explainable packages on one screen.

The first vertical is IT conferences. The event catalog is provided by confcal MCP, transport and lodging by Tutu MCP, and everything is assembled by a deterministic composer, not a model.

What's where

What

Where

Trip screen

/ at the address where you launched Zaezd

Trip by link

/t/<trip_id>, the link is provided by the screen and any of the tools

MCP endpoint

/mcp, streamable HTTP, no key

Liveness check

/healthz, responds with mode and reference date

User guide

docs/user-guide.md

Two-minute recording

docs/demo.mp4, server, screen, and agent

Related MCP server: Travel Planner MCP Server

End-to-end scenario

You open the root. The screen already shows an assembled trip, not an empty form. At the top: event, date, city, venue, and walking time to it from the nearest hotel. Below, up to three cards: the way there with the train or flight number, a hotel with the price for the entire stay and distance to the venue, the way back, a total as a single number, and an arithmetic line underneath that adds up. Then a city map with the venue and hotels, weather for the trip dates, other events on the topic, and a list of what was not included and why.

You click "Collect payment links" — a checklist of two or three Tutu links appears. Each label is taken from what Tutu actually returned: "Open cart" where a cart will open, and "Open selection page" where there will be no cart.

The same to an agent: find_event_trips with a topic and departure city returns the same trip as a structure, get_trip_details expands a package, create_trip_checkout assembles a checklist. A host that can render gets the same screen as an MCP App.

Running from source

npm install
ZAEZD_MODE=replay npm run dev

It will open at http://localhost:8080. In replay mode, the product works on recorded responses from fixtures/ and does not go to the network: you can use it without internet and without keys, and the reference date is the day of recording. Live mode is ZAEZD_MODE=live.

Full check:

npm run verify

This is rule synchronization, verification of documented commands, typing, linter, browser tree build, executable Gherkin scenarios, and unit tests. Everything is offline.

The browser tree is built before scenarios not for looks. One scenario requests from the server the very boot.js that goes to the host, and on a clean clone this file does not exist yet.

Running in a container

The image is built from the repository and contains both code and fixtures inside, so in replay mode the container needs neither internet nor secrets.

cp .env.example .env      # и отредактируйте
docker compose up -d --build

The screen will come up at http://127.0.0.1:8080. Without a .env file, compose will not start: this is intentional, so that no one runs the product on someone else's default values.

Without compose, the same with one command:

docker build -t zaezd .
docker run -d --name zaezd -p 127.0.0.1:8080:8080 --env-file .env zaezd

One-off, without an environment file, just to take a look:

docker run --rm -p 127.0.0.1:8080:8080 \
  -e ZAEZD_MODE=replay -e ZAEZD_PUBLIC_URL=http://localhost:8080 zaezd

Environment variables

The full list with comments is in .env.example. In short:

Variable

Purpose

Default

ZAEZD_MODE

live goes to sources, replay reads fixtures/

live

PORT

port inside the container

8080

ZAEZD_PUBLIC_URL

address at which the product is visible from outside. Trip links and widget CSP are built from it

http://localhost:8080

ZAEZD_CONTACT_EMAIL

contact in User-Agent; Nominatim bans anonymous requests

zaezd@example.com

ZAEZD_CONFCAL_URL

MCP of the event catalog

public confcal

ZAEZD_TUTU_URL

Tutu MCP

https://mcp.tutu.ru/mcp

There are no keys or tokens at all: both sources are open. It is important to set ZAEZD_PUBLIC_URL honestly — this exact address goes to the agent as a link to the screen and ends up in the widget CSP, and if it does not match the real one, the board inside the host will remain empty.

The container carries a HEALTHCHECK on /healthz, so docker ps shows healthy only when the application actually responds.

Behind a reverse proxy

docker-compose.yaml itself knows nothing about proxies, domains, and networks — these are properties of the site, not the product. All of this goes into docker-compose.override.yaml, it is in .gitignore and lives only on the machine that deploys the service. Example for Traefik:

services:
  zaezd:
    ports: !reset []          # наружу светит прокси, а не контейнер
    environment:
      ZAEZD_PUBLIC_URL: https://zaezd.example.com
    labels:
      traefik.enable: 'true'
      traefik.http.routers.zaezd.rule: Host(`zaezd.example.com`)
      traefik.http.routers.zaezd.entrypoints: https
      traefik.http.routers.zaezd.tls: 'true'
      traefik.http.routers.zaezd.tls.certresolver: letsencrypt
      traefik.http.services.zaezd.loadbalancer.server.port: '8080'
    networks: [proxy]

networks:
  proxy:
    external: true

Entry point, certificate resolver, and network names differ for everyone, so they are placeholder in the example. For nginx or Caddy, the override will be different; the product does not change because of this: it listens on PORT and serves /healthz.

Connect to an agent

The <address>/mcp endpoint works over streamable HTTP and requires no key. Locally it is http://localhost:8080/mcp, on a deployed service — your address from ZAEZD_PUBLIC_URL.

Claude Desktop does not accept remote servers directly in claude_desktop_config.json, only stdio commands live there, so either add Zaezd via Settings, Connectors, Add custom connector, or specify a proxying launch:

{
  "mcpServers": {
    "zaezd": { "command": "npx", "args": ["-y", "mcp-remote", "http://localhost:8080/mcp"] }
  }
}

Claude Code and Codex CLI:

claude mcp add --transport http zaezd http://localhost:8080/mcp
codex mcp add zaezd --url http://localhost:8080/mcp

Qwen Code:

qwen mcp add --transport http zaezd http://localhost:8080/mcp

A host that can render widgets will get the same screen via the ui://zaezd/trip-board resource. A host without widgets will get the same response as text.

Architecture

Dependencies go only downward.

Layer

Where

What it does

L0

src/composer/{types,dates,selection,feasibility,pricing,hotels,packages,checkout-labels}.ts

pure rules: dates, feasibility, price, package selection. No I/O and no clock

L1

src/sources/

confcal and Tutu clients, normalization, cache, replay mode

L2

src/enrich/

geocoding, production calendar, weather. Each with a timeout and fallback response

L3

src/composer/{build-trip,build-checkout,trip-id}.ts

trip assembly, budgets, live payment links, query in the link

L4

src/web/, src/mcp/

screen and three tools. No business logic here

The diagram and two sequences are in docs/architecture.md, decisions with rationale are in docs/decisions.md.

The key point: dates, prices, and feasibility are calculated by code, not a model. Three identical live runs through the model gave three different night counts and a price spread of one and a half times. Therefore the algorithm lives in src/composer/dates.ts and is covered by a scenario table.

Limitations

The list is honest; read it as part of the product.

  • An online event does not build a trip, and neither does an event in your own city. In both cases, Zaezd says so directly rather than showing an empty screen;

  • the live confcal catalog knows 21 cities, and live offline events exist in about 15 of them. Empty cities are not hidden; the counter is shown on the screen;

  • one trip is calculated per request. Up to five more events on the topic are shown as a list but not calculated: a fan of five builds is a spinner, not a product;

  • the weather forecast is available only 16 days ahead. Beyond that, the weather block simply disappears;

  • the venue address is taken from the catalog and never guessed. If the catalog did not provide it, the screen says so and does not place a marker on the map, and the agent's response asks to look up the address in open sources and tell the person that the address is not from the catalog;

  • Tutu multi-transport counts adults; there are no child or discounted fares in the trip;

  • a flight ticket link in a cold browser opens search, not a cart: a cart is only created in a browser with a live Tutu session. That is why the label of such a button says so;

  • there is no seat map in the carriage;

  • the event participation price is added to the total only if the catalog wrote it as a number. A textual price like "free for students" is shown as is by Zaezd and is not included in the sum;

  • in replay mode, payment links are assembled from the recording and have most likely expired. The screen and the agent response warn about this;

  • eight events are requested from the catalog at a time: on a larger number it stops streaming mid-response. The measurement and rationale are in the decision log.

Measured

Metric

Value

Tutu MCP tools

16

Tutu MCP manifest

102,143 characters, about 25.5 thousand tokens

Zaezd gateway tools

3

Zaezd gateway manifest

10,181 characters, about 2.5 thousand tokens

Live trip build, cold

12.1 s

Live trip build, repeated

0.2 s

Trip build from recording

36 ms

External sources

6

Executable scenarios

217

Unit tests

336

Verified in agents

Claude Code, Qwen Code

Repository map

specs/      спецификация продукта, она же источник правды
features/   исполняемые сценарии на Gherkin и шаги к ним
tests/      юнит-тесты чистого слоя
src/        код продукта по слоям
fixtures/   записанные ответы источников
scripts/    record.ts и вспомогательные утилиты
docs/       руководство пользователя, архитектура, журнал решений

License

MIT, see LICENSE.

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

View all related MCP servers

Related MCP Connectors

  • TravelMind: 8 MCP tools for travel (12306 trains, flights, hotels, geocode, planning, policy).

  • whentofly: flexible-date economy/business flight search + price-level context for AI agents

  • Flight search & booking for AI agents. 400+ airlines, $20-50 cheaper than OTAs.

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/EvilFreelancer/zaezd'

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