@2bad/ryanair-mcp 8.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 2BAD
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,91 @@
1
+ # Ryanair API
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/@2bad/ryanair)](https://www.npmjs.com/package/@2bad/ryanair)
4
+ [![License](https://img.shields.io/npm/l/@2bad/ryanair)](https://www.npmjs.com/package/@2bad/ryanair)
5
+ [![GitHub Build Status](https://img.shields.io/github/actions/workflow/status/2BAD/ryanair/build.yml)](https://github.com/2BAD/ryanair/actions/workflows/build.yml)
6
+ [![Code coverage](https://img.shields.io/codecov/c/github/2BAD/ryanair)](https://codecov.io/gh/2BAD/ryanair)
7
+ [![Written in TypeScript](https://img.shields.io/github/languages/top/2BAD/ryanair)](https://github.com/2BAD/ryanair/search?l=typescript)
8
+ [![Postman Collection](https://img.shields.io/badge/postman-collection-ff6c37)](https://www.postman.com/hakkotsu/workspace/ryanair)
9
+
10
+ Unofficial TypeScript client for Ryanair's API that provides easy access to flights, fares, and airport information.
11
+
12
+ ## Install
13
+
14
+ ```shell
15
+ npm install @2bad/ryanair
16
+ ```
17
+
18
+ **Warning:** This package is native [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) and no longer provides a CommonJS export. If your project uses CommonJS, you will have to [convert to ESM](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) or use the [dynamic `import()`](https://v8.dev/features/dynamic-import) function. Please don't open issues for questions regarding CommonJS / ESM.
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { airports, fares, flights } from '@2bad/ryanair'
24
+
25
+ // Find your nearest airport
26
+ const closest = await airports.getClosest()
27
+
28
+ // Check available flight dates
29
+ const dates = await flights.getDates('BER', 'DUB')
30
+
31
+ // Get cheapest fares for your trip
32
+ const deals = await fares.getCheapestPerDay('BER', 'DUB', '2024-02-01')
33
+ ```
34
+
35
+ ## API Overview
36
+
37
+ ### Airports API
38
+ - Get active airports list
39
+ - Find nearest airports
40
+ - Discover available destinations
41
+ - View airport details
42
+ - Search flight routes
43
+
44
+ [View Airports Documentation →](docs/airports.md)
45
+
46
+ ### Fares API
47
+ - Find cheapest daily fares
48
+ - Compare prices across date ranges
49
+ - Discover best round-trip deals
50
+ - Search by currency preference
51
+
52
+ [View Fares Documentation →](docs/fares.md)
53
+
54
+ ### Flights API
55
+ - Check flight availability
56
+ - View flight schedules
57
+ - Search available dates
58
+ - Access flight details
59
+
60
+ [View Flights Documentation →](docs/flights.md)
61
+
62
+ ## Understanding IATA Codes
63
+
64
+ IATA codes are three-letter identifiers used in aviation for airports worldwide. For example:
65
+ - `DUB` - Dublin Airport
66
+ - `BER` - Berlin Brandenburg Airport
67
+ - `STN` - London Stansted Airport
68
+
69
+ Find the complete list on [IATA's official website](https://www.iata.org/en/publications/directories/code-search/).
70
+
71
+ ## Disclaimer
72
+
73
+ This is an unofficial package and is not affiliated with Ryanair. Usage is subject to Ryanair's API terms and conditions.
74
+
75
+ ## Contributing
76
+
77
+ Contributions are welcome! Here's how you can help:
78
+
79
+ 1. Fork the repository
80
+ 2. Create a feature branch
81
+ 3. Submit a pull request
82
+
83
+ Please ensure your code passes all tests and follows our coding standards.
84
+
85
+ ## License
86
+
87
+ MIT © [2BAD](https://github.com/2BAD)
88
+
89
+ ---
90
+
91
+ Need help? [Open an issue](https://github.com/2BAD/ryanair/issues) or check our [Postman collection](https://www.postman.com/hakkotsu/workspace/ryanair).
package/build/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/build/cli.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "./index.js";
3
+ //#region source/cli.ts
4
+ await main();
5
+ //#endregion
6
+ export {};
@@ -0,0 +1,7 @@
1
+ //#region source/index.d.ts
2
+ /**
3
+ * Start the server using the stdio transport.
4
+ */
5
+ declare const main: () => Promise<void>;
6
+ //#endregion
7
+ export { main };
package/build/index.js ADDED
@@ -0,0 +1,32 @@
1
+ import { AIRPORTS_TOOLS } from "./tools/airports.js";
2
+ import { BOOKING_TOOLS } from "./tools/booking.js";
3
+ import { FARES_TOOLS } from "./tools/fares.js";
4
+ import { FLIGHTS_TOOLS } from "./tools/flights.js";
5
+ import { log } from "./utils/log.js";
6
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
+ //#region source/index.ts
9
+ const ALL_TOOLS = [
10
+ ...AIRPORTS_TOOLS,
11
+ ...FLIGHTS_TOOLS,
12
+ ...FARES_TOOLS,
13
+ ...BOOKING_TOOLS
14
+ ];
15
+ const server = new McpServer({
16
+ name: "ryanair",
17
+ version: "1.0.0",
18
+ description: "Model Context Protocol (MCP) server for Ryanair API with tools for querying flights, fares, airports, and generating booking links"
19
+ }, { capabilities: { tools: {} } });
20
+ for (const tool of ALL_TOOLS) server.tool(...tool);
21
+ /**
22
+ * Start the server using the stdio transport.
23
+ */
24
+ const main = async () => {
25
+ log("Starting server...");
26
+ const transport = new StdioServerTransport();
27
+ log("Created transport");
28
+ await server.connect(transport);
29
+ log("Server connected and running");
30
+ };
31
+ //#endregion
32
+ export { main };
@@ -0,0 +1,6 @@
1
+ import { ToolTuple } from "../utils/types.js";
2
+
3
+ //#region source/tools/airports.d.ts
4
+ declare const AIRPORTS_TOOLS: ToolTuple[];
5
+ //#endregion
6
+ export { AIRPORTS_TOOLS };
@@ -0,0 +1,219 @@
1
+ import { defineTool } from "../utils/types.js";
2
+ import { airports } from "@2bad/ryanair";
3
+ import { z } from "zod";
4
+ const AIRPORTS_TOOLS = [
5
+ defineTool("calculate_distance", "calculate total distance between consecutive locations", { locations: z.array(z.object({
6
+ latitude: z.number(),
7
+ longitude: z.number()
8
+ })) }, async ({ locations }) => {
9
+ try {
10
+ const data = airports.calculateDistance(locations);
11
+ return { content: [{
12
+ type: "text",
13
+ text: JSON.stringify({ distance: data }, null, 2)
14
+ }] };
15
+ } catch (error) {
16
+ const errorMessage = error instanceof Error ? error.message : String(error);
17
+ return {
18
+ isError: true,
19
+ content: [{
20
+ type: "text",
21
+ text: JSON.stringify({ error: errorMessage }, null, 2)
22
+ }]
23
+ };
24
+ }
25
+ }),
26
+ defineTool("find_routes", "find available routes between two airports", {
27
+ from: z.string().length(3),
28
+ to: z.string().length(3)
29
+ }, async ({ from, to }) => {
30
+ try {
31
+ const data = await airports.findRoutes(from, to);
32
+ return { content: [{
33
+ type: "text",
34
+ text: JSON.stringify(data, null, 2)
35
+ }] };
36
+ } catch (error) {
37
+ const errorMessage = error instanceof Error ? error.message : String(error);
38
+ return {
39
+ isError: true,
40
+ content: [{
41
+ type: "text",
42
+ text: JSON.stringify({ error: errorMessage }, null, 2)
43
+ }]
44
+ };
45
+ }
46
+ }),
47
+ defineTool("get_active_airports_v3", "get all active airports using API v3", {}, async () => {
48
+ try {
49
+ const data = await airports.getActiveV3();
50
+ return { content: [{
51
+ type: "text",
52
+ text: JSON.stringify(data, null, 2)
53
+ }] };
54
+ } catch (error) {
55
+ const errorMessage = error instanceof Error ? error.message : String(error);
56
+ return {
57
+ isError: true,
58
+ content: [{
59
+ type: "text",
60
+ text: JSON.stringify({ error: errorMessage }, null, 2)
61
+ }]
62
+ };
63
+ }
64
+ }),
65
+ defineTool("get_active_airports", "get all active airports", {}, async () => {
66
+ try {
67
+ const data = await airports.getActive();
68
+ return { content: [{
69
+ type: "text",
70
+ text: JSON.stringify(data, null, 2)
71
+ }] };
72
+ } catch (error) {
73
+ const errorMessage = error instanceof Error ? error.message : String(error);
74
+ return {
75
+ isError: true,
76
+ content: [{
77
+ type: "text",
78
+ text: JSON.stringify({ error: errorMessage }, null, 2)
79
+ }]
80
+ };
81
+ }
82
+ }),
83
+ defineTool("get_closest_airport", "get the closest airport based on user ip", {}, async () => {
84
+ try {
85
+ const data = await airports.getClosest();
86
+ return { content: [{
87
+ type: "text",
88
+ text: JSON.stringify(data, null, 2)
89
+ }] };
90
+ } catch (error) {
91
+ const errorMessage = error instanceof Error ? error.message : String(error);
92
+ return {
93
+ isError: true,
94
+ content: [{
95
+ type: "text",
96
+ text: JSON.stringify({ error: errorMessage }, null, 2)
97
+ }]
98
+ };
99
+ }
100
+ }),
101
+ defineTool("get_airport_destinations", "get available destinations from a specific airport", { code: z.string().length(3) }, async ({ code }) => {
102
+ try {
103
+ const data = await airports.getDestinations(code);
104
+ return { content: [{
105
+ type: "text",
106
+ text: JSON.stringify(data, null, 2)
107
+ }] };
108
+ } catch (error) {
109
+ const errorMessage = error instanceof Error ? error.message : String(error);
110
+ return {
111
+ isError: true,
112
+ content: [{
113
+ type: "text",
114
+ text: JSON.stringify({ error: errorMessage }, null, 2)
115
+ }]
116
+ };
117
+ }
118
+ }),
119
+ defineTool("get_airport_info", "get detailed information about a specific airport", { code: z.string().length(3) }, async ({ code }) => {
120
+ try {
121
+ const data = await airports.getInfo(code);
122
+ return { content: [{
123
+ type: "text",
124
+ text: JSON.stringify(data, null, 2)
125
+ }] };
126
+ } catch (error) {
127
+ const errorMessage = error instanceof Error ? error.message : String(error);
128
+ return {
129
+ isError: true,
130
+ content: [{
131
+ type: "text",
132
+ text: JSON.stringify({ error: errorMessage }, null, 2)
133
+ }]
134
+ };
135
+ }
136
+ }),
137
+ defineTool("get_nearby_airports", "get nearby airports based on user ip", { locale: z.string().optional() }, async ({ locale }) => {
138
+ try {
139
+ const data = await airports.getNearby(locale);
140
+ return { content: [{
141
+ type: "text",
142
+ text: JSON.stringify(data, null, 2)
143
+ }] };
144
+ } catch (error) {
145
+ const errorMessage = error instanceof Error ? error.message : String(error);
146
+ return {
147
+ isError: true,
148
+ content: [{
149
+ type: "text",
150
+ text: JSON.stringify({ error: errorMessage }, null, 2)
151
+ }]
152
+ };
153
+ }
154
+ }),
155
+ defineTool("get_schedules_by_period", "get flight schedules between two airports for a specific period", {
156
+ from: z.string().length(3),
157
+ to: z.string().length(3),
158
+ year: z.number(),
159
+ month: z.number()
160
+ }, async ({ from, to, year, month }) => {
161
+ try {
162
+ const data = await airports.getSchedulesByPeriod(from, to, year, month);
163
+ return { content: [{
164
+ type: "text",
165
+ text: JSON.stringify(data, null, 2)
166
+ }] };
167
+ } catch (error) {
168
+ const errorMessage = error instanceof Error ? error.message : String(error);
169
+ return {
170
+ isError: true,
171
+ content: [{
172
+ type: "text",
173
+ text: JSON.stringify({ error: errorMessage }, null, 2)
174
+ }]
175
+ };
176
+ }
177
+ }),
178
+ defineTool("get_schedules_by_route", "get flight schedule between two airports", {
179
+ from: z.string().length(3),
180
+ to: z.string().length(3)
181
+ }, async ({ from, to }) => {
182
+ try {
183
+ const data = await airports.getSchedulesByRoute(from, to);
184
+ return { content: [{
185
+ type: "text",
186
+ text: JSON.stringify(data, null, 2)
187
+ }] };
188
+ } catch (error) {
189
+ const errorMessage = error instanceof Error ? error.message : String(error);
190
+ return {
191
+ isError: true,
192
+ content: [{
193
+ type: "text",
194
+ text: JSON.stringify({ error: errorMessage }, null, 2)
195
+ }]
196
+ };
197
+ }
198
+ }),
199
+ defineTool("get_airport_schedules", "get all available flight schedules for a departure airport", { from: z.string().length(3) }, async ({ from }) => {
200
+ try {
201
+ const data = await airports.getSchedules(from);
202
+ return { content: [{
203
+ type: "text",
204
+ text: JSON.stringify(data, null, 2)
205
+ }] };
206
+ } catch (error) {
207
+ const errorMessage = error instanceof Error ? error.message : String(error);
208
+ return {
209
+ isError: true,
210
+ content: [{
211
+ type: "text",
212
+ text: JSON.stringify({ error: errorMessage }, null, 2)
213
+ }]
214
+ };
215
+ }
216
+ })
217
+ ];
218
+ //#endregion
219
+ export { AIRPORTS_TOOLS };
@@ -0,0 +1,6 @@
1
+ import { ToolTuple } from "../utils/types.js";
2
+
3
+ //#region source/tools/booking.d.ts
4
+ declare const BOOKING_TOOLS: ToolTuple[];
5
+ //#endregion
6
+ export { BOOKING_TOOLS };
@@ -0,0 +1,34 @@
1
+ import { defineTool } from "../utils/types.js";
2
+ import { helpers } from "@2bad/ryanair";
3
+ import { z } from "zod";
4
+ const BOOKING_TOOLS = [defineTool("generate_booking_link", "generate a Ryanair booking link based on flight details", {
5
+ originIata: z.string().length(3),
6
+ destinationIata: z.string().length(3),
7
+ dateOut: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
8
+ dateIn: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
9
+ adults: z.number().int().min(1).max(25).optional(),
10
+ teens: z.number().int().min(0).max(24).optional(),
11
+ children: z.number().int().min(0).max(24).optional(),
12
+ infants: z.number().int().min(0).max(24).optional(),
13
+ isReturn: z.boolean().optional(),
14
+ market: z.string().optional(),
15
+ locale: z.string().optional()
16
+ }, async (params) => {
17
+ try {
18
+ return { content: [{
19
+ type: "text",
20
+ text: helpers.generateBookingLink(params)
21
+ }] };
22
+ } catch (error) {
23
+ const errorMessage = error instanceof Error ? error.message : String(error);
24
+ return {
25
+ isError: true,
26
+ content: [{
27
+ type: "text",
28
+ text: JSON.stringify({ error: errorMessage }, null, 2)
29
+ }]
30
+ };
31
+ }
32
+ })];
33
+ //#endregion
34
+ export { BOOKING_TOOLS };
@@ -0,0 +1,6 @@
1
+ import { ToolTuple } from "../utils/types.js";
2
+
3
+ //#region source/tools/fares.d.ts
4
+ declare const FARES_TOOLS: ToolTuple[];
5
+ //#endregion
6
+ export { FARES_TOOLS };
@@ -0,0 +1,79 @@
1
+ import { defineTool } from "../utils/types.js";
2
+ import { fares } from "@2bad/ryanair";
3
+ import { z } from "zod";
4
+ const FARES_TOOLS = [
5
+ defineTool("find_cheapest_round_trip", "find the cheapest round trip fares for a route and date range", {
6
+ from: z.string().length(3),
7
+ to: z.string().length(3),
8
+ startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
9
+ endDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
10
+ currency: z.string().optional(),
11
+ limit: z.number().min(1).max(50).optional()
12
+ }, async ({ from, to, startDate, endDate, currency, limit }) => {
13
+ try {
14
+ const data = await fares.findCheapestRoundTrip(from, to, startDate, endDate, currency, limit);
15
+ return { content: [{
16
+ type: "text",
17
+ text: JSON.stringify(data, null, 2)
18
+ }] };
19
+ } catch (error) {
20
+ const errorMessage = error instanceof Error ? error.message : String(error);
21
+ return {
22
+ isError: true,
23
+ content: [{
24
+ type: "text",
25
+ text: JSON.stringify({ error: errorMessage }, null, 2)
26
+ }]
27
+ };
28
+ }
29
+ }),
30
+ defineTool("find_daily_fares_in_range", "find daily fares for a route within a specified date range", {
31
+ from: z.string().length(3),
32
+ to: z.string().length(3),
33
+ startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
34
+ endDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
35
+ currency: z.string().optional()
36
+ }, async ({ from, to, startDate, endDate, currency }) => {
37
+ try {
38
+ const data = await fares.findDailyFaresInRange(from, to, startDate, endDate, currency);
39
+ return { content: [{
40
+ type: "text",
41
+ text: JSON.stringify(data, null, 2)
42
+ }] };
43
+ } catch (error) {
44
+ const errorMessage = error instanceof Error ? error.message : String(error);
45
+ return {
46
+ isError: true,
47
+ content: [{
48
+ type: "text",
49
+ text: JSON.stringify({ error: errorMessage }, null, 2)
50
+ }]
51
+ };
52
+ }
53
+ }),
54
+ defineTool("get_cheapest_fares_per_day", "get the cheapest one-way fares between two airports for a given month", {
55
+ from: z.string().length(3),
56
+ to: z.string().length(3),
57
+ startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
58
+ currency: z.string().optional()
59
+ }, async ({ from, to, startDate, currency }) => {
60
+ try {
61
+ const data = await fares.getCheapestPerDay(from, to, startDate, currency);
62
+ return { content: [{
63
+ type: "text",
64
+ text: JSON.stringify(data, null, 2)
65
+ }] };
66
+ } catch (error) {
67
+ const errorMessage = error instanceof Error ? error.message : String(error);
68
+ return {
69
+ isError: true,
70
+ content: [{
71
+ type: "text",
72
+ text: JSON.stringify({ error: errorMessage }, null, 2)
73
+ }]
74
+ };
75
+ }
76
+ })
77
+ ];
78
+ //#endregion
79
+ export { FARES_TOOLS };
@@ -0,0 +1,6 @@
1
+ import { ToolTuple } from "../utils/types.js";
2
+
3
+ //#region source/tools/flights.d.ts
4
+ declare const FLIGHTS_TOOLS: ToolTuple[];
5
+ //#endregion
6
+ export { FLIGHTS_TOOLS };
@@ -0,0 +1,67 @@
1
+ import { defineTool } from "../utils/types.js";
2
+ import { flights } from "@2bad/ryanair";
3
+ import { z } from "zod";
4
+ const FLIGHTS_TOOLS = [defineTool("get_available_flights", "get available flights between two airports with flexible options", {
5
+ origin: z.string().length(3).optional(),
6
+ destination: z.string().length(3).optional(),
7
+ dateOut: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
8
+ dateIn: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
9
+ adults: z.number().min(1).max(25).optional(),
10
+ children: z.number().min(0).max(24).optional(),
11
+ teens: z.number().min(0).max(24).optional(),
12
+ infants: z.number().min(0).max(24).optional(),
13
+ includeConnecting: z.boolean().optional(),
14
+ roundTrip: z.boolean().optional(),
15
+ promoCode: z.string().optional()
16
+ }, async (params) => {
17
+ try {
18
+ const apiParams = {};
19
+ if (params.origin) apiParams["Origin"] = params.origin;
20
+ if (params.destination) apiParams["Destination"] = params.destination;
21
+ if (params.dateOut) apiParams["DateOut"] = params.dateOut;
22
+ if (params.dateIn) apiParams["DateIn"] = params.dateIn;
23
+ if (params.adults !== void 0 && params.adults !== null) apiParams["ADT"] = params.adults.toString();
24
+ if (params.children !== void 0 && params.children !== null) apiParams["CHD"] = params.children.toString();
25
+ if (params.teens !== void 0 && params.teens !== null) apiParams["TEEN"] = params.teens.toString();
26
+ if (params.infants !== void 0 && params.infants !== null) apiParams["INF"] = params.infants.toString();
27
+ if (params.includeConnecting !== void 0 && params.includeConnecting !== null) apiParams["IncludeConnectingFlights"] = params.includeConnecting.toString();
28
+ if (params.roundTrip !== void 0 && params.roundTrip !== null) apiParams["RoundTrip"] = params.roundTrip.toString();
29
+ if (params.promoCode) apiParams["promoCode"] = params.promoCode;
30
+ const data = await flights.getAvailable(apiParams);
31
+ return { content: [{
32
+ type: "text",
33
+ text: JSON.stringify(data, null, 2)
34
+ }] };
35
+ } catch (error) {
36
+ const errorMessage = error instanceof Error ? error.message : String(error);
37
+ return {
38
+ isError: true,
39
+ content: [{
40
+ type: "text",
41
+ text: JSON.stringify({ error: errorMessage }, null, 2)
42
+ }]
43
+ };
44
+ }
45
+ }), defineTool("get_available_flight_dates", "get a list of available flight dates between two airports", {
46
+ from: z.string().length(3),
47
+ to: z.string().length(3)
48
+ }, async ({ from, to }) => {
49
+ try {
50
+ const data = await flights.getDates(from, to);
51
+ return { content: [{
52
+ type: "text",
53
+ text: JSON.stringify(data, null, 2)
54
+ }] };
55
+ } catch (error) {
56
+ const errorMessage = error instanceof Error ? error.message : String(error);
57
+ return {
58
+ isError: true,
59
+ content: [{
60
+ type: "text",
61
+ text: JSON.stringify({ error: errorMessage }, null, 2)
62
+ }]
63
+ };
64
+ }
65
+ })];
66
+ //#endregion
67
+ export { FLIGHTS_TOOLS };
@@ -0,0 +1,9 @@
1
+ //#region source/utils/log.d.ts
2
+ /**
3
+ * Logs a message to the stderr to prevent stdout from being polluted
4
+ *
5
+ * @param args - The data to log
6
+ */
7
+ declare const log: (...args: unknown[]) => void;
8
+ //#endregion
9
+ export { log };
@@ -0,0 +1,12 @@
1
+ //#region source/utils/log.ts
2
+ /**
3
+ * Logs a message to the stderr to prevent stdout from being polluted
4
+ *
5
+ * @param args - The data to log
6
+ */
7
+ const log = (...args) => {
8
+ const msg = `[DEBUG ${(/* @__PURE__ */ new Date()).toISOString()}] ${args.join(" ")}\n`;
9
+ process.stderr.write(msg);
10
+ };
11
+ //#endregion
12
+ export { log };
@@ -0,0 +1,16 @@
1
+ import { ToolCallback } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { ZodRawShapeCompat } from "@modelcontextprotocol/sdk/server/zod-compat.js";
3
+
4
+ //#region source/utils/types.d.ts
5
+ type ToolTuple = [string, string, ZodRawShapeCompat, ToolCallback<any>];
6
+ /**
7
+ * Helper to define an MCP tool with proper type inference for the callback parameters.
8
+ *
9
+ * @param name - The tool name
10
+ * @param description - The tool description
11
+ * @param paramsSchema - Zod schema defining the tool parameters
12
+ * @param handler - Async callback that handles the tool invocation
13
+ */
14
+ declare const defineTool: <Args extends ZodRawShapeCompat>(name: string, description: string, paramsSchema: Args, handler: ToolCallback<Args>) => ToolTuple;
15
+ //#endregion
16
+ export { ToolTuple, defineTool };
@@ -0,0 +1,17 @@
1
+ //#region source/utils/types.ts
2
+ /**
3
+ * Helper to define an MCP tool with proper type inference for the callback parameters.
4
+ *
5
+ * @param name - The tool name
6
+ * @param description - The tool description
7
+ * @param paramsSchema - Zod schema defining the tool parameters
8
+ * @param handler - Async callback that handles the tool invocation
9
+ */
10
+ const defineTool = (name, description, paramsSchema, handler) => [
11
+ name,
12
+ description,
13
+ paramsSchema,
14
+ handler
15
+ ];
16
+ //#endregion
17
+ export { defineTool };
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@2bad/ryanair-mcp",
3
+ "version": "8.0.0",
4
+ "description": "Model Context Protocol (MCP) server for Ryanair API with tools for querying flights, fares, airports, and generating booking links",
5
+ "keywords": [
6
+ "mcp",
7
+ "ryanair",
8
+ "flights",
9
+ "booking",
10
+ "travel",
11
+ "airports",
12
+ "fares",
13
+ "ai",
14
+ "api",
15
+ "tools"
16
+ ],
17
+ "homepage": "https://github.com/2BAD/ryanair#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/2BAD/ryanair/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/2BAD/ryanair.git"
24
+ },
25
+ "license": "MIT",
26
+ "author": "2BAD (https://github.com/2BAD)",
27
+ "contributors": [
28
+ {
29
+ "name": "Jason Hyde",
30
+ "email": "github@2bad.me",
31
+ "url": "https://github.com/mrhyde"
32
+ }
33
+ ],
34
+ "type": "module",
35
+ "exports": {
36
+ ".": {
37
+ "import": {
38
+ "types": "./build/index.d.ts",
39
+ "default": "./build/index.js"
40
+ }
41
+ }
42
+ },
43
+ "files": [
44
+ "build"
45
+ ],
46
+ "dependencies": {
47
+ "@modelcontextprotocol/sdk": "1.29.0",
48
+ "zod": "4.4.3",
49
+ "@2bad/ryanair": "8.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@modelcontextprotocol/inspector": "0.21.2"
53
+ },
54
+ "engines": {
55
+ "node": ">=26"
56
+ },
57
+ "scripts": {
58
+ "build": "tsdown",
59
+ "check": "run-p check:**",
60
+ "check:code": "oxlint ./source",
61
+ "check:format": "oxfmt --check ./source",
62
+ "dev": "mcp-inspector tsx source/index.ts",
63
+ "fix": "run-p fix:**",
64
+ "fix:code": "oxlint --fix ./source",
65
+ "fix:format": "oxfmt ./source",
66
+ "preversion": "run-s check test build",
67
+ "test": "exit 0",
68
+ "test:integration": "exit 0",
69
+ "test:unit": "exit 0"
70
+ },
71
+ "bin": {
72
+ "ryanair-mcp": "./build/cli.js"
73
+ }
74
+ }