@ryancardin/noaa-tides-currents-mcp-server 1.0.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/.claude/settings.local.json +29 -0
- package/CLAUDE.md +71 -0
- package/Dockerfile +14 -0
- package/LICENSE +21 -0
- package/README.md +234 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +9 -0
- package/dist/interfaces/config.d.ts +6 -0
- package/dist/interfaces/config.js +1 -0
- package/dist/interfaces/moon.d.ts +65 -0
- package/dist/interfaces/moon.js +35 -0
- package/dist/interfaces/noaa.d.ts +334 -0
- package/dist/interfaces/noaa.js +98 -0
- package/dist/interfaces/parameters.d.ts +18 -0
- package/dist/interfaces/parameters.js +5 -0
- package/dist/interfaces/sun.d.ts +103 -0
- package/dist/interfaces/sun.js +45 -0
- package/dist/mcp-server.d.ts +12 -0
- package/dist/mcp-server.js +103 -0
- package/dist/moon-phase-service.d.ts +122 -0
- package/dist/moon-phase-service.js +187 -0
- package/dist/noaa-service.d.ts +60 -0
- package/dist/noaa-service.js +159 -0
- package/dist/schemas/common.d.ts +14 -0
- package/dist/schemas/common.js +18 -0
- package/dist/schemas/dpapi.d.ts +198 -0
- package/dist/schemas/dpapi.js +89 -0
- package/dist/server/config.d.ts +9 -0
- package/dist/server/config.js +40 -0
- package/dist/server/mcp-server.d.ts +12 -0
- package/dist/server/mcp-server.js +103 -0
- package/dist/services/dpapi-service.d.ts +72 -0
- package/dist/services/dpapi-service.js +164 -0
- package/dist/services/moon-phase-service.d.ts +34 -0
- package/dist/services/moon-phase-service.js +147 -0
- package/dist/services/noaa-parameters-service.d.ts +76 -0
- package/dist/services/noaa-parameters-service.js +128 -0
- package/dist/services/noaa-service.d.ts +52 -0
- package/dist/services/noaa-service.js +151 -0
- package/dist/services/sun-service.d.ts +60 -0
- package/dist/services/sun-service.js +234 -0
- package/dist/sun-service.d.ts +184 -0
- package/dist/sun-service.js +218 -0
- package/dist/tools/derived-product-tools.d.ts +6 -0
- package/dist/tools/derived-product-tools.js +168 -0
- package/dist/tools/index.d.ts +16 -0
- package/dist/tools/index.js +36 -0
- package/dist/tools/moon-tools.d.ts +6 -0
- package/dist/tools/moon-tools.js +69 -0
- package/dist/tools/parameter-tools.d.ts +6 -0
- package/dist/tools/parameter-tools.js +77 -0
- package/dist/tools/station-tools.d.ts +6 -0
- package/dist/tools/station-tools.js +51 -0
- package/dist/tools/sun-tools.d.ts +6 -0
- package/dist/tools/sun-tools.js +109 -0
- package/dist/tools/water-tools.d.ts +6 -0
- package/dist/tools/water-tools.js +150 -0
- package/dist/types/moon.d.ts +26 -0
- package/dist/types/moon.js +14 -0
- package/dist/types/sun.d.ts +49 -0
- package/dist/types/sun.js +19 -0
- package/dist/types.d.ts +337 -0
- package/dist/types.js +98 -0
- package/package.json +56 -0
- package/smithery.yaml +16 -0
- package/src/index.ts +13 -0
- package/src/interfaces/moon.ts +44 -0
- package/src/interfaces/noaa.ts +130 -0
- package/src/interfaces/parameters.ts +20 -0
- package/src/interfaces/sun.ts +57 -0
- package/src/schemas/common.ts +23 -0
- package/src/schemas/dpapi.ts +99 -0
- package/src/server/config.ts +43 -0
- package/src/server/mcp-server.ts +135 -0
- package/src/services/dpapi-service.ts +187 -0
- package/src/services/moon-phase-service.ts +167 -0
- package/src/services/noaa-parameters-service.ts +139 -0
- package/src/services/noaa-service.ts +171 -0
- package/src/services/sun-service.ts +275 -0
- package/src/tools/derived-product-tools.ts +180 -0
- package/src/tools/index.ts +40 -0
- package/src/tools/moon-tools.ts +79 -0
- package/src/tools/parameter-tools.ts +82 -0
- package/src/tools/station-tools.ts +57 -0
- package/src/tools/sun-tools.ts +120 -0
- package/src/tools/water-tools.ts +166 -0
- package/src/types/moon.ts +27 -0
- package/src/types/sun.ts +51 -0
- package/src/types/suncalc.d.ts +110 -0
- package/test-dpapi.js +0 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// Common parameter schemas
|
|
4
|
+
const StationSchema = z.string().min(1).describe('Station ID');
|
|
5
|
+
const DateSchema = z.string().optional().describe('Date to retrieve data for ("today", "latest", "recent", or specific date)');
|
|
6
|
+
const BeginDateSchema = z.string().optional().describe('Start date (YYYYMMDD or MM/DD/YYYY)');
|
|
7
|
+
const EndDateSchema = z.string().optional().describe('End date (YYYYMMDD or MM/DD/YYYY)');
|
|
8
|
+
const RangeSchema = z.number().optional().describe('Number of hours to retrieve data for');
|
|
9
|
+
const DatumSchema = z.string().optional().describe('Datum to use (MLLW, MSL, etc.)');
|
|
10
|
+
const UnitsSchema = z.enum(['english', 'metric']).optional().describe('Units to use ("english" or "metric")');
|
|
11
|
+
const TimeZoneSchema = z.enum(['gmt', 'lst', 'lst_ldt']).optional().describe('Time zone (gmt, lst, lst_ldt)');
|
|
12
|
+
const FormatSchema = z.enum(['json', 'xml', 'csv']).optional().describe('Output format (json, xml, csv)');
|
|
13
|
+
const BinSchema = z.number().optional().describe('Bin number');
|
|
14
|
+
const IntervalSchema = z.string().optional().describe('Interval (hilo, hl, h, or a number for minutes)');
|
|
15
|
+
|
|
16
|
+
// Water Level Schema
|
|
17
|
+
export const GetWaterLevelsSchema = z.object({
|
|
18
|
+
station: StationSchema,
|
|
19
|
+
date: DateSchema,
|
|
20
|
+
begin_date: BeginDateSchema,
|
|
21
|
+
end_date: EndDateSchema,
|
|
22
|
+
range: RangeSchema,
|
|
23
|
+
datum: DatumSchema,
|
|
24
|
+
units: UnitsSchema,
|
|
25
|
+
time_zone: TimeZoneSchema,
|
|
26
|
+
format: FormatSchema,
|
|
27
|
+
}).refine(
|
|
28
|
+
data => (data.date || (data.begin_date && data.end_date) || (data.begin_date && data.range) || (data.end_date && data.range) || data.range),
|
|
29
|
+
{ message: "You must provide either 'date', 'begin_date' and 'end_date', 'begin_date' and 'range', 'end_date' and 'range', or just 'range'" }
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// Tide Predictions Schema
|
|
33
|
+
export const GetTidePredictionsSchema = z.object({
|
|
34
|
+
station: StationSchema,
|
|
35
|
+
begin_date: BeginDateSchema,
|
|
36
|
+
end_date: EndDateSchema,
|
|
37
|
+
date: DateSchema,
|
|
38
|
+
range: RangeSchema,
|
|
39
|
+
datum: DatumSchema,
|
|
40
|
+
units: UnitsSchema,
|
|
41
|
+
time_zone: TimeZoneSchema,
|
|
42
|
+
interval: IntervalSchema,
|
|
43
|
+
format: FormatSchema,
|
|
44
|
+
}).refine(
|
|
45
|
+
data => (data.date || (data.begin_date && data.end_date) || (data.begin_date && data.range) || (data.end_date && data.range) || data.range),
|
|
46
|
+
{ message: "You must provide either 'date', 'begin_date' and 'end_date', 'begin_date' and 'range', 'end_date' and 'range', or just 'range'" }
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// Currents Schema
|
|
50
|
+
export const GetCurrentsSchema = z.object({
|
|
51
|
+
station: StationSchema,
|
|
52
|
+
date: DateSchema,
|
|
53
|
+
begin_date: BeginDateSchema,
|
|
54
|
+
end_date: EndDateSchema,
|
|
55
|
+
range: RangeSchema,
|
|
56
|
+
bin: BinSchema,
|
|
57
|
+
units: UnitsSchema,
|
|
58
|
+
time_zone: TimeZoneSchema,
|
|
59
|
+
format: FormatSchema,
|
|
60
|
+
}).refine(
|
|
61
|
+
data => (data.date || (data.begin_date && data.end_date) || (data.begin_date && data.range) || (data.end_date && data.range) || data.range),
|
|
62
|
+
{ message: "You must provide either 'date', 'begin_date' and 'end_date', 'begin_date' and 'range', 'end_date' and 'range', or just 'range'" }
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Current Predictions Schema
|
|
66
|
+
export const GetCurrentPredictionsSchema = z.object({
|
|
67
|
+
station: StationSchema,
|
|
68
|
+
date: DateSchema,
|
|
69
|
+
begin_date: BeginDateSchema,
|
|
70
|
+
end_date: EndDateSchema,
|
|
71
|
+
range: RangeSchema,
|
|
72
|
+
bin: BinSchema,
|
|
73
|
+
interval: z.string().optional().describe('Interval (MAX_SLACK or a number for minutes)'),
|
|
74
|
+
vel_type: z.enum(['speed_dir', 'default']).optional().describe('Velocity type (speed_dir or default)'),
|
|
75
|
+
units: UnitsSchema,
|
|
76
|
+
time_zone: TimeZoneSchema,
|
|
77
|
+
format: FormatSchema,
|
|
78
|
+
}).refine(
|
|
79
|
+
data => (data.date || (data.begin_date && data.end_date) || (data.begin_date && data.range) || (data.end_date && data.range) || data.range),
|
|
80
|
+
{ message: "You must provide either 'date', 'begin_date' and 'end_date', 'begin_date' and 'range', 'end_date' and 'range', or just 'range'" }
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Meteorological Data Schema
|
|
84
|
+
export const GetMeteorologicalDataSchema = z.object({
|
|
85
|
+
station: StationSchema,
|
|
86
|
+
product: z.string().min(1).describe('Product (air_temperature, wind, etc.)'),
|
|
87
|
+
date: DateSchema,
|
|
88
|
+
begin_date: BeginDateSchema,
|
|
89
|
+
end_date: EndDateSchema,
|
|
90
|
+
range: RangeSchema,
|
|
91
|
+
units: UnitsSchema,
|
|
92
|
+
time_zone: TimeZoneSchema,
|
|
93
|
+
format: FormatSchema,
|
|
94
|
+
}).refine(
|
|
95
|
+
data => (data.date || (data.begin_date && data.end_date) || (data.begin_date && data.range) || (data.end_date && data.range) || data.range),
|
|
96
|
+
{ message: "You must provide either 'date', 'begin_date' and 'end_date', 'begin_date' and 'range', 'end_date' and 'range', or just 'range'" }
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// Station List Schema
|
|
100
|
+
export const GetStationsSchema = z.object({
|
|
101
|
+
type: z.string().optional().describe('Station type (waterlevels, currents, etc.)'),
|
|
102
|
+
units: UnitsSchema,
|
|
103
|
+
format: z.enum(['json', 'xml']).optional().describe('Output format (json, xml)'),
|
|
104
|
+
name: z.string().optional().describe('Filter stations by name (partial match)'),
|
|
105
|
+
lat_min: z.number().optional().describe('Minimum latitude boundary'),
|
|
106
|
+
lat_max: z.number().optional().describe('Maximum latitude boundary'),
|
|
107
|
+
lon_min: z.number().optional().describe('Minimum longitude boundary'),
|
|
108
|
+
lon_max: z.number().optional().describe('Maximum longitude boundary'),
|
|
109
|
+
state: z.string().optional().describe('Filter stations by state code (e.g., CA, NY)'),
|
|
110
|
+
limit: z.number().optional().describe('Maximum number of stations to return'),
|
|
111
|
+
offset: z.number().optional().describe('Number of stations to skip for pagination'),
|
|
112
|
+
sort_by: z.enum(['name', 'id', 'state']).optional().describe('Field to sort results by'),
|
|
113
|
+
sort_order: z.enum(['asc', 'desc']).optional().describe('Sort order (ascending or descending)'),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Station Details Schema
|
|
117
|
+
export const GetStationDetailsSchema = z.object({
|
|
118
|
+
station: StationSchema,
|
|
119
|
+
units: UnitsSchema,
|
|
120
|
+
format: z.enum(['json', 'xml']).optional().describe('Output format (json, xml)'),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Define exported types
|
|
124
|
+
export type GetWaterLevelsParams = z.infer<typeof GetWaterLevelsSchema>;
|
|
125
|
+
export type GetTidePredictionsParams = z.infer<typeof GetTidePredictionsSchema>;
|
|
126
|
+
export type GetCurrentsParams = z.infer<typeof GetCurrentsSchema>;
|
|
127
|
+
export type GetCurrentPredictionsParams = z.infer<typeof GetCurrentPredictionsSchema>;
|
|
128
|
+
export type GetMeteorologicalDataParams = z.infer<typeof GetMeteorologicalDataSchema>;
|
|
129
|
+
export type GetStationsParams = z.infer<typeof GetStationsSchema>;
|
|
130
|
+
export type GetStationDetailsParams = z.infer<typeof GetStationDetailsSchema>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// Parameter type schema
|
|
4
|
+
export const ParameterSchema = z.object({
|
|
5
|
+
parameter: z.string().optional().describe('Parameter type to get information about (time_zones, datums, units, tide_intervals, current_intervals, velocity_types, products, station_types, date_formats, output_formats). If not provided, returns information about all parameter types.')
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export type GetParametersParams = z.infer<typeof ParameterSchema>;
|
|
9
|
+
|
|
10
|
+
// Interface for parameter info responses
|
|
11
|
+
export interface ParameterInfo {
|
|
12
|
+
id: string;
|
|
13
|
+
description: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DateFormatInfo {
|
|
17
|
+
format: string;
|
|
18
|
+
description: string;
|
|
19
|
+
example: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { SunEventType } from '../types/sun.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parameters for getting sun times
|
|
6
|
+
*/
|
|
7
|
+
export const SunTimesParamsSchema = z.object({
|
|
8
|
+
date: z.string().optional().describe('Date to get sun times for (YYYY-MM-DD format). Defaults to current date.'),
|
|
9
|
+
latitude: z.number().min(-90).max(90).describe('Latitude for location-specific calculations'),
|
|
10
|
+
longitude: z.number().min(-180).max(180).describe('Longitude for location-specific calculations'),
|
|
11
|
+
format: z.enum(['json', 'text']).optional().describe('Output format (json or text)'),
|
|
12
|
+
timezone: z.string().optional().describe('Timezone for the results. Defaults to UTC.')
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export type SunTimesParams = z.infer<typeof SunTimesParamsSchema>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parameters for getting sun times for a date range
|
|
19
|
+
*/
|
|
20
|
+
export const SunTimesRangeParamsSchema = z.object({
|
|
21
|
+
start_date: z.string().describe('Start date (YYYY-MM-DD format)'),
|
|
22
|
+
end_date: z.string().describe('End date (YYYY-MM-DD format)'),
|
|
23
|
+
latitude: z.number().min(-90).max(90).describe('Latitude for location-specific calculations'),
|
|
24
|
+
longitude: z.number().min(-180).max(180).describe('Longitude for location-specific calculations'),
|
|
25
|
+
format: z.enum(['json', 'text']).optional().describe('Output format (json or text)'),
|
|
26
|
+
timezone: z.string().optional().describe('Timezone for the results. Defaults to UTC.')
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export type SunTimesRangeParams = z.infer<typeof SunTimesRangeParamsSchema>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Parameters for getting sun position
|
|
33
|
+
*/
|
|
34
|
+
export const SunPositionParamsSchema = z.object({
|
|
35
|
+
date: z.string().optional().describe('Date to get sun position for (YYYY-MM-DD format). Defaults to current date.'),
|
|
36
|
+
time: z.string().optional().describe('Time to get sun position for (HH:MM:SS format). Defaults to current time.'),
|
|
37
|
+
latitude: z.number().min(-90).max(90).describe('Latitude for location-specific calculations'),
|
|
38
|
+
longitude: z.number().min(-180).max(180).describe('Longitude for location-specific calculations'),
|
|
39
|
+
format: z.enum(['json', 'text']).optional().describe('Output format (json or text)')
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export type SunPositionParams = z.infer<typeof SunPositionParamsSchema>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Parameters for finding the next sun event
|
|
46
|
+
*/
|
|
47
|
+
export const NextSunEventParamsSchema = z.object({
|
|
48
|
+
event: z.nativeEnum(SunEventType).describe('Sun event to find'),
|
|
49
|
+
date: z.string().optional().describe('Starting date (YYYY-MM-DD format). Defaults to current date.'),
|
|
50
|
+
latitude: z.number().min(-90).max(90).describe('Latitude for location-specific calculations'),
|
|
51
|
+
longitude: z.number().min(-180).max(180).describe('Longitude for location-specific calculations'),
|
|
52
|
+
count: z.number().positive().optional().describe('Number of occurrences to return. Defaults to 1.'),
|
|
53
|
+
format: z.enum(['json', 'text']).optional().describe('Output format (json or text)'),
|
|
54
|
+
timezone: z.string().optional().describe('Timezone for the results. Defaults to UTC.')
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export type NextSunEventParams = z.infer<typeof NextSunEventParamsSchema>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// Common parameter schemas
|
|
4
|
+
export const StationSchema = z.string().min(1).describe('Station ID');
|
|
5
|
+
export const DateSchema = z.string().optional().describe('Date to retrieve data for ("today", "latest", "recent", or specific date)');
|
|
6
|
+
export const BeginDateSchema = z.string().optional().describe('Start date (YYYYMMDD or MM/DD/YYYY)');
|
|
7
|
+
export const EndDateSchema = z.string().optional().describe('End date (YYYYMMDD or MM/DD/YYYY)');
|
|
8
|
+
export const RangeSchema = z.number().optional().describe('Number of hours to retrieve data for');
|
|
9
|
+
export const DatumSchema = z.string().optional().describe('Datum to use (MLLW, MSL, etc.)');
|
|
10
|
+
export const UnitsSchema = z.enum(['english', 'metric']).optional().describe('Units to use ("english" or "metric")');
|
|
11
|
+
export const TimeZoneSchema = z.enum(['gmt', 'lst', 'lst_ldt']).optional().describe('Time zone (gmt, lst, lst_ldt)');
|
|
12
|
+
export const FormatSchema = z.enum(['json', 'xml', 'csv']).optional().describe('Output format (json, xml, csv)');
|
|
13
|
+
export const BinSchema = z.number().optional().describe('Bin number');
|
|
14
|
+
export const IntervalSchema = z.string().optional().describe('Interval (hilo, hl, h, or a number for minutes)');
|
|
15
|
+
|
|
16
|
+
// Schema refinement function for date parameters
|
|
17
|
+
export const refineDateParams = (data: any) =>
|
|
18
|
+
(data.date || (data.begin_date && data.end_date) ||
|
|
19
|
+
(data.begin_date && data.range) || (data.end_date && data.range) ||
|
|
20
|
+
data.range);
|
|
21
|
+
|
|
22
|
+
export const dateRefinementMessage =
|
|
23
|
+
"You must provide either 'date', 'begin_date' and 'end_date', 'begin_date' and 'range', 'end_date' and 'range', or just 'range'";
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { StationSchema, UnitsSchema, FormatSchema } from './common.js';
|
|
3
|
+
|
|
4
|
+
// DPAPI-specific parameter schemas
|
|
5
|
+
export const AffiliationSchema = z.enum(['Global', 'US']).optional().describe('Station affiliation (Global or US)');
|
|
6
|
+
export const ScenarioSchema = z.enum(['all', 'low', 'intermediate-low', 'intermediate', 'intermediate-high', 'high', 'extreme']).optional().describe('Sea level rise scenario');
|
|
7
|
+
export const SeasonSchema = z.enum(['DJF', 'MAM', 'JJA', 'SON']).optional().describe('Season months (DJF-Winter, MAM-Spring, JJA-Summer, SON-Fall)');
|
|
8
|
+
export const DpapiDatumSchema = z.enum(['STND', 'MLLW', 'MHHW', 'GT', 'MSL', 'MLW', 'MHW']).optional().describe('Datum reference for DPAPI');
|
|
9
|
+
export const ThresholdSchema = z.enum(['minor', 'moderate', 'major']).optional().describe('Flood threshold level');
|
|
10
|
+
export const DecadeSchema = z.string().optional().describe('Decade for projections (e.g., "2050")');
|
|
11
|
+
export const YearSchema = z.string().optional().describe('Year for analysis (YYYY format)');
|
|
12
|
+
export const YearRangeSchema = z.string().optional().describe('Year range (YYYY-YYYY format)');
|
|
13
|
+
|
|
14
|
+
// Sea Level Trends schema
|
|
15
|
+
export const SeaLevelTrendsSchema = z.object({
|
|
16
|
+
station: StationSchema,
|
|
17
|
+
affil: AffiliationSchema,
|
|
18
|
+
format: FormatSchema
|
|
19
|
+
}).describe('Get sea level trends for a station');
|
|
20
|
+
|
|
21
|
+
// Extreme Water Levels schema
|
|
22
|
+
export const ExtremeWaterLevelsSchema = z.object({
|
|
23
|
+
station: StationSchema,
|
|
24
|
+
units: UnitsSchema,
|
|
25
|
+
format: FormatSchema
|
|
26
|
+
}).describe('Get extreme water levels for a station');
|
|
27
|
+
|
|
28
|
+
// High Tide Flooding Daily schema
|
|
29
|
+
export const HighTideFloodingDailySchema = z.object({
|
|
30
|
+
station: StationSchema,
|
|
31
|
+
format: FormatSchema,
|
|
32
|
+
datum: DpapiDatumSchema,
|
|
33
|
+
threshold: ThresholdSchema,
|
|
34
|
+
begin_date: z.string().optional().describe('Start date (YYYYMMDD format)'),
|
|
35
|
+
end_date: z.string().optional().describe('End date (YYYYMMDD format)'),
|
|
36
|
+
year: YearSchema
|
|
37
|
+
}).describe('Get high tide flooding daily count data');
|
|
38
|
+
|
|
39
|
+
// High Tide Flooding Monthly schema
|
|
40
|
+
export const HighTideFloodingMonthlySchema = z.object({
|
|
41
|
+
station: StationSchema,
|
|
42
|
+
format: FormatSchema,
|
|
43
|
+
datum: DpapiDatumSchema,
|
|
44
|
+
threshold: ThresholdSchema,
|
|
45
|
+
begin_date: z.string().optional().describe('Start date (YYYYMMDD format)'),
|
|
46
|
+
end_date: z.string().optional().describe('End date (YYYYMMDD format)'),
|
|
47
|
+
year: YearSchema
|
|
48
|
+
}).describe('Get high tide flooding monthly count data');
|
|
49
|
+
|
|
50
|
+
// High Tide Flooding Seasonal schema
|
|
51
|
+
export const HighTideFloodingSeasonalSchema = z.object({
|
|
52
|
+
station: StationSchema,
|
|
53
|
+
format: FormatSchema,
|
|
54
|
+
datum: DpapiDatumSchema,
|
|
55
|
+
threshold: ThresholdSchema,
|
|
56
|
+
season_months: SeasonSchema,
|
|
57
|
+
begin_date: z.string().optional().describe('Start date (YYYYMMDD format)'),
|
|
58
|
+
end_date: z.string().optional().describe('End date (YYYYMMDD format)'),
|
|
59
|
+
year: YearSchema
|
|
60
|
+
}).describe('Get high tide flooding seasonal count data');
|
|
61
|
+
|
|
62
|
+
// High Tide Flooding Annual schema
|
|
63
|
+
export const HighTideFloodingAnnualSchema = z.object({
|
|
64
|
+
station: StationSchema,
|
|
65
|
+
format: FormatSchema,
|
|
66
|
+
datum: DpapiDatumSchema,
|
|
67
|
+
threshold: ThresholdSchema,
|
|
68
|
+
begin_date: z.string().optional().describe('Start date (YYYYMMDD format)'),
|
|
69
|
+
end_date: z.string().optional().describe('End date (YYYYMMDD format)'),
|
|
70
|
+
year_range: YearRangeSchema
|
|
71
|
+
}).describe('Get high tide flooding annual count data');
|
|
72
|
+
|
|
73
|
+
// High Tide Flooding Projections schema
|
|
74
|
+
export const HighTideFloodingProjectionsSchema = z.object({
|
|
75
|
+
station: StationSchema,
|
|
76
|
+
format: FormatSchema,
|
|
77
|
+
scenario: ScenarioSchema,
|
|
78
|
+
datum: DpapiDatumSchema,
|
|
79
|
+
threshold: ThresholdSchema,
|
|
80
|
+
decade: DecadeSchema
|
|
81
|
+
}).describe('Get high tide flooding decadal projections');
|
|
82
|
+
|
|
83
|
+
// High Tide Flooding Likelihoods schema
|
|
84
|
+
export const HighTideFloodingLikelihoodsSchema = z.object({
|
|
85
|
+
station: StationSchema,
|
|
86
|
+
format: FormatSchema,
|
|
87
|
+
datum: DpapiDatumSchema,
|
|
88
|
+
threshold: ThresholdSchema,
|
|
89
|
+
date: z.string().optional().describe('Specific date (YYYYMMDD format)')
|
|
90
|
+
}).describe('Get high tide flooding daily likelihoods');
|
|
91
|
+
|
|
92
|
+
// Top Ten Water Levels schema
|
|
93
|
+
export const TopTenWaterLevelsSchema = z.object({
|
|
94
|
+
station: StationSchema,
|
|
95
|
+
format: FormatSchema,
|
|
96
|
+
datum: DpapiDatumSchema,
|
|
97
|
+
units: UnitsSchema,
|
|
98
|
+
analysis_type: z.enum(['highest', 'lowest']).optional().describe('Analysis type (highest or lowest)')
|
|
99
|
+
}).describe('Get top ten water levels for a station');
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create and configure the FastMCP server
|
|
5
|
+
*/
|
|
6
|
+
export function createServer() {
|
|
7
|
+
// Create the MCP server with fixed configuration
|
|
8
|
+
const server = new FastMCP({
|
|
9
|
+
name: 'LocalTides',
|
|
10
|
+
version: '1.0.0'
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
return server;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Start the FastMCP server with configurable transport
|
|
18
|
+
*/
|
|
19
|
+
export function startServer(server: FastMCP) {
|
|
20
|
+
// Check command line arguments for transport type
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
const httpIndex = args.indexOf('--http');
|
|
23
|
+
const portIndex = args.indexOf('--port');
|
|
24
|
+
|
|
25
|
+
if (httpIndex !== -1) {
|
|
26
|
+
// HTTP transport mode
|
|
27
|
+
const port = portIndex !== -1 && args[portIndex + 1] ? parseInt(args[portIndex + 1]) : 3000;
|
|
28
|
+
console.log(`Starting NOAA MCP server on HTTP port ${port}`);
|
|
29
|
+
server.start({
|
|
30
|
+
transportType: 'httpStream',
|
|
31
|
+
httpStream: {
|
|
32
|
+
endpoint: '/sse',
|
|
33
|
+
port: port
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
} else {
|
|
37
|
+
// Default stdio transport
|
|
38
|
+
console.log('Starting NOAA MCP server with stdio transport');
|
|
39
|
+
server.start({
|
|
40
|
+
transportType: 'stdio'
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { NoaaService } from '../services/noaa-service.js';
|
|
2
|
+
import { ZodSchema } from 'zod';
|
|
3
|
+
import {
|
|
4
|
+
GetWaterLevelsSchema,
|
|
5
|
+
GetTidePredictionsSchema,
|
|
6
|
+
GetCurrentsSchema,
|
|
7
|
+
GetCurrentPredictionsSchema,
|
|
8
|
+
GetMeteorologicalDataSchema,
|
|
9
|
+
GetStationsSchema,
|
|
10
|
+
GetStationDetailsSchema
|
|
11
|
+
} from '../interfaces/noaa.js';
|
|
12
|
+
|
|
13
|
+
// MCP Tool type
|
|
14
|
+
interface MCPTool<TParams = any, TResult = any> {
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
inputSchema: ZodSchema<TParams>;
|
|
18
|
+
handler: (params: TParams) => Promise<TResult>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Class for the MCP server
|
|
22
|
+
export class McpServer {
|
|
23
|
+
private tools: MCPTool[];
|
|
24
|
+
private noaaService: NoaaService;
|
|
25
|
+
|
|
26
|
+
constructor(noaaService: NoaaService) {
|
|
27
|
+
this.noaaService = noaaService;
|
|
28
|
+
this.tools = this.initializeTools();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Initialize the tools
|
|
32
|
+
private initializeTools(): MCPTool[] {
|
|
33
|
+
// Water Levels tool
|
|
34
|
+
const getWaterLevels: MCPTool = {
|
|
35
|
+
name: "get_water_levels",
|
|
36
|
+
description: "Get water level data for a station",
|
|
37
|
+
inputSchema: GetWaterLevelsSchema,
|
|
38
|
+
handler: async (params) => {
|
|
39
|
+
return this.noaaService.getWaterLevels(params);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Tide Predictions tool
|
|
44
|
+
const getTidePredictions: MCPTool = {
|
|
45
|
+
name: "get_tide_predictions",
|
|
46
|
+
description: "Get tide prediction data",
|
|
47
|
+
inputSchema: GetTidePredictionsSchema,
|
|
48
|
+
handler: async (params) => {
|
|
49
|
+
return this.noaaService.getTidePredictions(params);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Currents tool
|
|
54
|
+
const getCurrents: MCPTool = {
|
|
55
|
+
name: "get_currents",
|
|
56
|
+
description: "Get currents data for a station",
|
|
57
|
+
inputSchema: GetCurrentsSchema,
|
|
58
|
+
handler: async (params) => {
|
|
59
|
+
return this.noaaService.getCurrents(params);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Current Predictions tool
|
|
64
|
+
const getCurrentPredictions: MCPTool = {
|
|
65
|
+
name: "get_current_predictions",
|
|
66
|
+
description: "Get current predictions",
|
|
67
|
+
inputSchema: GetCurrentPredictionsSchema,
|
|
68
|
+
handler: async (params) => {
|
|
69
|
+
return this.noaaService.getCurrentPredictions(params);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Meteorological Data tool
|
|
74
|
+
const getMeteorologicalData: MCPTool = {
|
|
75
|
+
name: "get_meteorological_data",
|
|
76
|
+
description: "Get meteorological data",
|
|
77
|
+
inputSchema: GetMeteorologicalDataSchema,
|
|
78
|
+
handler: async (params) => {
|
|
79
|
+
return this.noaaService.getMeteorologicalData(params);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// Stations tool
|
|
84
|
+
const getStations: MCPTool = {
|
|
85
|
+
name: "get_stations",
|
|
86
|
+
description: "Get list of stations",
|
|
87
|
+
inputSchema: GetStationsSchema,
|
|
88
|
+
handler: async (params) => {
|
|
89
|
+
return this.noaaService.getStations(params);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Station Details tool
|
|
94
|
+
const getStationDetails: MCPTool = {
|
|
95
|
+
name: "get_station_details",
|
|
96
|
+
description: "Get detailed information about a station",
|
|
97
|
+
inputSchema: GetStationDetailsSchema,
|
|
98
|
+
handler: async (params) => {
|
|
99
|
+
return this.noaaService.getStationDetails(params);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return [
|
|
104
|
+
getWaterLevels,
|
|
105
|
+
getTidePredictions,
|
|
106
|
+
getCurrents,
|
|
107
|
+
getCurrentPredictions,
|
|
108
|
+
getMeteorologicalData,
|
|
109
|
+
getStations,
|
|
110
|
+
getStationDetails
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Method to get all tools
|
|
115
|
+
getTools(): { name: string, description: string }[] {
|
|
116
|
+
return this.tools.map(tool => ({
|
|
117
|
+
name: tool.name,
|
|
118
|
+
description: tool.description
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Method to handle tool execution
|
|
123
|
+
async executeTool(toolName: string, params: any): Promise<any> {
|
|
124
|
+
const tool = this.tools.find(t => t.name === toolName);
|
|
125
|
+
if (!tool) {
|
|
126
|
+
throw new Error(`Tool '${toolName}' not found`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Validate the parameters against the schema
|
|
130
|
+
const validatedParams = tool.inputSchema.parse(params);
|
|
131
|
+
|
|
132
|
+
// Execute the tool handler
|
|
133
|
+
return tool.handler(validatedParams);
|
|
134
|
+
}
|
|
135
|
+
}
|