@squawk/mcp 0.8.12 → 0.9.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 +53 -5
- package/dist/resolvers.d.ts +50 -7
- package/dist/resolvers.d.ts.map +1 -1
- package/dist/resolvers.js +102 -8
- package/dist/tools/icao-registry.d.ts +6 -4
- package/dist/tools/icao-registry.d.ts.map +1 -1
- package/dist/tools/icao-registry.js +36 -15
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -98,7 +98,7 @@ version explicitly in the client config:
|
|
|
98
98
|
"mcpServers": {
|
|
99
99
|
"squawk": {
|
|
100
100
|
"command": "npx",
|
|
101
|
-
"args": ["-y", "@squawk/mcp@0.
|
|
101
|
+
"args": ["-y", "@squawk/mcp@0.9.0"]
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -130,6 +130,50 @@ again, or fall back to a pinned version. The host process itself also has to res
|
|
|
130
130
|
update to take effect, since each MCP server is a long-running stdio subprocess that loads its
|
|
131
131
|
code once at spawn time.
|
|
132
132
|
|
|
133
|
+
### Enabling the aircraft registry (optional peer)
|
|
134
|
+
|
|
135
|
+
`@squawk/icao-registry-data` is the largest snapshot in the suite (roughly 8 MB on disk after
|
|
136
|
+
gzip). Most sessions never need a tail-number lookup, so the package is declared as an optional
|
|
137
|
+
**peer dependency** of `@squawk/mcp` rather than a required dep - npm 7+ does not auto-install
|
|
138
|
+
optional peers, which keeps the default `npx @squawk/mcp` install lean.
|
|
139
|
+
|
|
140
|
+
When the data package is not installed, `lookup_aircraft_by_icao_hex` is still listed in the tool
|
|
141
|
+
catalog. The first invocation returns a structured `isError: true` result whose
|
|
142
|
+
`structuredContent.missingDataPackage.installCommand` field names the exact command to run; the
|
|
143
|
+
rest of the server keeps working normally. If you do not need aircraft lookups, no further action
|
|
144
|
+
is required.
|
|
145
|
+
|
|
146
|
+
To enable lookups, install the data package alongside `@squawk/mcp`. Through `npx` the cleanest
|
|
147
|
+
option is the `-p` flag, which adds extra packages to the temporary install npx builds:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"mcpServers": {
|
|
152
|
+
"squawk": {
|
|
153
|
+
"command": "npx",
|
|
154
|
+
"args": ["-y", "-p", "@squawk/icao-registry-data", "@squawk/mcp"]
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Pinning works the same way:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"mcpServers": {
|
|
165
|
+
"squawk": {
|
|
166
|
+
"command": "npx",
|
|
167
|
+
"args": ["-y", "-p", "@squawk/icao-registry-data@0.8.3", "@squawk/mcp@0.9.0"]
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
For non-`npx` setups (a local install, a global install, a Docker image), add
|
|
174
|
+
`@squawk/icao-registry-data` to the same dependency manifest that pulls in `@squawk/mcp` and the
|
|
175
|
+
runtime will resolve it through ordinary Node module resolution.
|
|
176
|
+
|
|
133
177
|
### Pinning a specific Node binary
|
|
134
178
|
|
|
135
179
|
`npx` resolves `node` through whatever PATH the host launches with. On macOS, GUI apps often
|
|
@@ -262,8 +306,11 @@ Covers SIDs, STARs, and Instrument Approach Procedures (IAPs) from FAA CIFP.
|
|
|
262
306
|
| ----------------------------- | ------------------------------------------------------------- |
|
|
263
307
|
| `lookup_aircraft_by_icao_hex` | Resolve a 24-bit ICAO hex address to an aircraft registration |
|
|
264
308
|
|
|
265
|
-
|
|
266
|
-
|
|
309
|
+
`@squawk/icao-registry-data` is an optional peer dependency. Default installs of `@squawk/mcp` do
|
|
310
|
+
not include it; the tool reports a structured "data not installed" error with the exact install
|
|
311
|
+
command until the peer is added. See [Enabling the aircraft registry](#enabling-the-aircraft-registry-optional-peer)
|
|
312
|
+
for how to add it. Once present, the registry (~40 MB raw) is decompressed lazily on the first
|
|
313
|
+
lookup so sessions that never need it do not pay the cost.
|
|
267
314
|
|
|
268
315
|
### Weather (`@squawk/weather` + `@squawk/weather/fetch`)
|
|
269
316
|
|
|
@@ -351,5 +398,6 @@ left to the model itself.
|
|
|
351
398
|
override above). They are the only tools that touch the network at invocation time; everything
|
|
352
399
|
else operates against bundled snapshots in memory.
|
|
353
400
|
- The bundled snapshots are decompressed and indexed once when the server starts. Expect a few
|
|
354
|
-
hundred milliseconds of startup time. The aircraft registration snapshot (the largest
|
|
355
|
-
lazily on the first `lookup_aircraft_by_icao_hex` call
|
|
401
|
+
hundred milliseconds of startup time. The aircraft registration snapshot (the largest, and an
|
|
402
|
+
optional peer dependency) is decompressed lazily on the first `lookup_aircraft_by_icao_hex` call,
|
|
403
|
+
if the package is installed.
|
package/dist/resolvers.d.ts
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
* resolver is constructed once at module load time so the bundled FAA data
|
|
5
5
|
* snapshots are decoded and indexed exactly once per server process.
|
|
6
6
|
*
|
|
7
|
-
* The ICAO registry is the only resolver that loads lazily
|
|
8
|
-
* package
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* The ICAO registry is the only resolver that loads lazily, and its data
|
|
8
|
+
* package (`@squawk/icao-registry-data`) is declared as an optional peer
|
|
9
|
+
* dependency rather than a required dep. The registry is built on the first
|
|
10
|
+
* {@link getIcaoRegistry} call (decompressing ~40 MB on first access) and
|
|
11
|
+
* cached for subsequent calls. When the peer is not installed, the import
|
|
12
|
+
* throws `ERR_MODULE_NOT_FOUND` and {@link getIcaoRegistry} surfaces a
|
|
13
|
+
* {@link MissingDataPackageError} for the tool handler to format.
|
|
11
14
|
*/
|
|
12
15
|
import { type AirportResolver } from '@squawk/airports';
|
|
13
16
|
import { type AirspaceResolver } from '@squawk/airspace';
|
|
@@ -28,18 +31,57 @@ export declare const fixResolver: FixResolver;
|
|
|
28
31
|
export declare const navaidResolver: NavaidResolver;
|
|
29
32
|
/** Eagerly-built procedure resolver backed by the US NASR snapshot. */
|
|
30
33
|
export declare const procedureResolver: ProcedureResolver;
|
|
34
|
+
/**
|
|
35
|
+
* Error thrown when a tool tries to load an optional data package peer that
|
|
36
|
+
* has not been installed alongside `@squawk/mcp`. Tool handlers catch this
|
|
37
|
+
* and surface the install command to the MCP client so the user can resolve
|
|
38
|
+
* the missing dependency without inspecting the server logs.
|
|
39
|
+
*/
|
|
40
|
+
export declare class MissingDataPackageError extends Error {
|
|
41
|
+
/** Short dataset name shown to users (e.g. `"icao-registry"`). */
|
|
42
|
+
readonly datasetName: string;
|
|
43
|
+
/** npm package name the user must install (e.g. `"@squawk/icao-registry-data"`). */
|
|
44
|
+
readonly packageName: string;
|
|
45
|
+
/** Suggested install command, e.g. `"npm install @squawk/icao-registry-data"`. */
|
|
46
|
+
readonly installCommand: string;
|
|
47
|
+
/**
|
|
48
|
+
* Constructs a new error describing a missing optional data peer.
|
|
49
|
+
*
|
|
50
|
+
* @param datasetName - Short dataset name for the user-facing message.
|
|
51
|
+
* @param packageName - npm package name that needs to be installed.
|
|
52
|
+
*/
|
|
53
|
+
constructor(datasetName: string, packageName: string);
|
|
54
|
+
}
|
|
55
|
+
/** Loader signature for the optional `@squawk/icao-registry-data` peer. */
|
|
56
|
+
type IcaoRegistryDataLoader = () => Promise<typeof import('@squawk/icao-registry-data')>;
|
|
31
57
|
/**
|
|
32
58
|
* Returns the shared {@link IcaoRegistry} instance, decompressing and indexing
|
|
33
59
|
* the bundled FAA aircraft registration snapshot on the first call. Subsequent
|
|
34
60
|
* calls reuse the cached instance.
|
|
35
61
|
*
|
|
36
|
-
* The registry is initialized lazily because the underlying
|
|
37
|
-
*
|
|
38
|
-
*
|
|
62
|
+
* The registry is initialized lazily because the underlying data package is
|
|
63
|
+
* the largest snapshot in the suite (roughly 40 MB raw) and is declared as an
|
|
64
|
+
* optional peer dependency rather than a required dep. Sessions that never
|
|
65
|
+
* look up an aircraft by ICAO hex avoid the cost entirely, and consumers who
|
|
66
|
+
* never install the peer see only the structured missing-package error
|
|
67
|
+
* surfaced by the tool handler.
|
|
39
68
|
*
|
|
40
69
|
* @returns The shared registry instance.
|
|
70
|
+
* @throws {MissingDataPackageError} when `@squawk/icao-registry-data` is not
|
|
71
|
+
* installed alongside `@squawk/mcp`.
|
|
41
72
|
*/
|
|
42
73
|
export declare function getIcaoRegistry(): Promise<IcaoRegistry>;
|
|
74
|
+
/**
|
|
75
|
+
* @internal
|
|
76
|
+
*
|
|
77
|
+
* Test-only seam for swapping the optional data package loader. Production
|
|
78
|
+
* code must not call this. Pass `undefined` to restore the default loader
|
|
79
|
+
* and clear all cached state (instance, metadata, and the missing-peer
|
|
80
|
+
* sticky flag) so subsequent tests start from a clean slate.
|
|
81
|
+
*
|
|
82
|
+
* @param loader - Replacement loader, or `undefined` to reset.
|
|
83
|
+
*/
|
|
84
|
+
export declare function __setIcaoRegistryDataLoaderForTest(loader: IcaoRegistryDataLoader | undefined): void;
|
|
43
85
|
/**
|
|
44
86
|
* Reports whether the lazily-loaded ICAO aircraft registry has been
|
|
45
87
|
* initialized in this process.
|
|
@@ -57,4 +99,5 @@ export declare function getIcaoRegistryMetadata(): {
|
|
|
57
99
|
generatedAt: string;
|
|
58
100
|
recordCount: number;
|
|
59
101
|
} | undefined;
|
|
102
|
+
export {};
|
|
60
103
|
//# sourceMappingURL=resolvers.d.ts.map
|
package/dist/resolvers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../src/resolvers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../src/resolvers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGjF,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE5E,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE9E,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE5E,OAAO,EAA2B,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAErF,qEAAqE;AACrE,eAAO,MAAM,eAAe,EAAE,eAE5B,CAAC;AAEH,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,EAAE,gBAE7B,CAAC;AAEH,oEAAoE;AACpE,eAAO,MAAM,cAAc,EAAE,cAE3B,CAAC;AAEH,iEAAiE;AACjE,eAAO,MAAM,WAAW,EAAE,WAAiE,CAAC;AAE5F,oEAAoE;AACpE,eAAO,MAAM,cAAc,EAAE,cAE3B,CAAC;AAEH,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,EAAE,iBAE9B,CAAC;AAEH;;;;;GAKG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,kEAAkE;IAClE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kFAAkF;IAClF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC;;;;;OAKG;gBACS,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAQrD;AAoBD,2EAA2E;AAC3E,KAAK,sBAAsB,GAAG,MAAM,OAAO,CAAC,cAAc,4BAA4B,CAAC,CAAC,CAAC;AA2BzF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAuB7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,sBAAsB,GAAG,SAAS,GACzC,IAAI,CAKN;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,IACnC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC5C,SAAS,CAEZ"}
|
package/dist/resolvers.js
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
* resolver is constructed once at module load time so the bundled FAA data
|
|
5
5
|
* snapshots are decoded and indexed exactly once per server process.
|
|
6
6
|
*
|
|
7
|
-
* The ICAO registry is the only resolver that loads lazily
|
|
8
|
-
* package
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* The ICAO registry is the only resolver that loads lazily, and its data
|
|
8
|
+
* package (`@squawk/icao-registry-data`) is declared as an optional peer
|
|
9
|
+
* dependency rather than a required dep. The registry is built on the first
|
|
10
|
+
* {@link getIcaoRegistry} call (decompressing ~40 MB on first access) and
|
|
11
|
+
* cached for subsequent calls. When the peer is not installed, the import
|
|
12
|
+
* throws `ERR_MODULE_NOT_FOUND` and {@link getIcaoRegistry} surfaces a
|
|
13
|
+
* {@link MissingDataPackageError} for the tool handler to format.
|
|
11
14
|
*/
|
|
12
15
|
import { usBundledAirports } from '@squawk/airport-data';
|
|
13
16
|
import { createAirportResolver } from '@squawk/airports';
|
|
@@ -44,6 +47,34 @@ export const navaidResolver = createNavaidResolver({
|
|
|
44
47
|
export const procedureResolver = createProcedureResolver({
|
|
45
48
|
data: usBundledProcedures.records,
|
|
46
49
|
});
|
|
50
|
+
/**
|
|
51
|
+
* Error thrown when a tool tries to load an optional data package peer that
|
|
52
|
+
* has not been installed alongside `@squawk/mcp`. Tool handlers catch this
|
|
53
|
+
* and surface the install command to the MCP client so the user can resolve
|
|
54
|
+
* the missing dependency without inspecting the server logs.
|
|
55
|
+
*/
|
|
56
|
+
export class MissingDataPackageError extends Error {
|
|
57
|
+
/** Short dataset name shown to users (e.g. `"icao-registry"`). */
|
|
58
|
+
datasetName;
|
|
59
|
+
/** npm package name the user must install (e.g. `"@squawk/icao-registry-data"`). */
|
|
60
|
+
packageName;
|
|
61
|
+
/** Suggested install command, e.g. `"npm install @squawk/icao-registry-data"`. */
|
|
62
|
+
installCommand;
|
|
63
|
+
/**
|
|
64
|
+
* Constructs a new error describing a missing optional data peer.
|
|
65
|
+
*
|
|
66
|
+
* @param datasetName - Short dataset name for the user-facing message.
|
|
67
|
+
* @param packageName - npm package name that needs to be installed.
|
|
68
|
+
*/
|
|
69
|
+
constructor(datasetName, packageName) {
|
|
70
|
+
const installCommand = `npm install ${packageName}`;
|
|
71
|
+
super(`${datasetName} data is not installed. Run: ${installCommand}`);
|
|
72
|
+
this.name = 'MissingDataPackageError';
|
|
73
|
+
this.datasetName = datasetName;
|
|
74
|
+
this.packageName = packageName;
|
|
75
|
+
this.installCommand = installCommand;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
47
78
|
/** Cached ICAO registry instance, populated on the first {@link getIcaoRegistry} call. */
|
|
48
79
|
let icaoRegistryInstance;
|
|
49
80
|
/**
|
|
@@ -52,20 +83,67 @@ let icaoRegistryInstance;
|
|
|
52
83
|
* can return it without forcing another import.
|
|
53
84
|
*/
|
|
54
85
|
let icaoRegistryMetadata;
|
|
86
|
+
/**
|
|
87
|
+
* Sticky flag set once the optional `@squawk/icao-registry-data` peer is
|
|
88
|
+
* confirmed missing. Subsequent {@link getIcaoRegistry} calls short-circuit
|
|
89
|
+
* to a {@link MissingDataPackageError} without retrying the import; running
|
|
90
|
+
* `npm install` while the server is live is not a supported workflow.
|
|
91
|
+
*/
|
|
92
|
+
let icaoRegistryMissing = false;
|
|
93
|
+
/** Default loader: a dynamic import of the actual peer package. */
|
|
94
|
+
const defaultIcaoRegistryDataLoader = () => import('@squawk/icao-registry-data');
|
|
95
|
+
/**
|
|
96
|
+
* Active loader used by {@link getIcaoRegistry}. Replaceable in tests via
|
|
97
|
+
* {@link __setIcaoRegistryDataLoaderForTest} so the missing-peer code path
|
|
98
|
+
* can be exercised without uninstalling the workspace-symlinked package.
|
|
99
|
+
*/
|
|
100
|
+
let icaoRegistryDataLoader = defaultIcaoRegistryDataLoader;
|
|
101
|
+
/**
|
|
102
|
+
* Returns `true` when the given thrown value is Node's
|
|
103
|
+
* `ERR_MODULE_NOT_FOUND`, which the ESM loader raises both when the package
|
|
104
|
+
* specifier cannot be resolved and when a transitive resolution within the
|
|
105
|
+
* package fails. The latter is rare but should still surface as the missing-
|
|
106
|
+
* peer error so the user gets a single actionable message.
|
|
107
|
+
*
|
|
108
|
+
* @param err - The value caught from a dynamic import.
|
|
109
|
+
* @returns `true` when the value is an `ERR_MODULE_NOT_FOUND` error.
|
|
110
|
+
*/
|
|
111
|
+
function isModuleNotFoundError(err) {
|
|
112
|
+
return err instanceof Error && 'code' in err && err.code === 'ERR_MODULE_NOT_FOUND';
|
|
113
|
+
}
|
|
55
114
|
/**
|
|
56
115
|
* Returns the shared {@link IcaoRegistry} instance, decompressing and indexing
|
|
57
116
|
* the bundled FAA aircraft registration snapshot on the first call. Subsequent
|
|
58
117
|
* calls reuse the cached instance.
|
|
59
118
|
*
|
|
60
|
-
* The registry is initialized lazily because the underlying
|
|
61
|
-
*
|
|
62
|
-
*
|
|
119
|
+
* The registry is initialized lazily because the underlying data package is
|
|
120
|
+
* the largest snapshot in the suite (roughly 40 MB raw) and is declared as an
|
|
121
|
+
* optional peer dependency rather than a required dep. Sessions that never
|
|
122
|
+
* look up an aircraft by ICAO hex avoid the cost entirely, and consumers who
|
|
123
|
+
* never install the peer see only the structured missing-package error
|
|
124
|
+
* surfaced by the tool handler.
|
|
63
125
|
*
|
|
64
126
|
* @returns The shared registry instance.
|
|
127
|
+
* @throws {MissingDataPackageError} when `@squawk/icao-registry-data` is not
|
|
128
|
+
* installed alongside `@squawk/mcp`.
|
|
65
129
|
*/
|
|
66
130
|
export async function getIcaoRegistry() {
|
|
131
|
+
if (icaoRegistryMissing) {
|
|
132
|
+
throw new MissingDataPackageError('icao-registry', '@squawk/icao-registry-data');
|
|
133
|
+
}
|
|
67
134
|
if (icaoRegistryInstance === undefined) {
|
|
68
|
-
|
|
135
|
+
let registryDataModule;
|
|
136
|
+
try {
|
|
137
|
+
registryDataModule = await icaoRegistryDataLoader();
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
if (isModuleNotFoundError(err)) {
|
|
141
|
+
icaoRegistryMissing = true;
|
|
142
|
+
throw new MissingDataPackageError('icao-registry', '@squawk/icao-registry-data');
|
|
143
|
+
}
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
const { usBundledRegistry } = registryDataModule;
|
|
69
147
|
icaoRegistryInstance = createIcaoRegistry({ data: usBundledRegistry.records });
|
|
70
148
|
icaoRegistryMetadata = {
|
|
71
149
|
generatedAt: usBundledRegistry.properties.generatedAt,
|
|
@@ -74,6 +152,22 @@ export async function getIcaoRegistry() {
|
|
|
74
152
|
}
|
|
75
153
|
return icaoRegistryInstance;
|
|
76
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* @internal
|
|
157
|
+
*
|
|
158
|
+
* Test-only seam for swapping the optional data package loader. Production
|
|
159
|
+
* code must not call this. Pass `undefined` to restore the default loader
|
|
160
|
+
* and clear all cached state (instance, metadata, and the missing-peer
|
|
161
|
+
* sticky flag) so subsequent tests start from a clean slate.
|
|
162
|
+
*
|
|
163
|
+
* @param loader - Replacement loader, or `undefined` to reset.
|
|
164
|
+
*/
|
|
165
|
+
export function __setIcaoRegistryDataLoaderForTest(loader) {
|
|
166
|
+
icaoRegistryDataLoader = loader ?? defaultIcaoRegistryDataLoader;
|
|
167
|
+
icaoRegistryInstance = undefined;
|
|
168
|
+
icaoRegistryMetadata = undefined;
|
|
169
|
+
icaoRegistryMissing = false;
|
|
170
|
+
}
|
|
77
171
|
/**
|
|
78
172
|
* Reports whether the lazily-loaded ICAO aircraft registry has been
|
|
79
173
|
* initialized in this process.
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* lookup, backed by the FAA ReleasableAircraft snapshot in
|
|
5
5
|
* `@squawk/icao-registry-data`.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* The registry data package is an **optional peer dependency** of
|
|
8
|
+
* `@squawk/mcp`. The tool is always registered with the MCP server so it
|
|
9
|
+
* appears in the catalog, but the data is loaded lazily on the first tool
|
|
10
|
+
* invocation through {@link getIcaoRegistry}. When the peer is not installed
|
|
11
|
+
* the tool returns a structured `isError: true` result naming the package and
|
|
12
|
+
* the install command, rather than crashing the server.
|
|
11
13
|
*/
|
|
12
14
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icao-registry.d.ts","sourceRoot":"","sources":["../../src/tools/icao-registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"icao-registry.d.ts","sourceRoot":"","sources":["../../src/tools/icao-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQzE;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+CjE"}
|
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
* lookup, backed by the FAA ReleasableAircraft snapshot in
|
|
5
5
|
* `@squawk/icao-registry-data`.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* The registry data package is an **optional peer dependency** of
|
|
8
|
+
* `@squawk/mcp`. The tool is always registered with the MCP server so it
|
|
9
|
+
* appears in the catalog, but the data is loaded lazily on the first tool
|
|
10
|
+
* invocation through {@link getIcaoRegistry}. When the peer is not installed
|
|
11
|
+
* the tool returns a structured `isError: true` result naming the package and
|
|
12
|
+
* the install command, rather than crashing the server.
|
|
11
13
|
*/
|
|
12
14
|
import { z } from 'zod';
|
|
13
|
-
import { getIcaoRegistry } from '../resolvers.js';
|
|
15
|
+
import { MissingDataPackageError, getIcaoRegistry } from '../resolvers.js';
|
|
14
16
|
/** Pattern matching a valid 24-bit ICAO hex address (1-6 hex digits). */
|
|
15
17
|
const ICAO_HEX_PATTERN = /^[0-9A-Fa-f]{1,6}$/;
|
|
16
18
|
/**
|
|
@@ -21,7 +23,7 @@ const ICAO_HEX_PATTERN = /^[0-9A-Fa-f]{1,6}$/;
|
|
|
21
23
|
export function registerIcaoRegistryTools(server) {
|
|
22
24
|
server.registerTool('lookup_aircraft_by_icao_hex', {
|
|
23
25
|
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.',
|
|
26
|
+
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. Backed by `@squawk/icao-registry-data`, which is an optional peer dependency of `@squawk/mcp`; if the package is not installed the tool returns an actionable error including the install command. The first successful call may take a few hundred milliseconds while the bundled FAA registration snapshot decompresses.',
|
|
25
27
|
inputSchema: {
|
|
26
28
|
icaoHex: z
|
|
27
29
|
.string()
|
|
@@ -29,17 +31,36 @@ export function registerIcaoRegistryTools(server) {
|
|
|
29
31
|
.describe('24-bit ICAO hex address (1-6 hex digits, case-insensitive).'),
|
|
30
32
|
},
|
|
31
33
|
}, async ({ icaoHex }) => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
try {
|
|
35
|
+
const registry = await getIcaoRegistry();
|
|
36
|
+
const aircraft = registry.lookup(icaoHex);
|
|
37
|
+
if (aircraft === undefined) {
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: 'text', text: `No aircraft found for ICAO hex "${icaoHex}".` }],
|
|
40
|
+
structuredContent: { aircraft: null },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
35
43
|
return {
|
|
36
|
-
content: [{ type: 'text', text:
|
|
37
|
-
structuredContent: { aircraft
|
|
44
|
+
content: [{ type: 'text', text: JSON.stringify(aircraft, null, 2) }],
|
|
45
|
+
structuredContent: { aircraft },
|
|
38
46
|
};
|
|
39
47
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (err instanceof MissingDataPackageError) {
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: 'text', text: err.message }],
|
|
52
|
+
structuredContent: {
|
|
53
|
+
aircraft: null,
|
|
54
|
+
missingDataPackage: {
|
|
55
|
+
datasetName: err.datasetName,
|
|
56
|
+
packageName: err.packageName,
|
|
57
|
+
installCommand: err.installCommand,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
44
65
|
});
|
|
45
66
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squawk/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Model Context Protocol server exposing squawk's aviation libraries as tools for LLM clients",
|
|
6
6
|
"author": "Neil Cochran",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
42
42
|
"@squawk/airport-data": "^0.7.3",
|
|
43
43
|
"@squawk/airports": "^0.6.1",
|
|
44
|
-
"@squawk/airspace": "^0.
|
|
44
|
+
"@squawk/airspace": "^0.8.0",
|
|
45
45
|
"@squawk/airspace-data": "^0.5.2",
|
|
46
46
|
"@squawk/airway-data": "^0.5.3",
|
|
47
47
|
"@squawk/airways": "^0.4.1",
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"@squawk/flightplan": "^0.5.1",
|
|
52
52
|
"@squawk/geo": "^0.4.3",
|
|
53
53
|
"@squawk/icao-registry": "^0.5.1",
|
|
54
|
-
"@squawk/icao-registry-data": "^0.8.3",
|
|
55
54
|
"@squawk/navaid-data": "^0.6.3",
|
|
56
55
|
"@squawk/navaids": "^0.4.1",
|
|
57
56
|
"@squawk/notams": "^0.3.5",
|
|
@@ -61,7 +60,16 @@
|
|
|
61
60
|
"@squawk/weather": "^0.5.5",
|
|
62
61
|
"zod": "^4.4.3"
|
|
63
62
|
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@squawk/icao-registry-data": "^0.8.3"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"@squawk/icao-registry-data": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
64
71
|
"devDependencies": {
|
|
72
|
+
"@squawk/icao-registry-data": "^0.8.3",
|
|
65
73
|
"@types/node": "^25.6.0"
|
|
66
74
|
},
|
|
67
75
|
"keywords": [
|