travel-assistant-mcp 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Forgemesh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Travel Assistant MCP
2
+
3
+ Public MCP server for travel search workflows. It gives agents a small set of tools for airport lookup, route comparison, travel timing guidance, and external booking links.
4
+
5
+ ## Features
6
+
7
+ - Search workflow responses using generic travel search providers
8
+ - Airport metadata lookup by IATA code
9
+ - Basic route comparison for provider integrations
10
+ - External booking links for booking partners
11
+ - Commission-eligible links disclosed in tool output
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pnpm install
17
+ pnpm build
18
+ ```
19
+
20
+ ## Run
21
+
22
+ ```bash
23
+ pnpm start
24
+ ```
25
+
26
+ ## MCP Client Example
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "travel-assistant": {
32
+ "command": "travel-assistant-mcp"
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ ## Tools
39
+
40
+ - `search_travel_options`
41
+ - `get_airport_info`
42
+ - `compare_routes`
43
+ - `build_booking_link`
44
+ - `explain_travel_timing`
45
+
46
+ ## Public Data Boundary
47
+
48
+ This package uses generic language for provider integrations. Tool responses may include external booking links and commission-eligible links. Booking completion happens with booking partners outside this MCP server.
@@ -0,0 +1,9 @@
1
+ export interface Airport {
2
+ code: string;
3
+ name: string;
4
+ city: string;
5
+ country: string;
6
+ timezone: string;
7
+ }
8
+ export declare const AIRPORTS: Record<string, Airport>;
9
+ export declare function getAirport(code: string): Airport | null;
@@ -0,0 +1,20 @@
1
+ export const AIRPORTS = {
2
+ JFK: { code: "JFK", name: "John F. Kennedy International Airport", city: "New York", country: "US", timezone: "America/New_York" },
3
+ LGA: { code: "LGA", name: "LaGuardia Airport", city: "New York", country: "US", timezone: "America/New_York" },
4
+ EWR: { code: "EWR", name: "Newark Liberty International Airport", city: "Newark", country: "US", timezone: "America/New_York" },
5
+ LAX: { code: "LAX", name: "Los Angeles International Airport", city: "Los Angeles", country: "US", timezone: "America/Los_Angeles" },
6
+ SFO: { code: "SFO", name: "San Francisco International Airport", city: "San Francisco", country: "US", timezone: "America/Los_Angeles" },
7
+ ORD: { code: "ORD", name: "O'Hare International Airport", city: "Chicago", country: "US", timezone: "America/Chicago" },
8
+ ATL: { code: "ATL", name: "Hartsfield-Jackson Atlanta International Airport", city: "Atlanta", country: "US", timezone: "America/New_York" },
9
+ DFW: { code: "DFW", name: "Dallas/Fort Worth International Airport", city: "Dallas", country: "US", timezone: "America/Chicago" },
10
+ IAH: { code: "IAH", name: "George Bush Intercontinental Airport", city: "Houston", country: "US", timezone: "America/Chicago" },
11
+ HOU: { code: "HOU", name: "William P. Hobby Airport", city: "Houston", country: "US", timezone: "America/Chicago" },
12
+ MIA: { code: "MIA", name: "Miami International Airport", city: "Miami", country: "US", timezone: "America/New_York" },
13
+ LAS: { code: "LAS", name: "Harry Reid International Airport", city: "Las Vegas", country: "US", timezone: "America/Los_Angeles" },
14
+ SEA: { code: "SEA", name: "Seattle-Tacoma International Airport", city: "Seattle", country: "US", timezone: "America/Los_Angeles" },
15
+ BOS: { code: "BOS", name: "Boston Logan International Airport", city: "Boston", country: "US", timezone: "America/New_York" },
16
+ DEN: { code: "DEN", name: "Denver International Airport", city: "Denver", country: "US", timezone: "America/Denver" },
17
+ };
18
+ export function getAirport(code) {
19
+ return AIRPORTS[code.toUpperCase()] ?? null;
20
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { getAirport } from "./airports.js";
6
+ import { buildExternalBookingLink } from "./links.js";
7
+ import { getTravelTimingAdvice, isInternationalRoute } from "./timing.js";
8
+ const RESPONSE_BASE = {
9
+ source: "travel-assistant-mcp",
10
+ provider_language: "travel search providers",
11
+ integration_language: "provider integrations",
12
+ booking_language: "booking partners",
13
+ };
14
+ function textResponse(payload, isError = false) {
15
+ return {
16
+ content: [{ type: "text", text: JSON.stringify(payload) }],
17
+ isError,
18
+ };
19
+ }
20
+ const server = new Server({ name: "travel-assistant-mcp", version: "0.1.1" }, { capabilities: { tools: {} } });
21
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
22
+ tools: [
23
+ {
24
+ name: "search_travel_options",
25
+ description: "Prepare a travel search workflow for two airports. Returns generic provider guidance and external booking links.",
26
+ inputSchema: {
27
+ type: "object",
28
+ properties: {
29
+ origin: { type: "string", description: "Origin airport IATA code" },
30
+ destination: { type: "string", description: "Destination airport IATA code" },
31
+ departure_date: { type: "string", description: "Departure date YYYY-MM-DD" },
32
+ return_date: { type: "string", description: "Return date YYYY-MM-DD" },
33
+ currency: { type: "string", description: "Currency code" },
34
+ },
35
+ required: ["origin", "destination"],
36
+ },
37
+ },
38
+ {
39
+ name: "get_airport_info",
40
+ description: "Get basic metadata for an airport by IATA code.",
41
+ inputSchema: {
42
+ type: "object",
43
+ properties: {
44
+ code: { type: "string", description: "IATA airport code" },
45
+ },
46
+ required: ["code"],
47
+ },
48
+ },
49
+ {
50
+ name: "compare_routes",
51
+ description: "Compare several airport pairs using generic route metadata.",
52
+ inputSchema: {
53
+ type: "object",
54
+ properties: {
55
+ routes: {
56
+ type: "array",
57
+ items: {
58
+ type: "object",
59
+ properties: {
60
+ origin: { type: "string" },
61
+ destination: { type: "string" },
62
+ },
63
+ required: ["origin", "destination"],
64
+ },
65
+ },
66
+ },
67
+ required: ["routes"],
68
+ },
69
+ },
70
+ {
71
+ name: "build_booking_link",
72
+ description: "Build an external booking link for a route.",
73
+ inputSchema: {
74
+ type: "object",
75
+ properties: {
76
+ origin: { type: "string", description: "Origin airport code" },
77
+ destination: { type: "string", description: "Destination airport code" },
78
+ departure_date: { type: "string", description: "Departure date YYYY-MM-DD" },
79
+ return_date: { type: "string", description: "Return date YYYY-MM-DD" },
80
+ currency: { type: "string", description: "Currency code" },
81
+ },
82
+ required: [],
83
+ },
84
+ },
85
+ {
86
+ name: "explain_travel_timing",
87
+ description: "Return general timing guidance for domestic or international routes.",
88
+ inputSchema: {
89
+ type: "object",
90
+ properties: {
91
+ origin: { type: "string", description: "Origin airport code" },
92
+ destination: { type: "string", description: "Destination airport code" },
93
+ },
94
+ required: [],
95
+ },
96
+ },
97
+ ],
98
+ }));
99
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
100
+ const { name, arguments: args = {} } = request.params;
101
+ switch (name) {
102
+ case "search_travel_options": {
103
+ const origin = String(args.origin ?? "").toUpperCase();
104
+ const destination = String(args.destination ?? "").toUpperCase();
105
+ const departureDate = args.departure_date ? String(args.departure_date) : undefined;
106
+ const returnDate = args.return_date ? String(args.return_date) : undefined;
107
+ const currency = args.currency ? String(args.currency).toUpperCase() : "USD";
108
+ if (!origin || !destination) {
109
+ return textResponse({ ok: false, error: "origin and destination are required" }, true);
110
+ }
111
+ return textResponse({
112
+ ok: true,
113
+ ...RESPONSE_BASE,
114
+ results: {
115
+ route: { origin, destination },
116
+ trip_type: returnDate ? "round_trip" : "one_way",
117
+ departure_date: departureDate ?? null,
118
+ return_date: returnDate ?? null,
119
+ currency,
120
+ provider_integrations: "travel search providers",
121
+ booking_partners: "external booking links",
122
+ link_disclosure: "Results can include commission-eligible links.",
123
+ external_booking_link: buildExternalBookingLink({
124
+ origin,
125
+ destination,
126
+ departure_date: departureDate,
127
+ return_date: returnDate,
128
+ currency,
129
+ }),
130
+ },
131
+ });
132
+ }
133
+ case "get_airport_info": {
134
+ const code = String(args.code ?? "").toUpperCase();
135
+ if (!code)
136
+ return textResponse({ ok: false, error: "code is required" }, true);
137
+ const airport = getAirport(code);
138
+ if (!airport)
139
+ return textResponse({ ok: false, ...RESPONSE_BASE, results: null, error: `Airport ${code} not found` }, true);
140
+ return textResponse({ ok: true, ...RESPONSE_BASE, results: airport });
141
+ }
142
+ case "compare_routes": {
143
+ const routes = Array.isArray(args.routes) ? args.routes : [];
144
+ if (routes.length === 0)
145
+ return textResponse({ ok: false, error: "routes array is required" }, true);
146
+ const comparisons = routes.map((route) => {
147
+ const origin = String(route.origin ?? "").toUpperCase();
148
+ const destination = String(route.destination ?? "").toUpperCase();
149
+ return {
150
+ route: `${origin}-${destination}`,
151
+ origin,
152
+ destination,
153
+ route_type: isInternationalRoute(origin, destination) ? "international" : "domestic",
154
+ external_booking_link: buildExternalBookingLink({ origin, destination }),
155
+ };
156
+ });
157
+ return textResponse({
158
+ ok: true,
159
+ ...RESPONSE_BASE,
160
+ results: {
161
+ comparisons,
162
+ link_disclosure: "Comparison results can include commission-eligible links from booking partners.",
163
+ },
164
+ });
165
+ }
166
+ case "build_booking_link": {
167
+ const origin = args.origin ? String(args.origin).toUpperCase() : undefined;
168
+ const destination = args.destination ? String(args.destination).toUpperCase() : undefined;
169
+ const departureDate = args.departure_date ? String(args.departure_date) : undefined;
170
+ const returnDate = args.return_date ? String(args.return_date) : undefined;
171
+ const currency = args.currency ? String(args.currency).toUpperCase() : "USD";
172
+ return textResponse({
173
+ ok: true,
174
+ ...RESPONSE_BASE,
175
+ results: {
176
+ external_booking_link: buildExternalBookingLink({
177
+ origin,
178
+ destination,
179
+ departure_date: departureDate,
180
+ return_date: returnDate,
181
+ currency,
182
+ }),
183
+ link_disclosure: "This may be a commission-eligible link from booking partners.",
184
+ },
185
+ });
186
+ }
187
+ case "explain_travel_timing": {
188
+ const origin = args.origin ? String(args.origin).toUpperCase() : "";
189
+ const destination = args.destination ? String(args.destination).toUpperCase() : "";
190
+ const routeType = isInternationalRoute(origin, destination);
191
+ return textResponse({
192
+ ok: true,
193
+ ...RESPONSE_BASE,
194
+ results: {
195
+ route: origin && destination ? { origin, destination } : null,
196
+ timing_advice: getTravelTimingAdvice(routeType),
197
+ },
198
+ });
199
+ }
200
+ default:
201
+ return textResponse({ ok: false, error: `Unknown tool: ${name}` }, true);
202
+ }
203
+ });
204
+ const transport = new StdioServerTransport();
205
+ void server.connect(transport);
@@ -0,0 +1 @@
1
+ export declare function buildExternalBookingLink(params: Record<string, string | undefined>, baseUrl?: string): string;
package/dist/links.js ADDED
@@ -0,0 +1,9 @@
1
+ const DEFAULT_BASE_URL = "https://travel.forgemesh.io";
2
+ export function buildExternalBookingLink(params, baseUrl = DEFAULT_BASE_URL) {
3
+ const url = new URL(baseUrl);
4
+ for (const [key, value] of Object.entries(params)) {
5
+ if (value)
6
+ url.searchParams.set(key, value);
7
+ }
8
+ return url.toString();
9
+ }
@@ -0,0 +1,14 @@
1
+ export interface TimingAdvice {
2
+ route_type: "domestic" | "international";
3
+ booking_window: {
4
+ min_weeks: number;
5
+ max_weeks: number;
6
+ sweet_spot: string;
7
+ };
8
+ lower_demand_days: string[];
9
+ lower_demand_months: string[];
10
+ data_source: string;
11
+ note: string;
12
+ }
13
+ export declare function getTravelTimingAdvice(international: boolean): TimingAdvice;
14
+ export declare function isInternationalRoute(origin: string, destination: string): boolean;
package/dist/timing.js ADDED
@@ -0,0 +1,28 @@
1
+ import { getAirport } from "./airports.js";
2
+ export function getTravelTimingAdvice(international) {
3
+ const note = "General travel planning guidance based on broad public market patterns. " +
4
+ "Actual results vary by carrier, route, season, and provider integrations.";
5
+ if (international) {
6
+ return {
7
+ route_type: "international",
8
+ booking_window: { min_weeks: 8, max_weeks: 24, sweet_spot: "10 to 16 weeks before departure" },
9
+ lower_demand_days: ["Tuesday", "Wednesday"],
10
+ lower_demand_months: ["January", "February", "September", "October"],
11
+ data_source: "General public travel planning patterns",
12
+ note,
13
+ };
14
+ }
15
+ return {
16
+ route_type: "domestic",
17
+ booking_window: { min_weeks: 3, max_weeks: 10, sweet_spot: "4 to 8 weeks before departure" },
18
+ lower_demand_days: ["Tuesday", "Wednesday", "Saturday"],
19
+ lower_demand_months: ["January", "February", "September"],
20
+ data_source: "General public travel planning patterns",
21
+ note,
22
+ };
23
+ }
24
+ export function isInternationalRoute(origin, destination) {
25
+ const o = getAirport(origin);
26
+ const d = getAirport(destination);
27
+ return !(o && d && o.country === "US" && d.country === "US");
28
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "mcpServers": {
3
+ "travel-assistant": {
4
+ "command": "travel-assistant-mcp"
5
+ }
6
+ }
7
+ }
@@ -0,0 +1,24 @@
1
+ # Example Tool Calls
2
+
3
+ ## Search Travel Options
4
+
5
+ ```json
6
+ {
7
+ "origin": "JFK",
8
+ "destination": "LAX",
9
+ "departure_date": "2026-08-15",
10
+ "currency": "USD"
11
+ }
12
+ ```
13
+
14
+ ## Build Booking Link
15
+
16
+ ```json
17
+ {
18
+ "origin": "JFK",
19
+ "destination": "LAX",
20
+ "departure_date": "2026-08-15"
21
+ }
22
+ ```
23
+
24
+ Tool output uses generic provider integrations, booking partners, external booking links, and commission-eligible links.
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "travel-assistant-mcp",
3
+ "version": "0.1.1",
4
+ "description": "Public MCP server for travel search workflows, airport lookup, route comparison, and external booking links.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "travel-assistant-mcp": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/index.js",
13
+ "test": "vitest run",
14
+ "typecheck": "tsc --noEmit"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "LICENSE",
20
+ "examples"
21
+ ],
22
+ "dependencies": {
23
+ "@modelcontextprotocol/sdk": "^1.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20.11.0",
27
+ "typescript": "^5.3.3",
28
+ "vitest": "^1.2.0"
29
+ },
30
+ "keywords": [
31
+ "mcp",
32
+ "model-context-protocol",
33
+ "travel",
34
+ "flights",
35
+ "travel-search",
36
+ "travel-planning",
37
+ "booking-partners",
38
+ "forgemesh"
39
+ ],
40
+ "homepage": "https://github.com/forgemeshlabs/travel-mcp#readme",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/forgemeshlabs/travel-mcp.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/forgemeshlabs/travel-mcp/issues"
47
+ },
48
+ "author": "Forgemesh",
49
+ "license": "MIT",
50
+ "engines": {
51
+ "node": ">=18"
52
+ }
53
+ }