@squawk/mcp 0.4.1 → 0.5.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 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.4.1"]
101
+ "args": ["-y", "@squawk/mcp@0.5.0"]
102
102
  }
103
103
  }
104
104
  }
@@ -241,12 +241,17 @@ directly.
241
241
 
242
242
  ### Procedures (`@squawk/procedures` + `@squawk/procedure-data`)
243
243
 
244
- | Tool | Purpose |
245
- | ---------------------------- | ------------------------------------------------------------------------ |
246
- | `get_procedure_by_code` | Look up a SID/STAR by FAA computer code |
247
- | `find_procedures_by_airport` | Procedures associated with an airport |
248
- | `expand_procedure` | Expand a procedure into its waypoint sequence (with optional transition) |
249
- | `search_procedures` | Substring search by name or code, optionally filtered to SIDs or STARs |
244
+ Covers SIDs, STARs, and Instrument Approach Procedures (IAPs) from FAA CIFP.
245
+
246
+ | Tool | Purpose |
247
+ | ----------------------------------------- | ------------------------------------------------------------------------------------------- |
248
+ | `find_procedures_by_identifier` | Every procedure publishing a CIFP identifier (same name often appears at multiple airports) |
249
+ | `get_procedure_by_airport_and_identifier` | Resolve a specific procedure at a specific airport |
250
+ | `find_procedures_by_airport` | Procedures associated with an airport |
251
+ | `find_procedures_by_airport_and_runway` | Procedures at an airport serving a specific runway (IAP runway match or RW\* transition) |
252
+ | `find_approaches_by_type` | Every IAP of a given approach classification (ILS, RNAV, VOR, etc.) |
253
+ | `expand_procedure` | Expand a procedure into its leg sequence (with optional transition merge) |
254
+ | `search_procedures` | Substring search by name or identifier, optionally filtered by procedure or approach type |
250
255
 
251
256
  ### ICAO aircraft registry (`@squawk/icao-registry` + `@squawk/icao-registry-data`)
252
257
 
@@ -333,12 +338,13 @@ left to the model itself.
333
338
 
334
339
  ## Notes
335
340
 
336
- - All NASR-derived data sources cover the contiguous United States plus the territories included in
337
- the FAA NASR 28-day subscription. Outside the US the lookup tools will return empty results. Use
338
- `get_dataset_status` to confirm which NASR cycle the running server is serving.
341
+ - The bundled datasets (airports, airspace, navaids, fixes, airways from FAA NASR; procedures from
342
+ FAA CIFP) cover the contiguous United States plus the territories included in the respective FAA
343
+ subscriptions. Outside the US the lookup tools will return empty results. Use `get_dataset_status`
344
+ to confirm which NASR and CIFP cycles the running server is serving.
339
345
  - Live weather tools issue HTTPS requests to `https://aviationweather.gov/api/data/...` (or the
340
346
  override above). They are the only tools that touch the network at invocation time; everything
341
347
  else operates against bundled snapshots in memory.
342
- - The bundled NASR snapshots are decompressed and indexed once when the server starts. Expect a few
348
+ - The bundled snapshots are decompressed and indexed once when the server starts. Expect a few
343
349
  hundred milliseconds of startup time. The aircraft registration snapshot (the largest) is loaded
344
350
  lazily on the first `lookup_aircraft_by_icao_hex` call.
