@pipeworx/mcp-aviation-weather 0.1.0 → 0.1.2
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 +8 -8
- package/package.json +1 -1
- package/server.json +1 -1
- package/src/index.ts +40 -16
package/README.md
CHANGED
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
Aviation Weather MCP — METAR, TAF, PIREPs, AIRMET/SIGMET, station info
|
|
4
4
|
|
|
5
|
-
Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to
|
|
5
|
+
Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 1160+ live data sources.
|
|
6
6
|
|
|
7
7
|
## Tools
|
|
8
8
|
|
|
9
9
|
| Tool | Description |
|
|
10
10
|
|------|-------------|
|
|
11
11
|
| `metar` | METAR observations. ids = comma-sep ICAO codes (KSFO,EGLL,LFPG). |
|
|
12
|
-
| `taf` | Terminal Aerodrome
|
|
13
|
-
| `pirep` | Pilot reports.
|
|
14
|
-
| `sigmet` |
|
|
15
|
-
| `airmet` |
|
|
16
|
-
| `gairmet` | Graphical AIRMETs. |
|
|
17
|
-
| `windsaloft` | Winds aloft forecast. |
|
|
12
|
+
| `taf` | Terminal Aerodrome Forecast (TAF) for one or more ICAO airport codes (e.g. KSFO,EGLL); returns forecast periods covering wind, visibility, and cloud ceilings for the next 24–30 h. |
|
|
13
|
+
| `pirep` | Pilot reports (PIREPs). Call with no args for recent US-wide reports (default CONUS box), or pass a station `id` for reports within `distance_nm` of it, or a custom `bbox`. |
|
|
14
|
+
| `sigmet` | Fetch all currently active SIGMETs (significant en-route weather hazards: convection, turbulence, icing, volcanic ash) from the US Aviation Weather Center; no inputs required. |
|
|
15
|
+
| `airmet` | Fetch all currently active AIRMETs (moderate turbulence, icing, IFR/mountain-obscuration advisories for general aviation) from the US Aviation Weather Center; no inputs required. |
|
|
16
|
+
| `gairmet` | Fetch Graphical AIRMETs from the US Aviation Weather Center; optionally filter by type (turb, ice, sfc_winds, lifr, ifr); returns GeoJSON-style hazard polygons. |
|
|
17
|
+
| `windsaloft` | Winds and temperatures aloft forecast from the US Aviation Weather Center; specify US region (us/bos/mia/chi/dfw/slc/sfo/alaska) and level (low/high); returns an ASCII table or JSON. |
|
|
18
18
|
| `stationinfo` | Aerodrome metadata — lat/lon, elevation, country. |
|
|
19
19
|
|
|
20
20
|
## Quick Start
|
|
@@ -31,7 +31,7 @@ Add to your MCP client (Claude Desktop, Cursor, Windsurf, etc.):
|
|
|
31
31
|
}
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Or connect to the full Pipeworx gateway for access to all
|
|
34
|
+
Or connect to the full Pipeworx gateway for access to all 1160+ data sources:
|
|
35
35
|
|
|
36
36
|
```json
|
|
37
37
|
{
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.pipeworx-io/aviation-weather",
|
|
4
4
|
"title": "Aviation Weather",
|
|
5
5
|
"description": "Aviation Weather MCP — METAR, TAF, PIREPs, AIRMET/SIGMET, station info",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.2",
|
|
7
7
|
"websiteUrl": "https://pipeworx.io/packs/aviation-weather",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/pipeworx-io/mcp-aviation-weather",
|
package/src/index.ts
CHANGED
|
@@ -45,7 +45,7 @@ const tools: McpToolExport['tools'] = [
|
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
name: 'taf',
|
|
48
|
-
description: 'Terminal Aerodrome
|
|
48
|
+
description: 'Terminal Aerodrome Forecast (TAF) for one or more ICAO airport codes (e.g. KSFO,EGLL); returns forecast periods covering wind, visibility, and cloud ceilings for the next 24–30 h.',
|
|
49
49
|
inputSchema: {
|
|
50
50
|
type: 'object',
|
|
51
51
|
properties: {
|
|
@@ -58,13 +58,14 @@ const tools: McpToolExport['tools'] = [
|
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
name: 'pirep',
|
|
61
|
-
description: 'Pilot reports.
|
|
61
|
+
description: 'Pilot reports (PIREPs). Call with no args for recent US-wide reports (default CONUS box), or pass a station `id` for reports within `distance_nm` of it, or a custom `bbox`.',
|
|
62
62
|
inputSchema: {
|
|
63
63
|
type: 'object',
|
|
64
64
|
properties: {
|
|
65
|
-
id: { type: 'string', description: 'Center station for proximity filter' },
|
|
65
|
+
id: { type: 'string', description: 'Center station for a proximity filter (e.g. "KORD"); reports within distance_nm of it.' },
|
|
66
|
+
distance_nm: { type: 'number', description: 'Radius from `id` in nautical miles (default 200). Only used with `id`.' },
|
|
67
|
+
bbox: { type: 'string', description: 'Bounding box "minLat,minLon,maxLat,maxLon" (default CONUS "20,-130,55,-60" when no id).' },
|
|
66
68
|
age: { type: 'number', description: 'Lookback hours, default 1.5' },
|
|
67
|
-
distance_nm: { type: 'number', description: 'Distance from id in nautical miles, default 200' },
|
|
68
69
|
level: { type: 'number', description: 'Flight level filter (FL310 = 310)' },
|
|
69
70
|
format: { type: 'string', description: 'json (default) | raw' },
|
|
70
71
|
},
|
|
@@ -72,7 +73,7 @@ const tools: McpToolExport['tools'] = [
|
|
|
72
73
|
},
|
|
73
74
|
{
|
|
74
75
|
name: 'sigmet',
|
|
75
|
-
description: '
|
|
76
|
+
description: 'Fetch all currently active SIGMETs (significant en-route weather hazards: convection, turbulence, icing, volcanic ash) from the US Aviation Weather Center; no inputs required.',
|
|
76
77
|
inputSchema: {
|
|
77
78
|
type: 'object',
|
|
78
79
|
properties: { format: { type: 'string', description: 'json (default) | raw' } },
|
|
@@ -80,7 +81,7 @@ const tools: McpToolExport['tools'] = [
|
|
|
80
81
|
},
|
|
81
82
|
{
|
|
82
83
|
name: 'airmet',
|
|
83
|
-
description: '
|
|
84
|
+
description: 'Fetch all currently active AIRMETs (moderate turbulence, icing, IFR/mountain-obscuration advisories for general aviation) from the US Aviation Weather Center; no inputs required.',
|
|
84
85
|
inputSchema: {
|
|
85
86
|
type: 'object',
|
|
86
87
|
properties: { format: { type: 'string' } },
|
|
@@ -88,7 +89,7 @@ const tools: McpToolExport['tools'] = [
|
|
|
88
89
|
},
|
|
89
90
|
{
|
|
90
91
|
name: 'gairmet',
|
|
91
|
-
description: 'Graphical AIRMETs.',
|
|
92
|
+
description: 'Fetch Graphical AIRMETs from the US Aviation Weather Center; optionally filter by type (turb, ice, sfc_winds, lifr, ifr); returns GeoJSON-style hazard polygons.',
|
|
92
93
|
inputSchema: {
|
|
93
94
|
type: 'object',
|
|
94
95
|
properties: {
|
|
@@ -99,7 +100,7 @@ const tools: McpToolExport['tools'] = [
|
|
|
99
100
|
},
|
|
100
101
|
{
|
|
101
102
|
name: 'windsaloft',
|
|
102
|
-
description: 'Winds aloft forecast.',
|
|
103
|
+
description: 'Winds and temperatures aloft forecast from the US Aviation Weather Center; specify US region (us/bos/mia/chi/dfw/slc/sfo/alaska) and level (low/high); returns an ASCII table or JSON.',
|
|
103
104
|
inputSchema: {
|
|
104
105
|
type: 'object',
|
|
105
106
|
properties: {
|
|
@@ -134,17 +135,34 @@ async function callTool(name: string, args: Record<string, unknown>): Promise<un
|
|
|
134
135
|
format: String(args.format ?? 'json'),
|
|
135
136
|
});
|
|
136
137
|
case 'pirep': {
|
|
138
|
+
// The API REQUIRES either a station id + radial distance OR a bounding
|
|
139
|
+
// box — a bare /pirep 400s ("Must specify bounding box or stations ID and
|
|
140
|
+
// radial distance"). So: with `id`, always send a distance (default 200);
|
|
141
|
+
// without `id`, default to a CONUS bbox so a bare pirep() returns US-wide
|
|
142
|
+
// reports instead of an error.
|
|
137
143
|
const params: Record<string, string> = { format: String(args.format ?? 'json') };
|
|
138
|
-
if (args.id) params.id = String(args.id);
|
|
139
144
|
if (args.age !== undefined) params.age = String(args.age);
|
|
140
|
-
if (args.distance_nm !== undefined) params.distance = String(args.distance_nm);
|
|
141
145
|
if (args.level !== undefined) params.level = String(args.level);
|
|
146
|
+
if (args.id) {
|
|
147
|
+
params.id = String(args.id);
|
|
148
|
+
params.distance = String(args.distance_nm ?? 200);
|
|
149
|
+
} else {
|
|
150
|
+
params.bbox = typeof args.bbox === 'string' && args.bbox.trim() ? String(args.bbox) : '20,-130,55,-60';
|
|
151
|
+
}
|
|
142
152
|
return fetchAW('/pirep', params);
|
|
143
153
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
// The API's `hazard` param no longer accepts sigmet/airmet ("Invalid value
|
|
155
|
+
// for hazard" 400 — it means conv/turb/ice now), and server-side `type`
|
|
156
|
+
// filtering is unreliable. Fetch all air/sigmets and filter client-side on
|
|
157
|
+
// the airSigmetType field.
|
|
158
|
+
case 'sigmet': {
|
|
159
|
+
const all = await fetchAW('/airsigmet', { format: 'json' });
|
|
160
|
+
return Array.isArray(all) ? all.filter((x: Record<string, unknown>) => String(x.airSigmetType).toUpperCase() === 'SIGMET') : all;
|
|
161
|
+
}
|
|
162
|
+
case 'airmet': {
|
|
163
|
+
const all = await fetchAW('/airsigmet', { format: 'json' });
|
|
164
|
+
return Array.isArray(all) ? all.filter((x: Record<string, unknown>) => String(x.airSigmetType).toUpperCase() === 'AIRMET') : all;
|
|
165
|
+
}
|
|
148
166
|
case 'gairmet': {
|
|
149
167
|
const params: Record<string, string> = { format: String(args.format ?? 'json') };
|
|
150
168
|
if (args.type) params.type = String(args.type);
|
|
@@ -179,10 +197,16 @@ async function fetchAW(path: string, paramsObj: Record<string, string>) {
|
|
|
179
197
|
}
|
|
180
198
|
const format = paramsObj.format ?? 'json';
|
|
181
199
|
if (format === 'json') {
|
|
200
|
+
// Read once as text, then attempt JSON parse on the string. The earlier
|
|
201
|
+
// version called res.json() then fell through to res.text() on parse
|
|
202
|
+
// failure — but res.json() consumes the body, so the fallback hit
|
|
203
|
+
// "Body has already been used". Reading text first avoids that and
|
|
204
|
+
// also lets us return the raw payload when the upstream returns plain
|
|
205
|
+
// text (e.g. /windtemp ignores ?format=json and ships an ASCII table).
|
|
206
|
+
const text = await res.text();
|
|
182
207
|
try {
|
|
183
|
-
return
|
|
208
|
+
return JSON.parse(text);
|
|
184
209
|
} catch {
|
|
185
|
-
const text = await res.text();
|
|
186
210
|
return { format: 'raw', body: text };
|
|
187
211
|
}
|
|
188
212
|
}
|