How the JourneyBay ChatGPT app plans trips with MCP
What is the JourneyBay ChatGPT app?
The JourneyBay ChatGPT app is an authenticated MCP integration for travel planning. It lets ChatGPT work with a user's JourneyBay trips, places, itineraries, favorites, and visa context, then present selected results as interactive UI inside the conversation.
TL;DR
- -JourneyBay's production MCP server gives ChatGPT 23 focused travel tools: it can read trips, search places, edit itineraries, import a plan, and return useful results without relying on a widget.
- -Maps, day schedules, place cards, checklists, and action results render inside the conversation through MCP Apps UI resources.
- -OAuth 2.1 with PKCE, nine granular scopes, per-tool authorization, response filtering, rate limits, and audit events keep access narrower than a blanket account connection.
- -The same remote MCP transport can serve other compatible hosts, but authentication and UI support still need to be tested per client.
The useful part of a travel app inside ChatGPT is not another chatbot. It is the point where a sentence such as “move the museum to day three” becomes a controlled update to the same itinerary you see in JourneyBay.
The JourneyBay 2.0 release notes cover that itinerary from the traveler’s side. This article covers the server side and what has to happen before ChatGPT may touch the trip.
I built the JourneyBay integration around that constraint. ChatGPT decides which operation matches the request; the JourneyBay server authenticates it, checks the permission, executes the operation, and returns both a concise model-readable result and, where it helps, an interactive map or schedule.
This is a production walkthrough of that path: the tool surface, the UI boundary, and the authorization decisions that matter once an MCP integration touches real user data.
What the app can actually do
The OpenAI profile currently exposes 23 user-facing tools. They are deliberately narrower than one catch-all manage_trip function:
- read trips, trip details, day schedules, checklists, favorites, and chat history;
- search places, open place details, get recommendations, and retrieve visa context;
- create a trip, add or remove an activity, reorder a day, update notes, and archive a trip;
- generate or adjust an itinerary and send a message to JourneyBay’s travel assistant;
- import a complete itinerary drafted in the conversation into JourneyBay.
That separation is operational, not cosmetic. A model can select get_day_schedule for a question and never receive write access. A request to remove an activity reaches a different handler, requires a write scope, and carries a destructive-action annotation.
Four MCP resources provide compact context for trips, a selected trip, favorites, and the travel profile. They are also permission-aware. If a connection has no favorites:read scope, the favorites resource does not return the user’s saved places.
The result is more predictable than asking a general-purpose chat endpoint to interpret every request on its own. The tool name, schema, required scopes, and safety annotations form a contract between the model and the application. This matches OpenAI’s current guidance to define focused tools from recognizable user goals rather than bundling unrelated modes into one endpoint (official MCP server guide).
The request path
The production path is short enough to reason about:
ChatGPT
-> MCP over Streamable HTTP
-> OAuth token and scope checks
-> JourneyBay tool handler
-> Supabase data or Edge Function
-> text result + optional structured UI data
The public MCP endpoint is https://mcp.journeybay.co/mcp. The server runs on Deno and uses the official TypeScript MCP SDK. Each connection gets an MCP session; the server resolves a platform profile from the OAuth client and request origin before registering tools.
Platform profiles turned out to be important. ChatGPT does not need every internal field or every developer-only tool. The OpenAI profile removes the health tool, normalizes descriptions, strips prohibited inputs, and filters model-visible responses. Other clients can keep a different tool or UI profile without forking the business logic.
This is the part a launch announcement usually skips. “Built on MCP” is not enough. The server still needs deterministic authorization, bounded data returned to the model, stable tool contracts, and a useful fallback when a client cannot render custom UI.
Why the map is not part of the prompt
A day-by-day itinerary is hard to inspect as a paragraph. JourneyBay therefore associates selected tools with MCP Apps UI resources: trip maps, day schedules, place cards, search results, checklists, progress views, and compact confirmations for write actions.
The tool response has two channels:
contentgives the model enough text to continue the conversation.structuredContentgives the component the fields it needs to render.
The resource URI connects the tool to its component. ChatGPT renders that component in an iframe beside the conversation. The implementation uses the shared _meta.ui.resourceUri field and retains the OpenAI compatibility alias for hosts that expect openai/outputTemplate.
That distinction prevents a common MCP UI failure: building a pretty widget that contains the only usable result. JourneyBay’s tools still return meaningful text when the host has no component support. OpenAI now recommends the same standards-first approach and explicitly says tools should remain useful without UI (official UI guide).
The next refinement is to split more data operations from render operations. Attaching a component to every intermediate call can remount the iframe several times while the model is still working. A dedicated render tool lets the model fetch, filter, and validate data first, then mount one final view. That change is worth measuring on multi-step searches rather than applying blindly to every tool.
Authorization is a tool-level decision
Travel data is personal, and itinerary edits have side effects. The production server does not accept anonymous MCP calls. It publishes protected-resource and authorization-server metadata, uses an OAuth 2.1 authorization-code flow with PKCE, and validates the bearer token for every MCP request.
JourneyBay defines nine scopes:
trips:readandtrips:write;favorites:readandfavorites:write;places:read;chat:readandchat:write;profile:read;itinerary:generate.
Each tool declares the scopes it needs. The registry checks those scopes again before calling the handler. The backend query is then bound to the authenticated JourneyBay user. This is defense in depth: hiding a tool from tools/list is useful, but it is not authorization.
OpenAI’s current plugin documentation expects authenticated MCP servers that expose customer data or write actions to implement OAuth 2.1, publish discovery metadata, and support PKCE with S256 (official authentication guide). JourneyBay’s live metadata advertises those endpoints and scopes at mcp.journeybay.co.
Data minimization for two audiences
The model and the widget do not need identical data.
For model-visible JSON tool results, the OpenAI profile removes internal user and trip IDs, timestamps, subscription fields, deep links, precise location inputs, and other metadata that does not help answer the request.
The widget may still need a record ID to call the next tool or coordinates to draw a map. Its structured channel keeps those functional fields but strips prohibited provider identifiers, commerce data, and unusable deep links. The registry applies these filters to JSON results after the tool handler. Free-form text still needs its own review; a response filter is not a license to return arbitrary strings.
This does not make _meta or an iframe a security boundary. Tokens and secrets never belong in a tool result. Authorization stays on the server, and every widget-initiated tool call goes through the same checks as a model-initiated call. The same principle applies to the other controls in an MCP security review.
What happens when something fails
The app has to fail in a way the conversation can recover from.
- An expired or revoked token returns
401with protected-resource metadata so the host can reconnect. - A missing scope returns a specific permission error instead of attempting the operation.
- Rate limits are keyed by OAuth client and user, with a lower allowance for AI-generation tools.
- Tool calls produce audit events, duration metrics, and success or error counters without logging raw itinerary content.
- A component failure does not erase the text result.
The current limiter is in-memory, which is acceptable for the present single-instance deployment but not for horizontally scaled replicas. A distributed limiter is one of the conditions for adding instances; otherwise two replicas would enforce two independent budgets.
Connect JourneyBay to ChatGPT
Open the ChatGPT plugin or app directory, select JourneyBay, and choose Sign in with JourneyBay. Review the requested permissions and complete authorization. Then start with a bounded request:
- “Show my upcoming trips.”
- “Open the schedule for day two of my Tokyo trip.”
- “Find three museums near the places already saved for Paris.”
- “Move the dinner reservation to day three.”
The first two requests exercise read tools. The last one requires trip write access. Keeping those operations distinct makes the authorization prompt and the resulting audit trail easier to understand.
For another MCP-compatible client, use https://mcp.journeybay.co/mcp as the remote server URL. Do not assume identical behavior from protocol support alone. Verify that the client supports remote Streamable HTTP, the required OAuth flow, tool annotations, and, if you need maps or cards, MCP Apps UI.
What this build changed
The first version was easy to describe: connect a travel API to ChatGPT. The production version required a stricter definition of the boundary.
The model proposes and sequences actions. JourneyBay owns identity, permissions, data access, validation, side effects, and auditability. Components make structured results easier to inspect, but the underlying tools remain usable without them. MCP provides the transport and contracts; it does not replace application security.
That is the practical value of the integration. A trip discussed in ChatGPT no longer has to end as disposable prose. With explicit permission, it can become the same structured itinerary the traveler continues using in JourneyBay.
Sources
- OpenAI: build an MCP server
- OpenAI: add UI to an MCP server
- OpenAI: authenticate plugin users
- Model Context Protocol specification
JourneyBay provides visa context to help with trip preparation. Always verify entry requirements with the destination’s embassy, consulate, or official government portal before travel.