mcp-travelcode 1.0.0

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.
Files changed (70) hide show
  1. package/README.md +133 -0
  2. package/build/auth/cli-auth.d.ts +16 -0
  3. package/build/auth/cli-auth.js +281 -0
  4. package/build/auth/token-store.d.ts +39 -0
  5. package/build/auth/token-store.js +113 -0
  6. package/build/client/api-client.d.ts +42 -0
  7. package/build/client/api-client.js +235 -0
  8. package/build/client/types.d.ts +420 -0
  9. package/build/client/types.js +3 -0
  10. package/build/config.d.ts +9 -0
  11. package/build/config.js +30 -0
  12. package/build/formatters/aerodatabox-formatter.d.ts +6 -0
  13. package/build/formatters/aerodatabox-formatter.js +246 -0
  14. package/build/formatters/airline-formatter.d.ts +3 -0
  15. package/build/formatters/airline-formatter.js +12 -0
  16. package/build/formatters/airport-formatter.d.ts +4 -0
  17. package/build/formatters/airport-formatter.js +28 -0
  18. package/build/formatters/flight-formatter.d.ts +13 -0
  19. package/build/formatters/flight-formatter.js +100 -0
  20. package/build/formatters/hotel-formatter.d.ts +4 -0
  21. package/build/formatters/hotel-formatter.js +55 -0
  22. package/build/formatters/order-formatter.d.ts +8 -0
  23. package/build/formatters/order-formatter.js +115 -0
  24. package/build/http-server.d.ts +16 -0
  25. package/build/http-server.js +164 -0
  26. package/build/index.d.ts +3 -0
  27. package/build/index.js +16 -0
  28. package/build/polling/flight-poller.d.ts +11 -0
  29. package/build/polling/flight-poller.js +60 -0
  30. package/build/server.d.ts +4 -0
  31. package/build/server.js +54 -0
  32. package/build/tools/cancel-order.d.ts +9 -0
  33. package/build/tools/cancel-order.js +24 -0
  34. package/build/tools/check-order-cancellation.d.ts +8 -0
  35. package/build/tools/check-order-cancellation.js +22 -0
  36. package/build/tools/check-order-modification.d.ts +8 -0
  37. package/build/tools/check-order-modification.js +22 -0
  38. package/build/tools/create-order.d.ts +75 -0
  39. package/build/tools/create-order.js +52 -0
  40. package/build/tools/get-airport-delay-stats.d.ts +9 -0
  41. package/build/tools/get-airport-delay-stats.js +31 -0
  42. package/build/tools/get-airport-flights.d.ts +13 -0
  43. package/build/tools/get-airport-flights.js +78 -0
  44. package/build/tools/get-airport.d.ts +8 -0
  45. package/build/tools/get-airport.js +25 -0
  46. package/build/tools/get-flight-delay-stats.d.ts +8 -0
  47. package/build/tools/get-flight-delay-stats.js +28 -0
  48. package/build/tools/get-flight-results.d.ts +16 -0
  49. package/build/tools/get-flight-results.js +68 -0
  50. package/build/tools/get-flight-status.d.ts +11 -0
  51. package/build/tools/get-flight-status.js +42 -0
  52. package/build/tools/get-hotel-location.d.ts +8 -0
  53. package/build/tools/get-hotel-location.js +27 -0
  54. package/build/tools/get-order.d.ts +8 -0
  55. package/build/tools/get-order.js +22 -0
  56. package/build/tools/list-orders.d.ts +16 -0
  57. package/build/tools/list-orders.js +46 -0
  58. package/build/tools/modify-order.d.ts +10 -0
  59. package/build/tools/modify-order.js +33 -0
  60. package/build/tools/search-airlines.d.ts +9 -0
  61. package/build/tools/search-airlines.js +29 -0
  62. package/build/tools/search-airports.d.ts +9 -0
  63. package/build/tools/search-airports.js +30 -0
  64. package/build/tools/search-flights.d.ts +17 -0
  65. package/build/tools/search-flights.js +82 -0
  66. package/build/tools/search-hotel-locations.d.ts +9 -0
  67. package/build/tools/search-hotel-locations.js +23 -0
  68. package/build/tools/search-hotels.d.ts +46 -0
  69. package/build/tools/search-hotels.js +106 -0
  70. package/package.json +60 -0
