@squawk/mcp 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 +301 -0
- package/dist/bin.d.ts +11 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +41 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/resolvers.d.ts +60 -0
- package/dist/resolvers.d.ts.map +1 -0
- package/dist/resolvers.js +94 -0
- package/dist/server.d.ts +45 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +92 -0
- package/dist/tools/airports.d.ts +16 -0
- package/dist/tools/airports.d.ts.map +1 -0
- package/dist/tools/airports.js +142 -0
- package/dist/tools/airspace.d.ts +15 -0
- package/dist/tools/airspace.d.ts.map +1 -0
- package/dist/tools/airspace.js +81 -0
- package/dist/tools/airways.d.ts +14 -0
- package/dist/tools/airways.d.ts.map +1 -0
- package/dist/tools/airways.js +115 -0
- package/dist/tools/datasets.d.ts +18 -0
- package/dist/tools/datasets.d.ts.map +1 -0
- package/dist/tools/datasets.js +78 -0
- package/dist/tools/fixes.d.ts +14 -0
- package/dist/tools/fixes.d.ts.map +1 -0
- package/dist/tools/fixes.js +108 -0
- package/dist/tools/flight-math.d.ts +23 -0
- package/dist/tools/flight-math.d.ts.map +1 -0
- package/dist/tools/flight-math.js +643 -0
- package/dist/tools/flightplan.d.ts +17 -0
- package/dist/tools/flightplan.d.ts.map +1 -0
- package/dist/tools/flightplan.js +64 -0
- package/dist/tools/geo.d.ts +15 -0
- package/dist/tools/geo.d.ts.map +1 -0
- package/dist/tools/geo.js +127 -0
- package/dist/tools/icao-registry.d.ts +19 -0
- package/dist/tools/icao-registry.d.ts.map +1 -0
- package/dist/tools/icao-registry.js +45 -0
- package/dist/tools/navaids.d.ts +14 -0
- package/dist/tools/navaids.d.ts.map +1 -0
- package/dist/tools/navaids.js +143 -0
- package/dist/tools/notams.d.ts +13 -0
- package/dist/tools/notams.d.ts.map +1 -0
- package/dist/tools/notams.js +29 -0
- package/dist/tools/procedures.d.ts +15 -0
- package/dist/tools/procedures.d.ts.map +1 -0
- package/dist/tools/procedures.js +120 -0
- package/dist/tools/tool-helpers.d.ts +66 -0
- package/dist/tools/tool-helpers.d.ts.map +1 -0
- package/dist/tools/tool-helpers.js +55 -0
- package/dist/tools/weather.d.ts +18 -0
- package/dist/tools/weather.d.ts.map +1 -0
- package/dist/tools/weather.js +215 -0
- package/package.json +77 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/flightplan` route-string parsing and
|
|
4
|
+
* great-circle distance computation. The flightplan resolver composes the
|
|
5
|
+
* shared airport, navaid, fix, airway, and procedure resolvers from
|
|
6
|
+
* {@link ../resolvers.js}.
|
|
7
|
+
*/
|
|
8
|
+
import { computeRouteDistance, createFlightplanResolver } from '@squawk/flightplan';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { airportResolver, airwayResolver, fixResolver, navaidResolver, procedureResolver, } from '../resolvers.js';
|
|
11
|
+
/**
|
|
12
|
+
* Registers flight plan parsing and route distance tools on the given MCP
|
|
13
|
+
* server. The flightplan resolver is built once at registration time and
|
|
14
|
+
* shares the bundled NASR data via the resolver singletons.
|
|
15
|
+
*
|
|
16
|
+
* @param server - The MCP server instance to register tools on.
|
|
17
|
+
*/
|
|
18
|
+
export function registerFlightplanTools(server) {
|
|
19
|
+
const resolver = createFlightplanResolver({
|
|
20
|
+
airports: airportResolver,
|
|
21
|
+
navaids: navaidResolver,
|
|
22
|
+
fixes: fixResolver,
|
|
23
|
+
airways: airwayResolver,
|
|
24
|
+
procedures: procedureResolver,
|
|
25
|
+
});
|
|
26
|
+
server.registerTool('parse_flightplan_route', {
|
|
27
|
+
title: 'Parse a flight plan route string',
|
|
28
|
+
description: 'Parses a whitespace-separated flight plan route string (e.g. "KJFK DCT MERIT J60 MARTN DCT KLAX") into structured route elements. Each token is classified as an airport, SID, STAR, airway, direct (DCT), waypoint, lat/lon coordinate, speed/altitude group, or unresolved. Airway tokens are expanded into waypoint sequences between the entry and exit fixes, and SID/STAR tokens are expanded into their first common route.',
|
|
29
|
+
inputSchema: {
|
|
30
|
+
routeString: z
|
|
31
|
+
.string()
|
|
32
|
+
.min(1)
|
|
33
|
+
.describe('Whitespace-separated route string in ICAO Item 15 conventions.'),
|
|
34
|
+
},
|
|
35
|
+
}, ({ routeString }) => {
|
|
36
|
+
const route = resolver.parse(routeString);
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: JSON.stringify(route, null, 2) }],
|
|
39
|
+
structuredContent: { route },
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
server.registerTool('compute_route_distance', {
|
|
43
|
+
title: 'Compute route distance and ETE',
|
|
44
|
+
description: 'Parses a flight plan route string and computes the total great-circle distance in nautical miles, the ordered list of legs with cumulative distance, and (when groundSpeedKt is supplied) the estimated time enroute in hours. Uses FAA-published per-segment distances on airway segments when available; otherwise falls back to great-circle computation. Unresolved tokens are surfaced separately so the caller can decide whether to trust the total.',
|
|
45
|
+
inputSchema: {
|
|
46
|
+
routeString: z
|
|
47
|
+
.string()
|
|
48
|
+
.min(1)
|
|
49
|
+
.describe('Whitespace-separated route string in ICAO Item 15 conventions.'),
|
|
50
|
+
groundSpeedKt: z
|
|
51
|
+
.number()
|
|
52
|
+
.positive()
|
|
53
|
+
.optional()
|
|
54
|
+
.describe('Optional ground speed in knots used to compute estimated time enroute. Omit to skip ETE.'),
|
|
55
|
+
},
|
|
56
|
+
}, ({ routeString, groundSpeedKt }) => {
|
|
57
|
+
const route = resolver.parse(routeString);
|
|
58
|
+
const result = computeRouteDistance(route, groundSpeedKt);
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
61
|
+
structuredContent: { result },
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping the great-circle geometry utilities from
|
|
4
|
+
* `@squawk/geo`. Tools take plain lat/lon inputs and return distances in
|
|
5
|
+
* nautical miles and bearings in degrees true.
|
|
6
|
+
*/
|
|
7
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
/**
|
|
9
|
+
* Registers great-circle geometry tools (distance, bearing, midpoint,
|
|
10
|
+
* destination-point) on the given MCP server.
|
|
11
|
+
*
|
|
12
|
+
* @param server - The MCP server instance to register tools on.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerGeoTools(server: McpServer): void;
|
|
15
|
+
//# sourceMappingURL=geo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo.d.ts","sourceRoot":"","sources":["../../src/tools/geo.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkBzE;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmIxD"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping the great-circle geometry utilities from
|
|
4
|
+
* `@squawk/geo`. Tools take plain lat/lon inputs and return distances in
|
|
5
|
+
* nautical miles and bearings in degrees true.
|
|
6
|
+
*/
|
|
7
|
+
import { greatCircle } from '@squawk/geo';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
/** Reusable zod fragment describing a latitude input. */
|
|
10
|
+
const latFragment = z
|
|
11
|
+
.number()
|
|
12
|
+
.min(-90)
|
|
13
|
+
.max(90)
|
|
14
|
+
.describe('Latitude in decimal degrees (WGS84, positive north).');
|
|
15
|
+
/** Reusable zod fragment describing a longitude input. */
|
|
16
|
+
const lonFragment = z
|
|
17
|
+
.number()
|
|
18
|
+
.min(-180)
|
|
19
|
+
.max(180)
|
|
20
|
+
.describe('Longitude in decimal degrees (WGS84, positive east).');
|
|
21
|
+
/**
|
|
22
|
+
* Registers great-circle geometry tools (distance, bearing, midpoint,
|
|
23
|
+
* destination-point) on the given MCP server.
|
|
24
|
+
*
|
|
25
|
+
* @param server - The MCP server instance to register tools on.
|
|
26
|
+
*/
|
|
27
|
+
export function registerGeoTools(server) {
|
|
28
|
+
server.registerTool('great_circle_distance', {
|
|
29
|
+
title: 'Great-circle distance',
|
|
30
|
+
description: 'Computes the great-circle distance between two geographic positions in nautical miles using the Haversine formula on a spherical Earth.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
lat1: latFragment,
|
|
33
|
+
lon1: lonFragment,
|
|
34
|
+
lat2: latFragment,
|
|
35
|
+
lon2: lonFragment,
|
|
36
|
+
},
|
|
37
|
+
}, ({ lat1, lon1, lat2, lon2 }) => {
|
|
38
|
+
const distanceNm = greatCircle.distanceNm(lat1, lon1, lat2, lon2);
|
|
39
|
+
return {
|
|
40
|
+
content: [{ type: 'text', text: `${distanceNm.toFixed(2)} nm` }],
|
|
41
|
+
structuredContent: { distanceNm },
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
server.registerTool('great_circle_bearing', {
|
|
45
|
+
title: 'Great-circle initial bearing',
|
|
46
|
+
description: 'Computes the initial great-circle bearing (degrees true, 0-360) from the first position to the second.',
|
|
47
|
+
inputSchema: {
|
|
48
|
+
lat1: latFragment,
|
|
49
|
+
lon1: lonFragment,
|
|
50
|
+
lat2: latFragment,
|
|
51
|
+
lon2: lonFragment,
|
|
52
|
+
},
|
|
53
|
+
}, ({ lat1, lon1, lat2, lon2 }) => {
|
|
54
|
+
const bearingDeg = greatCircle.bearing(lat1, lon1, lat2, lon2);
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: 'text', text: `${bearingDeg.toFixed(1)} deg true` }],
|
|
57
|
+
structuredContent: { bearingDeg },
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
server.registerTool('great_circle_bearing_and_distance', {
|
|
61
|
+
title: 'Great-circle bearing and distance',
|
|
62
|
+
description: 'Computes the initial great-circle bearing (degrees true, 0-360) and distance (nautical miles) from the first position to the second in one call.',
|
|
63
|
+
inputSchema: {
|
|
64
|
+
lat1: latFragment,
|
|
65
|
+
lon1: lonFragment,
|
|
66
|
+
lat2: latFragment,
|
|
67
|
+
lon2: lonFragment,
|
|
68
|
+
},
|
|
69
|
+
}, ({ lat1, lon1, lat2, lon2 }) => {
|
|
70
|
+
const { bearingDeg, distanceNm } = greatCircle.bearingAndDistance(lat1, lon1, lat2, lon2);
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: `${bearingDeg.toFixed(1)} deg true, ${distanceNm.toFixed(2)} nm`,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
structuredContent: { bearingDeg, distanceNm },
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
server.registerTool('great_circle_midpoint', {
|
|
82
|
+
title: 'Great-circle midpoint',
|
|
83
|
+
description: 'Computes the midpoint along the great-circle arc between two geographic positions.',
|
|
84
|
+
inputSchema: {
|
|
85
|
+
lat1: latFragment,
|
|
86
|
+
lon1: lonFragment,
|
|
87
|
+
lat2: latFragment,
|
|
88
|
+
lon2: lonFragment,
|
|
89
|
+
},
|
|
90
|
+
}, ({ lat1, lon1, lat2, lon2 }) => {
|
|
91
|
+
const { lat, lon } = greatCircle.midpoint(lat1, lon1, lat2, lon2);
|
|
92
|
+
return {
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: 'text',
|
|
96
|
+
text: `${lat.toFixed(6)}, ${lon.toFixed(6)}`,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
structuredContent: { lat, lon },
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
server.registerTool('great_circle_destination', {
|
|
103
|
+
title: 'Great-circle destination point',
|
|
104
|
+
description: 'Computes the destination point reached by traveling a given distance (nautical miles) along a bearing (degrees true) from a starting position.',
|
|
105
|
+
inputSchema: {
|
|
106
|
+
lat: latFragment,
|
|
107
|
+
lon: lonFragment,
|
|
108
|
+
bearingDeg: z
|
|
109
|
+
.number()
|
|
110
|
+
.describe('Initial bearing in degrees true. Values outside [0, 360) are normalized.'),
|
|
111
|
+
travelDistanceNm: z
|
|
112
|
+
.number()
|
|
113
|
+
.describe('Distance to travel along the bearing in nautical miles. Negative values reverse direction.'),
|
|
114
|
+
},
|
|
115
|
+
}, ({ lat, lon, bearingDeg, travelDistanceNm }) => {
|
|
116
|
+
const destination = greatCircle.destination(lat, lon, bearingDeg, travelDistanceNm);
|
|
117
|
+
return {
|
|
118
|
+
content: [
|
|
119
|
+
{
|
|
120
|
+
type: 'text',
|
|
121
|
+
text: `${destination.lat.toFixed(6)}, ${destination.lon.toFixed(6)}`,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
structuredContent: { lat: destination.lat, lon: destination.lon },
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/icao-registry` aircraft registration
|
|
4
|
+
* lookup, backed by the FAA ReleasableAircraft snapshot in
|
|
5
|
+
* `@squawk/icao-registry-data`.
|
|
6
|
+
*
|
|
7
|
+
* Unlike the other domain modules, the registry data is loaded lazily on the
|
|
8
|
+
* first tool invocation through {@link getIcaoRegistry}. The bundled data
|
|
9
|
+
* package decompresses ~40 MB of records on import, which is wasteful for
|
|
10
|
+
* sessions that never look up an aircraft.
|
|
11
|
+
*/
|
|
12
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
|
+
/**
|
|
14
|
+
* Registers ICAO aircraft registration lookup tools on the given MCP server.
|
|
15
|
+
*
|
|
16
|
+
* @param server - The MCP server instance to register tools on.
|
|
17
|
+
*/
|
|
18
|
+
export declare function registerIcaoRegistryTools(server: McpServer): void;
|
|
19
|
+
//# sourceMappingURL=icao-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icao-registry.d.ts","sourceRoot":"","sources":["../../src/tools/icao-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6BjE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/icao-registry` aircraft registration
|
|
4
|
+
* lookup, backed by the FAA ReleasableAircraft snapshot in
|
|
5
|
+
* `@squawk/icao-registry-data`.
|
|
6
|
+
*
|
|
7
|
+
* Unlike the other domain modules, the registry data is loaded lazily on the
|
|
8
|
+
* first tool invocation through {@link getIcaoRegistry}. The bundled data
|
|
9
|
+
* package decompresses ~40 MB of records on import, which is wasteful for
|
|
10
|
+
* sessions that never look up an aircraft.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { getIcaoRegistry } from '../resolvers.js';
|
|
14
|
+
/** Pattern matching a valid 24-bit ICAO hex address (1-6 hex digits). */
|
|
15
|
+
const ICAO_HEX_PATTERN = /^[0-9A-Fa-f]{1,6}$/;
|
|
16
|
+
/**
|
|
17
|
+
* Registers ICAO aircraft registration lookup tools on the given MCP server.
|
|
18
|
+
*
|
|
19
|
+
* @param server - The MCP server instance to register tools on.
|
|
20
|
+
*/
|
|
21
|
+
export function registerIcaoRegistryTools(server) {
|
|
22
|
+
server.registerTool('lookup_aircraft_by_icao_hex', {
|
|
23
|
+
title: 'Look up an aircraft by ICAO hex address',
|
|
24
|
+
description: 'Looks up a US-registered aircraft by its 24-bit ICAO hex address (the same identifier transmitted by Mode S and ADS-B). Returns registration, make, model, operator, aircraft type, engine type, and year of manufacture when known. Returns null when no match is found. The first call may take a few hundred milliseconds while the bundled FAA registration snapshot decompresses.',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
icaoHex: z
|
|
27
|
+
.string()
|
|
28
|
+
.regex(ICAO_HEX_PATTERN, '1-6 hex digits (e.g. "AC82EC", "A4B5F2")')
|
|
29
|
+
.describe('24-bit ICAO hex address (1-6 hex digits, case-insensitive).'),
|
|
30
|
+
},
|
|
31
|
+
}, async ({ icaoHex }) => {
|
|
32
|
+
const registry = await getIcaoRegistry();
|
|
33
|
+
const aircraft = registry.lookup(icaoHex);
|
|
34
|
+
if (aircraft === undefined) {
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: 'text', text: `No aircraft found for ICAO hex "${icaoHex}".` }],
|
|
37
|
+
structuredContent: { aircraft: null },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: 'text', text: JSON.stringify(aircraft, null, 2) }],
|
|
42
|
+
structuredContent: { aircraft },
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/navaids` navaid lookup methods, backed
|
|
4
|
+
* by the US NASR snapshot in `@squawk/navaid-data`.
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
/**
|
|
8
|
+
* Registers navaid lookup tools on the given MCP server. Uses the shared
|
|
9
|
+
* {@link navaidResolver} built at module load time.
|
|
10
|
+
*
|
|
11
|
+
* @param server - The MCP server instance to register tools on.
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerNavaidTools(server: McpServer): void;
|
|
14
|
+
//# sourceMappingURL=navaids.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navaids.d.ts","sourceRoot":"","sources":["../../src/tools/navaids.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoBzE;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2I3D"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/navaids` navaid lookup methods, backed
|
|
4
|
+
* by the US NASR snapshot in `@squawk/navaid-data`.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { navaidResolver } from '../resolvers.js';
|
|
8
|
+
/** All {@link NavaidType} values, used for input validation. */
|
|
9
|
+
const NAVAID_TYPE_VALUES = [
|
|
10
|
+
'VOR',
|
|
11
|
+
'VORTAC',
|
|
12
|
+
'VOR/DME',
|
|
13
|
+
'TACAN',
|
|
14
|
+
'DME',
|
|
15
|
+
'NDB',
|
|
16
|
+
'NDB/DME',
|
|
17
|
+
'FAN_MARKER',
|
|
18
|
+
'MARINE_NDB',
|
|
19
|
+
'VOT',
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Registers navaid lookup tools on the given MCP server. Uses the shared
|
|
23
|
+
* {@link navaidResolver} built at module load time.
|
|
24
|
+
*
|
|
25
|
+
* @param server - The MCP server instance to register tools on.
|
|
26
|
+
*/
|
|
27
|
+
export function registerNavaidTools(server) {
|
|
28
|
+
server.registerTool('get_navaid_by_ident', {
|
|
29
|
+
title: 'Get navaids by identifier',
|
|
30
|
+
description: 'Looks up US navaids by identifier (e.g. "BOS", "JFK"). Multiple navaids can share the same identifier (for example a co-located NDB and VOR), so the result is always an array. Returns an empty array when no match is found.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
ident: z.string().min(1).describe('Navaid identifier (case-insensitive).'),
|
|
33
|
+
},
|
|
34
|
+
}, ({ ident }) => {
|
|
35
|
+
const navaids = navaidResolver.byIdent(ident);
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: 'text', text: JSON.stringify(navaids, null, 2) }],
|
|
38
|
+
structuredContent: { navaids },
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
server.registerTool('find_navaids_by_frequency', {
|
|
42
|
+
title: 'Find navaids by frequency',
|
|
43
|
+
description: 'Finds US navaids tuned to a given frequency. VOR-family navaids (VOR, VORTAC, VOR/DME, TACAN, DME, VOT) use MHz; NDB-family navaids (NDB, NDB/DME, MARINE_NDB) use kHz. Filter by navaid types when needed to disambiguate the unit.',
|
|
44
|
+
inputSchema: {
|
|
45
|
+
frequency: z
|
|
46
|
+
.number()
|
|
47
|
+
.positive()
|
|
48
|
+
.describe('Frequency value (MHz for VOR-family, kHz for NDB-family).'),
|
|
49
|
+
navaidTypes: z
|
|
50
|
+
.array(z.enum(NAVAID_TYPE_VALUES))
|
|
51
|
+
.optional()
|
|
52
|
+
.describe('Restrict results to these navaid types. Omit to include all types.'),
|
|
53
|
+
limit: z
|
|
54
|
+
.number()
|
|
55
|
+
.int()
|
|
56
|
+
.positive()
|
|
57
|
+
.optional()
|
|
58
|
+
.describe('Maximum number of results to return. Defaults to 20.'),
|
|
59
|
+
},
|
|
60
|
+
}, ({ frequency, navaidTypes, limit }) => {
|
|
61
|
+
const query = { frequency };
|
|
62
|
+
if (navaidTypes !== undefined) {
|
|
63
|
+
query.types = new Set(navaidTypes);
|
|
64
|
+
}
|
|
65
|
+
if (limit !== undefined) {
|
|
66
|
+
query.limit = limit;
|
|
67
|
+
}
|
|
68
|
+
const navaids = navaidResolver.byFrequency(query);
|
|
69
|
+
return {
|
|
70
|
+
content: [{ type: 'text', text: JSON.stringify(navaids, null, 2) }],
|
|
71
|
+
structuredContent: { navaids },
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
server.registerTool('find_nearest_navaids', {
|
|
75
|
+
title: 'Find nearest navaids',
|
|
76
|
+
description: 'Finds US navaids near a geographic position, sorted by great-circle distance in nautical miles.',
|
|
77
|
+
inputSchema: {
|
|
78
|
+
lat: z.number().min(-90).max(90).describe('Latitude in decimal degrees (WGS84).'),
|
|
79
|
+
lon: z.number().min(-180).max(180).describe('Longitude in decimal degrees (WGS84).'),
|
|
80
|
+
maxDistanceNm: z
|
|
81
|
+
.number()
|
|
82
|
+
.positive()
|
|
83
|
+
.optional()
|
|
84
|
+
.describe('Maximum search radius in nautical miles. Defaults to 30.'),
|
|
85
|
+
limit: z
|
|
86
|
+
.number()
|
|
87
|
+
.int()
|
|
88
|
+
.positive()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('Maximum number of results to return. Defaults to 10.'),
|
|
91
|
+
navaidTypes: z
|
|
92
|
+
.array(z.enum(NAVAID_TYPE_VALUES))
|
|
93
|
+
.optional()
|
|
94
|
+
.describe('Restrict results to these navaid types. Omit to include all types.'),
|
|
95
|
+
},
|
|
96
|
+
}, ({ lat, lon, maxDistanceNm, limit, navaidTypes }) => {
|
|
97
|
+
const query = { lat, lon };
|
|
98
|
+
if (maxDistanceNm !== undefined) {
|
|
99
|
+
query.maxDistanceNm = maxDistanceNm;
|
|
100
|
+
}
|
|
101
|
+
if (limit !== undefined) {
|
|
102
|
+
query.limit = limit;
|
|
103
|
+
}
|
|
104
|
+
if (navaidTypes !== undefined) {
|
|
105
|
+
query.types = new Set(navaidTypes);
|
|
106
|
+
}
|
|
107
|
+
const results = navaidResolver.nearest(query);
|
|
108
|
+
return {
|
|
109
|
+
content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
|
|
110
|
+
structuredContent: { results },
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
server.registerTool('search_navaids', {
|
|
114
|
+
title: 'Search navaids by name or identifier',
|
|
115
|
+
description: 'Searches US navaids using case-insensitive substring matching against the navaid name and identifier. Results are returned in alphabetical order by name.',
|
|
116
|
+
inputSchema: {
|
|
117
|
+
text: z.string().min(1).describe('Substring to match against navaid name or identifier.'),
|
|
118
|
+
navaidTypes: z
|
|
119
|
+
.array(z.enum(NAVAID_TYPE_VALUES))
|
|
120
|
+
.optional()
|
|
121
|
+
.describe('Restrict results to these navaid types. Omit to include all types.'),
|
|
122
|
+
limit: z
|
|
123
|
+
.number()
|
|
124
|
+
.int()
|
|
125
|
+
.positive()
|
|
126
|
+
.optional()
|
|
127
|
+
.describe('Maximum number of results to return. Defaults to 20.'),
|
|
128
|
+
},
|
|
129
|
+
}, ({ text, navaidTypes, limit }) => {
|
|
130
|
+
const query = { text };
|
|
131
|
+
if (navaidTypes !== undefined) {
|
|
132
|
+
query.types = new Set(navaidTypes);
|
|
133
|
+
}
|
|
134
|
+
if (limit !== undefined) {
|
|
135
|
+
query.limit = limit;
|
|
136
|
+
}
|
|
137
|
+
const navaids = navaidResolver.search(query);
|
|
138
|
+
return {
|
|
139
|
+
content: [{ type: 'text', text: JSON.stringify(navaids, null, 2) }],
|
|
140
|
+
structuredContent: { navaids },
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/notams` ICAO-format and FAA domestic
|
|
4
|
+
* NOTAM parsers.
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
/**
|
|
8
|
+
* Registers NOTAM parsing tools on the given MCP server.
|
|
9
|
+
*
|
|
10
|
+
* @param server - The MCP server instance to register tools on.
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerNotamTools(server: McpServer): void;
|
|
13
|
+
//# sourceMappingURL=notams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notams.d.ts","sourceRoot":"","sources":["../../src/tools/notams.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0B1D"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/notams` ICAO-format and FAA domestic
|
|
4
|
+
* NOTAM parsers.
|
|
5
|
+
*/
|
|
6
|
+
import { parseFaaNotam, parseNotam } from '@squawk/notams';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { runParser } from './tool-helpers.js';
|
|
9
|
+
/**
|
|
10
|
+
* Registers NOTAM parsing tools on the given MCP server.
|
|
11
|
+
*
|
|
12
|
+
* @param server - The MCP server instance to register tools on.
|
|
13
|
+
*/
|
|
14
|
+
export function registerNotamTools(server) {
|
|
15
|
+
server.registerTool('parse_icao_notam', {
|
|
16
|
+
title: 'Parse an ICAO-format NOTAM',
|
|
17
|
+
description: 'Parses a raw ICAO-format NOTAM string into a structured object including the action (NEW/REPLACE/CANCEL), Q-line qualifier (FIR, NOTAM code, traffic, purpose, scope, altitude bounds, coordinates/radius), location codes, effective period, schedule, free-text description, and altitude limits.',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
raw: z.string().min(1).describe('Raw ICAO-format NOTAM string.'),
|
|
20
|
+
},
|
|
21
|
+
}, ({ raw }) => runParser(raw, parseNotam, 'notam'));
|
|
22
|
+
server.registerTool('parse_faa_notam', {
|
|
23
|
+
title: 'Parse an FAA domestic NOTAM',
|
|
24
|
+
description: 'Parses a raw FAA domestic (legacy) format NOTAM string into a structured object with the location, classification, keyword (RWY/TWY/NAV/AIRSPACE/etc.), text body, and effective period (including PERM/EST/UFN modifiers).',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
raw: z.string().min(1).describe('Raw FAA domestic NOTAM string.'),
|
|
27
|
+
},
|
|
28
|
+
}, ({ raw }) => runParser(raw, parseFaaNotam, 'notam'));
|
|
29
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/procedures` SID/STAR lookup, filtering,
|
|
4
|
+
* and expansion methods, backed by the US NASR snapshot in
|
|
5
|
+
* `@squawk/procedure-data`.
|
|
6
|
+
*/
|
|
7
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
|
+
/**
|
|
9
|
+
* Registers SID/STAR procedure lookup tools on the given MCP server. Uses
|
|
10
|
+
* the shared {@link procedureResolver} built at module load time.
|
|
11
|
+
*
|
|
12
|
+
* @param server - The MCP server instance to register tools on.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerProcedureTools(server: McpServer): void;
|
|
15
|
+
//# sourceMappingURL=procedures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"procedures.d.ts","sourceRoot":"","sources":["../../src/tools/procedures.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgI9D"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* MCP tool module wrapping `@squawk/procedures` SID/STAR lookup, filtering,
|
|
4
|
+
* and expansion methods, backed by the US NASR snapshot in
|
|
5
|
+
* `@squawk/procedure-data`.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { procedureResolver } from '../resolvers.js';
|
|
9
|
+
/** All {@link ProcedureType} values, used for input validation. */
|
|
10
|
+
const PROCEDURE_TYPE_VALUES = ['SID', 'STAR'];
|
|
11
|
+
/**
|
|
12
|
+
* Registers SID/STAR procedure lookup tools on the given MCP server. Uses
|
|
13
|
+
* the shared {@link procedureResolver} built at module load time.
|
|
14
|
+
*
|
|
15
|
+
* @param server - The MCP server instance to register tools on.
|
|
16
|
+
*/
|
|
17
|
+
export function registerProcedureTools(server) {
|
|
18
|
+
server.registerTool('get_procedure_by_code', {
|
|
19
|
+
title: 'Get procedure by FAA computer code',
|
|
20
|
+
description: 'Looks up a US instrument procedure (SID or STAR) by its FAA computer code (e.g. "AALLE4", "ACCRA5"). Returns null when no match is found.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
computerCode: z
|
|
23
|
+
.string()
|
|
24
|
+
.min(1)
|
|
25
|
+
.describe('FAA computer code for the procedure (case-insensitive).'),
|
|
26
|
+
},
|
|
27
|
+
}, ({ computerCode }) => {
|
|
28
|
+
const procedure = procedureResolver.byName(computerCode);
|
|
29
|
+
if (procedure === undefined) {
|
|
30
|
+
return {
|
|
31
|
+
content: [
|
|
32
|
+
{ type: 'text', text: `No procedure found with computer code "${computerCode}".` },
|
|
33
|
+
],
|
|
34
|
+
structuredContent: { procedure: null },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: JSON.stringify(procedure, null, 2) }],
|
|
39
|
+
structuredContent: { procedure },
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
server.registerTool('find_procedures_by_airport', {
|
|
43
|
+
title: 'Find procedures associated with an airport',
|
|
44
|
+
description: 'Finds all US instrument procedures (SIDs and STARs) associated with a given airport identifier (FAA ID). Returns an empty array when no match is found.',
|
|
45
|
+
inputSchema: {
|
|
46
|
+
airportId: z.string().min(1).describe('Airport FAA identifier (case-insensitive).'),
|
|
47
|
+
},
|
|
48
|
+
}, ({ airportId }) => {
|
|
49
|
+
const procedures = procedureResolver.byAirport(airportId);
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: 'text', text: JSON.stringify(procedures, null, 2) }],
|
|
52
|
+
structuredContent: { procedures },
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
server.registerTool('expand_procedure', {
|
|
56
|
+
title: 'Expand a procedure into a waypoint sequence',
|
|
57
|
+
description: "Expands a procedure into an ordered waypoint sequence. Without a transition, returns the first common route. With a transition name, returns the matching transition's waypoints followed by the first common route's waypoints (with overlapping connecting fixes deduplicated). Returns null when the procedure or transition is not found.",
|
|
58
|
+
inputSchema: {
|
|
59
|
+
computerCode: z
|
|
60
|
+
.string()
|
|
61
|
+
.min(1)
|
|
62
|
+
.describe('FAA computer code for the procedure (case-insensitive).'),
|
|
63
|
+
transitionName: z
|
|
64
|
+
.string()
|
|
65
|
+
.min(1)
|
|
66
|
+
.optional()
|
|
67
|
+
.describe('Optional transition name (typically the entry/exit fix identifier, case-insensitive). Omit to use the first common route.'),
|
|
68
|
+
},
|
|
69
|
+
}, ({ computerCode, transitionName }) => {
|
|
70
|
+
const expansion = procedureResolver.expand(computerCode, transitionName);
|
|
71
|
+
if (expansion === undefined) {
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: 'text',
|
|
76
|
+
text: `Could not expand procedure "${computerCode}"${transitionName ? ` with transition "${transitionName}"` : ''}.`,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
structuredContent: { expansion: null },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: 'text', text: JSON.stringify(expansion, null, 2) }],
|
|
84
|
+
structuredContent: { expansion },
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
server.registerTool('search_procedures', {
|
|
88
|
+
title: 'Search procedures by name or code',
|
|
89
|
+
description: 'Searches US instrument procedures by case-insensitive substring matching against both the procedure name and computer code. Results are returned in alphabetical order by computer code.',
|
|
90
|
+
inputSchema: {
|
|
91
|
+
text: z
|
|
92
|
+
.string()
|
|
93
|
+
.min(1)
|
|
94
|
+
.describe('Substring to match against the procedure name or computer code.'),
|
|
95
|
+
procedureType: z
|
|
96
|
+
.enum(PROCEDURE_TYPE_VALUES)
|
|
97
|
+
.optional()
|
|
98
|
+
.describe('Restrict results to SIDs or STARs only. Omit to include both.'),
|
|
99
|
+
limit: z
|
|
100
|
+
.number()
|
|
101
|
+
.int()
|
|
102
|
+
.positive()
|
|
103
|
+
.optional()
|
|
104
|
+
.describe('Maximum number of results to return. Defaults to 20.'),
|
|
105
|
+
},
|
|
106
|
+
}, ({ text, procedureType, limit }) => {
|
|
107
|
+
const query = { text };
|
|
108
|
+
if (procedureType !== undefined) {
|
|
109
|
+
query.type = procedureType;
|
|
110
|
+
}
|
|
111
|
+
if (limit !== undefined) {
|
|
112
|
+
query.limit = limit;
|
|
113
|
+
}
|
|
114
|
+
const procedures = procedureResolver.search(query);
|
|
115
|
+
return {
|
|
116
|
+
content: [{ type: 'text', text: JSON.stringify(procedures, null, 2) }],
|
|
117
|
+
structuredContent: { procedures },
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
}
|