@cyanheads/aviation-weather-mcp-server 0.1.1
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/AGENTS.md +379 -0
- package/CLAUDE.md +379 -0
- package/Dockerfile +99 -0
- package/LICENSE +201 -0
- package/README.md +311 -0
- package/changelog/0.1.x/0.1.1.md +23 -0
- package/changelog/template.md +127 -0
- package/dist/config/server-config.d.ts +14 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +31 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/prompts/definitions/aviation-preflight-brief.prompt.d.ts +12 -0
- package/dist/mcp-server/prompts/definitions/aviation-preflight-brief.prompt.d.ts.map +1 -0
- package/dist/mcp-server/prompts/definitions/aviation-preflight-brief.prompt.js +65 -0
- package/dist/mcp-server/prompts/definitions/aviation-preflight-brief.prompt.js.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-find-stations.tool.d.ts +40 -0
- package/dist/mcp-server/tools/definitions/aviation-find-stations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-find-stations.tool.js +130 -0
- package/dist/mcp-server/tools/definitions/aviation-find-stations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-get-advisories.tool.d.ts +49 -0
- package/dist/mcp-server/tools/definitions/aviation-get-advisories.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-get-advisories.tool.js +133 -0
- package/dist/mcp-server/tools/definitions/aviation-get-advisories.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-get-metar.tool.d.ts +42 -0
- package/dist/mcp-server/tools/definitions/aviation-get-metar.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-get-metar.tool.js +129 -0
- package/dist/mcp-server/tools/definitions/aviation-get-metar.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-get-pireps.tool.d.ts +60 -0
- package/dist/mcp-server/tools/definitions/aviation-get-pireps.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-get-pireps.tool.js +238 -0
- package/dist/mcp-server/tools/definitions/aviation-get-pireps.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-get-taf.tool.d.ts +42 -0
- package/dist/mcp-server/tools/definitions/aviation-get-taf.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/aviation-get-taf.tool.js +140 -0
- package/dist/mcp-server/tools/definitions/aviation-get-taf.tool.js.map +1 -0
- package/dist/services/aviation-weather/aviation-weather-service.d.ts +60 -0
- package/dist/services/aviation-weather/aviation-weather-service.d.ts.map +1 -0
- package/dist/services/aviation-weather/aviation-weather-service.js +512 -0
- package/dist/services/aviation-weather/aviation-weather-service.js.map +1 -0
- package/dist/services/aviation-weather/types.d.ts +283 -0
- package/dist/services/aviation-weather/types.d.ts.map +1 -0
- package/dist/services/aviation-weather/types.js +7 -0
- package/dist/services/aviation-weather/types.js.map +1 -0
- package/package.json +107 -0
- package/server.json +127 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool to fetch current weather observations (METARs) for one or more airports.
|
|
3
|
+
* @module mcp-server/tools/definitions/aviation-get-metar
|
|
4
|
+
*/
|
|
5
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
import { getAviationWeatherService } from '../../../services/aviation-weather/aviation-weather-service.js';
|
|
8
|
+
const CloudLayerSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
cover: z.string().describe('Sky cover code: FEW, SCT, BKN, OVC, SKC, CLR.'),
|
|
11
|
+
base_ft: z.number().describe('Cloud base altitude in feet MSL.'),
|
|
12
|
+
})
|
|
13
|
+
.describe('A reported cloud layer.');
|
|
14
|
+
export const aviationGetMetar = tool('aviation_get_metar', {
|
|
15
|
+
title: 'Get METAR Weather Observations',
|
|
16
|
+
description: 'Get current weather observations (METARs) for one or more airports. Returns decoded fields — wind direction/speed/gusts, visibility, ceiling, temperature, dewpoint, altimeter, cloud layers — plus the computed flight category (VFR/MVFR/IFR/LIFR) and the raw METAR string. Accepts 1–10 ICAO station IDs (e.g., KSEA, KJFK). Use aviation_find_stations to resolve or verify an ICAO ID, or to discover nearby stations.',
|
|
17
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
18
|
+
input: z.object({
|
|
19
|
+
station_ids: z
|
|
20
|
+
.array(z
|
|
21
|
+
.string()
|
|
22
|
+
.regex(/^[A-Z]{4}$/)
|
|
23
|
+
.describe('4-letter ICAO station ID (e.g., KSEA, KJFK).'))
|
|
24
|
+
.min(1)
|
|
25
|
+
.max(10)
|
|
26
|
+
.describe('ICAO station IDs to query. 1–10 stations per call.'),
|
|
27
|
+
hours: z
|
|
28
|
+
.number()
|
|
29
|
+
.int()
|
|
30
|
+
.min(1)
|
|
31
|
+
.max(12)
|
|
32
|
+
.default(1)
|
|
33
|
+
.describe('Hours of observation history to return (1–12). Default 1 returns only the most recent observation per station.'),
|
|
34
|
+
}),
|
|
35
|
+
output: z.object({
|
|
36
|
+
observations: z
|
|
37
|
+
.array(z
|
|
38
|
+
.object({
|
|
39
|
+
station_id: z.string().describe('ICAO 4-letter station identifier (e.g., KSEA).'),
|
|
40
|
+
name: z.string().describe('Human-readable station or airport name.'),
|
|
41
|
+
lat: z.number().describe('Station latitude in decimal degrees.'),
|
|
42
|
+
lon: z.number().describe('Station longitude in decimal degrees.'),
|
|
43
|
+
elevation_ft: z.number().describe('Station elevation in feet MSL.'),
|
|
44
|
+
flight_category: z
|
|
45
|
+
.string()
|
|
46
|
+
.describe('Flight category: VFR, MVFR, IFR, or LIFR based on ceiling and visibility.'),
|
|
47
|
+
metar_type: z
|
|
48
|
+
.string()
|
|
49
|
+
.describe('METAR (routine) or SPECI (special observation triggered by significant weather change).'),
|
|
50
|
+
observed_at: z.string().describe('Observation time in ISO 8601 format (UTC).'),
|
|
51
|
+
wind: z
|
|
52
|
+
.object({
|
|
53
|
+
direction_deg: z
|
|
54
|
+
.number()
|
|
55
|
+
.nullable()
|
|
56
|
+
.describe('Wind direction in degrees true. Null when variable.'),
|
|
57
|
+
speed_kt: z.number().describe('Wind speed in knots.'),
|
|
58
|
+
gust_kt: z
|
|
59
|
+
.number()
|
|
60
|
+
.nullable()
|
|
61
|
+
.describe('Gust speed in knots, or null if no gusts reported.'),
|
|
62
|
+
})
|
|
63
|
+
.describe('Wind conditions at the station.'),
|
|
64
|
+
visibility_sm: z
|
|
65
|
+
.string()
|
|
66
|
+
.describe('Prevailing visibility in statute miles (e.g., "10+", "3", "1/2").'),
|
|
67
|
+
ceiling_ft: z
|
|
68
|
+
.number()
|
|
69
|
+
.nullable()
|
|
70
|
+
.describe('Ceiling in feet MSL — lowest BKN or OVC layer base. Null when sky is clear.'),
|
|
71
|
+
clouds: z
|
|
72
|
+
.array(CloudLayerSchema)
|
|
73
|
+
.describe('All reported cloud layers from lowest to highest.'),
|
|
74
|
+
temp_c: z.number().describe('Temperature in degrees Celsius.'),
|
|
75
|
+
dewpoint_c: z.number().describe('Dewpoint in degrees Celsius.'),
|
|
76
|
+
altimeter_inhg: z.number().describe('Altimeter setting in inches of mercury.'),
|
|
77
|
+
raw_metar: z
|
|
78
|
+
.string()
|
|
79
|
+
.describe('Original encoded METAR string (e.g., "KSEA 041453Z 18006KT 10SM FEW035 09/03 A2991").'),
|
|
80
|
+
})
|
|
81
|
+
.describe('A single weather observation from one station at one time.'))
|
|
82
|
+
.describe('Weather observations, one per station/time pair. Multiple entries per station when hours > 1.'),
|
|
83
|
+
}),
|
|
84
|
+
errors: [
|
|
85
|
+
{
|
|
86
|
+
reason: 'no_stations_found',
|
|
87
|
+
code: JsonRpcErrorCode.NotFound,
|
|
88
|
+
when: 'None of the requested station IDs returned METAR data.',
|
|
89
|
+
recovery: 'Verify ICAO IDs with aviation_find_stations. Not all stations transmit METARs. Check that the station IDs are 4-letter ICAO format (e.g., KSEA not SEA).',
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
async handler(input, ctx) {
|
|
93
|
+
ctx.log.info('Fetching METARs', { stationIds: input.station_ids, hours: input.hours });
|
|
94
|
+
const svc = getAviationWeatherService();
|
|
95
|
+
const observations = await svc.fetchMetar(input.station_ids, input.hours, ctx);
|
|
96
|
+
if (observations.length === 0) {
|
|
97
|
+
throw ctx.fail('no_stations_found', `No METAR data found for: ${input.station_ids.join(', ')}`, {
|
|
98
|
+
stationIds: input.station_ids,
|
|
99
|
+
...ctx.recoveryFor('no_stations_found'),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
ctx.log.info('METARs retrieved', { count: observations.length });
|
|
103
|
+
return { observations };
|
|
104
|
+
},
|
|
105
|
+
format: (result) => {
|
|
106
|
+
const lines = [];
|
|
107
|
+
for (const obs of result.observations) {
|
|
108
|
+
lines.push(`## ${obs.station_id} — ${obs.name}`);
|
|
109
|
+
lines.push(`**Flight Category:** ${obs.flight_category} | **Type:** ${obs.metar_type} | **Observed:** ${obs.observed_at}`);
|
|
110
|
+
lines.push(`**Location:** ${obs.lat.toFixed(4)}, ${obs.lon.toFixed(4)} | **Elevation:** ${obs.elevation_ft} ft`);
|
|
111
|
+
lines.push('');
|
|
112
|
+
const gustStr = obs.wind.gust_kt != null ? ` gusting ${obs.wind.gust_kt} kt` : '';
|
|
113
|
+
const dirStr = obs.wind.direction_deg != null ? `${obs.wind.direction_deg}°` : 'variable';
|
|
114
|
+
lines.push(`**Wind:** ${dirStr} at ${obs.wind.speed_kt} kt${gustStr}`);
|
|
115
|
+
lines.push(`**Visibility:** ${obs.visibility_sm} sm | **Ceiling:** ${obs.ceiling_ft != null ? `${obs.ceiling_ft} ft` : 'Clear'}`);
|
|
116
|
+
lines.push(`**Temperature:** ${obs.temp_c}°C | **Dewpoint:** ${obs.dewpoint_c}°C | **Altimeter:** ${obs.altimeter_inhg} inHg`);
|
|
117
|
+
if (obs.clouds.length > 0) {
|
|
118
|
+
lines.push(`**Clouds:** ${obs.clouds.map((c) => `${c.cover} @ ${c.base_ft} ft`).join(', ')}`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
lines.push(`**Clouds:** Clear`);
|
|
122
|
+
}
|
|
123
|
+
lines.push(`**Raw METAR:** \`${obs.raw_metar}\``);
|
|
124
|
+
lines.push('');
|
|
125
|
+
}
|
|
126
|
+
return [{ type: 'text', text: lines.join('\n').trim() }];
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=aviation-get-metar.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aviation-get-metar.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/aviation-get-metar.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool to fetch recent Pilot Reports (PIREPs) near an airport or within a bounding box.
|
|
3
|
+
* @module mcp-server/tools/definitions/aviation-get-pireps
|
|
4
|
+
*/
|
|
5
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
export declare const aviationGetPireps: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
|
+
station_id: z.ZodOptional<z.ZodString>;
|
|
9
|
+
bbox: z.ZodOptional<z.ZodObject<{
|
|
10
|
+
minLat: z.ZodNumber;
|
|
11
|
+
minLon: z.ZodNumber;
|
|
12
|
+
maxLat: z.ZodNumber;
|
|
13
|
+
maxLon: z.ZodNumber;
|
|
14
|
+
}, z.core.$strip>>;
|
|
15
|
+
distance_nm: z.ZodDefault<z.ZodNumber>;
|
|
16
|
+
hours: z.ZodDefault<z.ZodNumber>;
|
|
17
|
+
altitude_min_ft: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
altitude_max_ft: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
20
|
+
pireps: z.ZodArray<z.ZodObject<{
|
|
21
|
+
observed_at: z.ZodString;
|
|
22
|
+
lat: z.ZodNumber;
|
|
23
|
+
lon: z.ZodNumber;
|
|
24
|
+
altitude_ft: z.ZodNumber;
|
|
25
|
+
aircraft_type: z.ZodNullable<z.ZodString>;
|
|
26
|
+
pirep_type: z.ZodString;
|
|
27
|
+
turbulence: z.ZodArray<z.ZodObject<{
|
|
28
|
+
base_ft: z.ZodNullable<z.ZodNumber>;
|
|
29
|
+
top_ft: z.ZodNullable<z.ZodNumber>;
|
|
30
|
+
intensity: z.ZodString;
|
|
31
|
+
type: z.ZodNullable<z.ZodString>;
|
|
32
|
+
frequency: z.ZodNullable<z.ZodString>;
|
|
33
|
+
}, z.core.$strip>>;
|
|
34
|
+
icing: z.ZodArray<z.ZodObject<{
|
|
35
|
+
base_ft: z.ZodNullable<z.ZodNumber>;
|
|
36
|
+
top_ft: z.ZodNullable<z.ZodNumber>;
|
|
37
|
+
intensity: z.ZodString;
|
|
38
|
+
type: z.ZodNullable<z.ZodString>;
|
|
39
|
+
}, z.core.$strip>>;
|
|
40
|
+
clouds: z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
41
|
+
cover: z.ZodString;
|
|
42
|
+
base_ft: z.ZodNumber;
|
|
43
|
+
top_ft: z.ZodNumber;
|
|
44
|
+
}, z.core.$strip>>>;
|
|
45
|
+
visibility_sm: z.ZodNullable<z.ZodNumber>;
|
|
46
|
+
remarks: z.ZodNullable<z.ZodString>;
|
|
47
|
+
raw_pirep: z.ZodString;
|
|
48
|
+
}, z.core.$strip>>;
|
|
49
|
+
}, z.core.$strip>, readonly [{
|
|
50
|
+
readonly reason: "no_pireps_found";
|
|
51
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
52
|
+
readonly when: "No pilot reports found in the search area and time window.";
|
|
53
|
+
readonly recovery: "Expand the distance_nm or hours parameters, or try a different region. PIREPs are sparse; absence of reports does not mean smooth conditions.";
|
|
54
|
+
}, {
|
|
55
|
+
readonly reason: "missing_location";
|
|
56
|
+
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
57
|
+
readonly when: "Neither station_id nor bbox was provided.";
|
|
58
|
+
readonly recovery: "Provide station_id for a radial search (ICAO ID + distance_nm) or bbox for an area search (minLat, minLon, maxLat, maxLon).";
|
|
59
|
+
}], undefined>;
|
|
60
|
+
//# sourceMappingURL=aviation-get-pireps.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aviation-get-pireps.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/aviation-get-pireps.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAsEjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA2M5B,CAAC"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool to fetch recent Pilot Reports (PIREPs) near an airport or within a bounding box.
|
|
3
|
+
* @module mcp-server/tools/definitions/aviation-get-pireps
|
|
4
|
+
*/
|
|
5
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
import { getAviationWeatherService } from '../../../services/aviation-weather/aviation-weather-service.js';
|
|
8
|
+
const BboxSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
minLat: z.number().min(-90).max(90).describe('Southern boundary latitude in decimal degrees.'),
|
|
11
|
+
minLon: z
|
|
12
|
+
.number()
|
|
13
|
+
.min(-180)
|
|
14
|
+
.max(180)
|
|
15
|
+
.describe('Western boundary longitude in decimal degrees.'),
|
|
16
|
+
maxLat: z.number().min(-90).max(90).describe('Northern boundary latitude in decimal degrees.'),
|
|
17
|
+
maxLon: z
|
|
18
|
+
.number()
|
|
19
|
+
.min(-180)
|
|
20
|
+
.max(180)
|
|
21
|
+
.describe('Eastern boundary longitude in decimal degrees.'),
|
|
22
|
+
})
|
|
23
|
+
.describe('Geographic bounding box for area PIREP search.');
|
|
24
|
+
const TurbulenceLayerSchema = z
|
|
25
|
+
.object({
|
|
26
|
+
base_ft: z
|
|
27
|
+
.number()
|
|
28
|
+
.nullable()
|
|
29
|
+
.describe('Turbulence layer base altitude in feet MSL, or null if not specified.'),
|
|
30
|
+
top_ft: z
|
|
31
|
+
.number()
|
|
32
|
+
.nullable()
|
|
33
|
+
.describe('Turbulence layer top altitude in feet MSL, or null if not specified.'),
|
|
34
|
+
intensity: z
|
|
35
|
+
.string()
|
|
36
|
+
.describe('Turbulence intensity (e.g., NEG, LGT, LGT-MOD, MOD, SEV, EXTRM).'),
|
|
37
|
+
type: z
|
|
38
|
+
.string()
|
|
39
|
+
.nullable()
|
|
40
|
+
.describe('Turbulence type (e.g., CHOP, CAT), or null if not reported.'),
|
|
41
|
+
frequency: z
|
|
42
|
+
.string()
|
|
43
|
+
.nullable()
|
|
44
|
+
.describe('Turbulence frequency (e.g., OCNL, CONT), or null if not reported.'),
|
|
45
|
+
})
|
|
46
|
+
.describe('A reported turbulence layer.');
|
|
47
|
+
const IcingLayerSchema = z
|
|
48
|
+
.object({
|
|
49
|
+
base_ft: z
|
|
50
|
+
.number()
|
|
51
|
+
.nullable()
|
|
52
|
+
.describe('Icing layer base altitude in feet MSL, or null if not specified.'),
|
|
53
|
+
top_ft: z
|
|
54
|
+
.number()
|
|
55
|
+
.nullable()
|
|
56
|
+
.describe('Icing layer top altitude in feet MSL, or null if not specified.'),
|
|
57
|
+
intensity: z.string().describe('Icing intensity (e.g., NEG, TRC, LGT, MOD, SEV).'),
|
|
58
|
+
type: z
|
|
59
|
+
.string()
|
|
60
|
+
.nullable()
|
|
61
|
+
.describe('Icing type (e.g., RIME, MIXED, CLEAR), or null if not reported.'),
|
|
62
|
+
})
|
|
63
|
+
.describe('A reported icing layer.');
|
|
64
|
+
const PirepCloudLayerSchema = z
|
|
65
|
+
.object({
|
|
66
|
+
cover: z.string().describe('Cloud cover code (e.g., FEW, SCT, BKN, OVC).'),
|
|
67
|
+
base_ft: z.number().describe('Cloud base altitude in feet MSL.'),
|
|
68
|
+
top_ft: z.number().describe('Cloud top altitude in feet MSL.'),
|
|
69
|
+
})
|
|
70
|
+
.describe('A cloud layer with base and top altitudes.');
|
|
71
|
+
export const aviationGetPireps = tool('aviation_get_pireps', {
|
|
72
|
+
title: 'Get Pilot Reports (PIREPs)',
|
|
73
|
+
description: 'Get recent Pilot Reports (PIREPs) near an airport or within a bounding box. Returns decoded turbulence, icing, and cloud reports with altitude, aircraft type, intensity, and the raw PIREP string. Requires either station_id (ICAO center point for radial search, e.g., KSEA) or bbox (area search) — not both. Coverage is US-centric; PIREPs are sparse and absence of reports does not imply smooth conditions.',
|
|
74
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
75
|
+
input: z.object({
|
|
76
|
+
station_id: z
|
|
77
|
+
.string()
|
|
78
|
+
.regex(/^[A-Z]{4}$/)
|
|
79
|
+
.optional()
|
|
80
|
+
.describe('ICAO station ID as center point for radial search (e.g., KSEA). Use with distance_nm.'),
|
|
81
|
+
bbox: BboxSchema.optional(),
|
|
82
|
+
distance_nm: z
|
|
83
|
+
.number()
|
|
84
|
+
.int()
|
|
85
|
+
.min(10)
|
|
86
|
+
.max(500)
|
|
87
|
+
.default(100)
|
|
88
|
+
.describe('Search radius in nautical miles around station_id. Only used when station_id is provided. Default 100.'),
|
|
89
|
+
hours: z
|
|
90
|
+
.number()
|
|
91
|
+
.int()
|
|
92
|
+
.min(1)
|
|
93
|
+
.max(12)
|
|
94
|
+
.default(3)
|
|
95
|
+
.describe('How many hours of history to return. Default 3.'),
|
|
96
|
+
altitude_min_ft: z
|
|
97
|
+
.number()
|
|
98
|
+
.int()
|
|
99
|
+
.optional()
|
|
100
|
+
.describe('Filter by minimum altitude in feet MSL (e.g., 18000 for FL180). Optional.'),
|
|
101
|
+
altitude_max_ft: z
|
|
102
|
+
.number()
|
|
103
|
+
.int()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('Filter by maximum altitude in feet MSL (e.g., 35000 for FL350). Optional.'),
|
|
106
|
+
}),
|
|
107
|
+
output: z.object({
|
|
108
|
+
pireps: z
|
|
109
|
+
.array(z
|
|
110
|
+
.object({
|
|
111
|
+
observed_at: z.string().describe('Observation time in ISO 8601 format (UTC).'),
|
|
112
|
+
lat: z.number().describe('Latitude of the PIREP location in decimal degrees.'),
|
|
113
|
+
lon: z.number().describe('Longitude of the PIREP location in decimal degrees.'),
|
|
114
|
+
altitude_ft: z.number().describe('Reported altitude in feet MSL.'),
|
|
115
|
+
aircraft_type: z
|
|
116
|
+
.string()
|
|
117
|
+
.nullable()
|
|
118
|
+
.describe('Aircraft type designator (e.g., B737, C172), or null if not reported.'),
|
|
119
|
+
pirep_type: z
|
|
120
|
+
.string()
|
|
121
|
+
.describe('Report type: PIREP (pilot report) or AIREP (position report with wx).'),
|
|
122
|
+
turbulence: z
|
|
123
|
+
.array(TurbulenceLayerSchema)
|
|
124
|
+
.describe('Turbulence layers reported. Empty array if no turbulence encountered (NEG).'),
|
|
125
|
+
icing: z
|
|
126
|
+
.array(IcingLayerSchema)
|
|
127
|
+
.describe('Icing layers reported. Empty array if no icing encountered (NEG).'),
|
|
128
|
+
clouds: z
|
|
129
|
+
.array(PirepCloudLayerSchema)
|
|
130
|
+
.nullable()
|
|
131
|
+
.describe('Cloud layers with base and top altitudes, or null if not reported.'),
|
|
132
|
+
visibility_sm: z
|
|
133
|
+
.number()
|
|
134
|
+
.nullable()
|
|
135
|
+
.describe('In-flight visibility in statute miles, or null if not reported.'),
|
|
136
|
+
remarks: z
|
|
137
|
+
.string()
|
|
138
|
+
.nullable()
|
|
139
|
+
.describe('Weather remarks or additional conditions, or null if none.'),
|
|
140
|
+
raw_pirep: z
|
|
141
|
+
.string()
|
|
142
|
+
.describe('Original encoded PIREP string (e.g., "SEA UA /OV KSEA/TM 1530/FL080/TP B737/TB LGT").'),
|
|
143
|
+
})
|
|
144
|
+
.describe('A single Pilot Report (PIREP) with decoded hazard information.'))
|
|
145
|
+
.describe('Pilot reports matching the search criteria, ordered by observation time descending.'),
|
|
146
|
+
}),
|
|
147
|
+
errors: [
|
|
148
|
+
{
|
|
149
|
+
reason: 'no_pireps_found',
|
|
150
|
+
code: JsonRpcErrorCode.NotFound,
|
|
151
|
+
when: 'No pilot reports found in the search area and time window.',
|
|
152
|
+
recovery: 'Expand the distance_nm or hours parameters, or try a different region. PIREPs are sparse; absence of reports does not mean smooth conditions.',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
reason: 'missing_location',
|
|
156
|
+
code: JsonRpcErrorCode.InvalidParams,
|
|
157
|
+
when: 'Neither station_id nor bbox was provided.',
|
|
158
|
+
recovery: 'Provide station_id for a radial search (ICAO ID + distance_nm) or bbox for an area search (minLat, minLon, maxLat, maxLon).',
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
async handler(input, ctx) {
|
|
162
|
+
if (!input.station_id && !input.bbox) {
|
|
163
|
+
throw ctx.fail('missing_location', 'Either station_id or bbox is required for PIREP search.', {
|
|
164
|
+
...ctx.recoveryFor('missing_location'),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
ctx.log.info('Fetching PIREPs', {
|
|
168
|
+
stationId: input.station_id,
|
|
169
|
+
hasBbox: !!input.bbox,
|
|
170
|
+
distanceNm: input.distance_nm,
|
|
171
|
+
hours: input.hours,
|
|
172
|
+
});
|
|
173
|
+
const svc = getAviationWeatherService();
|
|
174
|
+
let pireps = await svc.fetchPireps({
|
|
175
|
+
...(input.station_id ? { stationId: input.station_id } : {}),
|
|
176
|
+
...(input.bbox ? { bbox: input.bbox } : {}),
|
|
177
|
+
distanceNm: input.distance_nm,
|
|
178
|
+
hours: input.hours,
|
|
179
|
+
}, ctx);
|
|
180
|
+
// Client-side altitude filter (capture to const so TypeScript narrows inside the callback)
|
|
181
|
+
const altMin = input.altitude_min_ft;
|
|
182
|
+
const altMax = input.altitude_max_ft;
|
|
183
|
+
if (altMin != null)
|
|
184
|
+
pireps = pireps.filter((p) => p.altitude_ft >= altMin);
|
|
185
|
+
if (altMax != null)
|
|
186
|
+
pireps = pireps.filter((p) => p.altitude_ft <= altMax);
|
|
187
|
+
// Sort by observation time descending
|
|
188
|
+
pireps.sort((a, b) => new Date(b.observed_at).getTime() - new Date(a.observed_at).getTime());
|
|
189
|
+
if (pireps.length === 0) {
|
|
190
|
+
throw ctx.fail('no_pireps_found', `No PIREPs found in the search area for the past ${input.hours} hour(s).`, { ...ctx.recoveryFor('no_pireps_found') });
|
|
191
|
+
}
|
|
192
|
+
ctx.log.info('PIREPs retrieved', { count: pireps.length });
|
|
193
|
+
return { pireps };
|
|
194
|
+
},
|
|
195
|
+
format: (result) => {
|
|
196
|
+
const lines = [`**${result.pireps.length} PIREP(s) found**\n`];
|
|
197
|
+
for (const p of result.pireps) {
|
|
198
|
+
lines.push(`## ${p.pirep_type} — ${p.observed_at}`);
|
|
199
|
+
lines.push(`**Location:** ${p.lat.toFixed(4)}, ${p.lon.toFixed(4)} | **Altitude:** ${p.altitude_ft.toLocaleString()} ft`);
|
|
200
|
+
if (p.aircraft_type)
|
|
201
|
+
lines.push(`**Aircraft:** ${p.aircraft_type}`);
|
|
202
|
+
if (p.turbulence.length > 0) {
|
|
203
|
+
lines.push('**Turbulence:**');
|
|
204
|
+
for (const t of p.turbulence) {
|
|
205
|
+
const altStr = t.base_ft != null && t.top_ft != null
|
|
206
|
+
? ` (${t.base_ft.toLocaleString()}–${t.top_ft.toLocaleString()} ft)`
|
|
207
|
+
: '';
|
|
208
|
+
const details = [t.intensity, t.type, t.frequency].filter(Boolean).join(', ');
|
|
209
|
+
lines.push(` - ${details}${altStr}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (p.icing.length > 0) {
|
|
213
|
+
lines.push('**Icing:**');
|
|
214
|
+
for (const i of p.icing) {
|
|
215
|
+
const altStr = i.base_ft != null && i.top_ft != null
|
|
216
|
+
? ` (${i.base_ft.toLocaleString()}–${i.top_ft.toLocaleString()} ft)`
|
|
217
|
+
: '';
|
|
218
|
+
const details = [i.intensity, i.type].filter(Boolean).join(', ');
|
|
219
|
+
lines.push(` - ${details}${altStr}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (p.clouds && p.clouds.length > 0) {
|
|
223
|
+
const cloudStr = p.clouds
|
|
224
|
+
.map((c) => `${c.cover} ${c.base_ft.toLocaleString()}–${c.top_ft.toLocaleString()} ft`)
|
|
225
|
+
.join(', ');
|
|
226
|
+
lines.push(`**Clouds:** ${cloudStr}`);
|
|
227
|
+
}
|
|
228
|
+
if (p.visibility_sm != null)
|
|
229
|
+
lines.push(`**Visibility:** ${p.visibility_sm} sm`);
|
|
230
|
+
if (p.remarks)
|
|
231
|
+
lines.push(`**Remarks:** ${p.remarks}`);
|
|
232
|
+
lines.push(`**Raw:** \`${p.raw_pirep}\``);
|
|
233
|
+
lines.push('');
|
|
234
|
+
}
|
|
235
|
+
return [{ type: 'text', text: lines.join('\n').trim() }];
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
//# sourceMappingURL=aviation-get-pireps.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aviation-get-pireps.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/aviation-get-pireps.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool to fetch Terminal Aerodrome Forecasts (TAFs) for one or more airports.
|
|
3
|
+
* @module mcp-server/tools/definitions/aviation-get-taf
|
|
4
|
+
*/
|
|
5
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
export declare const aviationGetTaf: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
|
+
station_ids: z.ZodArray<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
10
|
+
forecasts: z.ZodArray<z.ZodObject<{
|
|
11
|
+
station_id: z.ZodString;
|
|
12
|
+
name: z.ZodString;
|
|
13
|
+
issued_at: z.ZodString;
|
|
14
|
+
valid_from: z.ZodString;
|
|
15
|
+
valid_to: z.ZodString;
|
|
16
|
+
forecast_periods: z.ZodArray<z.ZodObject<{
|
|
17
|
+
from: z.ZodString;
|
|
18
|
+
to: z.ZodString;
|
|
19
|
+
change_type: z.ZodNullable<z.ZodString>;
|
|
20
|
+
probability: z.ZodNullable<z.ZodNumber>;
|
|
21
|
+
wind: z.ZodObject<{
|
|
22
|
+
direction_deg: z.ZodNullable<z.ZodNumber>;
|
|
23
|
+
speed_kt: z.ZodNumber;
|
|
24
|
+
gust_kt: z.ZodNullable<z.ZodNumber>;
|
|
25
|
+
}, z.core.$strip>;
|
|
26
|
+
visibility_sm: z.ZodNullable<z.ZodString>;
|
|
27
|
+
weather: z.ZodNullable<z.ZodString>;
|
|
28
|
+
clouds: z.ZodArray<z.ZodObject<{
|
|
29
|
+
cover: z.ZodString;
|
|
30
|
+
base_ft: z.ZodNumber;
|
|
31
|
+
type: z.ZodNullable<z.ZodString>;
|
|
32
|
+
}, z.core.$strip>>;
|
|
33
|
+
}, z.core.$strip>>;
|
|
34
|
+
raw_taf: z.ZodString;
|
|
35
|
+
}, z.core.$strip>>;
|
|
36
|
+
}, z.core.$strip>, readonly [{
|
|
37
|
+
readonly reason: "no_taf_available";
|
|
38
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
39
|
+
readonly when: "Station does not issue TAFs or no TAF is currently available.";
|
|
40
|
+
readonly recovery: "Not all airports have TAFs — only major airports with scheduled commercial service typically issue them. Check data_types from aviation_find_stations to confirm TAF capability. Smaller airports may only have METARs.";
|
|
41
|
+
}], undefined>;
|
|
42
|
+
//# sourceMappingURL=aviation-get-taf.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aviation-get-taf.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/aviation-get-taf.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAoDjE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyGzB,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool to fetch Terminal Aerodrome Forecasts (TAFs) for one or more airports.
|
|
3
|
+
* @module mcp-server/tools/definitions/aviation-get-taf
|
|
4
|
+
*/
|
|
5
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
import { getAviationWeatherService } from '../../../services/aviation-weather/aviation-weather-service.js';
|
|
8
|
+
const TafCloudLayerSchema = z
|
|
9
|
+
.object({
|
|
10
|
+
cover: z.string().describe('Sky cover code: FEW, SCT, BKN, OVC, SKC, CLR.'),
|
|
11
|
+
base_ft: z.number().describe('Cloud base altitude in feet MSL.'),
|
|
12
|
+
type: z
|
|
13
|
+
.string()
|
|
14
|
+
.nullable()
|
|
15
|
+
.describe('Cloud type qualifier: CB (cumulonimbus), TCU (towering cumulus), or null.'),
|
|
16
|
+
})
|
|
17
|
+
.describe('A forecast cloud layer.');
|
|
18
|
+
const ForecastPeriodSchema = z
|
|
19
|
+
.object({
|
|
20
|
+
from: z.string().describe('Period start time in ISO 8601 format (UTC).'),
|
|
21
|
+
to: z.string().describe('Period end time in ISO 8601 format (UTC).'),
|
|
22
|
+
change_type: z
|
|
23
|
+
.string()
|
|
24
|
+
.nullable()
|
|
25
|
+
.describe('Change indicator: FM (from), TEMPO (temporary), BECMG (becoming), or null for the base period.'),
|
|
26
|
+
probability: z
|
|
27
|
+
.number()
|
|
28
|
+
.nullable()
|
|
29
|
+
.describe('Probability percentage (30 or 40) for TEMPO/PROB groups. Null if not specified.'),
|
|
30
|
+
wind: z
|
|
31
|
+
.object({
|
|
32
|
+
direction_deg: z
|
|
33
|
+
.number()
|
|
34
|
+
.nullable()
|
|
35
|
+
.describe('Forecast wind direction in degrees true. Null when variable.'),
|
|
36
|
+
speed_kt: z.number().describe('Forecast wind speed in knots.'),
|
|
37
|
+
gust_kt: z.number().nullable().describe('Forecast gust speed in knots, or null if none.'),
|
|
38
|
+
})
|
|
39
|
+
.describe('Forecast wind conditions for this period.'),
|
|
40
|
+
visibility_sm: z
|
|
41
|
+
.string()
|
|
42
|
+
.nullable()
|
|
43
|
+
.describe('Forecast visibility in statute miles (e.g., "6", "1/2"). Null if not specified.'),
|
|
44
|
+
weather: z
|
|
45
|
+
.string()
|
|
46
|
+
.nullable()
|
|
47
|
+
.describe('Decoded weather condition (e.g., "light rain showers", "thunderstorm with rain"). Null if none.'),
|
|
48
|
+
clouds: z.array(TafCloudLayerSchema).describe('Forecast cloud layers for this period.'),
|
|
49
|
+
})
|
|
50
|
+
.describe('A single TAF forecast period.');
|
|
51
|
+
export const aviationGetTaf = tool('aviation_get_taf', {
|
|
52
|
+
title: 'Get Terminal Aerodrome Forecast (TAF)',
|
|
53
|
+
description: 'Get the Terminal Aerodrome Forecast (TAF) for one or more airports. Returns each forecast period with valid times, wind, visibility, decoded weather conditions, and cloud layers, plus the raw TAF string. TAFs cover the next 24–30 hours and are issued only for airports with scheduled commercial service; check data_types from aviation_find_stations to confirm TAF availability. Accepts 1–4 ICAO station IDs (e.g., KSEA, KJFK).',
|
|
54
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
55
|
+
input: z.object({
|
|
56
|
+
station_ids: z
|
|
57
|
+
.array(z
|
|
58
|
+
.string()
|
|
59
|
+
.regex(/^[A-Z]{4}$/)
|
|
60
|
+
.describe('4-letter ICAO station ID (e.g., KSEA, KJFK).'))
|
|
61
|
+
.min(1)
|
|
62
|
+
.max(4)
|
|
63
|
+
.describe('ICAO station IDs to query. 1–4 stations per call.'),
|
|
64
|
+
}),
|
|
65
|
+
output: z.object({
|
|
66
|
+
forecasts: z
|
|
67
|
+
.array(z
|
|
68
|
+
.object({
|
|
69
|
+
station_id: z.string().describe('ICAO 4-letter station identifier (e.g., KSEA).'),
|
|
70
|
+
name: z.string().describe('Human-readable station or airport name.'),
|
|
71
|
+
issued_at: z.string().describe('TAF issue time in ISO 8601 format (UTC).'),
|
|
72
|
+
valid_from: z
|
|
73
|
+
.string()
|
|
74
|
+
.describe('Forecast validity period start in ISO 8601 format (UTC).'),
|
|
75
|
+
valid_to: z.string().describe('Forecast validity period end in ISO 8601 format (UTC).'),
|
|
76
|
+
forecast_periods: z
|
|
77
|
+
.array(ForecastPeriodSchema)
|
|
78
|
+
.describe('Ordered list of forecast periods from base to end of validity.'),
|
|
79
|
+
raw_taf: z
|
|
80
|
+
.string()
|
|
81
|
+
.describe('Original encoded TAF string (e.g., "TAF KSEA 041730Z 0418/0524 18010KT P6SM SKC ...").'),
|
|
82
|
+
})
|
|
83
|
+
.describe('A Terminal Aerodrome Forecast for one station.'))
|
|
84
|
+
.describe('TAF forecasts, one per requested station.'),
|
|
85
|
+
}),
|
|
86
|
+
errors: [
|
|
87
|
+
{
|
|
88
|
+
reason: 'no_taf_available',
|
|
89
|
+
code: JsonRpcErrorCode.NotFound,
|
|
90
|
+
when: 'Station does not issue TAFs or no TAF is currently available.',
|
|
91
|
+
recovery: 'Not all airports have TAFs — only major airports with scheduled commercial service typically issue them. Check data_types from aviation_find_stations to confirm TAF capability. Smaller airports may only have METARs.',
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
async handler(input, ctx) {
|
|
95
|
+
ctx.log.info('Fetching TAFs', { stationIds: input.station_ids });
|
|
96
|
+
const svc = getAviationWeatherService();
|
|
97
|
+
const forecasts = await svc.fetchTaf(input.station_ids, ctx);
|
|
98
|
+
if (forecasts.length === 0) {
|
|
99
|
+
throw ctx.fail('no_taf_available', `No TAF data found for: ${input.station_ids.join(', ')}`, {
|
|
100
|
+
stationIds: input.station_ids,
|
|
101
|
+
...ctx.recoveryFor('no_taf_available'),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
ctx.log.info('TAFs retrieved', { count: forecasts.length });
|
|
105
|
+
return { forecasts };
|
|
106
|
+
},
|
|
107
|
+
format: (result) => {
|
|
108
|
+
const lines = [];
|
|
109
|
+
for (const taf of result.forecasts) {
|
|
110
|
+
lines.push(`## ${taf.station_id} — ${taf.name}`);
|
|
111
|
+
lines.push(`**Issued:** ${taf.issued_at} | **Valid:** ${taf.valid_from} → ${taf.valid_to}`);
|
|
112
|
+
lines.push('');
|
|
113
|
+
for (const period of taf.forecast_periods) {
|
|
114
|
+
const changeLabel = period.change_type ? `**${period.change_type}** ` : '';
|
|
115
|
+
const probLabel = period.probability ? ` (${period.probability}%)` : '';
|
|
116
|
+
lines.push(`### ${changeLabel}${period.from} → ${period.to}${probLabel}`);
|
|
117
|
+
const gustStr = period.wind.gust_kt != null ? ` gusting ${period.wind.gust_kt} kt` : '';
|
|
118
|
+
const dirStr = period.wind.direction_deg != null ? `${period.wind.direction_deg}°` : 'variable';
|
|
119
|
+
lines.push(`**Wind:** ${dirStr} at ${period.wind.speed_kt} kt${gustStr}`);
|
|
120
|
+
if (period.visibility_sm != null) {
|
|
121
|
+
lines.push(`**Visibility:** ${period.visibility_sm} sm`);
|
|
122
|
+
}
|
|
123
|
+
if (period.weather) {
|
|
124
|
+
lines.push(`**Weather:** ${period.weather}`);
|
|
125
|
+
}
|
|
126
|
+
if (period.clouds.length > 0) {
|
|
127
|
+
const cloudStr = period.clouds
|
|
128
|
+
.map((c) => `${c.cover} @ ${c.base_ft} ft${c.type ? ` (${c.type})` : ''}`)
|
|
129
|
+
.join(', ');
|
|
130
|
+
lines.push(`**Clouds:** ${cloudStr}`);
|
|
131
|
+
}
|
|
132
|
+
lines.push('');
|
|
133
|
+
}
|
|
134
|
+
lines.push(`**Raw TAF:** \`${taf.raw_taf}\``);
|
|
135
|
+
lines.push('');
|
|
136
|
+
}
|
|
137
|
+
return [{ type: 'text', text: lines.join('\n').trim() }];
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=aviation-get-taf.tool.js.map
|