Seatline Booking MCP Server
Powers a WhatsApp seat-booking agent that turns a seat request into a paid, confirmed ticket without staff. The server exposes tools to search trips by route and date, hold a seat for 10 minutes, generate a Paystack payment link, verify payment before issuing a ticket reference, and look up bookings by reference and phone number.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Seatline Booking Agent
A WhatsApp seat-booking agent built on Chord. It turns a seat request into a paid, confirmed ticket without staff, and it only confirms a seat when Paystack has verified the payment.
Fictional business, made-up routes and fares, Paystack test mode only.
The problem
Seatline Shuttles runs fixed-route trips and takes bookings on WhatsApp. Staff check availability by hand, collect Mobile Money screenshots, and confirm seats manually. That causes slow replies out of hours, double-booked seats, forgeable payment proof, and seats held and never released.
The gap is between seat inventory and verified payment. This agent closes it.
Related MCP server: soloway-mcp
What it does / does not do
Does | Does not (hands off to a human) |
Finds trips by route and date | Refunds and cancellations |
Holds a seat for 10 minutes | Group bookings |
Sends a Paystack payment link | Price negotiation |
Verifies payment with Paystack | General questions outside booking |
Issues a ticket reference |
Architecture
WhatsApp simulator -> Chord teammate (skill files)
| MCP (Streamable HTTP, bearer)
v
Express MCP server (this repo)
| ^
v | webhook (HMAC-SHA512)
Neon Postgres (Prisma) Paystack (test mode)Key decisions
Express over NestJS: smallest surface for a time-boxed build.
Stateless MCP over Streamable HTTP: survives restarts, no session store.
Database-enforced seat integrity:
UNIQUE(trip_id, seat_no)inside a transaction.Lazy hold expiry: no cron, holds past
expires_atcount as free.Paystack verify is the source of truth; the webhook is a backup.
Integer pesewas for all money.
Tools
Tool | Purpose |
| Search trips by origin, destination, date |
| Reserve a seat for 10 minutes |
| Initialize a Paystack transaction |
| Verify with Paystack, confirm the booking, issue the ticket |
| Look up a booking (reference + phone must match) |
Errors return { ok: false, code, retryable, next_action } so the agent can recover.
Run locally
cp .env.example .env
npm install
npm run db:push
npm run db:seed
npm run devSet DATABASE_URL to a PostgreSQL connection string, PAYSTACK_SECRET_KEY to a Paystack test secret, MCP_BEARER_TOKEN to a long random token, and PUBLIC_BASE_URL to the public HTTPS origin of this server. PORT defaults to 3000. Never use a real payment key for local/demo testing.
The Paystack webhook endpoint is POST /webhooks/paystack; configure it in the Paystack dashboard. GET /health is a liveness check and does not check database connectivity. The MCP endpoint is POST /mcp and requires Authorization: Bearer <MCP_BEARER_TOKEN>.
Deploy (Render)
Build command: npm run build. Start command: npm start. Health-check path: /health. Set the environment variables listed above in the hosting provider's secret manager and expose the webhook over HTTPS.
The server pings its /health endpoint through RENDER_EXTERNAL_URL every 13 minutes to reduce free-instance spin-downs. Render provides RENDER_EXTERNAL_URL automatically. This in-process cron can help while the service is running, but it is not an external wake-up mechanism and cannot guarantee availability if the service has already spun down. The first request after a spin-down can take about a minute. Keeping a free instance awake can consume nearly all of Render's 750 monthly free instance hours for a workspace, so use a paid instance if reliable always-on service is required.
Connect to Chord
Set MCP_SERVER_URL, MCP_BEARER_TOKEN, CHORD_API_TOKEN, CHORD_REGISTER_ENDPOINT, CHORD_ASSIGN_ENDPOINT, and CHORD_TEAMMATE_ID, then run bash scripts/register-chord.sh. The script health-checks the server, registers only the five booking tools, and assigns the resulting server ID to the teammate. The two Chord endpoint variables must be the API endpoints for your workspace; the script expects the registration response to contain an id or server.id.
Test the full conversation
Happy path: search Accra to Kumasi on a seeded date, choose a departure, hold a seat, create a payment link, complete the Paystack test payment, then verify using the returned payment reference. Confirm that a ticket reference is returned only after verification. For a failure path, select a fully occupied trip or attempt to pay after a hold expires; the tool returns a structured error with a safe next action.
Scenario 1: Happy path (the main demo)
Customer: Hi, any seat to Kumasi tomorrow 6am?
Expect: The agent calls find_trips, then returns with no results for the set time date tomorrow.
Customer: Book me one seat in November. Expect: The agent asks for a date, finds seats availability in November and asks you to choose.
Customer: Seat [2]. Number is 09000000000.
Expect: hold_seat runs. The agent says the seat is held for 10 minutes. create_payment_link runs and it sends the Paystack link.
Customer: (Opens the link and pays with a Paystack test card, then returns to the chat) I've paid.
Expect: verify_payment runs against Paystack. The agent confirms the payment and gives a ticket reference.
Customer: Can you send my booking details again?
Expect: get_booking runs. The agent repeats the trip, seat, amount and ticket reference.
Scenario 2: No trips found
Customer: Any seat to Tamale tomorrow 6am?
Expect: The no trips found case. The agent says there is no such trip and offers nearby times or the routes it does serve. It does not invent a trip.
Scenario 3: Sold out
Customer: One seat to Kumasi at [a fully booked time], please.
Expect: The sold out case. The agent says the trip is full and suggests the next available trip.
Scenario 4: Seat already taken (double-booking protection)
Use two chat links, one for Customer A and one for Customer B.
Customer A: Hold seat [7] on the Kumasi 6am for me. Expect: Seat 7 is held.
Customer B: I want seat [7] on the same trip. Expect: The agent says seat 7 is unavailable and offers other free seats. This shows the unique constraint working.
Scenario 5: Hold expires
Customer: Hold seat [9] on the Kumasi 6am. (Do not pay. Wait more than 10 minutes.)
Customer: Okay, I'm ready to pay now.
Expect: The hold expired case. The agent says the hold has lapsed. If the seat is still free, it offers to hold it again with a new link. If not, it offers alternatives.
Scenario 6: Payment abandoned or pending
Customer: Hold seat [10]. (Open the payment link but close it without paying.)
Customer: I've paid.
Expect: verify_payment returns abandoned or pending. The agent does not confirm the seat. It says it can't see the payment yet, and offers to check again or send a fresh link.
Status
Item | Status |
MCP server and tools | Implemented |
Paystack integration and failure paths | Implemented (test-mode wiring; requires credentials) |
Skill published | Local skill files ready for Chord |
Simulator conversation | Not included |
How I used AI tools
AI assistance was used for planning the project and scaffolding the project, reviewing code. Testing was handled first in Postman collections by myself, and then via Chord Chat Simulator
Known limitations
Refunds, cancellations, group bookings, a staff admin UI, background hold cleanup, database-backed readiness checks, and proactive WhatsApp notifications are not implemented. Expired holds are cleaned lazily on availability/hold operations.
Further reading
This server cannot be deployed
Maintenance
Related MCP Connectors
Search and book live flights and hotels. No API key; the traveller confirms on their phone.
Discover, read and book verified real-world businesses through one endpoint.
Search places, compare ride-hailing options, and plan trotro minibus journeys.
Search ~300 airlines and book flights with a checkout link. OAuth sign-in by email code.
Related MCP Servers
- AlicenseAqualityFmaintenanceReal-time last-minute tour and activity booking across 18 suppliers in 15 countries via the OCTO open standard. Search available slots, create Stripe checkout sessions, and check booking status.41MIT
- AlicenseNot gradedqualityCmaintenanceLive 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
- FlicenseAqualityDmaintenanceEnables AI clients to search trips, find locations, and manage bookings through the Flowteller backend.9-
- AlicenseNot gradedqualityDmaintenanceEnables booking for movies, flights, trains, and buses with a 2-step confirmation flow and idempotency keys.69 npmMIT