@reneturcios/flightdata 0.0.0-stage → 0.1.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 +21 -0
- package/README.md +151 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +78 -0
- package/dist/cli.js.map +1 -0
- package/dist/forward.d.ts +84 -0
- package/dist/forward.js +409 -0
- package/dist/forward.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +35 -0
- package/dist/mcp.js +60 -0
- package/dist/mcp.js.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +1 -6
- package/server.json +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rene Turcios
|
|
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
CHANGED
|
@@ -1,3 +1,152 @@
|
|
|
1
|
-
#
|
|
1
|
+
# flightdata
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
flightdata is a small local bridge to the hosted
|
|
4
|
+
HasData Google Flights MCP server, which returns
|
|
5
|
+
Google Flights search results as JSON. Give it a
|
|
6
|
+
departure, a destination and an outbound date, and
|
|
7
|
+
it fetches matching itineraries: each option's
|
|
8
|
+
price, total duration and stops, its flight legs
|
|
9
|
+
with airline, flight number, aircraft, airports
|
|
10
|
+
and times, and its CO2 emissions, plus the booking
|
|
11
|
+
and departure tokens the upstream issues for
|
|
12
|
+
following up on a chosen itinerary.
|
|
13
|
+
|
|
14
|
+
Searches cover one-way, round-trip and multi-city
|
|
15
|
+
trips. They can be shaped by passenger mix (adults,
|
|
16
|
+
children, infants in a seat or on a lap), travel
|
|
17
|
+
class, carry-on bags, a maximum price, sort order
|
|
18
|
+
(price, duration, emissions, departure or arrival
|
|
19
|
+
time), stop limits, included or excluded airlines
|
|
20
|
+
and connections, departure and return time windows,
|
|
21
|
+
layover duration bounds, a maximum total duration,
|
|
22
|
+
an emissions preference and a deep-search mode.
|
|
23
|
+
|
|
24
|
+
The bridge stores no fares of its own. It serves
|
|
25
|
+
the upstream server's tool list locally, exactly as
|
|
26
|
+
captured from the live endpoint, and forwards each
|
|
27
|
+
tool call upstream, returning the result untouched.
|
|
28
|
+
The captured surface is a single read-only fare
|
|
29
|
+
search: there is no booking, reservation, ticketing
|
|
30
|
+
or payment tool in it.
|
|
31
|
+
|
|
32
|
+
## Tools
|
|
33
|
+
|
|
34
|
+
- `hasdata_google_travel_flights_getGoogleFlights`
|
|
35
|
+
— search Google Flights. Required: `departureId`
|
|
36
|
+
(IATA code or location kgmid; comma-separated
|
|
37
|
+
multiples allowed), `arrivalId` (same formats),
|
|
38
|
+
and `outboundDate` (`yyyy-MM-dd`). Optional:
|
|
39
|
+
`returnDate`, `type` (`roundTrip` / `oneWay` /
|
|
40
|
+
`multiCity`), `multiCityJson`, `gl`, `hl`,
|
|
41
|
+
`currency`, `travelClass` (`economy` /
|
|
42
|
+
`premiumEconomy` / `business` / `first`),
|
|
43
|
+
`showHidden`, `adults`, `children`,
|
|
44
|
+
`infantsInSeat`, `infantsOnLap`, `sortBy`
|
|
45
|
+
(`topFlights` / `price` / `departureTime` /
|
|
46
|
+
`arrivalTime` / `duration` / `emissions`),
|
|
47
|
+
`stops` (`nonStop` / `oneStopOrFewer` /
|
|
48
|
+
`twoStopsOrFewer`), `excludeAirlines`,
|
|
49
|
+
`includeAirlines`, `bags`, `maxPrice`,
|
|
50
|
+
`outboundTimes`, `returnTimes`, `lessEmissions`,
|
|
51
|
+
`layoverDuration`, `includeConnections`,
|
|
52
|
+
`excludeConnections`, `maxDuration`, `deepSearch`,
|
|
53
|
+
`departureToken` and `bookingToken`. Returns
|
|
54
|
+
per-itinerary price, duration, stops and legs,
|
|
55
|
+
emissions, and booking/departure tokens.
|
|
56
|
+
|
|
57
|
+
## Configuration
|
|
58
|
+
|
|
59
|
+
- `HASDATA_GOOGLE_FLIGHTS_MCP_URL` (optional) —
|
|
60
|
+
override the upstream endpoint. Defaults to
|
|
61
|
+
`https://mcp.hasdata.com/mcp?apis=google_travel_flights`.
|
|
62
|
+
(The override hook is this rebuild's own labelled
|
|
63
|
+
reconstruction.)
|
|
64
|
+
- `HASDATA_API_KEY` (optional) — when set, every
|
|
65
|
+
upstream request carries an `x-api-key: <key>`
|
|
66
|
+
header, for the caller's own HasData API key. When
|
|
67
|
+
it is not set, no key header is sent. (The header
|
|
68
|
+
name and the env name are pinned by the original's
|
|
69
|
+
registry record; forwarding the key from this env
|
|
70
|
+
var is a labelled reconstruction — the original
|
|
71
|
+
surface was captured keyless.)
|
|
72
|
+
|
|
73
|
+
### Forwarding mechanics
|
|
74
|
+
|
|
75
|
+
On the first tool call the client opens a streamable
|
|
76
|
+
HTTP session with the upstream: a JSON-RPC
|
|
77
|
+
`initialize` request (protocolVersion `2025-03-26`,
|
|
78
|
+
clientInfo name `flightdata`), then a
|
|
79
|
+
`notifications/initialized` notification, then the
|
|
80
|
+
`tools/call` request carrying the caller's arguments
|
|
81
|
+
unchanged. When the upstream answers `initialize`
|
|
82
|
+
with an `Mcp-Session-Id` header, that value rides on
|
|
83
|
+
every later request of the session, which is reused
|
|
84
|
+
for the life of the process. Replies may arrive as
|
|
85
|
+
plain JSON or as server-sent events; both are read.
|
|
86
|
+
|
|
87
|
+
Successful upstream results pass through verbatim,
|
|
88
|
+
including any `isError` flag the upstream sets.
|
|
89
|
+
Failures — a JSON-RPC error, a non-2xx status, an
|
|
90
|
+
unreadable response, or a request that cannot be
|
|
91
|
+
completed — come back as an `isError` result whose
|
|
92
|
+
text starts with `flightdata error:` (this rendering
|
|
93
|
+
is this rebuild's own labelled reconstruction).
|
|
94
|
+
|
|
95
|
+
## CLI
|
|
96
|
+
|
|
97
|
+
The tool is also a subcommand taking one JSON
|
|
98
|
+
argument string:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npx @reneturcios/flightdata hasdata_google_travel_flights_getGoogleFlights '{"departureId":"SFO","arrivalId":"LHR","outboundDate":"2026-12-01","type":"oneWay","travelClass":"economy","stops":"nonStop"}'
|
|
102
|
+
npx @reneturcios/flightdata --version
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Exit codes: `0` on success, `1` on an `isError`
|
|
106
|
+
result, `2` on a usage error.
|
|
107
|
+
|
|
108
|
+
## MCP server
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npx -y @reneturcios/flightdata mcp
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
MCP client config:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"mcpServers": {
|
|
119
|
+
"flightdata": {
|
|
120
|
+
"command": "npx",
|
|
121
|
+
"args": ["-y", "@reneturcios/flightdata", "mcp"]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Docker
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
docker run -i ghcr.io/cloudcorprecords/flightdata
|
|
131
|
+
docker run --rm ghcr.io/cloudcorprecords/flightdata --version
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The container's default command is `mcp`, so the first
|
|
135
|
+
form is a stdio MCP server; any other arguments reach
|
|
136
|
+
the CLI normally.
|
|
137
|
+
|
|
138
|
+
## Development
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm install
|
|
142
|
+
npm run build
|
|
143
|
+
npm test
|
|
144
|
+
npm run dev
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The test suite runs entirely against a stubbed
|
|
148
|
+
JSON-RPC upstream — no live network calls.
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
MIT — see `LICENSE`.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* flightdata CLI.
|
|
4
|
+
*
|
|
5
|
+
* flightdata <tool> '<json-args>'
|
|
6
|
+
* flightdata mcp
|
|
7
|
+
* flightdata --version
|
|
8
|
+
*
|
|
9
|
+
* <tool> is the 1 forwarded tool. Each tool subcommand
|
|
10
|
+
* takes one JSON argument string with the tool's
|
|
11
|
+
* arguments, forwards the call like the MCP path, and
|
|
12
|
+
* prints the forwarded result content. Exit codes:
|
|
13
|
+
* 0 success, 1 on an isError result, 2 usage error.
|
|
14
|
+
*/
|
|
15
|
+
import { callTool, TOOL_NAMES, VERSION } from "./forward.js";
|
|
16
|
+
function usage() {
|
|
17
|
+
console.error(`Usage:
|
|
18
|
+
flightdata <tool> '<json-args>' one of: ${TOOL_NAMES.join(", ")}
|
|
19
|
+
flightdata mcp
|
|
20
|
+
flightdata --version`);
|
|
21
|
+
process.exit(2);
|
|
22
|
+
}
|
|
23
|
+
function firstText(result) {
|
|
24
|
+
const content = result.content;
|
|
25
|
+
if (Array.isArray(content)) {
|
|
26
|
+
for (const item of content) {
|
|
27
|
+
if (item !== null &&
|
|
28
|
+
typeof item === "object" &&
|
|
29
|
+
item.type === "text" &&
|
|
30
|
+
typeof item.text === "string") {
|
|
31
|
+
return item.text;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return typeof content === "string" ? content : JSON.stringify(content);
|
|
36
|
+
}
|
|
37
|
+
async function main() {
|
|
38
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
39
|
+
if (cmd === "--version" || cmd === "-v") {
|
|
40
|
+
console.log(VERSION);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (cmd === "mcp") {
|
|
44
|
+
if (rest.length !== 0)
|
|
45
|
+
usage();
|
|
46
|
+
const { startMcpServer } = await import("./mcp.js");
|
|
47
|
+
await startMcpServer();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!TOOL_NAMES.includes(cmd ?? ""))
|
|
51
|
+
usage();
|
|
52
|
+
if (rest.length > 1)
|
|
53
|
+
usage();
|
|
54
|
+
let args = {};
|
|
55
|
+
if (rest.length === 1) {
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(rest[0]);
|
|
58
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
59
|
+
usage();
|
|
60
|
+
}
|
|
61
|
+
args = parsed;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
console.error("error: argument must be a JSON object string");
|
|
65
|
+
process.exit(2);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const result = await callTool(cmd, args);
|
|
69
|
+
if (result.isError) {
|
|
70
|
+
console.error(`error: ${firstText(result)}`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
console.log(typeof result.content === "string"
|
|
74
|
+
? result.content
|
|
75
|
+
: JSON.stringify(result.content, null, 2));
|
|
76
|
+
}
|
|
77
|
+
void main();
|
|
78
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flightdata core: a forwarding client for the hosted
|
|
3
|
+
* HasData Google Flights MCP server.
|
|
4
|
+
*
|
|
5
|
+
* No flight search is run locally. tools/list is answered from
|
|
6
|
+
* the literal tool definition below, taken verbatim from
|
|
7
|
+
* a live capture of the upstream server (name, title,
|
|
8
|
+
* description and inputSchema exactly as captured,
|
|
9
|
+
* including the title key the tool carries). A tools/call
|
|
10
|
+
* is forwarded over a streamable-HTTP JSON-RPC session:
|
|
11
|
+
* an initialize POST, a notifications/initialized POST,
|
|
12
|
+
* then the tools/call POST, honouring the Mcp-Session-Id
|
|
13
|
+
* response header when the upstream issues one. The
|
|
14
|
+
* session is established lazily on the first forwarded
|
|
15
|
+
* call and reused for the lifetime of the client.
|
|
16
|
+
*
|
|
17
|
+
* The upstream endpoint is pinned to
|
|
18
|
+
* https://mcp.hasdata.com/mcp?apis=google_travel_flights — the query
|
|
19
|
+
* string is part of the pinned URL — and can be
|
|
20
|
+
* overridden with the HASDATA_GOOGLE_FLIGHTS_MCP_URL environment
|
|
21
|
+
* variable (that override is a labelled reconstruction).
|
|
22
|
+
* When HASDATA_API_KEY is set in the environment, every
|
|
23
|
+
* upstream request carries an `x-api-key: <key>` header
|
|
24
|
+
* (the header name is pinned by the registry record's
|
|
25
|
+
* remote declaration; forwarding the key from this env
|
|
26
|
+
* var is a labelled reconstruction — the capture itself
|
|
27
|
+
* was taken keyless). When the variable is unset, no key
|
|
28
|
+
* header is sent, and no Authorization header is sent in
|
|
29
|
+
* either case.
|
|
30
|
+
*
|
|
31
|
+
* Upstream results pass through verbatim, including any
|
|
32
|
+
* isError flag and any extra result fields. Failures — a
|
|
33
|
+
* JSON-RPC error from the upstream, a non-2xx status, an
|
|
34
|
+
* unparseable response, or a fetch that throws or times
|
|
35
|
+
* out — surface as an isError result whose text starts
|
|
36
|
+
* with `flightdata error:` (that rendering is a labelled
|
|
37
|
+
* reconstruction). Responses may be plain JSON or SSE
|
|
38
|
+
* (data: lines); the JSON-RPC message with the matching
|
|
39
|
+
* id wins.
|
|
40
|
+
*/
|
|
41
|
+
import type { ForwardDeps, ToolArgs, ToolDef, ToolResult } from "./types.js";
|
|
42
|
+
export declare const VERSION = "0.1.0";
|
|
43
|
+
export declare const DEFAULT_ENDPOINT_URL = "https://mcp.hasdata.com/mcp?apis=google_travel_flights";
|
|
44
|
+
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
45
|
+
export declare const PROTOCOL_VERSION = "2025-03-26";
|
|
46
|
+
export declare const TOOL_DEFS: ToolDef[];
|
|
47
|
+
export declare const TOOL_NAMES: string[];
|
|
48
|
+
/** Whether `name` is one of the captured tools. */
|
|
49
|
+
export declare function isKnownTool(name: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Parse a JSON-RPC response body, tolerating SSE framing.
|
|
52
|
+
* Returns the message whose id matches `expectedId` when
|
|
53
|
+
* one is present, else the last parseable message, else
|
|
54
|
+
* null when nothing parses.
|
|
55
|
+
*/
|
|
56
|
+
export declare function parseRpcBody(text: string, expectedId?: number): Record<string, unknown> | null;
|
|
57
|
+
/**
|
|
58
|
+
* A forwarding client holding one upstream session. The
|
|
59
|
+
* session is established lazily on the first forwarded
|
|
60
|
+
* call and reused for the lifetime of the client (the
|
|
61
|
+
* process lifetime when the client is the MCP server's
|
|
62
|
+
* or a one-shot client for the CLI).
|
|
63
|
+
*/
|
|
64
|
+
export declare class FlightdataClient {
|
|
65
|
+
private readonly deps;
|
|
66
|
+
private sessionId;
|
|
67
|
+
private ready;
|
|
68
|
+
private sessionPromise;
|
|
69
|
+
private idCounter;
|
|
70
|
+
constructor(deps?: ForwardDeps);
|
|
71
|
+
private fetchFn;
|
|
72
|
+
private endpointUrl;
|
|
73
|
+
private apiKey;
|
|
74
|
+
private timeoutMs;
|
|
75
|
+
private nextId;
|
|
76
|
+
private post;
|
|
77
|
+
private ensureSession;
|
|
78
|
+
/** Forward one tool call; upstream failures come back as isError results. */
|
|
79
|
+
callTool(name: string, args: ToolArgs): Promise<ToolResult>;
|
|
80
|
+
}
|
|
81
|
+
/** Create a forwarding client; tests inject a fake fetch and env through deps. */
|
|
82
|
+
export declare function createClient(deps?: ForwardDeps): FlightdataClient;
|
|
83
|
+
/** One-shot helper: a fresh client per call (the CLI path). */
|
|
84
|
+
export declare function callTool(name: string, args: ToolArgs, deps?: ForwardDeps): Promise<ToolResult>;
|
package/dist/forward.js
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
export const VERSION = "0.1.0";
|
|
2
|
+
export const DEFAULT_ENDPOINT_URL = "https://mcp.hasdata.com/mcp?apis=google_travel_flights";
|
|
3
|
+
export const DEFAULT_TIMEOUT_MS = 30000;
|
|
4
|
+
export const PROTOCOL_VERSION = "2025-03-26";
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Tool definitions (tools/list literals, verbatim from the live */
|
|
7
|
+
/* capture in harness/fixtures/hasdata-google-flights-tools-original.json) */
|
|
8
|
+
/* ------------------------------------------------------------------ */
|
|
9
|
+
export const TOOL_DEFS = [
|
|
10
|
+
{
|
|
11
|
+
"name": "hasdata_google_travel_flights_getGoogleFlights",
|
|
12
|
+
"title": "google_travel_flights: GET /",
|
|
13
|
+
"description": "Get Google Flights Results\n\nSearches Google Flights for one-way, round-trip, or multi-city itineraries with passenger mix (adults, children, infants in-seat/on-lap), travel class, bags, max price, sort order (price, duration, emissions, departure/arrival time), stops, include/exclude airlines and connections, time windows, layover duration, and deep-search mode. Returns per-itinerary price, total duration, stops, flight legs with airline, flight number, aircraft, departure/arrival airports and times, CO2 emissions, plus booking and departure tokens for round-trip returns or booking options. Use for travel-planning agents, fare monitoring, corporate travel dashboards, emission-aware trip optimization, and comparing routes and airlines across markets.",
|
|
14
|
+
"inputSchema": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"properties": {
|
|
17
|
+
"departureId": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Specifies the departure airport code (IATA) or location kgmid.\n\n - **IATA Code**: A 3-letter uppercase code (e.g., SFO for San Francisco, LHR for London Heathrow). Search on [IATA](https://www.iata.org/en/publications/directories/code-search).\n - **Location kgmid**: A string starting with `/m/`, found in Wikidata under \"Freebase ID\" (e.g., `/m/02_286` for New York, NY).\n\nMultiple values can be separated by commas (e.g., `JFK,LGA,/m/0hptm`).\n"
|
|
20
|
+
},
|
|
21
|
+
"arrivalId": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Specifies the arrival airport code (IATA) or location kgmid.\n\n - **IATA Code**: A 3-letter uppercase code (e.g., `SFO` for San Francisco, `LHR` for London Heathrow). Search on [IATA](https://www.iata.org/en/publications/directories/code-search).\n - **Location kgmid**: A string starting with `/m/`, found in Wikidata under \"Freebase ID\" (e.g., `/m/02_286` for New York, NY).\n\nMultiple values can be separated by commas (e.g., `JFK,LGA,/m/0hptm`).\n"
|
|
24
|
+
},
|
|
25
|
+
"outboundDate": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "The outbound travel date in 'yyyy-MM-dd' format.\n"
|
|
28
|
+
},
|
|
29
|
+
"returnDate": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "The return travel date in 'yyyy-MM-dd' format. Required when **type** is `roundTrip`.\n"
|
|
32
|
+
},
|
|
33
|
+
"type": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"enum": [
|
|
36
|
+
"roundTrip",
|
|
37
|
+
"oneWay",
|
|
38
|
+
"multiCity"
|
|
39
|
+
],
|
|
40
|
+
"description": "Specifies the type of flight. Options:\n\n - `roundTrip` (default)\n - `oneWay`\n - `multiCity` (requires `multiCityJson` for flight details)\n\nFor round trips, retrieve return flight details with a separate request using `departureToken`.\n"
|
|
41
|
+
},
|
|
42
|
+
"multiCityJson": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"description": "This parameter specifies flight details for multi-city trips. It is a JSON string containing multiple flight objects. Each object must include the following fields:\n\n- **departureId** – The departure airport code or location KGMID. Uses the same format as the main `departureId` parameter.\n- **arrivalId** – The arrival airport code or location KGMID. Uses the same format as the main `arrivalId` parameter.\n- **date** – The flight date. Uses the same format as the `outboundDate` parameter.\n- **times** *(optional)* – The time range for the flight. Uses the same format as the `outboundTimes` parameter.\n"
|
|
45
|
+
},
|
|
46
|
+
"gl": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"description": "The two-letter country code for the country you want to limit the search to. Provide one exact documented value (245 allowed), e.g. `ac`, `af`."
|
|
49
|
+
},
|
|
50
|
+
"hl": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"description": "The two-letter language code for the language you want to use for the search. Provide one exact documented value (159 allowed), e.g. `af`, `ak`."
|
|
53
|
+
},
|
|
54
|
+
"currency": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"description": "Parameter defines the currency of the returned prices Provide one exact documented value (71 allowed), e.g. `ALL`, `DZD`."
|
|
57
|
+
},
|
|
58
|
+
"travelClass": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"enum": [
|
|
61
|
+
"economy",
|
|
62
|
+
"premiumEconomy",
|
|
63
|
+
"business",
|
|
64
|
+
"first"
|
|
65
|
+
],
|
|
66
|
+
"description": "The travel class for the flight (Economy, Premium Economy, Business, or First).\n"
|
|
67
|
+
},
|
|
68
|
+
"showHidden": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"description": "Indicates whether to include hidden options in the results.\n"
|
|
71
|
+
},
|
|
72
|
+
"adults": {
|
|
73
|
+
"type": "number",
|
|
74
|
+
"description": "Number of adult passengers (>= 1 if specified).\n"
|
|
75
|
+
},
|
|
76
|
+
"children": {
|
|
77
|
+
"type": "number",
|
|
78
|
+
"description": "Number of child passengers.\n"
|
|
79
|
+
},
|
|
80
|
+
"infantsInSeat": {
|
|
81
|
+
"type": "number",
|
|
82
|
+
"description": "Number of infants occupying seats.\n"
|
|
83
|
+
},
|
|
84
|
+
"infantsOnLap": {
|
|
85
|
+
"type": "number",
|
|
86
|
+
"description": "Number of infants sitting on an adult's lap.\n"
|
|
87
|
+
},
|
|
88
|
+
"sortBy": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"enum": [
|
|
91
|
+
"topFlights",
|
|
92
|
+
"price",
|
|
93
|
+
"departureTime",
|
|
94
|
+
"arrivalTime",
|
|
95
|
+
"duration",
|
|
96
|
+
"emissions"
|
|
97
|
+
],
|
|
98
|
+
"description": "Sort the flight results based on price, departure time, arrival time, etc.\n"
|
|
99
|
+
},
|
|
100
|
+
"stops": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"enum": [
|
|
103
|
+
"nonStop",
|
|
104
|
+
"oneStopOrFewer",
|
|
105
|
+
"twoStopsOrFewer"
|
|
106
|
+
],
|
|
107
|
+
"description": "Restrict the number of stops (layovers) in the flight itinerary.\n"
|
|
108
|
+
},
|
|
109
|
+
"excludeAirlines": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"description": "A comma separated list of airline codes to exclude from results. You can search for airline codes on [IATA](https://www.iata.org/en/publications/directories/code-search). For example, `UA` is United Airlines.\n"
|
|
112
|
+
},
|
|
113
|
+
"includeAirlines": {
|
|
114
|
+
"type": "string",
|
|
115
|
+
"description": "A comma separated list of airline codes to exclusively include in results. You can search for airline codes on [IATA](https://www.iata.org/en/publications/directories/code-search). For example, `UA` is United Airlines.\n\n`excludeAirlines` and `includeAirlines` parameters can't be used together.\n"
|
|
116
|
+
},
|
|
117
|
+
"bags": {
|
|
118
|
+
"type": "number",
|
|
119
|
+
"description": "Number of carry-on bags per passenger.\n"
|
|
120
|
+
},
|
|
121
|
+
"maxPrice": {
|
|
122
|
+
"type": "number",
|
|
123
|
+
"description": "Maximum price limit for the flight search, in the selected currency.\n"
|
|
124
|
+
},
|
|
125
|
+
"outboundTimes": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"description": "Set up to 4 time boundaries (2 for departure, 2 for arrival) to filter flights. Each number represents the start of an hour.\n\nExamples:\n - `6,20` → 6:00 AM - 9:00 PM departure\n - `1,15` → 1:00 AM - 4:00 PM departure\n - `7,18,2,21` → 7:00 AM - 9:00 PM departure, 2:00 AM - 10:00 PM arrival\n"
|
|
128
|
+
},
|
|
129
|
+
"returnTimes": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"description": "Set up to 4 time boundaries (2 for departure, 2 for arrival) to filter return flights. Each number represents the start of an hour.\n\nExamples:\n - `6,20` → 6:00 AM - 9:00 PM departure\n - `1,15` → 1:00 AM - 4:00 PM departure\n - `7,18,2,21` → 7:00 AM - 9:00 PM departure, 2:00 AM - 10:00 PM arrival\n"
|
|
132
|
+
},
|
|
133
|
+
"lessEmissions": {
|
|
134
|
+
"type": "boolean",
|
|
135
|
+
"description": "Prefer flight options with lower carbon emissions.\n"
|
|
136
|
+
},
|
|
137
|
+
"layoverDuration": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"description": "Set the maximum layover duration in minutes to filter flights. For example, `120, 360` filters layovers between 2 hours and 6 hours, while `45, 180` allows layovers from 45 minutes to 3 hours.\n"
|
|
140
|
+
},
|
|
141
|
+
"includeConnections": {
|
|
142
|
+
"type": "string",
|
|
143
|
+
"description": "A comma separated list of specific airports to allow as connections.\n"
|
|
144
|
+
},
|
|
145
|
+
"excludeConnections": {
|
|
146
|
+
"type": "string",
|
|
147
|
+
"description": "A comma separated list of specific airports to exclude as connections.\n"
|
|
148
|
+
},
|
|
149
|
+
"maxDuration": {
|
|
150
|
+
"type": "number",
|
|
151
|
+
"description": "The maximum total flight duration in minutes.\n"
|
|
152
|
+
},
|
|
153
|
+
"deepSearch": {
|
|
154
|
+
"type": "boolean",
|
|
155
|
+
"description": "Enable deep search. Returns the same results as Google Flights in a browser, but takes longer to respond. Default is `false`.\n"
|
|
156
|
+
},
|
|
157
|
+
"departureToken": {
|
|
158
|
+
"type": "string",
|
|
159
|
+
"description": "Used to select a flight and retrieve return flights for a round trip or the next leg of the itinerary for a multi-city trip.\n"
|
|
160
|
+
},
|
|
161
|
+
"bookingToken": {
|
|
162
|
+
"type": "string",
|
|
163
|
+
"description": "Used to request booking options for selected flights. This token is found in the flight results and cannot be used with `departureToken`.\n"
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
"required": [
|
|
167
|
+
"departureId",
|
|
168
|
+
"arrivalId",
|
|
169
|
+
"outboundDate"
|
|
170
|
+
],
|
|
171
|
+
"additionalProperties": false,
|
|
172
|
+
"$schema": "http://json-schema.org/draft-07/schema#"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
];
|
|
176
|
+
export const TOOL_NAMES = TOOL_DEFS.map((t) => t.name);
|
|
177
|
+
/** Whether `name` is one of the captured tools. */
|
|
178
|
+
export function isKnownTool(name) {
|
|
179
|
+
return TOOL_NAMES.includes(name);
|
|
180
|
+
}
|
|
181
|
+
/* ------------------------------------------------------------------ */
|
|
182
|
+
/* Forwarding client */
|
|
183
|
+
/* ------------------------------------------------------------------ */
|
|
184
|
+
function errorResult(detail) {
|
|
185
|
+
return {
|
|
186
|
+
content: [{ type: "text", text: `flightdata error: ${detail}` }],
|
|
187
|
+
isError: true,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function rpcErrorMessage(error) {
|
|
191
|
+
if (error !== null && typeof error === "object") {
|
|
192
|
+
const message = error.message;
|
|
193
|
+
if (typeof message === "string" && message !== "")
|
|
194
|
+
return message;
|
|
195
|
+
return JSON.stringify(error);
|
|
196
|
+
}
|
|
197
|
+
return String(error);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Parse a JSON-RPC response body, tolerating SSE framing.
|
|
201
|
+
* Returns the message whose id matches `expectedId` when
|
|
202
|
+
* one is present, else the last parseable message, else
|
|
203
|
+
* null when nothing parses.
|
|
204
|
+
*/
|
|
205
|
+
export function parseRpcBody(text, expectedId) {
|
|
206
|
+
const trimmed = text.trim();
|
|
207
|
+
if (trimmed === "")
|
|
208
|
+
return null;
|
|
209
|
+
const candidates = [];
|
|
210
|
+
const tryPush = (payload) => {
|
|
211
|
+
try {
|
|
212
|
+
const parsed = JSON.parse(payload);
|
|
213
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
214
|
+
candidates.push(parsed);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// Not JSON; ignore this candidate.
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
if (trimmed.includes("data:")) {
|
|
222
|
+
for (const line of trimmed.split("\n")) {
|
|
223
|
+
const t = line.trim();
|
|
224
|
+
if (!t.startsWith("data:"))
|
|
225
|
+
continue;
|
|
226
|
+
const payload = t.slice("data:".length).trim();
|
|
227
|
+
if (payload !== "" && payload !== "[DONE]")
|
|
228
|
+
tryPush(payload);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
tryPush(trimmed);
|
|
233
|
+
}
|
|
234
|
+
if (candidates.length === 0)
|
|
235
|
+
return null;
|
|
236
|
+
if (expectedId !== undefined) {
|
|
237
|
+
const match = candidates.find((c) => c.id === expectedId);
|
|
238
|
+
if (match !== undefined)
|
|
239
|
+
return match;
|
|
240
|
+
}
|
|
241
|
+
return candidates[candidates.length - 1];
|
|
242
|
+
}
|
|
243
|
+
async function defaultFetch(url, init) {
|
|
244
|
+
return fetch(url, init);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* A forwarding client holding one upstream session. The
|
|
248
|
+
* session is established lazily on the first forwarded
|
|
249
|
+
* call and reused for the lifetime of the client (the
|
|
250
|
+
* process lifetime when the client is the MCP server's
|
|
251
|
+
* or a one-shot client for the CLI).
|
|
252
|
+
*/
|
|
253
|
+
export class FlightdataClient {
|
|
254
|
+
deps;
|
|
255
|
+
sessionId = null;
|
|
256
|
+
ready = false;
|
|
257
|
+
sessionPromise = null;
|
|
258
|
+
idCounter = 0;
|
|
259
|
+
constructor(deps = {}) {
|
|
260
|
+
this.deps = deps;
|
|
261
|
+
}
|
|
262
|
+
fetchFn() {
|
|
263
|
+
return this.deps.fetchFn ?? defaultFetch;
|
|
264
|
+
}
|
|
265
|
+
endpointUrl() {
|
|
266
|
+
if (this.deps.url && this.deps.url.trim() !== "")
|
|
267
|
+
return this.deps.url.trim();
|
|
268
|
+
const raw = (this.deps.env ?? process.env).HASDATA_GOOGLE_FLIGHTS_MCP_URL;
|
|
269
|
+
if (raw && raw.trim() !== "")
|
|
270
|
+
return raw.trim();
|
|
271
|
+
return DEFAULT_ENDPOINT_URL;
|
|
272
|
+
}
|
|
273
|
+
apiKey() {
|
|
274
|
+
const raw = (this.deps.env ?? process.env).HASDATA_API_KEY;
|
|
275
|
+
if (raw && raw.trim() !== "")
|
|
276
|
+
return raw.trim();
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
timeoutMs() {
|
|
280
|
+
if (typeof this.deps.timeoutMs === "number" && this.deps.timeoutMs > 0) {
|
|
281
|
+
return this.deps.timeoutMs;
|
|
282
|
+
}
|
|
283
|
+
return DEFAULT_TIMEOUT_MS;
|
|
284
|
+
}
|
|
285
|
+
nextId() {
|
|
286
|
+
this.idCounter += 1;
|
|
287
|
+
return this.idCounter;
|
|
288
|
+
}
|
|
289
|
+
async post(body, withSession) {
|
|
290
|
+
const headers = {
|
|
291
|
+
"Content-Type": "application/json",
|
|
292
|
+
Accept: "application/json, text/event-stream",
|
|
293
|
+
};
|
|
294
|
+
const key = this.apiKey();
|
|
295
|
+
if (key !== null)
|
|
296
|
+
headers["x-api-key"] = key;
|
|
297
|
+
if (withSession && this.sessionId !== null) {
|
|
298
|
+
headers["Mcp-Session-Id"] = this.sessionId;
|
|
299
|
+
}
|
|
300
|
+
const controller = new AbortController();
|
|
301
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs());
|
|
302
|
+
try {
|
|
303
|
+
return await this.fetchFn()(this.endpointUrl(), {
|
|
304
|
+
method: "POST",
|
|
305
|
+
headers,
|
|
306
|
+
body: JSON.stringify(body),
|
|
307
|
+
signal: controller.signal,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
finally {
|
|
311
|
+
clearTimeout(timer);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async ensureSession() {
|
|
315
|
+
if (this.ready)
|
|
316
|
+
return;
|
|
317
|
+
if (this.sessionPromise === null) {
|
|
318
|
+
this.sessionPromise = (async () => {
|
|
319
|
+
const initId = this.nextId();
|
|
320
|
+
const initRes = await this.post({
|
|
321
|
+
jsonrpc: "2.0",
|
|
322
|
+
id: initId,
|
|
323
|
+
method: "initialize",
|
|
324
|
+
params: {
|
|
325
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
326
|
+
capabilities: {},
|
|
327
|
+
clientInfo: { name: "flightdata", version: VERSION },
|
|
328
|
+
},
|
|
329
|
+
}, false);
|
|
330
|
+
const sessionId = initRes.headers.get("mcp-session-id");
|
|
331
|
+
if (sessionId)
|
|
332
|
+
this.sessionId = sessionId;
|
|
333
|
+
const initText = await initRes.text();
|
|
334
|
+
const initParsed = parseRpcBody(initText, initId);
|
|
335
|
+
if (initParsed !== null && initParsed.error) {
|
|
336
|
+
throw new Error(rpcErrorMessage(initParsed.error));
|
|
337
|
+
}
|
|
338
|
+
if (initRes.status < 200 || initRes.status >= 300) {
|
|
339
|
+
throw new Error(`HTTP ${initRes.status}`);
|
|
340
|
+
}
|
|
341
|
+
if (initParsed === null && initText.trim() !== "") {
|
|
342
|
+
throw new Error("malformed response");
|
|
343
|
+
}
|
|
344
|
+
const initializedRes = await this.post({ jsonrpc: "2.0", method: "notifications/initialized" }, true);
|
|
345
|
+
try {
|
|
346
|
+
await initializedRes.text();
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
// The notification response body carries nothing we need.
|
|
350
|
+
}
|
|
351
|
+
this.ready = true;
|
|
352
|
+
})();
|
|
353
|
+
}
|
|
354
|
+
try {
|
|
355
|
+
await this.sessionPromise;
|
|
356
|
+
}
|
|
357
|
+
catch (err) {
|
|
358
|
+
this.sessionPromise = null;
|
|
359
|
+
this.sessionId = null;
|
|
360
|
+
throw err;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/** Forward one tool call; upstream failures come back as isError results. */
|
|
364
|
+
async callTool(name, args) {
|
|
365
|
+
try {
|
|
366
|
+
await this.ensureSession();
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
370
|
+
}
|
|
371
|
+
const callId = this.nextId();
|
|
372
|
+
let callRes;
|
|
373
|
+
try {
|
|
374
|
+
callRes = await this.post({
|
|
375
|
+
jsonrpc: "2.0",
|
|
376
|
+
id: callId,
|
|
377
|
+
method: "tools/call",
|
|
378
|
+
params: { name, arguments: args ?? {} },
|
|
379
|
+
}, true);
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
return errorResult(`request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
383
|
+
}
|
|
384
|
+
const parsed = parseRpcBody(await callRes.text(), callId);
|
|
385
|
+
if (parsed !== null && parsed.error) {
|
|
386
|
+
return errorResult(rpcErrorMessage(parsed.error));
|
|
387
|
+
}
|
|
388
|
+
if (callRes.status < 200 || callRes.status >= 300) {
|
|
389
|
+
return errorResult(`HTTP ${callRes.status}`);
|
|
390
|
+
}
|
|
391
|
+
if (parsed === null)
|
|
392
|
+
return errorResult("malformed response");
|
|
393
|
+
const result = parsed.result;
|
|
394
|
+
if (result === undefined || result === null || typeof result !== "object") {
|
|
395
|
+
return errorResult("malformed response");
|
|
396
|
+
}
|
|
397
|
+
// Pass the upstream result through verbatim.
|
|
398
|
+
return result;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/** Create a forwarding client; tests inject a fake fetch and env through deps. */
|
|
402
|
+
export function createClient(deps = {}) {
|
|
403
|
+
return new FlightdataClient(deps);
|
|
404
|
+
}
|
|
405
|
+
/** One-shot helper: a fresh client per call (the CLI path). */
|
|
406
|
+
export async function callTool(name, args, deps = {}) {
|
|
407
|
+
return new FlightdataClient(deps).callTool(name, args);
|
|
408
|
+
}
|
|
409
|
+
//# sourceMappingURL=forward.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forward.js","sourceRoot":"","sources":["../src/forward.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flightdata MCP server. Tools: the 1 captured HasData
|
|
3
|
+
* Google Flights tool (see forward.ts).
|
|
4
|
+
*
|
|
5
|
+
* Why the low-level Server instead of McpServer: the
|
|
6
|
+
* high-level helper converts zod schemas to JSON Schema
|
|
7
|
+
* and rewrites the served schemas, which breaks exact
|
|
8
|
+
* tool-list/schema parity with the live capture. This
|
|
9
|
+
* file serves tools/list locally from the core's explicit
|
|
10
|
+
* literals — the verbatim tool objects from the upstream
|
|
11
|
+
* server's live tools/list — and forwards every
|
|
12
|
+
* tools/call upstream.
|
|
13
|
+
*
|
|
14
|
+
* A forwarded result is returned unchanged (including any
|
|
15
|
+
* upstream isError flag and extra result fields). An
|
|
16
|
+
* upstream failure comes back as an isError result
|
|
17
|
+
* carrying a `flightdata error:` text, synthesised by the
|
|
18
|
+
* forwarding client. An unknown tool name is rejected
|
|
19
|
+
* with McpError MethodNotFound, and arguments that are
|
|
20
|
+
* not a JSON object with McpError InvalidParams, before
|
|
21
|
+
* any network hop.
|
|
22
|
+
*/
|
|
23
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
24
|
+
import { type FlightdataClient } from "./forward.js";
|
|
25
|
+
import type { ForwardDeps, ToolResult } from "./types.js";
|
|
26
|
+
/**
|
|
27
|
+
* Validate and forward one tools/call through `client`.
|
|
28
|
+
* Exported so the forwarding behaviour can be tested
|
|
29
|
+
* directly without a stdio transport.
|
|
30
|
+
*/
|
|
31
|
+
export declare function handleCallTool(client: FlightdataClient, name: string, args: unknown): Promise<ToolResult>;
|
|
32
|
+
/** Build the stdio MCP server (transport not yet connected). */
|
|
33
|
+
export declare function createServer(deps?: ForwardDeps): Server;
|
|
34
|
+
/** Connect the MCP server over stdio. */
|
|
35
|
+
export declare function startMcpServer(deps?: ForwardDeps): Promise<void>;
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flightdata MCP server. Tools: the 1 captured HasData
|
|
3
|
+
* Google Flights tool (see forward.ts).
|
|
4
|
+
*
|
|
5
|
+
* Why the low-level Server instead of McpServer: the
|
|
6
|
+
* high-level helper converts zod schemas to JSON Schema
|
|
7
|
+
* and rewrites the served schemas, which breaks exact
|
|
8
|
+
* tool-list/schema parity with the live capture. This
|
|
9
|
+
* file serves tools/list locally from the core's explicit
|
|
10
|
+
* literals — the verbatim tool objects from the upstream
|
|
11
|
+
* server's live tools/list — and forwards every
|
|
12
|
+
* tools/call upstream.
|
|
13
|
+
*
|
|
14
|
+
* A forwarded result is returned unchanged (including any
|
|
15
|
+
* upstream isError flag and extra result fields). An
|
|
16
|
+
* upstream failure comes back as an isError result
|
|
17
|
+
* carrying a `flightdata error:` text, synthesised by the
|
|
18
|
+
* forwarding client. An unknown tool name is rejected
|
|
19
|
+
* with McpError MethodNotFound, and arguments that are
|
|
20
|
+
* not a JSON object with McpError InvalidParams, before
|
|
21
|
+
* any network hop.
|
|
22
|
+
*/
|
|
23
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
24
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
25
|
+
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
26
|
+
import { createClient, isKnownTool, TOOL_DEFS, VERSION, } from "./forward.js";
|
|
27
|
+
/**
|
|
28
|
+
* Validate and forward one tools/call through `client`.
|
|
29
|
+
* Exported so the forwarding behaviour can be tested
|
|
30
|
+
* directly without a stdio transport.
|
|
31
|
+
*/
|
|
32
|
+
export async function handleCallTool(client, name, args) {
|
|
33
|
+
if (!isKnownTool(name)) {
|
|
34
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
35
|
+
}
|
|
36
|
+
if (args !== undefined &&
|
|
37
|
+
(typeof args !== "object" || args === null || Array.isArray(args))) {
|
|
38
|
+
throw new McpError(ErrorCode.InvalidParams, `Arguments for tool ${name} must be a JSON object`);
|
|
39
|
+
}
|
|
40
|
+
return client.callTool(name, (args ?? {}));
|
|
41
|
+
}
|
|
42
|
+
/** Build the stdio MCP server (transport not yet connected). */
|
|
43
|
+
export function createServer(deps = {}) {
|
|
44
|
+
const client = createClient(deps);
|
|
45
|
+
const server = new Server({ name: "flightdata", version: VERSION }, { capabilities: { tools: {} } });
|
|
46
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
47
|
+
tools: TOOL_DEFS,
|
|
48
|
+
}));
|
|
49
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
50
|
+
const { name, arguments: args } = request.params;
|
|
51
|
+
const result = await handleCallTool(client, name, args);
|
|
52
|
+
return result;
|
|
53
|
+
});
|
|
54
|
+
return server;
|
|
55
|
+
}
|
|
56
|
+
/** Connect the MCP server over stdio. */
|
|
57
|
+
export async function startMcpServer(deps = {}) {
|
|
58
|
+
await createServer(deps).connect(new StdioServerTransport());
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,SAAS,EACT,sBAAsB,EACtB,QAAQ,GACT,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,YAAY,EACZ,WAAW,EACX,SAAS,EACT,OAAO,GAER,MAAM,cAAc,CAAC;AAGtB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAwB,EACxB,IAAY,EACZ,IAAa;IAEb,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,iBAAiB,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,IACE,IAAI,KAAK,SAAS;QAClB,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAClE,CAAC;QACD,MAAM,IAAI,QAAQ,CAChB,SAAS,CAAC,aAAa,EACvB,sBAAsB,IAAI,wBAAwB,CACnD,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC,CAAC;AACxE,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,YAAY,CAAC,OAAoB,EAAE;IACjD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EACxC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACxD,OAAO,MAAe,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,yCAAyC;AACzC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAoB,EAAE;IACzD,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;AAC/D,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flightdata types.
|
|
3
|
+
*
|
|
4
|
+
* flightdata holds no flight data of its own. It is a forwarding
|
|
5
|
+
* client: the captured tool surface lives here as data (ToolDef
|
|
6
|
+
* entries served verbatim for tools/list) and every tools/call
|
|
7
|
+
* travels to the hosted HasData Google Flights MCP endpoint through an
|
|
8
|
+
* injectable fetch, so the test suite never touches the live
|
|
9
|
+
* network.
|
|
10
|
+
*/
|
|
11
|
+
/** One captured tool definition, served verbatim for tools/list. */
|
|
12
|
+
export interface ToolDef {
|
|
13
|
+
name: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
description: string;
|
|
16
|
+
inputSchema: Record<string, unknown>;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
/** A tool's arguments, as decoded JSON. */
|
|
20
|
+
export type ToolArgs = Record<string, unknown>;
|
|
21
|
+
/** A tools/call result: upstream results pass through verbatim; failures use this shape. */
|
|
22
|
+
export interface ToolResult {
|
|
23
|
+
content?: unknown;
|
|
24
|
+
isError?: boolean;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
/** The minimal slice of a fetch Response this client relies on. */
|
|
28
|
+
export interface FetchResponseLike {
|
|
29
|
+
ok: boolean;
|
|
30
|
+
status: number;
|
|
31
|
+
headers: {
|
|
32
|
+
get(name: string): string | null;
|
|
33
|
+
};
|
|
34
|
+
text(): Promise<string>;
|
|
35
|
+
}
|
|
36
|
+
/** Injectable fetch, so tests never touch the live network. */
|
|
37
|
+
export type FetchFn = (url: string, init?: {
|
|
38
|
+
method?: string;
|
|
39
|
+
headers?: Record<string, string>;
|
|
40
|
+
body?: string;
|
|
41
|
+
signal?: AbortSignal;
|
|
42
|
+
}) => Promise<FetchResponseLike>;
|
|
43
|
+
/** Runtime dependencies for the forwarding client, all injectable in tests. */
|
|
44
|
+
export interface ForwardDeps {
|
|
45
|
+
/** Fetch implementation. Defaults to the global fetch. */
|
|
46
|
+
fetchFn?: FetchFn;
|
|
47
|
+
/** Environment (HASDATA_GOOGLE_FLIGHTS_MCP_URL, HASDATA_API_KEY). Defaults to process.env. */
|
|
48
|
+
env?: Record<string, string | undefined>;
|
|
49
|
+
/** Endpoint URL override. Defaults to env HASDATA_GOOGLE_FLIGHTS_MCP_URL or the pinned default. */
|
|
50
|
+
url?: string;
|
|
51
|
+
/** Per-request timeout in ms. Defaults to 30000. */
|
|
52
|
+
timeoutMs?: number;
|
|
53
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flightdata types.
|
|
3
|
+
*
|
|
4
|
+
* flightdata holds no flight data of its own. It is a forwarding
|
|
5
|
+
* client: the captured tool surface lives here as data (ToolDef
|
|
6
|
+
* entries served verbatim for tools/list) and every tools/call
|
|
7
|
+
* travels to the hosted HasData Google Flights MCP endpoint through an
|
|
8
|
+
* injectable fetch, so the test suite never touches the live
|
|
9
|
+
* network.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@reneturcios/flightdata",
|
|
3
|
-
"version": "0.0.0-stage",
|
|
4
|
-
"stub": true,
|
|
5
|
-
"description": "Temporary package placeholder for staged publishing"
|
|
6
|
-
}
|
|
1
|
+
{"bin":{"flightdata":"dist/cli.js"},"dependencies":{"@modelcontextprotocol/sdk":"^1","zod":"^4"},"description":"Google Flights results as JSON from your agent: a local bridge to the hosted HasData Google Flights MCP service that searches one-way, round-trip and multi-city itineraries with passenger mix, travel class, stops, airline and emissions filters, returning per-itinerary prices, durations, legs and tokens as returned upstream. One bin serves a small CLI and a stdio MCP server.","devDependencies":{"@types/node":"^20","tsx":"^4","typescript":"^5"},"engines":{"node":">=20"},"files":["dist","server.json"],"homepage":"https://github.com/CloudCorpRecords/flightdata#readme","license":"MIT","mcpName":"io.github.CloudCorpRecords/flightdata","name":"@reneturcios/flightdata","private":false,"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/CloudCorpRecords/flightdata.git"},"scripts":{"build":"tsc","dev":"tsx src/cli.ts","test":"tsx --test test/*.test.ts"},"type":"module","version":"0.1.0"}
|
package/server.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"$schema":"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json","description":"Google Flights search as JSON: itineraries, prices, times, stops and emissions filters.","name":"io.github.CloudCorpRecords/flightdata","packages":[{"identifier":"@reneturcios/flightdata","packageArguments":[{"type":"positional","value":"mcp"}],"registryBaseUrl":"https://registry.npmjs.org","registryType":"npm","runtimeHint":"npx","transport":{"type":"stdio"},"version":"0.1.0"},{"identifier":"ghcr.io/cloudcorprecords/flightdata:0.1.0","packageArguments":[{"type":"positional","value":"mcp"}],"registryType":"oci","runtimeArguments":[{"name":"--rm","type":"named"},{"name":"-i","type":"named"}],"runtimeHint":"docker","transport":{"type":"stdio"}}],"repository":{"source":"github","url":"https://github.com/CloudCorpRecords/flightdata"},"version":"0.1.0"}
|