@pipeworx/mcp-bts-ontime 0.1.0 → 0.2.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/README.md +17 -12
- package/bin/cli.js +55 -11
- package/lib/index.js +333 -0
- package/package.json +17 -16
- package/server.json +1 -1
- package/tools.json +127 -0
- package/src/index.ts +0 -362
- package/src/server.ts +0 -45
- package/src/store.ts +0 -360
- package/tsconfig.json +0 -18
package/src/index.ts
DELETED
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
interface McpToolDefinition {
|
|
2
|
-
name: string;
|
|
3
|
-
description: string;
|
|
4
|
-
/** Human-facing one-liner (fleet #1967). Optional; consumers fall back to
|
|
5
|
-
* description. Kept in step with shared/src/types.ts — scripts/lib/
|
|
6
|
-
* check-inlined-types.mjs reports drift at publish time. */
|
|
7
|
-
summary?: string;
|
|
8
|
-
inputSchema: {
|
|
9
|
-
type: 'object';
|
|
10
|
-
properties: Record<string, unknown>;
|
|
11
|
-
required?: string[];
|
|
12
|
-
anyOf?: Array<{ required: string[] }>;
|
|
13
|
-
oneOf?: Array<{ required: string[] }>;
|
|
14
|
-
allOf?: Array<{ required: string[] }>;
|
|
15
|
-
};
|
|
16
|
-
outputSchema?: Record<string, unknown>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface McpToolExport {
|
|
20
|
-
tools: McpToolDefinition[];
|
|
21
|
-
callTool: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
22
|
-
meter?: { credits: number };
|
|
23
|
-
cost?: Record<string, unknown>;
|
|
24
|
-
provider?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* bts-ontime -- US airline on-time performance and delay causes (fleet #2953).
|
|
29
|
-
*
|
|
30
|
-
* Data: US DOT Bureau of Transportation Statistics (BTS) TranStats,
|
|
31
|
-
* "Reporting Carrier On-Time Performance (1987-present)" monthly bulk CSVs
|
|
32
|
-
* (transtats.bts.gov/PREZIP). US federal government work -- public domain
|
|
33
|
-
* (17 U.S.C. §105). The site publishes bulk files only (no live API), so
|
|
34
|
-
* this pack builds a copy (scripts/bts-ontime/load-data.mjs) into a D1
|
|
35
|
-
* database the gateway hands it as `_d1` (pack-manifest "d1Binding":
|
|
36
|
-
* "BTS_ONTIME_DB"). Raw flight-level rows are NEVER stored -- the loader
|
|
37
|
-
* aggregates each month to two small tables and discards the ~600k-row raw
|
|
38
|
-
* file before moving to the next month. Design note: this file + store.ts.
|
|
39
|
-
*
|
|
40
|
-
* SCOPE: the most recent N months as of the load (see bts_ontime_meta /
|
|
41
|
-
* list_coverage below) -- not the full 1987-present or 2003-present history,
|
|
42
|
-
* because BTS throttles per connection hard enough that a multi-decade
|
|
43
|
-
* backfill is a multi-hour job better run as a scheduled extension than
|
|
44
|
-
* inline in one build. See README.md "Known gaps" / "Refresh".
|
|
45
|
-
*
|
|
46
|
-
* Every response carries `source`, `source_url`, `license` and `data_as_of`
|
|
47
|
-
* (the latest BTS month actually loaded).
|
|
48
|
-
*/
|
|
49
|
-
import {
|
|
50
|
-
carrierMonths,
|
|
51
|
-
clampLimit,
|
|
52
|
-
clampMonths,
|
|
53
|
-
delayCauses,
|
|
54
|
-
delayCausesAtAirport,
|
|
55
|
-
getMeta,
|
|
56
|
-
normAirport,
|
|
57
|
-
requireDb,
|
|
58
|
-
resolveCarrierCode,
|
|
59
|
-
routeMonths,
|
|
60
|
-
SOURCE,
|
|
61
|
-
validAirport,
|
|
62
|
-
validCarrier,
|
|
63
|
-
type D1Like,
|
|
64
|
-
} from './store.js';
|
|
65
|
-
|
|
66
|
-
const tools: McpToolExport['tools'] = [
|
|
67
|
-
{
|
|
68
|
-
name: 'route_ontime',
|
|
69
|
-
description:
|
|
70
|
-
'Monthly on-time performance for one US domestic flight route (origin airport -> destination airport), from BTS TranStats Reporting Carrier On-Time Performance. Returns, per month (and per carrier if more than one serves the route): flights, completed flights, on-time arrivals and on-time %, average arrival delay in minutes, cancellations, diversions, and delay minutes broken down by cause (carrier, weather, NAS/air-traffic-control, security, late aircraft). Pass carrier (2-letter code like "DL", or a common name like "Delta") to scope to one airline; omit it to see every carrier that flew the route. months caps how many of the most recently loaded months to return (default 12). Covers the most recent months loaded (see data_as_of and the earliest/latest fields), not full history. Unknown origin/destination airport codes are refused with a clear error, never an empty success.',
|
|
71
|
-
summary: 'Monthly on-time %, average delay and delay causes for one origin->destination route.',
|
|
72
|
-
inputSchema: {
|
|
73
|
-
type: 'object' as const,
|
|
74
|
-
properties: {
|
|
75
|
-
origin: { type: 'string', description: 'Origin airport code, e.g. "JFK".' },
|
|
76
|
-
dest: { type: 'string', description: 'Destination airport code, e.g. "LAX".' },
|
|
77
|
-
carrier: { type: 'string', description: 'Optional: 2-letter carrier code ("DL") or common name ("Delta") to scope to one airline.' },
|
|
78
|
-
months: { type: 'number', description: 'How many of the most recently loaded months to return, most recent first. Default 12.' },
|
|
79
|
-
},
|
|
80
|
-
required: ['origin', 'dest'],
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
name: 'carrier_ontime',
|
|
85
|
-
description:
|
|
86
|
-
'Monthly on-time performance for one airline, aggregated across all its routes (or just the routes touching one airport), from BTS TranStats Reporting Carrier On-Time Performance. Pass carrier as a 2-letter code ("WN") or common name ("Southwest"). Pass airport to scope to flights where that airport is the origin or destination. Returns the same per-month shape as route_ontime (flights, on-time %, average arrival delay, cancellations, diversions, delay minutes by cause). months caps how many of the most recently loaded months to return (default 12). Unknown carrier codes are refused with a clear error, never an empty success.',
|
|
87
|
-
summary: "Monthly on-time %, average delay and delay causes for one airline, system-wide or at one airport.",
|
|
88
|
-
inputSchema: {
|
|
89
|
-
type: 'object' as const,
|
|
90
|
-
properties: {
|
|
91
|
-
carrier: { type: 'string', description: '2-letter carrier code ("WN") or common name ("Southwest").' },
|
|
92
|
-
airport: { type: 'string', description: 'Optional: scope to flights where this airport is the origin or destination.' },
|
|
93
|
-
months: { type: 'number', description: 'How many of the most recently loaded months to return, most recent first. Default 12.' },
|
|
94
|
-
},
|
|
95
|
-
required: ['carrier'],
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
name: 'bts_airport_delays',
|
|
100
|
-
description:
|
|
101
|
-
'Delay-cause breakdown at one US airport (as the ARRIVAL airport), by carrier, from BTS TranStats on-time data: arriving flights, how many arrived 15+ minutes late, cancellations, diversions, and delay minutes attributed to carrier, weather, NAS (air-traffic-control/system), security, and late-aircraft causes. Pass year and/or month to scope to a specific period; omit both to get every loaded month, most recent first. Rows beyond `limit` are reported via truncated/total_matching rather than silently dropped -- narrow with year/month or page with limit/offset to see the rest. Unknown airport codes are refused with a clear error, never an empty success.',
|
|
102
|
-
summary: 'Delay-cause breakdown by carrier for arrivals at one airport.',
|
|
103
|
-
inputSchema: {
|
|
104
|
-
type: 'object' as const,
|
|
105
|
-
properties: {
|
|
106
|
-
airport: { type: 'string', description: 'Airport code, e.g. "ORD".' },
|
|
107
|
-
year: { type: 'number', description: 'Optional: scope to one calendar year.' },
|
|
108
|
-
month: { type: 'number', description: 'Optional: scope to one month (1-12). Requires year to be meaningful alongside it, but works alone too (matches that month in any loaded year).' },
|
|
109
|
-
limit: { type: 'number', description: 'Max rows to return, 1-200. Default 50. A truncated response carries truncated:true and total_matching.' },
|
|
110
|
-
offset: { type: 'number', description: 'Pagination offset. Default 0.' },
|
|
111
|
-
},
|
|
112
|
-
required: ['airport'],
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
name: 'delay_causes',
|
|
117
|
-
description:
|
|
118
|
-
'Delay-cause rows for a given year, optionally scoped to one carrier and/or one (arrival) airport, from BTS TranStats on-time data. Same fields as bts_airport_delays (arriving flights, 15+ minute-late arrivals, cancellations, diversions, delay minutes by cause) but organized by year first rather than by airport first -- use this to scan a whole year across carriers/airports, or to compare one carrier\'s delay profile across the airports it serves. Rows beyond `limit` are reported via truncated/total_matching rather than silently dropped -- narrow with carrier/airport or page with limit/offset to see the rest. Unknown carrier or airport codes are refused with a clear error, never an empty success.',
|
|
119
|
-
summary: 'Year-scoped delay-cause rows, optionally filtered by carrier and/or airport.',
|
|
120
|
-
inputSchema: {
|
|
121
|
-
type: 'object' as const,
|
|
122
|
-
properties: {
|
|
123
|
-
year: { type: 'number', description: 'Calendar year, e.g. 2026.' },
|
|
124
|
-
carrier: { type: 'string', description: 'Optional: 2-letter carrier code ("AA") or common name ("American").' },
|
|
125
|
-
airport: { type: 'string', description: 'Optional: arrival-airport code, e.g. "DFW".' },
|
|
126
|
-
limit: { type: 'number', description: 'Max rows to return, 1-200. Default 50. A truncated response carries truncated:true and total_matching.' },
|
|
127
|
-
offset: { type: 'number', description: 'Pagination offset. Default 0.' },
|
|
128
|
-
},
|
|
129
|
-
required: ['year'],
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: 'list_coverage',
|
|
134
|
-
description:
|
|
135
|
-
'What this pack actually has loaded right now: the earliest and latest BTS month covered, how many months, and when it was last loaded. Call this before route_ontime/carrier_ontime/bts_airport_delays/delay_causes if you are not sure a given month or year is covered.',
|
|
136
|
-
summary: 'Earliest/latest BTS month loaded, and when.',
|
|
137
|
-
inputSchema: { type: 'object' as const, properties: {} },
|
|
138
|
-
},
|
|
139
|
-
];
|
|
140
|
-
|
|
141
|
-
function notFoundAirport(code: unknown) {
|
|
142
|
-
return {
|
|
143
|
-
found: false,
|
|
144
|
-
reason: 'unknown_airport',
|
|
145
|
-
message: `${JSON.stringify(code)} is not a recognized airport code in this pack's loaded data (it may be a valid IATA code that simply had no flights in the loaded window, or a typo). Call list_coverage to see the loaded date range.`,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
function notFoundCarrier(code: unknown) {
|
|
149
|
-
return {
|
|
150
|
-
found: false,
|
|
151
|
-
reason: 'unknown_carrier',
|
|
152
|
-
message: `${JSON.stringify(code)} is not a recognized carrier code in this pack's loaded data. Use a 2-letter Reporting Carrier code (e.g. "DL", "WN", "AA") or a common airline name.`,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async function routeOntimeTool(db: D1Like, args: Record<string, unknown>) {
|
|
157
|
-
const meta = await getMeta(db);
|
|
158
|
-
const origin = normAirport(args.origin);
|
|
159
|
-
const dest = normAirport(args.dest);
|
|
160
|
-
if (!origin) return { found: false, reason: 'invalid_origin', message: `${JSON.stringify(args.origin)} is not a valid airport code (3-4 letters).`, data_as_of: meta.latest_month };
|
|
161
|
-
if (!dest) return { found: false, reason: 'invalid_dest', message: `${JSON.stringify(args.dest)} is not a valid airport code (3-4 letters).`, data_as_of: meta.latest_month };
|
|
162
|
-
if (!(await validAirport(db, origin))) return { ...notFoundAirport(args.origin), data_as_of: meta.latest_month };
|
|
163
|
-
if (!(await validAirport(db, dest))) return { ...notFoundAirport(args.dest), data_as_of: meta.latest_month };
|
|
164
|
-
|
|
165
|
-
let carrierCode: string | null = null;
|
|
166
|
-
if (args.carrier != null && args.carrier !== '') {
|
|
167
|
-
carrierCode = resolveCarrierCode(args.carrier);
|
|
168
|
-
if (!carrierCode || !(await validCarrier(db, carrierCode))) return { ...notFoundCarrier(args.carrier), data_as_of: meta.latest_month };
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const months = clampMonths(args.months, meta.months_loaded);
|
|
172
|
-
const rows = await routeMonths(db, origin, dest, carrierCode, months);
|
|
173
|
-
if (!rows.length) {
|
|
174
|
-
return {
|
|
175
|
-
found: false,
|
|
176
|
-
reason: 'no_flights',
|
|
177
|
-
origin,
|
|
178
|
-
dest,
|
|
179
|
-
carrier: carrierCode,
|
|
180
|
-
message: `No ${origin}->${dest} flights found in the loaded window (${meta.earliest_month} to ${meta.latest_month})${carrierCode ? ` for carrier ${carrierCode}` : ''}. The airports are valid but this route may not have been flown (or not by that carrier) in that window.`,
|
|
181
|
-
coverage: { earliest_month: meta.earliest_month, latest_month: meta.latest_month },
|
|
182
|
-
...SOURCE,
|
|
183
|
-
data_as_of: meta.latest_month,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
return {
|
|
187
|
-
found: true,
|
|
188
|
-
origin,
|
|
189
|
-
dest,
|
|
190
|
-
carrier: carrierCode,
|
|
191
|
-
returned: rows.length,
|
|
192
|
-
coverage: { earliest_month: meta.earliest_month, latest_month: meta.latest_month },
|
|
193
|
-
months: rows,
|
|
194
|
-
...SOURCE,
|
|
195
|
-
data_as_of: meta.latest_month,
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async function carrierOntimeTool(db: D1Like, args: Record<string, unknown>) {
|
|
200
|
-
const meta = await getMeta(db);
|
|
201
|
-
const carrierCode = resolveCarrierCode(args.carrier);
|
|
202
|
-
if (!carrierCode || !(await validCarrier(db, carrierCode))) return { ...notFoundCarrier(args.carrier), data_as_of: meta.latest_month };
|
|
203
|
-
|
|
204
|
-
let airport: string | null = null;
|
|
205
|
-
if (args.airport != null && args.airport !== '') {
|
|
206
|
-
airport = normAirport(args.airport);
|
|
207
|
-
if (!airport) return { found: false, reason: 'invalid_airport', message: `${JSON.stringify(args.airport)} is not a valid airport code.`, data_as_of: meta.latest_month };
|
|
208
|
-
if (!(await validAirport(db, airport))) return { ...notFoundAirport(args.airport), data_as_of: meta.latest_month };
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const months = clampMonths(args.months, meta.months_loaded);
|
|
212
|
-
const rows = await carrierMonths(db, carrierCode, airport, months);
|
|
213
|
-
if (!rows.length) {
|
|
214
|
-
return {
|
|
215
|
-
found: false,
|
|
216
|
-
reason: 'no_flights',
|
|
217
|
-
carrier: carrierCode,
|
|
218
|
-
airport,
|
|
219
|
-
message: `No flights found for carrier ${carrierCode}${airport ? ` at ${airport}` : ''} in the loaded window (${meta.earliest_month} to ${meta.latest_month}).`,
|
|
220
|
-
coverage: { earliest_month: meta.earliest_month, latest_month: meta.latest_month },
|
|
221
|
-
...SOURCE,
|
|
222
|
-
data_as_of: meta.latest_month,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
return {
|
|
226
|
-
found: true,
|
|
227
|
-
carrier: carrierCode,
|
|
228
|
-
airport,
|
|
229
|
-
returned: rows.length,
|
|
230
|
-
coverage: { earliest_month: meta.earliest_month, latest_month: meta.latest_month },
|
|
231
|
-
months: rows,
|
|
232
|
-
...SOURCE,
|
|
233
|
-
data_as_of: meta.latest_month,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
async function airportDelaysTool(db: D1Like, args: Record<string, unknown>) {
|
|
238
|
-
const meta = await getMeta(db);
|
|
239
|
-
const airport = normAirport(args.airport);
|
|
240
|
-
if (!airport) return { found: false, reason: 'invalid_airport', message: `${JSON.stringify(args.airport)} is not a valid airport code.`, data_as_of: meta.latest_month };
|
|
241
|
-
if (!(await validAirport(db, airport))) return { ...notFoundAirport(args.airport), data_as_of: meta.latest_month };
|
|
242
|
-
|
|
243
|
-
const year = args.year != null && args.year !== '' ? Math.floor(Number(args.year)) : null;
|
|
244
|
-
if (args.year != null && args.year !== '' && !Number.isFinite(year)) throw new Error('year must be a valid number');
|
|
245
|
-
const month = args.month != null && args.month !== '' ? Math.floor(Number(args.month)) : null;
|
|
246
|
-
if (args.month != null && args.month !== '' && (!Number.isFinite(month) || (month as number) < 1 || (month as number) > 12)) {
|
|
247
|
-
return { found: false, reason: 'invalid_month', message: `month must be 1-12 (got ${JSON.stringify(args.month)}).`, data_as_of: meta.latest_month };
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const limit = clampLimit(args.limit);
|
|
251
|
-
const offset = Math.max(0, Math.floor(Number(args.offset) || 0));
|
|
252
|
-
const { rows, total_matching, truncated } = await delayCausesAtAirport(db, airport, year, month, limit, offset);
|
|
253
|
-
if (!rows.length) {
|
|
254
|
-
return {
|
|
255
|
-
found: false,
|
|
256
|
-
reason: 'no_data',
|
|
257
|
-
airport,
|
|
258
|
-
year,
|
|
259
|
-
month,
|
|
260
|
-
message: `No delay-cause rows for ${airport}${year ? ` in ${year}` : ''}${month ? ` month ${month}` : ''} in the loaded window (${meta.earliest_month} to ${meta.latest_month}).`,
|
|
261
|
-
coverage: { earliest_month: meta.earliest_month, latest_month: meta.latest_month },
|
|
262
|
-
...SOURCE,
|
|
263
|
-
data_as_of: meta.latest_month,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
return {
|
|
267
|
-
found: true,
|
|
268
|
-
airport,
|
|
269
|
-
year,
|
|
270
|
-
month,
|
|
271
|
-
returned: rows.length,
|
|
272
|
-
total_matching,
|
|
273
|
-
truncated,
|
|
274
|
-
...(truncated ? { hint: 'More rows exist than were returned. Narrow with year/month, or page with limit/offset.' } : {}),
|
|
275
|
-
coverage: { earliest_month: meta.earliest_month, latest_month: meta.latest_month },
|
|
276
|
-
rows,
|
|
277
|
-
...SOURCE,
|
|
278
|
-
data_as_of: meta.latest_month,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
async function delayCausesTool(db: D1Like, args: Record<string, unknown>) {
|
|
283
|
-
const meta = await getMeta(db);
|
|
284
|
-
const year = Math.floor(Number(args.year));
|
|
285
|
-
if (!Number.isFinite(year)) throw new Error('year must be a valid number');
|
|
286
|
-
|
|
287
|
-
let carrierCode: string | null = null;
|
|
288
|
-
if (args.carrier != null && args.carrier !== '') {
|
|
289
|
-
carrierCode = resolveCarrierCode(args.carrier);
|
|
290
|
-
if (!carrierCode || !(await validCarrier(db, carrierCode))) return { ...notFoundCarrier(args.carrier), data_as_of: meta.latest_month };
|
|
291
|
-
}
|
|
292
|
-
let airport: string | null = null;
|
|
293
|
-
if (args.airport != null && args.airport !== '') {
|
|
294
|
-
airport = normAirport(args.airport);
|
|
295
|
-
if (!airport) return { found: false, reason: 'invalid_airport', message: `${JSON.stringify(args.airport)} is not a valid airport code.`, data_as_of: meta.latest_month };
|
|
296
|
-
if (!(await validAirport(db, airport))) return { ...notFoundAirport(args.airport), data_as_of: meta.latest_month };
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const limit = clampLimit(args.limit);
|
|
300
|
-
const offset = Math.max(0, Math.floor(Number(args.offset) || 0));
|
|
301
|
-
const { rows, total_matching, truncated } = await delayCauses(db, carrierCode, airport, year, limit, offset);
|
|
302
|
-
if (!rows.length) {
|
|
303
|
-
return {
|
|
304
|
-
found: false,
|
|
305
|
-
reason: 'no_data',
|
|
306
|
-
year,
|
|
307
|
-
carrier: carrierCode,
|
|
308
|
-
airport,
|
|
309
|
-
message: `No delay-cause rows for ${year}${carrierCode ? ` carrier ${carrierCode}` : ''}${airport ? ` airport ${airport}` : ''} in the loaded window (${meta.earliest_month} to ${meta.latest_month}).`,
|
|
310
|
-
coverage: { earliest_month: meta.earliest_month, latest_month: meta.latest_month },
|
|
311
|
-
...SOURCE,
|
|
312
|
-
data_as_of: meta.latest_month,
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
return {
|
|
316
|
-
found: true,
|
|
317
|
-
year,
|
|
318
|
-
carrier: carrierCode,
|
|
319
|
-
airport,
|
|
320
|
-
returned: rows.length,
|
|
321
|
-
total_matching,
|
|
322
|
-
truncated,
|
|
323
|
-
...(truncated ? { hint: 'More rows exist than were returned. Narrow with carrier/airport, or page with limit/offset.' } : {}),
|
|
324
|
-
coverage: { earliest_month: meta.earliest_month, latest_month: meta.latest_month },
|
|
325
|
-
rows,
|
|
326
|
-
...SOURCE,
|
|
327
|
-
data_as_of: meta.latest_month,
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
async function listCoverageTool(db: D1Like) {
|
|
332
|
-
const meta = await getMeta(db);
|
|
333
|
-
return {
|
|
334
|
-
earliest_month: meta.earliest_month,
|
|
335
|
-
latest_month: meta.latest_month,
|
|
336
|
-
months_loaded: meta.months_loaded,
|
|
337
|
-
loaded_at: meta.loaded_at,
|
|
338
|
-
note: 'Scoped to the most recent months as of the load, not full BTS history (1987-present). Re-run the loader with a larger --months to extend further back.',
|
|
339
|
-
...SOURCE,
|
|
340
|
-
data_as_of: meta.latest_month,
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
async function callTool(name: string, args: Record<string, unknown>): Promise<unknown> {
|
|
345
|
-
const bound = requireDb(args._d1);
|
|
346
|
-
switch (name) {
|
|
347
|
-
case 'route_ontime':
|
|
348
|
-
return routeOntimeTool(bound, args);
|
|
349
|
-
case 'carrier_ontime':
|
|
350
|
-
return carrierOntimeTool(bound, args);
|
|
351
|
-
case 'bts_airport_delays':
|
|
352
|
-
return airportDelaysTool(bound, args);
|
|
353
|
-
case 'delay_causes':
|
|
354
|
-
return delayCausesTool(bound, args);
|
|
355
|
-
case 'list_coverage':
|
|
356
|
-
return listCoverageTool(bound);
|
|
357
|
-
default:
|
|
358
|
-
throw new Error(`Unknown tool: ${name}`);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
export default { tools, callTool, meter: { credits: 1 } } satisfies McpToolExport;
|
package/src/server.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stdio MCP server entry point for @pipeworx/mcp-bts-ontime.
|
|
3
|
-
* Generated by scripts/publish-pack.sh — do not hand-edit in the pack repo;
|
|
4
|
-
* edit scripts/publish-pack.sh (the server.ts heredoc) and republish instead.
|
|
5
|
-
*/
|
|
6
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
7
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
8
|
-
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
-
import pack from './index.js';
|
|
10
|
-
|
|
11
|
-
const server = new Server(
|
|
12
|
-
{ name: '@pipeworx/mcp-bts-ontime', version: '0.1.0' },
|
|
13
|
-
{ capabilities: { tools: {} } },
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
17
|
-
tools: pack.tools.map((t) => ({
|
|
18
|
-
name: t.name,
|
|
19
|
-
description: t.description,
|
|
20
|
-
inputSchema: t.inputSchema,
|
|
21
|
-
})),
|
|
22
|
-
}));
|
|
23
|
-
|
|
24
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
25
|
-
const { name, arguments: args } = request.params;
|
|
26
|
-
try {
|
|
27
|
-
const result = await pack.callTool(name, (args ?? {}) as Record<string, unknown>);
|
|
28
|
-
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
29
|
-
} catch (err) {
|
|
30
|
-
return {
|
|
31
|
-
content: [{ type: 'text', text: err instanceof Error ? err.message : String(err) }],
|
|
32
|
-
isError: true,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
async function main() {
|
|
38
|
-
const transport = new StdioServerTransport();
|
|
39
|
-
await server.connect(transport);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
main().catch((err) => {
|
|
43
|
-
console.error('Fatal error running server:', err);
|
|
44
|
-
process.exit(1);
|
|
45
|
-
});
|