Inspiration

Planning one occasion can mean visiting separate restaurant, salon, and hotel services, repeating the same dates and preferences, and starting again whenever availability changes. We wanted to explore a more unified experience: one conversational assistant that could coordinate hospitality reservations while still keeping the user in control of every important action.

We also wanted to solve a trust problem. A conversational interface should not silently turn a suggestion into a booking. Search, temporary holds, confirmation, modification, and cancellation need to be separate and visible steps—especially when availability can change between them.

This hackathon was also a personal learning journey. Before this project, my experience with MCP was limited to creating workflows in n8n. This was my first time building an MCP server directly in code, working with typed tool schemas, protocol sessions, Streamable HTTP, structured errors, and reservation state.

What it does

Hospitality Assistant MCP is a simulated Alexa+ web experience powered by a self-hosted MCP server. It supports restaurants, salons, and hotels through one shared reservation contract.

A user can:

  • Search deterministic sample inventory using conversational requests.
  • Review matching places, times, prices, and reasons for each match.
  • Create a temporary five-minute hold without confirming a booking.
  • Explicitly approve the hold before confirmation.
  • Receive nearby alternatives when another guest takes the selected slot.
  • Modify a confirmed reservation while preserving the original booking if the change fails.
  • Cancel safely, including repeated cancellation requests.
  • Use push-to-talk to transcribe a request into an editable message before sending it.
  • View the real MCP handshake and every tools/list and tools/call interaction.

Our Occasion Concierge turns one request into a coordinated plan across multiple hospitality categories. For example, one anniversary request can search for a manicure, dinner, and hotel stay on the same day.

The plan is reviewed before anything is held. When the user chooses Hold whole plan, each reservation is held in sequence. If a later step fails, the assistant releases earlier holds. Before confirmation, it verifies that every hold is still active. If confirmation fails partway through, it performs compensating cancellation and keeps unresolved cleanup visible for retry.

How we built it

The frontend is a React and TypeScript application using the official MCP TypeScript client. It connects to the backend using MCP 2025-11-25 over stateful Streamable HTTP and retains the MCP session ID returned by the server.

A deterministic conversational parser converts a focused set of booking phrases into typed tool arguments. We intentionally did not describe this parser as an LLM: predictable behavior was more valuable for a repeatable reservation demonstration. Push-to-talk uses the browser Web Speech API, but voice only fills the message box. The user must review and send the text, and booking confirmation still requires explicit approval.

The Python backend uses the official MCP Python SDK and exposes exactly seven tools:

  • search_availability
  • get_listing_details
  • create_booking_hold
  • confirm_booking
  • modify_booking
  • cancel_booking
  • get_booking

Strict Pydantic models define the tool inputs, outputs, booking objects, and stable business errors. Restaurant, salon, and hotel adapters apply provider-specific matching while sharing one reservation lifecycle.

SQLite stores deterministic synthetic listings, availability templates, holds, and bookings. Atomic BEGIN IMMEDIATE transactions prevent overlapping holds or confirmed bookings. Expired holds are applied before availability and booking state are returned. Confirmation requires an active hold and user_confirmed: true, while modification is atomic and confirmation and cancellation are safe to retry.

The interface includes an MCP activity panel that displays the real initialize, notifications/initialized, tools/list, and tools/call traffic. The conflict in our demo is also real within the application: a second MCP client session takes the preferred table immediately before the first user attempts to hold it.

Challenges we ran into

The first challenge was learning how the current MCP SDK maps onto the protocol. Examples from different SDK versions sometimes used different server APIs, so we relied on the installed SDK, the protocol contract, and real initialize/list/call tests instead of assuming an example still matched.

Connecting a browser directly to Streamable HTTP also required coordinating allowed origins, allowed hosts, MCP headers, session retention, and CORS configuration. A health endpoint was not enough—we needed live tests that performed the actual MCP handshake and tool calls.

Reservation safety created another challenge. Search results can become unavailable before a hold is created, holds can expire before confirmation, and a multi-part itinerary can fail after earlier legs have succeeded. We addressed these cases with atomic overlap checks, structured alternatives, expiry handling, hold verification, compensating cancellation, and visible retryable cleanup.

This was also my first experience collaborating with a friend on a software project through GitHub. We separated backend and frontend work into dedicated branches, synchronized with main, reviewed pull requests, resolved integration issues, and ran the complete test suite before merging. Learning how to coordinate contracts and avoid breaking each other's work was as valuable as learning the MCP protocol itself.

Accomplishments that we're proud of

We are proud that this is more than a conversational mock-up. The browser uses the official MCP client to communicate with a working Python MCP server, and the protocol activity is visible instead of hidden.

One seven-tool contract supports three different hospitality categories and the complete lifecycle from search to cancellation. The system demonstrates a genuine competing-session conflict, expiring holds, explicit approval, atomic modification, idempotent operations, and structured alternatives.

Occasion Concierge adds multi-step orchestration without pretending that separate providers share a distributed transaction. It verifies state, compensates for partial failure, and clearly reports any cleanup it cannot confirm.

Our final verification passed 17 backend tests and 141 frontend tests against the live MCP server, along with TypeScript checking and a production build. The project uses synthetic data and requires no API keys, which keeps the demo reproducible and prevents real guest information from being exposed.

What we learned

We learned that MCP is not simply a way to call functions. A reliable MCP integration needs a clear contract, typed inputs and outputs, protocol-aware error handling, session management, and careful rules around state-changing actions.

Building the server in code helped me understand MCP at a much deeper level than my previous n8n workflows. I learned how the handshake, tool discovery, structured content, transport, and application business rules fit together.

We also learned that voice input should not automatically become authorization. Transcription, sending, holding, and confirming remain separate actions so the user can understand and control the outcome.

Finally, we learned how important collaboration discipline is. Branch ownership, small commits, pull-request reviews, shared contracts, and integration tests allowed backend and frontend work to progress independently and still become one coherent product.

What's next for Hospitality Assistant MCP

The current project is intentionally a local hackathon demonstration using synthetic inventory. Our next steps would be:

  • Connect authenticated restaurant, salon, and hotel provider APIs.
  • Add HTTPS, identity, authorization, rate limiting, monitoring, and audit controls.
  • Move from SQLite to production-grade storage for multi-instance deployment.
  • Add richer language understanding while preserving typed MCP inputs and confirmation gates.
  • Support provider-specific deposits, cancellation policies, and availability rules.
  • Persist preferences and itinerary context with clear privacy controls.
  • Add idempotency keys and stronger operational recovery for external provider calls.
  • Explore an official production Alexa+ integration when supported access and deployment guidance are available.

The goal is not to let an assistant make invisible decisions. It is to make complicated hospitality planning feel simple while keeping every commitment understandable, reversible, and under the user's control.

View the source code and setup instructions on GitHub

Built With

Share this project:

Updates

Submission history