@@ -0,0 +1,82 @@
1
+ import { z } from "zod";
2
+ import { executeFlightSearch } from "../polling/flight-poller.js";
3
+ import { formatFlightResults } from "../formatters/flight-formatter.js";
4
+ function convertDate(isoDate) {
5
+ // YYYY-MM-DD → DD.MM.YYYY
6
+ const [year, month, day] = isoDate.split("-");
7
+ return `${day}.${month}.${year}`;
8
+ }
9
+ export const searchFlightsSchema = {
10
+ origin: z.string().describe("Departure airport or city IATA code (e.g. 'LHR', 'LON', 'JFK'). Use search_airports to find codes."),
11
+ destination: z.string().describe("Arrival airport or city IATA code (e.g. 'CDG', 'BCN', 'NYC'). Use search_airports to find codes."),
12
+ departure_date: z.string().describe("Departure date in YYYY-MM-DD format (e.g. '2026-03-15')"),
13
+ return_date: z.string().optional().describe("Return date in YYYY-MM-DD format for round-trip. Omit for one-way."),
14
+ cabin_class: z
15
+ .enum(["economy", "premium_economy", "business", "first"])
16
+ .default("economy")
17
+ .describe("Cabin class"),
18
+ adults: z.number().int().min(1).max(9).default(1).describe("Number of adult passengers"),
19
+ children: z.number().int().min(0).max(9).default(0).describe("Number of children (2-11 years)"),
20
+ infants: z.number().int().min(0).max(4).default(0).describe("Number of infants (under 2 years)"),
21
+ preferred_airlines: z
22
+ .array(z.string())
23
+ .optional()
24
+ .describe("Optional list of preferred airline IATA codes to filter results (e.g. ['BA', 'LH'])"),
25
+ };
26
+ export function registerSearchFlights(server, client, config) {
27
+ server.tool("search_flights", "Search for flights between two airports. Handles the full search process including waiting for results from multiple airline sources. May take 15-60 seconds. For round-trip, provide both departure and return dates. Returns top results sorted by price with a cache ID for follow-up filtering.", searchFlightsSchema, async ({ origin, destination, departure_date, return_date, cabin_class, adults, children, infants, preferred_airlines }, extra) => {
28
+ try {
29
+ const searchParams = {
30
+ locationFrom: origin.toUpperCase(),
31
+ locationTo: destination.toUpperCase(),
32
+ date: convertDate(departure_date),
33
+ dateEnd: return_date ? convertDate(return_date) : "",
34
+ cabinClass: cabin_class,
35
+ adults,
36
+ children,
37
+ infants,
38
+ };
39
+ if (preferred_airlines && preferred_airlines.length > 0) {
40
+ searchParams.airlines = preferred_airlines.map((a) => a.toUpperCase());
41
+ }
42
+ // Build progress callback using MCP progress notifications
43
+ const progressToken = extra._meta?.progressToken;
44
+ let onProgress;
45
+ if (progressToken !== undefined) {
46
+ onProgress = async (progress, total, message) => {
47
+ await extra.sendNotification({
48
+ method: "notifications/progress",
49
+ params: { progressToken, progress, total, message },
50
+ });
51
+ };
52
+ }
53
+ const result = await executeFlightSearch(client, searchParams, config, onProgress);
54
+ // Build passengers description
55
+ const parts = [];
56
+ if (adults > 0)
57
+ parts.push(`${adults} adult${adults > 1 ? "s" : ""}`);
58
+ if (children > 0)
59
+ parts.push(`${children} child${children > 1 ? "ren" : ""}`);
60
+ if (infants > 0)
61
+ parts.push(`${infants} infant${infants > 1 ? "s" : ""}`);
62
+ const text = formatFlightResults(result.response, result.cacheId, {
63
+ origin: origin.toUpperCase(),
64
+ destination: destination.toUpperCase(),
65
+ departureDate: departure_date,
66
+ returnDate: return_date,
67
+ cabinClass: cabin_class,
68
+ passengers: parts.join(", "),
69
+ }, result.completed);
70
+ return {
71
+ content: [{ type: "text", text }],
72
+ };
73
+ }
74
+ catch (error) {
75
+ return {
76
+ content: [{ type: "text", text: `Error searching flights: ${error.message}` }],
77
+ isError: true,
78
+ };
79
+ }
80
+ });
81
+ }
82
+ //# sourceMappingURL=search-flights.js.map
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { TravelCodeApiClient } from "../client/api-client.js";
4
+ export declare const searchHotelLocationsSchema: {
5
+ query: z.ZodString;
6
+ limit: z.ZodDefault<z.ZodNumber>;
7
+ };
8
+ export declare function registerSearchHotelLocations(server: McpServer, client: TravelCodeApiClient): void;
9
+ //# sourceMappingURL=search-hotel-locations.d.ts.map
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import { formatHotelLocations } from "../formatters/hotel-formatter.js";
3
+ export const searchHotelLocationsSchema = {
4
+ query: z.string().describe("Search query — city, region, or hotel name (supports Cyrillic and Latin)"),
5
+ limit: z.number().int().min(1).max(50).default(15).describe("Max results to return"),
6
+ };
7
+ export function registerSearchHotelLocations(server, client) {
8
+ server.tool("search_hotel_locations", "Search for hotel locations (cities, regions, hotels) by name. Returns location IDs needed for hotel search.", searchHotelLocationsSchema, async ({ query, limit }) => {
9
+ try {
10
+ const data = await client.getWithTokenParam("/data/hotel-locations", { search: query, limit });
11
+ return {
12
+ content: [{ type: "text", text: formatHotelLocations(data) }],
13
+ };
14
+ }
15
+ catch (error) {
16
+ return {
17
+ content: [{ type: "text", text: `Error searching hotel locations: ${error.message}` }],
18
+ isError: true,
19
+ };
20
+ }
21
+ });
22
+ }
23
+ //# sourceMappingURL=search-hotel-locations.js.map
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { TravelCodeApiClient } from "../client/api-client.js";
4
+ export declare const searchHotelsSchema: {
5
+ location: z.ZodNumber;
6
+ checkin: z.ZodString;
7
+ checkout: z.ZodString;
8
+ country_code: z.ZodString;
9
+ guests: z.ZodArray<z.ZodObject<{
10
+ adults: z.ZodNumber;
11
+ children: z.ZodOptional<z.ZodNumber>;
12
+ childrenAges: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
13
+ }, "strip", z.ZodTypeAny, {
14
+ adults: number;
15
+ children?: number | undefined;
16
+ childrenAges?: number[] | undefined;
17
+ }, {
18
+ adults: number;
19
+ children?: number | undefined;
20
+ childrenAges?: number[] | undefined;
21
+ }>, "many">;
22
+ sort: z.ZodDefault<z.ZodEnum<["recommend", "price"]>>;
23
+ offset: z.ZodDefault<z.ZodNumber>;
24
+ limit: z.ZodDefault<z.ZodNumber>;
25
+ filter: z.ZodOptional<z.ZodObject<{
26
+ minPrice: z.ZodOptional<z.ZodNumber>;
27
+ maxPrice: z.ZodOptional<z.ZodNumber>;
28
+ starRating: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
29
+ boards: z.ZodOptional<z.ZodArray<z.ZodEnum<["RO", "BI", "LI", "DI", "HB", "FB", "AI"]>, "many">>;
30
+ payments: z.ZodOptional<z.ZodArray<z.ZodEnum<["full_refund"]>, "many">>;
31
+ }, "strip", z.ZodTypeAny, {
32
+ starRating?: number[] | undefined;
33
+ minPrice?: number | undefined;
34
+ maxPrice?: number | undefined;
35
+ boards?: ("RO" | "BI" | "LI" | "DI" | "HB" | "FB" | "AI")[] | undefined;
36
+ payments?: "full_refund"[] | undefined;
37
+ }, {
38
+ starRating?: number[] | undefined;
39
+ minPrice?: number | undefined;
40
+ maxPrice?: number | undefined;
41
+ boards?: ("RO" | "BI" | "LI" | "DI" | "HB" | "FB" | "AI")[] | undefined;
42
+ payments?: "full_refund"[] | undefined;
43
+ }>>;
44
+ };
45
+ export declare function registerSearchHotels(server: McpServer, client: TravelCodeApiClient): void;
46
+ //# sourceMappingURL=search-hotels.d.ts.map
@@ -0,0 +1,106 @@
1
+ import { z } from "zod";
2
+ import { formatHotelResults } from "../formatters/hotel-formatter.js";
3
+ const guestSchema = z.object({
4
+ adults: z.number().int().min(1).max(4).describe("Number of adults (1-4)"),
5
+ children: z.number().int().min(0).max(3).optional().describe("Number of children (0-3)"),
6
+ childrenAges: z
7
+ .array(z.number().int().min(0).max(17))
8
+ .optional()
9
+ .describe("Array of child ages (0-17), required if children > 0"),
10
+ });
11
+ const filterSchema = z.object({
12
+ minPrice: z.number().int().optional().describe("Minimum price per night"),
13
+ maxPrice: z.number().int().optional().describe("Maximum price per night"),
14
+ starRating: z.array(z.number().int().min(1).max(5)).optional().describe("Hotel star ratings, e.g. [4, 5]"),
15
+ boards: z
16
+ .array(z.enum(["RO", "BI", "LI", "DI", "HB", "FB", "AI"]))
17
+ .optional()
18
+ .describe("Meal plan codes: RO=Room Only, BI=Breakfast, HB=Half Board, FB=Full Board, AI=All Inclusive"),
19
+ payments: z
20
+ .array(z.enum(["full_refund"]))
21
+ .optional()
22
+ .describe("Payment filters: full_refund = only fully refundable"),
23
+ }).optional();
24
+ export const searchHotelsSchema = {
25
+ location: z
26
+ .number()
27
+ .int()
28
+ .describe("Location ID from search_hotel_locations. Positive = city/region, negative = single hotel"),
29
+ checkin: z.string().describe("Check-in date (YYYY-MM-DD)"),
30
+ checkout: z.string().describe("Check-out date (YYYY-MM-DD)"),
31
+ country_code: z.string().describe("Guest nationality ISO code (e.g. BY, RU, US)"),
32
+ guests: z.array(guestSchema).min(1).describe("Array of rooms, each with adults count and optional children"),
33
+ sort: z
34
+ .enum(["recommend", "price"])
35
+ .default("recommend")
36
+ .describe("Sort mode: recommend (default) or price"),
37
+ offset: z.number().int().min(0).default(0).describe("Pagination offset"),
38
+ limit: z.number().int().min(1).max(50).default(20).describe("Hotels per page"),
39
+ filter: filterSchema,
40
+ };
41
+ export function registerSearchHotels(server, client) {
42
+ server.tool("search_hotels", "Search hotels by location, dates, and guests. First use search_hotel_locations to get a location ID. Returns hotel offers with prices, star ratings, and meal plans. Supports filtering by stars, price, meal plan, and refundability.", searchHotelsSchema, async ({ location, checkin, checkout, country_code, guests, sort, offset, limit, filter }) => {
43
+ try {
44
+ const body = {
45
+ location,
46
+ checkin,
47
+ checkout,
48
+ countryCode: country_code,
49
+ guests,
50
+ sort,
51
+ offset,
52
+ limit,
53
+ };
54
+ if (filter) {
55
+ body.filter = filter;
56
+ }
57
+ const events = await client.postSSE("/search/hotels/stream", body);
58
+ // Collect hotels from SSE events
59
+ const hotels = [];
60
+ let totalCount = 0;
61
+ for (const { event, data } of events) {
62
+ if (event === "hotels") {
63
+ const batch = data;
64
+ hotels.push(...batch.hotels);
65
+ }
66
+ else if (event === "sorted_hotels") {
67
+ const batch = data;
68
+ hotels.push(...batch.hotels);
69
+ totalCount = batch.total;
70
+ }
71
+ else if (event === "completed") {
72
+ const completed = data;
73
+ totalCount = completed.count;
74
+ // In price mode, completed contains the hotels
75
+ if (completed.hotels && completed.hotels.length > 0) {
76
+ hotels.length = 0; // clear intermediate results
77
+ hotels.push(...completed.hotels);
78
+ }
79
+ }
80
+ else if (event === "error") {
81
+ const err = data;
82
+ return {
83
+ content: [{ type: "text", text: `Hotel search error: ${err.message}` }],
84
+ isError: true,
85
+ };
86
+ }
87
+ else if (event === "timeout") {
88
+ return {
89
+ content: [{ type: "text", text: `Hotel search timed out. Try narrowing your search (fewer dates, specific filters).` }],
90
+ isError: true,
91
+ };
92
+ }
93
+ }
94
+ return {
95
+ content: [{ type: "text", text: formatHotelResults(hotels, totalCount) }],
96
+ };
97
+ }
98
+ catch (error) {
99
+ return {
100
+ content: [{ type: "text", text: `Error searching hotels: ${error.message}` }],
101
+ isError: true,
102
+ };
103
+ }
104
+ });
105
+ }
106
+ //# sourceMappingURL=search-hotels.js.map
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "mcp-travelcode",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for TravelCode — flights, hotels, orders. Search flights & hotels, manage bookings via AI assistants.",
5
+ "type": "module",
6
+ "main": "./build/index.js",
7
+ "bin": {
8
+ "mcp-travelcode": "./build/index.js",
9
+ "mcp-travelcode-auth": "./build/auth/cli-auth.js"
10
+ },
11
+ "files": [
12
+ "build/**/*.js",
13
+ "build/**/*.d.ts",
14
+ "README.md"
15
+ ],
16
+ "keywords": [
17
+ "mcp",
18
+ "model-context-protocol",
19
+ "travel",
20
+ "flights",
21
+ "hotels",
22
+ "booking",
23
+ "claude",
24
+ "ai-tools"
25
+ ],
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/egorceo/mcp-travelcode"
29
+ },
30
+ "scripts": {
31
+ "prepublishOnly": "npm run build",
32
+ "build": "tsc",
33
+ "start": "node build/index.js",
34
+ "start:http": "node build/http-server.js",
35
+ "dev": "tsx src/index.ts",
36
+ "dev:http": "tsx src/http-server.ts",
37
+ "auth": "node build/auth/cli-auth.js auth",
38
+ "auth:status": "node build/auth/cli-auth.js status",
39
+ "auth:logout": "node build/auth/cli-auth.js logout",
40
+ "test": "vitest run",
41
+ "test:watch": "vitest",
42
+ "inspect": "npx @modelcontextprotocol/inspector node build/index.js"
43
+ },
44
+ "dependencies": {
45
+ "@modelcontextprotocol/sdk": "^1.12.0",
46
+ "express": "^5.2.1",
47
+ "zod": "^3.24.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/express": "^5.0.6",
51
+ "@types/node": "^22.0.0",
52
+ "tsx": "^4.0.0",
53
+ "typescript": "^5.7.0",
54
+ "vitest": "^3.0.0"
55
+ },
56
+ "engines": {
57
+ "node": ">=18.0.0"
58
+ },
59
+ "license": "MIT"
60
+ }