Motus
Enables agents to search airports and find group meetup flights for multiple travelers with optimal pricing and arrival windows.
README
Motus
Motus finds group meetup flights. You give it a destination, a set of travelers with their home airports, and a date range. It searches each person's flights and returns options where everyone lands within one arrival window of each other. Every price is all-in: the base fare plus each traveler's checked and carry-on bag fees. With the live RouteStack provider the bag fees are estimated, so the total is a close approximation rather than the exact airline charge.
Quick start
The app runs with no configuration. It ships with a built-in mock provider that returns demo flights, so you can try it without any API keys.
pnpm install
pnpm dev
Then open http://localhost:3000. The form starts with three sample travelers and a destination already filled in, so you can press "Find meetups" right away.
Using real fares
To search live fares and schedules, switch to the RouteStack provider. Copy .env.example to .env.local and set the provider and your credentials:
FLIGHT_PROVIDER=routestack
ROUTESTACK_API_KEY=your-key
ROUTESTACK_API_SECRET=your-secret
The server validates this at startup. If you set FLIGHT_PROVIDER=routestack without both credentials, it fails loudly and tells you what is missing. ROUTESTACK_BASE_URL defaults to the public endpoint and only needs setting if you point at a different host.
The RouteStack adapter authenticates with an HMAC-signed request, caches the partner token, and parses each fare into Motus's flight shape. When RouteStack returns a flight for a different airport than the one requested, the adapter logs that substitution so you can see when upstream results do not match the exact origin and destination you asked for.
MCP server
Motus exposes a Code-Mode MCP endpoint at POST /api/mcp. It offers two tools. An agent calls describe to learn the motus SDK: the available functions, their arguments, and return shapes. The agent then writes a short JavaScript program and sends it to execute, which runs the program against that SDK and returns its result.
const airports = await motus.searchAirports("denver");
return airports;
The guest code runs in a locked-down sandbox with no network, environment, or filesystem access, so it can only call the SDK functions Motus provides. The endpoint is rate-limited.
Deploying
Set SITE_URL to the public base URL of your deployment, for example https://your-domain.com. Motus uses it for canonical tags, the sitemap, Open Graph image URLs, and robots. It is required in production. On Vercel it falls back to the deployment URL when unset, but a stable custom domain is better for search engines. In local development it defaults to http://localhost:3000.
Scripts
| Command | What it does |
|---|---|
pnpm dev |
Run the app locally with hot reload |
pnpm build |
Build the production bundle |
pnpm test |
Run the unit tests once |
pnpm test:coverage |
Run the unit tests with coverage |
pnpm test:e2e |
Run the Playwright end-to-end tests |
pnpm lint |
Lint the codebase, zero warnings allowed |
pnpm typecheck |
Type-check without emitting |
pnpm verify |
Run lint, ASCII check, typecheck, coverage, ratchet, build, and format check |
Architecture
| Directory | Job |
|---|---|
src/domain |
Core types and schemas for flights, people, and search requests |
src/matching |
The matcher and the search service that drive a request and rank results |
src/providers |
The flight provider seam: the mock provider, the RouteStack adapter, and the selector that picks one |
src/app/api |
The HTTP routes for search and airport lookup |
src/components |
The React form and results UI |
src/lib |
Shared helpers: typed errors, logger, HTTP responses, rate limiting, dates, and the client fetcher |
How the matching works
The matcher anchors an arrival window at each flight's arrival time across all travelers. For each anchor it takes every traveler's cheapest all-in flight that lands inside that window. If even one traveler has no flight in the window, that anchor is dropped. The surviving options are ranked by your objective: min_total puts the cheapest combined cost first, and min_max puts the lowest single fare first so no one person carries an outsized share.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.