@@ -1 +1 @@
1
- {"version":3,"file":"datasets.d.ts","sourceRoot":"","sources":["../../src/tools/datasets.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6D5D"}
1
+ {"version":3,"file":"datasets.d.ts","sourceRoot":"","sources":["../../src/tools/datasets.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8D5D"}
@@ -23,7 +23,7 @@ import { getIcaoRegistryMetadata, isIcaoRegistryLoaded } from '../resolvers.js';
23
23
  export function registerDatasetTools(server) {
24
24
  server.registerTool('get_dataset_status', {
25
25
  title: 'Report status of every bundled dataset',
26
- description: 'Returns the FAA NASR cycle effective date, build timestamp, and record counts for each dataset the server loads (airports, airspace, navaids, fixes, airways, procedures, ICAO aircraft registry). Use this when a user asks "how current is the data?" or before answering a question that depends on procedure/navaid currency. The aircraft registry is lazily loaded and reports its load state without forcing initialization.',
26
+ description: 'Returns the cycle effective date (FAA NASR for airports/airspace/navaids/fixes/airways; FAA CIFP for procedures), build timestamp, and record counts for each dataset the server loads (airports, airspace, navaids, fixes, airways, procedures, ICAO aircraft registry). Use this when a user asks "how current is the data?" or before answering a question that depends on procedure/navaid currency. The aircraft registry is lazily loaded and reports its load state without forcing initialization.',
27
27
  inputSchema: {},
28
28
  }, () => {
29
29
  const registryMetadata = getIcaoRegistryMetadata();
@@ -55,12 +55,13 @@ export function registerDatasetTools(server) {
55
55
  waypointCount: usBundledAirways.properties.waypointCount,
56
56
  },
57
57
  procedures: {
58
- nasrCycleDate: usBundledProcedures.properties.nasrCycleDate,
58
+ cifpCycleDate: usBundledProcedures.properties.cifpCycleDate,
59
59
  generatedAt: usBundledProcedures.properties.generatedAt,
60
60
  recordCount: usBundledProcedures.properties.recordCount,
61
61
  sidCount: usBundledProcedures.properties.sidCount,
62
62
  starCount: usBundledProcedures.properties.starCount,
63
- waypointCount: usBundledProcedures.properties.waypointCount,
63
+ iapCount: usBundledProcedures.properties.iapCount,
64
+ legCount: usBundledProcedures.properties.legCount,
64
65
  },
65
66
  icaoRegistry: registryMetadata !== undefined
66
67
  ? {
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * @packageDocumentation
3
- * MCP tool module wrapping `@squawk/procedures` SID/STAR lookup, filtering,
4
- * and expansion methods, backed by the US NASR snapshot in
3
+ * MCP tool module wrapping `@squawk/procedures` SID / STAR / IAP lookup,
4
+ * filtering, and expansion methods, backed by the FAA CIFP snapshot in
5
5
  * `@squawk/procedure-data`.
6
6
  */
7
7
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
8
8
  /**
9
- * Registers SID/STAR procedure lookup tools on the given MCP server. Uses
10
- * the shared {@link procedureResolver} built at module load time.
9
+ * Registers procedure lookup tools (SIDs, STARs, and IAPs) on the given
10
+ * MCP server. Uses the shared {@link procedureResolver} built at module
11
+ * load time from the bundled FAA CIFP snapshot.
11
12
  *
12
13
  * @param server - The MCP server instance to register tools on.
13
14
  */
@@ -1 +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"}
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;AA8BzE;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2M9D"}
@@ -1,35 +1,76 @@
1
1
  /**
2
2
  * @packageDocumentation
3
- * MCP tool module wrapping `@squawk/procedures` SID/STAR lookup, filtering,
4
- * and expansion methods, backed by the US NASR snapshot in
3
+ * MCP tool module wrapping `@squawk/procedures` SID / STAR / IAP lookup,
4
+ * filtering, and expansion methods, backed by the FAA CIFP snapshot in
5
5
  * `@squawk/procedure-data`.
6
6
  */
7
7
  import { z } from 'zod';
8
8
  import { procedureResolver } from '../resolvers.js';
9
9
  /** All {@link ProcedureType} values, used for input validation. */
10
- const PROCEDURE_TYPE_VALUES = ['SID', 'STAR'];
10
+ const PROCEDURE_TYPE_VALUES = ['SID', 'STAR', 'IAP'];
11
+ /** All {@link ApproachType} values, used for input validation. */
12
+ const APPROACH_TYPE_VALUES = [
13
+ 'ILS',
14
+ 'LOC',
15
+ 'LOC_BC',
16
+ 'RNAV',
17
+ 'RNAV_RNP',
18
+ 'VOR',
19
+ 'VOR_DME',
20
+ 'NDB',
21
+ 'NDB_DME',
22
+ 'TACAN',
23
+ 'GLS',
24
+ 'IGS',
25
+ 'LDA',
26
+ 'SDF',
27
+ 'GPS',
28
+ 'FMS',
29
+ 'MLS',
30
+ ];
11
31
  /**
12
- * Registers SID/STAR procedure lookup tools on the given MCP server. Uses
13
- * the shared {@link procedureResolver} built at module load time.
32
+ * Registers procedure lookup tools (SIDs, STARs, and IAPs) on the given
33
+ * MCP server. Uses the shared {@link procedureResolver} built at module
34
+ * load time from the bundled FAA CIFP snapshot.
14
35
  *
15
36
  * @param server - The MCP server instance to register tools on.
16
37
  */
17
38
  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.',
39
+ server.registerTool('find_procedures_by_identifier', {
40
+ title: 'Find procedures by CIFP identifier',
41
+ description: 'Looks up every US instrument procedure (SID, STAR, or IAP) whose CIFP identifier matches (case-insensitive). The same identifier is often published at multiple airports (e.g. the approach "I04L" exists at any airport with an ILS 04L), so this returns all matches. Returns an empty array when no match is found.',
21
42
  inputSchema: {
22
- computerCode: z
43
+ identifier: z
23
44
  .string()
24
45
  .min(1)
25
- .describe('FAA computer code for the procedure (case-insensitive).'),
46
+ .describe('CIFP procedure identifier (case-insensitive). Examples: "AALLE4", "NUBLE4", "I04L", "R13".'),
26
47
  },
27
- }, ({ computerCode }) => {
28
- const procedure = procedureResolver.byName(computerCode);
48
+ }, ({ identifier }) => {
49
+ const procedures = procedureResolver.byIdentifier(identifier);
50
+ return {
51
+ content: [{ type: 'text', text: JSON.stringify(procedures, null, 2) }],
52
+ structuredContent: { procedures },
53
+ };
54
+ });
55
+ server.registerTool('get_procedure_by_airport_and_identifier', {
56
+ title: 'Get a specific procedure at an airport',
57
+ description: 'Looks up a single US instrument procedure at a specific airport by CIFP identifier. Use this when the same procedure identifier is published at multiple airports and the caller knows which airport is intended. Returns null when no match is found.',
58
+ inputSchema: {
59
+ airportId: z
60
+ .string()
61
+ .min(1)
62
+ .describe('Airport identifier (ICAO or FAA, case-insensitive).'),
63
+ identifier: z.string().min(1).describe('CIFP procedure identifier (case-insensitive).'),
64
+ },
65
+ }, ({ airportId, identifier }) => {
66
+ const procedure = procedureResolver.byAirportAndIdentifier(airportId, identifier);
29
67
  if (procedure === undefined) {
30
68
  return {
31
69
  content: [
32
- { type: 'text', text: `No procedure found with computer code "${computerCode}".` },
70
+ {
71
+ type: 'text',
72
+ text: `No procedure with identifier "${identifier}" found at "${airportId}".`,
73
+ },
33
74
  ],
34
75
  structuredContent: { procedure: null },
35
76
  };
@@ -41,9 +82,9 @@ export function registerProcedureTools(server) {
41
82
  });
42
83
  server.registerTool('find_procedures_by_airport', {
43
84
  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.',
85
+ description: 'Finds all US instrument procedures (SIDs, STARs, and IAPs) associated with a given airport identifier. Returns an empty array when no match is found.',
45
86
  inputSchema: {
46
- airportId: z.string().min(1).describe('Airport FAA identifier (case-insensitive).'),
87
+ airportId: z.string().min(1).describe('Airport identifier (case-insensitive).'),
47
88
  },
48
89
  }, ({ airportId }) => {
49
90
  const procedures = procedureResolver.byAirport(airportId);
@@ -52,28 +93,58 @@ export function registerProcedureTools(server) {
52
93
  structuredContent: { procedures },
53
94
  };
54
95
  });
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.",
96
+ server.registerTool('find_procedures_by_airport_and_runway', {
97
+ title: 'Find procedures serving a runway at an airport',
98
+ description: 'Finds procedures at an airport that serve a specific runway. Matches IAPs whose runway field equals the runway, and SIDs/STARs with a runway transition named "RW<runway>" (for example "RW04L"). Returns an empty array when no match is found.',
58
99
  inputSchema: {
59
- computerCode: z
100
+ airportId: z.string().min(1).describe('Airport identifier (case-insensitive).'),
101
+ runway: z
60
102
  .string()
61
103
  .min(1)
62
- .describe('FAA computer code for the procedure (case-insensitive).'),
104
+ .describe('Runway identifier, without the "RW" prefix (e.g. "04L", "13", "27R").'),
105
+ },
106
+ }, ({ airportId, runway }) => {
107
+ const procedures = procedureResolver.byAirportAndRunway(airportId, runway);
108
+ return {
109
+ content: [{ type: 'text', text: JSON.stringify(procedures, null, 2) }],
110
+ structuredContent: { procedures },
111
+ };
112
+ });
113
+ server.registerTool('find_approaches_by_type', {
114
+ title: 'Find approaches by approach type',
115
+ description: 'Returns every Instrument Approach Procedure of a given approach classification (ILS, LOC, RNAV, VOR, NDB, etc.).',
116
+ inputSchema: {
117
+ approachType: z
118
+ .enum(APPROACH_TYPE_VALUES)
119
+ .describe('Approach classification. Use LOC_BC for localizer back-course approaches.'),
120
+ },
121
+ }, ({ approachType }) => {
122
+ const procedures = procedureResolver.byApproachType(approachType);
123
+ return {
124
+ content: [{ type: 'text', text: JSON.stringify(procedures, null, 2) }],
125
+ structuredContent: { procedures },
126
+ };
127
+ });
128
+ server.registerTool('expand_procedure', {
129
+ title: 'Expand a procedure into an ordered leg sequence',
130
+ description: "Expands a procedure at an airport into an ordered leg sequence. Without a transition name, returns the procedure's common route. With a transition name, merges the named transition's legs with the common route in flying order (SID: common then transition for enroute exits, transition then common for runway transitions; STAR: transition then common for enroute entries; IAP: approach transition then final approach segment). Returns null when the airport, procedure, or transition is not found.",
131
+ inputSchema: {
132
+ airportId: z.string().min(1).describe('Airport identifier (case-insensitive).'),
133
+ identifier: z.string().min(1).describe('CIFP procedure identifier (case-insensitive).'),
63
134
  transitionName: z
64
135
  .string()
65
136
  .min(1)
66
137
  .optional()
67
- .describe('Optional transition name (typically the entry/exit fix identifier, case-insensitive). Omit to use the first common route.'),
138
+ .describe('Optional transition name. Omit to return just the common route.'),
68
139
  },
69
- }, ({ computerCode, transitionName }) => {
70
- const expansion = procedureResolver.expand(computerCode, transitionName);
140
+ }, ({ airportId, identifier, transitionName }) => {
141
+ const expansion = procedureResolver.expand(airportId, identifier, transitionName);
71
142
  if (expansion === undefined) {
72
143
  return {
73
144
  content: [
74
145
  {
75
146
  type: 'text',
76
- text: `Could not expand procedure "${computerCode}"${transitionName ? ` with transition "${transitionName}"` : ''}.`,
147
+ text: `Could not expand procedure "${identifier}" at "${airportId}"${transitionName ? ` with transition "${transitionName}"` : ''}.`,
77
148
  },
78
149
  ],
79
150
  structuredContent: { expansion: null },
@@ -85,17 +156,21 @@ export function registerProcedureTools(server) {
85
156
  };
86
157
  });
87
158
  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.',
159
+ title: 'Search procedures by name or identifier',
160
+ description: 'Searches US instrument procedures (SIDs, STARs, IAPs) by case-insensitive substring matching against both the procedure name and identifier. Results are returned sorted by airport and identifier.',
90
161
  inputSchema: {
91
162
  text: z
92
163
  .string()
93
164
  .min(1)
94
- .describe('Substring to match against the procedure name or computer code.'),
165
+ .describe('Substring to match against the procedure name or identifier.'),
95
166
  procedureType: z
96
167
  .enum(PROCEDURE_TYPE_VALUES)
97
168
  .optional()
98
- .describe('Restrict results to SIDs or STARs only. Omit to include both.'),
169
+ .describe('Restrict results to SIDs, STARs, or IAPs only. Omit to include all types.'),
170
+ approachType: z
171
+ .enum(APPROACH_TYPE_VALUES)
172
+ .optional()
173
+ .describe('Restrict results to IAPs of a given approach classification.'),
99
174
  limit: z
100
175
  .number()
101
176
  .int()
@@ -103,11 +178,14 @@ export function registerProcedureTools(server) {
103
178
  .optional()
104
179
  .describe('Maximum number of results to return. Defaults to 20.'),
105
180
  },
106
- }, ({ text, procedureType, limit }) => {
181
+ }, ({ text, procedureType, approachType, limit }) => {
107
182
  const query = { text };
108
183
  if (procedureType !== undefined) {
109
184
  query.type = procedureType;
110
185
  }
186
+ if (approachType !== undefined) {
187
+ query.approachType = approachType;
188
+ }
111
189
  if (limit !== undefined) {
112
190
  query.limit = limit;
113
191
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squawk/mcp",
3
- "version": "0.4.1",
3
+ "version": "0.5.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",
@@ -38,26 +38,26 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@modelcontextprotocol/sdk": "^1.29.0",
41
- "@squawk/airport-data": "^0.4.1",
42
- "@squawk/airports": "^0.3.2",
43
- "@squawk/airspace": "^0.4.1",
41
+ "@squawk/airport-data": "^0.5.0",
42
+ "@squawk/airports": "^0.4.0",
43
+ "@squawk/airspace": "^0.5.0",
44
44
  "@squawk/airspace-data": "^0.3.2",
45
- "@squawk/airway-data": "^0.3.3",
46
- "@squawk/airways": "^0.2.3",
47
- "@squawk/fix-data": "^0.4.1",
48
- "@squawk/fixes": "^0.1.4",
45
+ "@squawk/airway-data": "^0.4.0",
46
+ "@squawk/airways": "^0.3.0",
47
+ "@squawk/fix-data": "^0.5.0",
48
+ "@squawk/fixes": "^0.2.0",
49
49
  "@squawk/flight-math": "^0.5.1",
50
- "@squawk/flightplan": "^0.3.3",
51
- "@squawk/geo": "^0.2.1",
52
- "@squawk/icao-registry": "^0.2.3",
53
- "@squawk/icao-registry-data": "^0.3.3",
54
- "@squawk/navaid-data": "^0.4.1",
55
- "@squawk/navaids": "^0.2.4",
56
- "@squawk/notams": "^0.2.3",
57
- "@squawk/procedure-data": "^0.3.3",
58
- "@squawk/procedures": "^0.2.4",
59
- "@squawk/types": "^0.3.1",
60
- "@squawk/weather": "^0.3.4",
50
+ "@squawk/flightplan": "^0.4.0",
51
+ "@squawk/geo": "^0.3.0",
52
+ "@squawk/icao-registry": "^0.3.0",
53
+ "@squawk/icao-registry-data": "^0.4.0",
54
+ "@squawk/navaid-data": "^0.5.0",
55
+ "@squawk/navaids": "^0.3.0",
56
+ "@squawk/notams": "^0.3.0",
57
+ "@squawk/procedure-data": "^0.5.0",
58
+ "@squawk/procedures": "^0.4.0",
59
+ "@squawk/types": "^0.5.0",
60
+ "@squawk/weather": "^0.4.0",
61
61
  "zod": "^4.3.6"
62
62
  },
63
63
  "devDependencies": {