@squawk/mcp 0.11.0 → 0.12.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 +87 -11
- package/dist/bin.js +25 -8
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/resolvers.d.ts.map +1 -1
- package/dist/server.d.ts +27 -9
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +49 -32
- package/dist/tool-groups.d.ts +95 -0
- package/dist/tool-groups.d.ts.map +1 -0
- package/dist/tool-groups.js +190 -0
- package/package.json +24 -24
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.12.0"]
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -164,7 +164,7 @@ Pinning works the same way:
|
|
|
164
164
|
"mcpServers": {
|
|
165
165
|
"squawk": {
|
|
166
166
|
"command": "npx",
|
|
167
|
-
"args": ["-y", "-p", "@squawk/icao-registry-data@0.8.
|
|
167
|
+
"args": ["-y", "-p", "@squawk/icao-registry-data@0.8.12", "@squawk/mcp@0.12.0"]
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
}
|
|
@@ -193,8 +193,8 @@ the absolute path to a modern node + the absolute path to the installed `bin.js`
|
|
|
193
193
|
}
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
The server logs `[squawk-mcp] node <version> on <platform>/<arch>` and
|
|
197
|
-
to stderr on every startup so you can verify the right runtime is being used.
|
|
196
|
+
The server logs `[squawk-mcp] node <version> on <platform>/<arch>` and how many tool groups
|
|
197
|
+
registered to stderr on every startup so you can verify the right runtime is being used.
|
|
198
198
|
|
|
199
199
|
### Example prompts
|
|
200
200
|
|
|
@@ -226,6 +226,17 @@ const server = createSquawkMcpServer();
|
|
|
226
226
|
await server.connect(new StdioServerTransport());
|
|
227
227
|
```
|
|
228
228
|
|
|
229
|
+
Pass `toolGroups` to register part of the catalog. An explicit list takes precedence over
|
|
230
|
+
the environment variables described under [Configuration](#configuration); omit the option
|
|
231
|
+
entirely to honor them. `TOOL_GROUP_NAMES` holds every valid group name, and an unknown one
|
|
232
|
+
throws a `ToolGroupConfigError`.
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import { createSquawkMcpServer, TOOL_GROUP_NAMES } from '@squawk/mcp';
|
|
236
|
+
|
|
237
|
+
const server = createSquawkMcpServer({ toolGroups: ['airports', 'navaids', 'geo'] });
|
|
238
|
+
```
|
|
239
|
+
|
|
229
240
|
## Tool catalog
|
|
230
241
|
|
|
231
242
|
Tools are grouped by domain. Every tool returns both a human-readable text block and a structured
|
|
@@ -390,9 +401,74 @@ left to the model itself.
|
|
|
390
401
|
|
|
391
402
|
## Configuration
|
|
392
403
|
|
|
393
|
-
| Environment variable
|
|
394
|
-
|
|
|
395
|
-
| `
|
|
404
|
+
| Environment variable | Effect |
|
|
405
|
+
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
406
|
+
| `SQUAWK_MCP_TOOLS` | Register only the named tool groups. See [Choosing which tools to register](#choosing-which-tools-to-register). |
|
|
407
|
+
| `SQUAWK_MCP_DISABLE_TOOLS` | Register every tool group except the named ones. Mutually exclusive with `SQUAWK_MCP_TOOLS`. |
|
|
408
|
+
| `SQUAWK_AWC_BASE_URL` | Override the Aviation Weather Center base URL used by every `fetch_*` tool. Defaults to `https://aviationweather.gov/api/data`. Useful for proxies and regional mirrors. |
|
|
409
|
+
|
|
410
|
+
### Choosing which tools to register
|
|
411
|
+
|
|
412
|
+
The full catalog is 79 tools, which costs roughly 18k tokens of context in every session
|
|
413
|
+
before you ask anything. If you only reach for part of it, register only that part and the
|
|
414
|
+
rest never reaches your client.
|
|
415
|
+
|
|
416
|
+
Each tool group is one row below. Set `SQUAWK_MCP_TOOLS` to the groups you want, or
|
|
417
|
+
`SQUAWK_MCP_DISABLE_TOOLS` to the groups you do not. With neither set, every group is
|
|
418
|
+
registered.
|
|
419
|
+
|
|
420
|
+
| Group | Tools | ~Tokens |
|
|
421
|
+
| --------------- | ----: | ------: |
|
|
422
|
+
| `geo` | 5 | 1,100 |
|
|
423
|
+
| `flight-math` | 24 | 5,300 |
|
|
424
|
+
| `airports` | 4 | 900 |
|
|
425
|
+
| `airspace` | 5 | 1,700 |
|
|
426
|
+
| `navaids` | 5 | 1,300 |
|
|
427
|
+
| `fixes` | 4 | 1,000 |
|
|
428
|
+
| `airways` | 4 | 800 |
|
|
429
|
+
| `procedures` | 8 | 1,900 |
|
|
430
|
+
| `icao-registry` | 1 | 250 |
|
|
431
|
+
| `weather` | 12 | 2,100 |
|
|
432
|
+
| `notams` | 2 | 300 |
|
|
433
|
+
| `flightplan` | 4 | 1,400 |
|
|
434
|
+
| `datasets` | 1 | 180 |
|
|
435
|
+
|
|
436
|
+
A VFR pilot who wants airport, navaid, and fix lookups plus a distance calculator:
|
|
437
|
+
|
|
438
|
+
```json
|
|
439
|
+
{
|
|
440
|
+
"mcpServers": {
|
|
441
|
+
"squawk": {
|
|
442
|
+
"command": "npx",
|
|
443
|
+
"args": ["-y", "@squawk/mcp"],
|
|
444
|
+
"env": { "SQUAWK_MCP_TOOLS": "airports,navaids,fixes,geo" }
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
That registers 18 tools for roughly 4.3k tokens, down from 79 and 18k. Dropping just
|
|
451
|
+
`flight-math` and `weather` - the two largest groups - takes the catalog to 43 tools and
|
|
452
|
+
roughly 11k tokens while leaving every lookup tool in place.
|
|
453
|
+
|
|
454
|
+
Names are case-insensitive and whitespace around them is ignored. The server refuses to
|
|
455
|
+
start, with an explanation on stderr, when a group name is unrecognized, when both
|
|
456
|
+
variables are set, or when the result would leave it with no tools at all. Check your
|
|
457
|
+
host's MCP log if the server fails to come up after a config change; the startup
|
|
458
|
+
diagnostic also reports how many groups registered and names the ones that did not.
|
|
459
|
+
|
|
460
|
+
Two things worth knowing before you trim:
|
|
461
|
+
|
|
462
|
+
- **`datasets` is a group like any other.** It holds `get_dataset_status`, the tool that
|
|
463
|
+
reports which NASR and CIFP cycles the running server is serving. An allowlist that
|
|
464
|
+
leaves it out means you can no longer ask how current the data is, so include it unless
|
|
465
|
+
you are sure you do not want it. It is the cheapest group in the catalog.
|
|
466
|
+
- **Groups gate the catalog, not the data.** The bundled snapshots are loaded and indexed
|
|
467
|
+
at startup no matter which groups you register, so trimming the catalog does not reduce
|
|
468
|
+
the server's startup time or memory use. It also means a group you kept keeps working
|
|
469
|
+
even when it reads data belonging to a group you dropped - `flightplan` still resolves
|
|
470
|
+
airports and navaids in a route string with `airports` and `navaids` disabled, because
|
|
471
|
+
you disabled those tools, not that data.
|
|
396
472
|
|
|
397
473
|
## Notes
|
|
398
474
|
|
|
@@ -403,7 +479,7 @@ left to the model itself.
|
|
|
403
479
|
- Live weather tools issue HTTPS requests to `https://aviationweather.gov/api/data/...` (or the
|
|
404
480
|
override above). They are the only tools that touch the network at invocation time; everything
|
|
405
481
|
else operates against bundled snapshots in memory.
|
|
406
|
-
- The bundled snapshots are decompressed and indexed once when the server starts
|
|
407
|
-
|
|
408
|
-
optional peer dependency) is decompressed lazily on
|
|
409
|
-
if the package is installed.
|
|
482
|
+
- The bundled snapshots are decompressed and indexed once when the server starts, which takes on
|
|
483
|
+
the order of a second and is unaffected by which tool groups you register. The aircraft
|
|
484
|
+
registration snapshot (the largest, and an optional peer dependency) is decompressed lazily on
|
|
485
|
+
the first `lookup_aircraft_by_icao_hex` call, if the package is installed.
|
package/dist/bin.js
CHANGED
|
@@ -8,21 +8,31 @@
|
|
|
8
8
|
* All logs go to stderr; stdout is reserved for MCP protocol messages.
|
|
9
9
|
*/
|
|
10
10
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
11
|
-
import { createSquawkMcpServer, PACKAGE_NAME, PACKAGE_VERSION
|
|
11
|
+
import { createSquawkMcpServer, PACKAGE_NAME, PACKAGE_VERSION } from './server.js';
|
|
12
|
+
import { TOOL_GROUP_NAMES, resolveToolGroupsFromEnv } from './tool-groups.js';
|
|
12
13
|
/**
|
|
13
14
|
* Logs the Node.js version this process is running on, the running build's
|
|
14
|
-
* package version,
|
|
15
|
-
* missing capabilities the live weather fetch tools require.
|
|
15
|
+
* package version, which tool groups ended up registered, and warns when the
|
|
16
|
+
* environment is missing capabilities the live weather fetch tools require.
|
|
16
17
|
*
|
|
17
18
|
* GUI MCP hosts (Claude Desktop, etc.) often launch child processes with a
|
|
18
19
|
* different PATH than the user's interactive shell, so `node` may resolve to
|
|
19
20
|
* an older binary than `which node` suggests. Surfacing the actual runtime
|
|
20
21
|
* version and the running package version up front makes mismatches easy to
|
|
21
|
-
* diagnose from the host's MCP log without bisecting tool failures.
|
|
22
|
+
* diagnose from the host's MCP log without bisecting tool failures. Naming the
|
|
23
|
+
* disabled groups does the same for a mistyped tool-group variable, which
|
|
24
|
+
* otherwise shows up only as tools the model never calls.
|
|
25
|
+
*
|
|
26
|
+
* @param enabledGroups - Tool groups the server is about to register.
|
|
22
27
|
*/
|
|
23
|
-
function logRuntimeDiagnostics() {
|
|
28
|
+
function logRuntimeDiagnostics(enabledGroups) {
|
|
24
29
|
console.error(`[squawk-mcp] node ${process.version} on ${process.platform}/${process.arch}`);
|
|
25
|
-
console.error(`[squawk-mcp] ${PACKAGE_NAME} v${PACKAGE_VERSION},
|
|
30
|
+
console.error(`[squawk-mcp] ${PACKAGE_NAME} v${PACKAGE_VERSION}, ` +
|
|
31
|
+
`${enabledGroups.length}/${TOOL_GROUP_NAMES.length} tool groups registered`);
|
|
32
|
+
const disabled = TOOL_GROUP_NAMES.filter((name) => !enabledGroups.includes(name));
|
|
33
|
+
if (disabled.length > 0) {
|
|
34
|
+
console.error(`[squawk-mcp] disabled tool groups: ${disabled.join(', ')}`);
|
|
35
|
+
}
|
|
26
36
|
if (typeof fetch !== 'function') {
|
|
27
37
|
console.error('[squawk-mcp] WARNING: global fetch() is unavailable in this Node runtime. ' +
|
|
28
38
|
'Live weather fetch_* tools will fail. Upgrade to Node >=22, or pin an ' +
|
|
@@ -30,12 +40,19 @@ function logRuntimeDiagnostics() {
|
|
|
30
40
|
}
|
|
31
41
|
}
|
|
32
42
|
async function main() {
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
const resolution = resolveToolGroupsFromEnv(process.env);
|
|
44
|
+
if (!resolution.ok) {
|
|
45
|
+
console.error(`[squawk-mcp] configuration error: ${resolution.error}`);
|
|
46
|
+
// eslint-disable-next-line n/no-process-exit -- serving a catalog the user did not ask for is worse than refusing to start; the host surfaces this line in its MCP log.
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
logRuntimeDiagnostics(resolution.toolGroups);
|
|
50
|
+
const server = createSquawkMcpServer({ toolGroups: resolution.toolGroups });
|
|
35
51
|
const transport = new StdioServerTransport();
|
|
36
52
|
await server.connect(transport);
|
|
37
53
|
}
|
|
38
54
|
main().catch((err) => {
|
|
39
55
|
console.error('[squawk-mcp] fatal error:', err);
|
|
56
|
+
// eslint-disable-next-line n/no-process-exit -- a failed stdio connect can leave the transport holding stdin; exiting beats hanging the host that spawned us.
|
|
40
57
|
process.exit(1);
|
|
41
58
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,15 @@
|
|
|
19
19
|
* const server = createSquawkMcpServer();
|
|
20
20
|
* await server.connect(new StdioServerTransport());
|
|
21
21
|
* ```
|
|
22
|
+
*
|
|
23
|
+
* Pass `toolGroups` to register only part of the catalog:
|
|
24
|
+
*
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const server = createSquawkMcpServer({ toolGroups: ['airports', 'navaids', 'geo'] });
|
|
27
|
+
* ```
|
|
22
28
|
*/
|
|
23
29
|
export { createSquawkMcpServer } from './server.js';
|
|
30
|
+
export { TOOL_GROUP_NAMES, ToolGroupConfigError } from './tool-groups.js';
|
|
31
|
+
export type { CreateSquawkMcpServerOptions } from './server.js';
|
|
32
|
+
export type { ToolGroupName } from './tool-groups.js';
|
|
24
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,YAAY,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAChE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -19,5 +19,12 @@
|
|
|
19
19
|
* const server = createSquawkMcpServer();
|
|
20
20
|
* await server.connect(new StdioServerTransport());
|
|
21
21
|
* ```
|
|
22
|
+
*
|
|
23
|
+
* Pass `toolGroups` to register only part of the catalog:
|
|
24
|
+
*
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const server = createSquawkMcpServer({ toolGroups: ['airports', 'navaids', 'geo'] });
|
|
27
|
+
* ```
|
|
22
28
|
*/
|
|
23
29
|
export { createSquawkMcpServer } from './server.js';
|
|
30
|
+
export { TOOL_GROUP_NAMES, ToolGroupConfigError } from './tool-groups.js';
|
package/dist/resolvers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,IACrC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAEzD"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @packageDocumentation
|
|
3
|
-
* Server factory for @squawk/mcp. Assembles an {@link McpServer}
|
|
4
|
-
*
|
|
3
|
+
* Server factory for @squawk/mcp. Assembles an {@link McpServer} carrying the
|
|
4
|
+
* squawk aviation tool modules the caller asked for, defaulting to all of them.
|
|
5
5
|
*/
|
|
6
6
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
+
import { type ToolGroupName } from './tool-groups.js';
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
-
* so the stdio entrypoint can include the count in its startup diagnostic
|
|
10
|
-
* without re-counting at runtime.
|
|
9
|
+
* Options accepted by {@link createSquawkMcpServer}.
|
|
11
10
|
*/
|
|
12
|
-
export
|
|
11
|
+
export interface CreateSquawkMcpServerOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Tool groups to register. Omit to resolve the set from the
|
|
14
|
+
* `SQUAWK_MCP_TOOLS` / `SQUAWK_MCP_DISABLE_TOOLS` environment variables,
|
|
15
|
+
* which default to every group. Order is ignored; groups always register in
|
|
16
|
+
* `TOOL_GROUP_NAMES` order.
|
|
17
|
+
*/
|
|
18
|
+
readonly toolGroups?: readonly ToolGroupName[];
|
|
19
|
+
}
|
|
13
20
|
/**
|
|
14
21
|
* Package name as published to npm. Convenient for diagnostic logs that want
|
|
15
22
|
* to identify the running server without re-reading `package.json`.
|
|
@@ -21,7 +28,14 @@ export declare const PACKAGE_NAME: string;
|
|
|
21
28
|
*/
|
|
22
29
|
export declare const PACKAGE_VERSION: string;
|
|
23
30
|
/**
|
|
24
|
-
* Creates an MCP server
|
|
31
|
+
* Creates an MCP server carrying the requested squawk aviation tool groups,
|
|
32
|
+
* defaulting to all of them.
|
|
33
|
+
*
|
|
34
|
+
* Disabling a group keeps its tools out of the catalog the LLM client sees,
|
|
35
|
+
* which is the point: the full catalog is roughly 18k tokens of context on
|
|
36
|
+
* every session. It does not reduce the server's startup time or memory
|
|
37
|
+
* footprint - the bundled snapshots are imported and indexed at module load
|
|
38
|
+
* regardless of which groups register.
|
|
25
39
|
*
|
|
26
40
|
* Tool registration triggers eager construction of the shared resolver
|
|
27
41
|
* singletons in `./resolvers.js` for every domain except the ICAO aircraft
|
|
@@ -33,13 +47,17 @@ export declare const PACKAGE_VERSION: string;
|
|
|
33
47
|
* import { createSquawkMcpServer } from '@squawk/mcp';
|
|
34
48
|
* import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
35
49
|
*
|
|
36
|
-
* const server = createSquawkMcpServer();
|
|
50
|
+
* const server = createSquawkMcpServer({ toolGroups: ['airports', 'geo'] });
|
|
37
51
|
* await server.connect(new StdioServerTransport());
|
|
38
52
|
* ```
|
|
39
53
|
*
|
|
54
|
+
* @param options - Server options. Omit to honor the environment variables.
|
|
40
55
|
* @returns A fully configured MCP server instance. Connect it to a transport
|
|
41
56
|
* (typically `StdioServerTransport` for CLI use) via
|
|
42
57
|
* `server.connect(transport)` to begin handling protocol messages.
|
|
58
|
+
* @throws {ToolGroupConfigError} when `options.toolGroups` names an unknown
|
|
59
|
+
* group or is empty, or when the environment variables cannot be
|
|
60
|
+
* honored (both set at once, unknown names, or nothing left enabled).
|
|
43
61
|
*/
|
|
44
|
-
export declare function createSquawkMcpServer(): McpServer;
|
|
62
|
+
export declare function createSquawkMcpServer(options?: CreateSquawkMcpServerOptions): McpServer;
|
|
45
63
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AA0C1B;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CAChD;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,MAAyB,CAAC;AAErD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAA4B,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAsBvF"}
|
package/dist/server.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @packageDocumentation
|
|
3
|
-
* Server factory for @squawk/mcp. Assembles an {@link McpServer}
|
|
4
|
-
*
|
|
3
|
+
* Server factory for @squawk/mcp. Assembles an {@link McpServer} carrying the
|
|
4
|
+
* squawk aviation tool modules the caller asked for, defaulting to all of them.
|
|
5
5
|
*/
|
|
6
6
|
import { readFileSync } from 'node:fs';
|
|
7
7
|
import { dirname, resolve } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import { ToolGroupConfigError, normalizeToolGroups, resolveToolGroupsFromEnv, } from './tool-groups.js';
|
|
10
11
|
import { registerAirportTools } from './tools/airports.js';
|
|
11
12
|
import { registerAirspaceTools } from './tools/airspace.js';
|
|
12
13
|
import { registerAirwayTools } from './tools/airways.js';
|
|
@@ -23,32 +24,26 @@ import { registerWeatherTools } from './tools/weather.js';
|
|
|
23
24
|
const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../package.json');
|
|
24
25
|
const packageMeta = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
25
26
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
27
|
+
* Registrar for each toggleable tool group. Keying by {@link ToolGroupName}
|
|
28
|
+
* makes the mapping exhaustive: adding a name to `TOOL_GROUP_NAMES` without
|
|
29
|
+
* wiring its registrar here is a compile error, so the group list and the
|
|
30
|
+
* modules it toggles cannot drift apart.
|
|
30
31
|
*/
|
|
31
|
-
const
|
|
32
|
-
registerGeoTools,
|
|
33
|
-
registerFlightMathTools,
|
|
34
|
-
registerAirportTools,
|
|
35
|
-
registerAirspaceTools,
|
|
36
|
-
registerNavaidTools,
|
|
37
|
-
registerFixTools,
|
|
38
|
-
registerAirwayTools,
|
|
39
|
-
registerProcedureTools,
|
|
40
|
-
registerIcaoRegistryTools,
|
|
41
|
-
registerWeatherTools,
|
|
42
|
-
registerNotamTools,
|
|
43
|
-
registerFlightplanTools,
|
|
44
|
-
registerDatasetTools,
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Number of tool modules registered by {@link createSquawkMcpServer}. Exposed
|
|
48
|
-
* so the stdio entrypoint can include the count in its startup diagnostic
|
|
49
|
-
* without re-counting at runtime.
|
|
50
|
-
*/
|
|
51
|
-
export const TOOL_MODULE_COUNT = TOOL_MODULE_REGISTRARS.length;
|
|
32
|
+
const TOOL_GROUP_REGISTRARS = {
|
|
33
|
+
geo: registerGeoTools,
|
|
34
|
+
'flight-math': registerFlightMathTools,
|
|
35
|
+
airports: registerAirportTools,
|
|
36
|
+
airspace: registerAirspaceTools,
|
|
37
|
+
navaids: registerNavaidTools,
|
|
38
|
+
fixes: registerFixTools,
|
|
39
|
+
airways: registerAirwayTools,
|
|
40
|
+
procedures: registerProcedureTools,
|
|
41
|
+
'icao-registry': registerIcaoRegistryTools,
|
|
42
|
+
weather: registerWeatherTools,
|
|
43
|
+
notams: registerNotamTools,
|
|
44
|
+
flightplan: registerFlightplanTools,
|
|
45
|
+
datasets: registerDatasetTools,
|
|
46
|
+
};
|
|
52
47
|
/**
|
|
53
48
|
* Package name as published to npm. Convenient for diagnostic logs that want
|
|
54
49
|
* to identify the running server without re-reading `package.json`.
|
|
@@ -60,7 +55,14 @@ export const PACKAGE_NAME = packageMeta.name;
|
|
|
60
55
|
*/
|
|
61
56
|
export const PACKAGE_VERSION = packageMeta.version;
|
|
62
57
|
/**
|
|
63
|
-
* Creates an MCP server
|
|
58
|
+
* Creates an MCP server carrying the requested squawk aviation tool groups,
|
|
59
|
+
* defaulting to all of them.
|
|
60
|
+
*
|
|
61
|
+
* Disabling a group keeps its tools out of the catalog the LLM client sees,
|
|
62
|
+
* which is the point: the full catalog is roughly 18k tokens of context on
|
|
63
|
+
* every session. It does not reduce the server's startup time or memory
|
|
64
|
+
* footprint - the bundled snapshots are imported and indexed at module load
|
|
65
|
+
* regardless of which groups register.
|
|
64
66
|
*
|
|
65
67
|
* Tool registration triggers eager construction of the shared resolver
|
|
66
68
|
* singletons in `./resolvers.js` for every domain except the ICAO aircraft
|
|
@@ -72,21 +74,36 @@ export const PACKAGE_VERSION = packageMeta.version;
|
|
|
72
74
|
* import { createSquawkMcpServer } from '@squawk/mcp';
|
|
73
75
|
* import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
74
76
|
*
|
|
75
|
-
* const server = createSquawkMcpServer();
|
|
77
|
+
* const server = createSquawkMcpServer({ toolGroups: ['airports', 'geo'] });
|
|
76
78
|
* await server.connect(new StdioServerTransport());
|
|
77
79
|
* ```
|
|
78
80
|
*
|
|
81
|
+
* @param options - Server options. Omit to honor the environment variables.
|
|
79
82
|
* @returns A fully configured MCP server instance. Connect it to a transport
|
|
80
83
|
* (typically `StdioServerTransport` for CLI use) via
|
|
81
84
|
* `server.connect(transport)` to begin handling protocol messages.
|
|
85
|
+
* @throws {ToolGroupConfigError} when `options.toolGroups` names an unknown
|
|
86
|
+
* group or is empty, or when the environment variables cannot be
|
|
87
|
+
* honored (both set at once, unknown names, or nothing left enabled).
|
|
82
88
|
*/
|
|
83
|
-
export function createSquawkMcpServer() {
|
|
89
|
+
export function createSquawkMcpServer(options) {
|
|
84
90
|
const server = new McpServer({
|
|
85
91
|
name: PACKAGE_NAME,
|
|
86
92
|
version: PACKAGE_VERSION,
|
|
87
93
|
});
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
let enabledGroups;
|
|
95
|
+
if (options?.toolGroups === undefined) {
|
|
96
|
+
const resolution = resolveToolGroupsFromEnv(process.env);
|
|
97
|
+
if (!resolution.ok) {
|
|
98
|
+
throw new ToolGroupConfigError(resolution.error);
|
|
99
|
+
}
|
|
100
|
+
enabledGroups = resolution.toolGroups;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
enabledGroups = normalizeToolGroups(options.toolGroups);
|
|
104
|
+
}
|
|
105
|
+
for (const group of enabledGroups) {
|
|
106
|
+
TOOL_GROUP_REGISTRARS[group](server);
|
|
90
107
|
}
|
|
91
108
|
return server;
|
|
92
109
|
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Tool-group identity and configuration parsing for @squawk/mcp. Every domain
|
|
4
|
+
* module under `src/tools/` is one toggleable group, so a client that only
|
|
5
|
+
* needs part of the catalog can keep the rest out of its context window.
|
|
6
|
+
*
|
|
7
|
+
* This module owns the canonical group-name list and turns the server's
|
|
8
|
+
* environment variables into the concrete set of groups to register.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Every toggleable tool group, in the order they are registered on the
|
|
12
|
+
* server. Each name matches exactly one domain module filename under
|
|
13
|
+
* `src/tools/`, so `airports` maps to `src/tools/airports.ts`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const TOOL_GROUP_NAMES: readonly ["geo", "flight-math", "airports", "airspace", "navaids", "fixes", "airways", "procedures", "icao-registry", "weather", "notams", "flightplan", "datasets"];
|
|
16
|
+
/** Name of a single toggleable tool group. */
|
|
17
|
+
export type ToolGroupName = (typeof TOOL_GROUP_NAMES)[number];
|
|
18
|
+
/**
|
|
19
|
+
* Environment variable naming the only tool groups to register. Acts as an
|
|
20
|
+
* allowlist: groups absent from the list are not registered, including groups
|
|
21
|
+
* added by future releases.
|
|
22
|
+
*/
|
|
23
|
+
export declare const TOOL_ALLOWLIST_ENV_VAR = "SQUAWK_MCP_TOOLS";
|
|
24
|
+
/**
|
|
25
|
+
* Environment variable naming tool groups to skip. Acts as a denylist: every
|
|
26
|
+
* group not listed is registered, including groups added by future releases.
|
|
27
|
+
*/
|
|
28
|
+
export declare const TOOL_DENYLIST_ENV_VAR = "SQUAWK_MCP_DISABLE_TOOLS";
|
|
29
|
+
/**
|
|
30
|
+
* Successful resolution of the tool-group configuration.
|
|
31
|
+
*/
|
|
32
|
+
export interface ToolGroupResolutionSuccess {
|
|
33
|
+
/** Discriminant marking a successful resolution. */
|
|
34
|
+
readonly ok: true;
|
|
35
|
+
/** Groups to register, in {@link TOOL_GROUP_NAMES} order. Never empty. */
|
|
36
|
+
readonly toolGroups: readonly ToolGroupName[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Failed resolution of the tool-group configuration, carrying a message ready
|
|
40
|
+
* to print for the user.
|
|
41
|
+
*/
|
|
42
|
+
export interface ToolGroupResolutionFailure {
|
|
43
|
+
/** Discriminant marking a failed resolution. */
|
|
44
|
+
readonly ok: false;
|
|
45
|
+
/** Human-readable explanation naming the offending value and the fix. */
|
|
46
|
+
readonly error: string;
|
|
47
|
+
}
|
|
48
|
+
/** Outcome of resolving the tool-group environment variables. */
|
|
49
|
+
export type ToolGroupResolution = ToolGroupResolutionSuccess | ToolGroupResolutionFailure;
|
|
50
|
+
/**
|
|
51
|
+
* Error thrown by `createSquawkMcpServer` when the tool-group configuration
|
|
52
|
+
* cannot be honored. A server has no partial-success shape to return - an
|
|
53
|
+
* unusable catalog is worse than a failed start, particularly for aviation
|
|
54
|
+
* data - so the factory throws rather than silently registering the wrong
|
|
55
|
+
* tools.
|
|
56
|
+
*/
|
|
57
|
+
export declare class ToolGroupConfigError extends Error {
|
|
58
|
+
/**
|
|
59
|
+
* Constructs a new configuration error.
|
|
60
|
+
*
|
|
61
|
+
* @param message - Human-readable explanation naming the offending value.
|
|
62
|
+
*/
|
|
63
|
+
constructor(message: string);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Resolves which tool groups to register from the process environment.
|
|
67
|
+
*
|
|
68
|
+
* With neither variable set, every group is enabled, matching the behavior of
|
|
69
|
+
* a server that predates this configuration. {@link TOOL_ALLOWLIST_ENV_VAR}
|
|
70
|
+
* and {@link TOOL_DENYLIST_ENV_VAR} are mutually exclusive: setting both is an
|
|
71
|
+
* error rather than a precedence rule, so the resolved catalog is always
|
|
72
|
+
* readable straight off the configuration.
|
|
73
|
+
*
|
|
74
|
+
* ```typescript
|
|
75
|
+
* const resolution = resolveToolGroupsFromEnv({ SQUAWK_MCP_TOOLS: 'airports,geo' });
|
|
76
|
+
* if (resolution.ok) {
|
|
77
|
+
* console.log(resolution.toolGroups); // ['geo', 'airports']
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @param env - Environment to read, normally `process.env`.
|
|
82
|
+
* @returns The resolved groups, or a failure carrying a printable message.
|
|
83
|
+
*/
|
|
84
|
+
export declare function resolveToolGroupsFromEnv(env: Record<string, string | undefined>): ToolGroupResolution;
|
|
85
|
+
/**
|
|
86
|
+
* Validates an explicitly supplied group list and returns it in registration
|
|
87
|
+
* order. Unlike {@link resolveToolGroupsFromEnv}, a bad value here is a
|
|
88
|
+
* programmer error rather than user misconfiguration, so it throws.
|
|
89
|
+
*
|
|
90
|
+
* @param toolGroups - Group names supplied by the caller.
|
|
91
|
+
* @returns The distinct groups in {@link TOOL_GROUP_NAMES} order.
|
|
92
|
+
* @throws {ToolGroupConfigError} when a name is unknown or the list is empty.
|
|
93
|
+
*/
|
|
94
|
+
export declare function normalizeToolGroups(toolGroups: readonly ToolGroupName[]): readonly ToolGroupName[];
|
|
95
|
+
//# sourceMappingURL=tool-groups.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-groups.d.ts","sourceRoot":"","sources":["../src/tool-groups.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,sKAcnB,CAAC;AAEX,8CAA8C;AAC9C,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAEzD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,oDAAoD;IACpD,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;CAC/C;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,gDAAgD;IAChD,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,iEAAiE;AACjE,MAAM,MAAM,mBAAmB,GAAG,0BAA0B,GAAG,0BAA0B,CAAC;AAE1F;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C;;;;OAIG;gBACS,OAAO,EAAE,MAAM;CAI5B;AAsED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,mBAAmB,CAuCrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,SAAS,aAAa,EAAE,GACnC,SAAS,aAAa,EAAE,CAU1B"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Tool-group identity and configuration parsing for @squawk/mcp. Every domain
|
|
4
|
+
* module under `src/tools/` is one toggleable group, so a client that only
|
|
5
|
+
* needs part of the catalog can keep the rest out of its context window.
|
|
6
|
+
*
|
|
7
|
+
* This module owns the canonical group-name list and turns the server's
|
|
8
|
+
* environment variables into the concrete set of groups to register.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Every toggleable tool group, in the order they are registered on the
|
|
12
|
+
* server. Each name matches exactly one domain module filename under
|
|
13
|
+
* `src/tools/`, so `airports` maps to `src/tools/airports.ts`.
|
|
14
|
+
*/
|
|
15
|
+
export const TOOL_GROUP_NAMES = [
|
|
16
|
+
'geo',
|
|
17
|
+
'flight-math',
|
|
18
|
+
'airports',
|
|
19
|
+
'airspace',
|
|
20
|
+
'navaids',
|
|
21
|
+
'fixes',
|
|
22
|
+
'airways',
|
|
23
|
+
'procedures',
|
|
24
|
+
'icao-registry',
|
|
25
|
+
'weather',
|
|
26
|
+
'notams',
|
|
27
|
+
'flightplan',
|
|
28
|
+
'datasets',
|
|
29
|
+
];
|
|
30
|
+
/**
|
|
31
|
+
* Environment variable naming the only tool groups to register. Acts as an
|
|
32
|
+
* allowlist: groups absent from the list are not registered, including groups
|
|
33
|
+
* added by future releases.
|
|
34
|
+
*/
|
|
35
|
+
export const TOOL_ALLOWLIST_ENV_VAR = 'SQUAWK_MCP_TOOLS';
|
|
36
|
+
/**
|
|
37
|
+
* Environment variable naming tool groups to skip. Acts as a denylist: every
|
|
38
|
+
* group not listed is registered, including groups added by future releases.
|
|
39
|
+
*/
|
|
40
|
+
export const TOOL_DENYLIST_ENV_VAR = 'SQUAWK_MCP_DISABLE_TOOLS';
|
|
41
|
+
/**
|
|
42
|
+
* Error thrown by `createSquawkMcpServer` when the tool-group configuration
|
|
43
|
+
* cannot be honored. A server has no partial-success shape to return - an
|
|
44
|
+
* unusable catalog is worse than a failed start, particularly for aviation
|
|
45
|
+
* data - so the factory throws rather than silently registering the wrong
|
|
46
|
+
* tools.
|
|
47
|
+
*/
|
|
48
|
+
export class ToolGroupConfigError extends Error {
|
|
49
|
+
/**
|
|
50
|
+
* Constructs a new configuration error.
|
|
51
|
+
*
|
|
52
|
+
* @param message - Human-readable explanation naming the offending value.
|
|
53
|
+
*/
|
|
54
|
+
constructor(message) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.name = 'ToolGroupConfigError';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** Comma-separated list of every valid group name, for error messages. */
|
|
60
|
+
const VALID_GROUPS_SUFFIX = `Valid groups: ${TOOL_GROUP_NAMES.join(', ')}.`;
|
|
61
|
+
/**
|
|
62
|
+
* Returns `true` when an environment variable carries no usable value. Hosts
|
|
63
|
+
* routinely pass empty strings for unset entries, so a blank value means
|
|
64
|
+
* "not configured" rather than "configured to nothing".
|
|
65
|
+
*
|
|
66
|
+
* @param value - Raw environment variable value.
|
|
67
|
+
* @returns `true` when the value is absent or whitespace-only.
|
|
68
|
+
*/
|
|
69
|
+
function isBlank(value) {
|
|
70
|
+
return value === undefined || value.trim() === '';
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Narrows an arbitrary string to a {@link ToolGroupName}.
|
|
74
|
+
*
|
|
75
|
+
* @param value - Candidate group name, already trimmed and lowercased.
|
|
76
|
+
* @returns `true` when the value names a known group.
|
|
77
|
+
*/
|
|
78
|
+
function isToolGroupName(value) {
|
|
79
|
+
return TOOL_GROUP_NAMES.some((name) => name === value);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Splits a comma-separated group list into normalized, deduplicated tokens.
|
|
83
|
+
* Tokens are trimmed and lowercased so `Airports, WEATHER` resolves the same
|
|
84
|
+
* way as `airports,weather`.
|
|
85
|
+
*
|
|
86
|
+
* @param value - Raw environment variable value.
|
|
87
|
+
* @returns The distinct tokens, in the order they first appeared.
|
|
88
|
+
*/
|
|
89
|
+
function parseGroupList(value) {
|
|
90
|
+
const tokens = value
|
|
91
|
+
.split(',')
|
|
92
|
+
.map((token) => token.trim().toLowerCase())
|
|
93
|
+
.filter((token) => token !== '');
|
|
94
|
+
return [...new Set(tokens)];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validates parsed tokens against {@link TOOL_GROUP_NAMES}.
|
|
98
|
+
*
|
|
99
|
+
* @param tokens - Normalized tokens from {@link parseGroupList}.
|
|
100
|
+
* @param envVar - Variable the tokens came from, named in the error message.
|
|
101
|
+
* @returns The validated group names, or a failure describing the bad tokens.
|
|
102
|
+
*/
|
|
103
|
+
function validateGroupList(tokens, envVar) {
|
|
104
|
+
if (tokens.length === 0) {
|
|
105
|
+
return {
|
|
106
|
+
ok: false,
|
|
107
|
+
error: `${envVar} names no tool groups. Remove it to use the default, or list at least one group. ${VALID_GROUPS_SUFFIX}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const unknown = tokens.filter((token) => !isToolGroupName(token));
|
|
111
|
+
if (unknown.length > 0) {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
error: `${envVar} names unknown tool ${unknown.length === 1 ? 'group' : 'groups'}: ${unknown.join(', ')}. ${VALID_GROUPS_SUFFIX}`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return { ok: true, groups: tokens.filter(isToolGroupName) };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Resolves which tool groups to register from the process environment.
|
|
121
|
+
*
|
|
122
|
+
* With neither variable set, every group is enabled, matching the behavior of
|
|
123
|
+
* a server that predates this configuration. {@link TOOL_ALLOWLIST_ENV_VAR}
|
|
124
|
+
* and {@link TOOL_DENYLIST_ENV_VAR} are mutually exclusive: setting both is an
|
|
125
|
+
* error rather than a precedence rule, so the resolved catalog is always
|
|
126
|
+
* readable straight off the configuration.
|
|
127
|
+
*
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const resolution = resolveToolGroupsFromEnv({ SQUAWK_MCP_TOOLS: 'airports,geo' });
|
|
130
|
+
* if (resolution.ok) {
|
|
131
|
+
* console.log(resolution.toolGroups); // ['geo', 'airports']
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* @param env - Environment to read, normally `process.env`.
|
|
136
|
+
* @returns The resolved groups, or a failure carrying a printable message.
|
|
137
|
+
*/
|
|
138
|
+
export function resolveToolGroupsFromEnv(env) {
|
|
139
|
+
const rawAllowlist = env[TOOL_ALLOWLIST_ENV_VAR];
|
|
140
|
+
const rawDenylist = env[TOOL_DENYLIST_ENV_VAR];
|
|
141
|
+
const hasAllowlist = !isBlank(rawAllowlist);
|
|
142
|
+
const hasDenylist = !isBlank(rawDenylist);
|
|
143
|
+
if (hasAllowlist && hasDenylist) {
|
|
144
|
+
return {
|
|
145
|
+
ok: false,
|
|
146
|
+
error: `${TOOL_ALLOWLIST_ENV_VAR} and ${TOOL_DENYLIST_ENV_VAR} are mutually exclusive. Set one or the other, not both.`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
if (hasAllowlist && rawAllowlist !== undefined) {
|
|
150
|
+
const validated = validateGroupList(parseGroupList(rawAllowlist), TOOL_ALLOWLIST_ENV_VAR);
|
|
151
|
+
if (!validated.ok) {
|
|
152
|
+
return validated;
|
|
153
|
+
}
|
|
154
|
+
const allowed = new Set(validated.groups);
|
|
155
|
+
return { ok: true, toolGroups: TOOL_GROUP_NAMES.filter((name) => allowed.has(name)) };
|
|
156
|
+
}
|
|
157
|
+
if (hasDenylist && rawDenylist !== undefined) {
|
|
158
|
+
const validated = validateGroupList(parseGroupList(rawDenylist), TOOL_DENYLIST_ENV_VAR);
|
|
159
|
+
if (!validated.ok) {
|
|
160
|
+
return validated;
|
|
161
|
+
}
|
|
162
|
+
const denied = new Set(validated.groups);
|
|
163
|
+
const remaining = TOOL_GROUP_NAMES.filter((name) => !denied.has(name));
|
|
164
|
+
if (remaining.length === 0) {
|
|
165
|
+
return {
|
|
166
|
+
ok: false,
|
|
167
|
+
error: `${TOOL_DENYLIST_ENV_VAR} disables every tool group, leaving the server with no tools to offer.`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return { ok: true, toolGroups: remaining };
|
|
171
|
+
}
|
|
172
|
+
return { ok: true, toolGroups: TOOL_GROUP_NAMES };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Validates an explicitly supplied group list and returns it in registration
|
|
176
|
+
* order. Unlike {@link resolveToolGroupsFromEnv}, a bad value here is a
|
|
177
|
+
* programmer error rather than user misconfiguration, so it throws.
|
|
178
|
+
*
|
|
179
|
+
* @param toolGroups - Group names supplied by the caller.
|
|
180
|
+
* @returns The distinct groups in {@link TOOL_GROUP_NAMES} order.
|
|
181
|
+
* @throws {ToolGroupConfigError} when a name is unknown or the list is empty.
|
|
182
|
+
*/
|
|
183
|
+
export function normalizeToolGroups(toolGroups) {
|
|
184
|
+
const validated = validateGroupList([...new Set(toolGroups.map((group) => group.trim().toLowerCase()))], 'toolGroups');
|
|
185
|
+
if (!validated.ok) {
|
|
186
|
+
throw new ToolGroupConfigError(validated.error);
|
|
187
|
+
}
|
|
188
|
+
const requested = new Set(validated.groups);
|
|
189
|
+
return TOOL_GROUP_NAMES.filter((name) => requested.has(name));
|
|
190
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squawk/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.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",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"!dist/**/*.spec.*"
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
34
|
-
"build": "tsc &&
|
|
34
|
+
"build": "tsc && node -e \"require('fs').chmodSync('dist/bin.js', 0o755)\"",
|
|
35
35
|
"test": "vitest run",
|
|
36
36
|
"test:coverage": "vitest run --coverage",
|
|
37
37
|
"lint": "tsc --noEmit && eslint src",
|
|
@@ -40,30 +40,30 @@
|
|
|
40
40
|
"api:report": "api-extractor run --local --verbose"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
44
|
-
"@squawk/airport-data": "^0.7.
|
|
45
|
-
"@squawk/airports": "^0.7.
|
|
46
|
-
"@squawk/airspace": "^0.9.
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
44
|
+
"@squawk/airport-data": "^0.7.12",
|
|
45
|
+
"@squawk/airports": "^0.7.1",
|
|
46
|
+
"@squawk/airspace": "^0.9.1",
|
|
47
47
|
"@squawk/airspace-data": "^0.5.2",
|
|
48
|
-
"@squawk/airway-data": "^0.5.
|
|
49
|
-
"@squawk/airways": "^0.5.
|
|
50
|
-
"@squawk/fix-data": "^0.6.
|
|
51
|
-
"@squawk/fixes": "^0.5.
|
|
48
|
+
"@squawk/airway-data": "^0.5.12",
|
|
49
|
+
"@squawk/airways": "^0.5.1",
|
|
50
|
+
"@squawk/fix-data": "^0.6.12",
|
|
51
|
+
"@squawk/fixes": "^0.5.1",
|
|
52
52
|
"@squawk/flight-math": "^0.5.3",
|
|
53
|
-
"@squawk/flightplan": "^0.6.
|
|
54
|
-
"@squawk/geo": "^0.4.
|
|
55
|
-
"@squawk/icao-registry": "^0.5.
|
|
56
|
-
"@squawk/navaid-data": "^0.6.
|
|
57
|
-
"@squawk/navaids": "^0.6.
|
|
58
|
-
"@squawk/notams": "^0.3.
|
|
59
|
-
"@squawk/procedure-data": "^0.7.
|
|
60
|
-
"@squawk/procedures": "^0.7.
|
|
61
|
-
"@squawk/types": "^0.
|
|
62
|
-
"@squawk/weather": "^0.6.
|
|
63
|
-
"zod": "^4.
|
|
53
|
+
"@squawk/flightplan": "^0.6.1",
|
|
54
|
+
"@squawk/geo": "^0.4.10",
|
|
55
|
+
"@squawk/icao-registry": "^0.5.8",
|
|
56
|
+
"@squawk/navaid-data": "^0.6.12",
|
|
57
|
+
"@squawk/navaids": "^0.6.1",
|
|
58
|
+
"@squawk/notams": "^0.3.12",
|
|
59
|
+
"@squawk/procedure-data": "^0.7.10",
|
|
60
|
+
"@squawk/procedures": "^0.7.1",
|
|
61
|
+
"@squawk/types": "^0.9.0",
|
|
62
|
+
"@squawk/weather": "^0.6.1",
|
|
63
|
+
"zod": "^4.6.2"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@squawk/icao-registry-data": "^0.8.
|
|
66
|
+
"@squawk/icao-registry-data": "^0.8.12"
|
|
67
67
|
},
|
|
68
68
|
"peerDependenciesMeta": {
|
|
69
69
|
"@squawk/icao-registry-data": {
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@squawk/icao-registry-data": "^0.8.
|
|
75
|
-
"@types/node": "^
|
|
74
|
+
"@squawk/icao-registry-data": "^0.8.12",
|
|
75
|
+
"@types/node": "^26.5.1"
|
|
76
76
|
},
|
|
77
77
|
"keywords": [
|
|
78
78
|
"aviation",
|