@cyanheads/earthquake-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.
Files changed (57) hide show
  1. package/CLAUDE.md +388 -0
  2. package/Dockerfile +98 -0
  3. package/LICENSE +201 -0
  4. package/README.md +291 -0
  5. package/changelog/0.1.x/0.1.0.md +19 -0
  6. package/changelog/0.1.x/0.1.1.md +20 -0
  7. package/changelog/template.md +119 -0
  8. package/dist/config/server-config.d.ts +14 -0
  9. package/dist/config/server-config.d.ts.map +1 -0
  10. package/dist/config/server-config.js +43 -0
  11. package/dist/config/server-config.js.map +1 -0
  12. package/dist/index.d.ts +7 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +26 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/mcp-server/resources/definitions/earthquake-event.resource.d.ts +40 -0
  17. package/dist/mcp-server/resources/definitions/earthquake-event.resource.d.ts.map +1 -0
  18. package/dist/mcp-server/resources/definitions/earthquake-event.resource.js +27 -0
  19. package/dist/mcp-server/resources/definitions/earthquake-event.resource.js.map +1 -0
  20. package/dist/mcp-server/resources/definitions/earthquake-feed.resource.d.ts +24 -0
  21. package/dist/mcp-server/resources/definitions/earthquake-feed.resource.d.ts.map +1 -0
  22. package/dist/mcp-server/resources/definitions/earthquake-feed.resource.js +76 -0
  23. package/dist/mcp-server/resources/definitions/earthquake-feed.resource.js.map +1 -0
  24. package/dist/mcp-server/tools/definitions/earthquake-count.tool.d.ts +48 -0
  25. package/dist/mcp-server/tools/definitions/earthquake-count.tool.d.ts.map +1 -0
  26. package/dist/mcp-server/tools/definitions/earthquake-count.tool.js +170 -0
  27. package/dist/mcp-server/tools/definitions/earthquake-count.tool.js.map +1 -0
  28. package/dist/mcp-server/tools/definitions/earthquake-get-event.tool.d.ts +46 -0
  29. package/dist/mcp-server/tools/definitions/earthquake-get-event.tool.d.ts.map +1 -0
  30. package/dist/mcp-server/tools/definitions/earthquake-get-event.tool.js +50 -0
  31. package/dist/mcp-server/tools/definitions/earthquake-get-event.tool.js.map +1 -0
  32. package/dist/mcp-server/tools/definitions/earthquake-get-feed.tool.d.ts +61 -0
  33. package/dist/mcp-server/tools/definitions/earthquake-get-feed.tool.d.ts.map +1 -0
  34. package/dist/mcp-server/tools/definitions/earthquake-get-feed.tool.js +88 -0
  35. package/dist/mcp-server/tools/definitions/earthquake-get-feed.tool.js.map +1 -0
  36. package/dist/mcp-server/tools/definitions/earthquake-search.tool.d.ts +89 -0
  37. package/dist/mcp-server/tools/definitions/earthquake-search.tool.d.ts.map +1 -0
  38. package/dist/mcp-server/tools/definitions/earthquake-search.tool.js +199 -0
  39. package/dist/mcp-server/tools/definitions/earthquake-search.tool.js.map +1 -0
  40. package/dist/mcp-server/tools/schemas.d.ts +60 -0
  41. package/dist/mcp-server/tools/schemas.d.ts.map +1 -0
  42. package/dist/mcp-server/tools/schemas.js +83 -0
  43. package/dist/mcp-server/tools/schemas.js.map +1 -0
  44. package/dist/services/emsc/emsc-service.d.ts +30 -0
  45. package/dist/services/emsc/emsc-service.d.ts.map +1 -0
  46. package/dist/services/emsc/emsc-service.js +170 -0
  47. package/dist/services/emsc/emsc-service.js.map +1 -0
  48. package/dist/services/usgs/types.d.ts +136 -0
  49. package/dist/services/usgs/types.d.ts.map +1 -0
  50. package/dist/services/usgs/types.js +6 -0
  51. package/dist/services/usgs/types.js.map +1 -0
  52. package/dist/services/usgs/usgs-service.d.ts +39 -0
  53. package/dist/services/usgs/usgs-service.d.ts.map +1 -0
  54. package/dist/services/usgs/usgs-service.js +283 -0
  55. package/dist/services/usgs/usgs-service.js.map +1 -0
  56. package/package.json +78 -0
  57. package/server.json +99 -0
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @fileoverview Tool definition for fetching USGS pre-computed real-time earthquake feeds.
3
+ * @module mcp-server/tools/definitions/earthquake-get-feed.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const earthquakeGetFeed: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ magnitude_tier: z.ZodDefault<z.ZodEnum<{
9
+ all: "all";
10
+ "1.0": "1.0";
11
+ 2.5: "2.5";
12
+ 4.5: "4.5";
13
+ significant: "significant";
14
+ }>>;
15
+ time_window: z.ZodDefault<z.ZodEnum<{
16
+ hour: "hour";
17
+ day: "day";
18
+ week: "week";
19
+ month: "month";
20
+ }>>;
21
+ }, z.core.$strip>, z.ZodObject<{
22
+ count: z.ZodNumber;
23
+ generated_at: z.ZodString;
24
+ events: z.ZodArray<z.ZodObject<{
25
+ id: z.ZodString;
26
+ title: z.ZodString;
27
+ magnitude: z.ZodNumber;
28
+ magnitude_type: z.ZodString;
29
+ time: z.ZodString;
30
+ updated: z.ZodString;
31
+ place: z.ZodString;
32
+ latitude: z.ZodNumber;
33
+ longitude: z.ZodNumber;
34
+ depth_km: z.ZodNumber;
35
+ felt: z.ZodNullable<z.ZodNumber>;
36
+ cdi: z.ZodNullable<z.ZodNumber>;
37
+ mmi: z.ZodNullable<z.ZodNumber>;
38
+ alert: z.ZodNullable<z.ZodEnum<{
39
+ green: "green";
40
+ yellow: "yellow";
41
+ orange: "orange";
42
+ red: "red";
43
+ }>>;
44
+ tsunami: z.ZodNumber;
45
+ significance: z.ZodNullable<z.ZodNumber>;
46
+ status: z.ZodEnum<{
47
+ automatic: "automatic";
48
+ reviewed: "reviewed";
49
+ deleted: "deleted";
50
+ }>;
51
+ event_url: z.ZodOptional<z.ZodString>;
52
+ detail_url: z.ZodOptional<z.ZodString>;
53
+ }, z.core.$strip>>;
54
+ feed_url: z.ZodString;
55
+ }, z.core.$strip>, readonly [{
56
+ readonly reason: "feed_unavailable";
57
+ readonly code: JsonRpcErrorCode.ServiceUnavailable;
58
+ readonly when: "USGS feed endpoint returns non-2xx or times out.";
59
+ readonly recovery: "Try a smaller time_window, or use earthquake_search as a fallback.";
60
+ }]>;
61
+ //# sourceMappingURL=earthquake-get-feed.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"earthquake-get-feed.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/earthquake-get-feed.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4F5B,CAAC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @fileoverview Tool definition for fetching USGS pre-computed real-time earthquake feeds.
3
+ * @module mcp-server/tools/definitions/earthquake-get-feed.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { EarthquakeEventSchema, formatEvent } from '../../../mcp-server/tools/schemas.js';
8
+ import { getUsgsService } from '../../../services/usgs/usgs-service.js';
9
+ export const earthquakeGetFeed = tool('earthquake_get_feed', {
10
+ title: 'Get USGS Earthquake Feed',
11
+ description: 'Fetch a USGS pre-computed real-time earthquake feed by magnitude tier and time window. ' +
12
+ 'These feeds are CDN-cached by USGS and faster and more available than the query API — ' +
13
+ 'use them for "what\'s happening now" queries. ' +
14
+ '"all" includes microseisms (M<1); "significant" is a USGS curation based on magnitude, ' +
15
+ 'felt reports, and PAGER impact estimates. ' +
16
+ '"hour" returns 0–10 events typically; "month" can exceed 10,000 for the "all" tier. ' +
17
+ 'For historical or filtered queries, use earthquake_search instead.',
18
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
19
+ input: z.object({
20
+ magnitude_tier: z
21
+ .enum(['all', '1.0', '2.5', '4.5', 'significant'])
22
+ .default('2.5')
23
+ .describe('Minimum magnitude threshold for the feed. ' +
24
+ '"all" includes microseisms (M<1). ' +
25
+ '"1.0" is M1.0+. "2.5" is M2.5+. "4.5" is M4.5+. ' +
26
+ '"significant" is a USGS curated selection based on magnitude, felt reports, and PAGER impact estimates — not purely magnitude-based.'),
27
+ time_window: z
28
+ .enum(['hour', 'day', 'week', 'month'])
29
+ .default('day')
30
+ .describe('Time window for the feed. ' +
31
+ '"hour" typically returns 0–10 events; "month" can exceed 10,000 for the "all" tier. ' +
32
+ 'Prefer "hour" or "day" for real-time status checks.'),
33
+ }),
34
+ output: z.object({
35
+ count: z.number().describe('Number of events in the feed.'),
36
+ generated_at: z
37
+ .string()
38
+ .describe('ISO 8601 UTC timestamp when this feed was generated by USGS.'),
39
+ events: z
40
+ .array(EarthquakeEventSchema.describe('A single earthquake event.'))
41
+ .describe('Earthquake events, newest first.'),
42
+ feed_url: z.string().describe('Source feed URL.'),
43
+ }),
44
+ errors: [
45
+ {
46
+ reason: 'feed_unavailable',
47
+ code: JsonRpcErrorCode.ServiceUnavailable,
48
+ when: 'USGS feed endpoint returns non-2xx or times out.',
49
+ recovery: 'Try a smaller time_window, or use earthquake_search as a fallback.',
50
+ },
51
+ ],
52
+ async handler(input, ctx) {
53
+ ctx.log.info('Fetching USGS feed', {
54
+ magnitude_tier: input.magnitude_tier,
55
+ time_window: input.time_window,
56
+ });
57
+ const result = await getUsgsService().getFeed(input.magnitude_tier, input.time_window, ctx);
58
+ ctx.log.info('Feed fetched', {
59
+ count: result.count,
60
+ magnitude_tier: input.magnitude_tier,
61
+ time_window: input.time_window,
62
+ });
63
+ return {
64
+ count: result.count,
65
+ generated_at: result.generatedAt,
66
+ events: result.events,
67
+ feed_url: result.feedUrl,
68
+ };
69
+ },
70
+ format: (result) => {
71
+ const lines = [
72
+ `**Feed:** ${result.feed_url}`,
73
+ `**Generated:** ${result.generated_at} | **Count:** ${result.count}`,
74
+ '',
75
+ ];
76
+ if (result.count === 0) {
77
+ lines.push('_No events in this feed window._');
78
+ }
79
+ else {
80
+ for (const event of result.events) {
81
+ lines.push(...formatEvent(event));
82
+ lines.push('');
83
+ }
84
+ }
85
+ return [{ type: 'text', text: lines.join('\n') }];
86
+ },
87
+ });
88
+ //# sourceMappingURL=earthquake-get-feed.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"earthquake-get-feed.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/earthquake-get-feed.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @fileoverview Tool definition for searching earthquakes via USGS or EMSC FDSN query API.
3
+ * @module mcp-server/tools/definitions/earthquake-search.tool
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ export declare const earthquakeSearch: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
+ start_time: z.ZodOptional<z.ZodString>;
9
+ end_time: z.ZodOptional<z.ZodString>;
10
+ min_magnitude: z.ZodOptional<z.ZodNumber>;
11
+ max_magnitude: z.ZodOptional<z.ZodNumber>;
12
+ latitude: z.ZodOptional<z.ZodNumber>;
13
+ longitude: z.ZodOptional<z.ZodNumber>;
14
+ radius_km: z.ZodOptional<z.ZodNumber>;
15
+ min_depth_km: z.ZodOptional<z.ZodNumber>;
16
+ max_depth_km: z.ZodOptional<z.ZodNumber>;
17
+ alert_level: z.ZodOptional<z.ZodEnum<{
18
+ green: "green";
19
+ yellow: "yellow";
20
+ orange: "orange";
21
+ red: "red";
22
+ }>>;
23
+ min_felt: z.ZodOptional<z.ZodNumber>;
24
+ min_significance: z.ZodOptional<z.ZodNumber>;
25
+ source: z.ZodDefault<z.ZodEnum<{
26
+ usgs: "usgs";
27
+ emsc: "emsc";
28
+ }>>;
29
+ limit: z.ZodOptional<z.ZodNumber>;
30
+ order_by: z.ZodDefault<z.ZodEnum<{
31
+ magnitude: "magnitude";
32
+ time: "time";
33
+ "time-asc": "time-asc";
34
+ "magnitude-asc": "magnitude-asc";
35
+ }>>;
36
+ }, z.core.$strip>, z.ZodObject<{
37
+ count: z.ZodNumber;
38
+ total_count: z.ZodOptional<z.ZodNumber>;
39
+ source: z.ZodEnum<{
40
+ usgs: "usgs";
41
+ emsc: "emsc";
42
+ }>;
43
+ events: z.ZodArray<z.ZodObject<{
44
+ id: z.ZodString;
45
+ title: z.ZodString;
46
+ magnitude: z.ZodNumber;
47
+ magnitude_type: z.ZodString;
48
+ time: z.ZodString;
49
+ updated: z.ZodString;
50
+ place: z.ZodString;
51
+ latitude: z.ZodNumber;
52
+ longitude: z.ZodNumber;
53
+ depth_km: z.ZodNumber;
54
+ felt: z.ZodNullable<z.ZodNumber>;
55
+ cdi: z.ZodNullable<z.ZodNumber>;
56
+ mmi: z.ZodNullable<z.ZodNumber>;
57
+ alert: z.ZodNullable<z.ZodEnum<{
58
+ green: "green";
59
+ yellow: "yellow";
60
+ orange: "orange";
61
+ red: "red";
62
+ }>>;
63
+ tsunami: z.ZodNumber;
64
+ significance: z.ZodNullable<z.ZodNumber>;
65
+ status: z.ZodEnum<{
66
+ automatic: "automatic";
67
+ reviewed: "reviewed";
68
+ deleted: "deleted";
69
+ }>;
70
+ event_url: z.ZodOptional<z.ZodString>;
71
+ detail_url: z.ZodOptional<z.ZodString>;
72
+ }, z.core.$strip>>;
73
+ }, z.core.$strip>, readonly [{
74
+ readonly reason: "query_too_broad";
75
+ readonly code: JsonRpcErrorCode.InvalidParams;
76
+ readonly when: "Query matches more than 20,000 events — exceeds USGS search limit.";
77
+ readonly recovery: string;
78
+ }, {
79
+ readonly reason: "invalid_radius";
80
+ readonly code: JsonRpcErrorCode.InvalidParams;
81
+ readonly when: "latitude or longitude provided without radius_km, or vice versa.";
82
+ readonly recovery: "Provide latitude, longitude, and radius_km together for a location-based search.";
83
+ }, {
84
+ readonly reason: "source_unavailable";
85
+ readonly code: JsonRpcErrorCode.ServiceUnavailable;
86
+ readonly when: "Selected source API returns non-2xx or times out.";
87
+ readonly recovery: "Try the other source (usgs or emsc) or retry after a short delay.";
88
+ }]>;
89
+ //# sourceMappingURL=earthquake-search.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"earthquake-search.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/earthquake-search.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAOjE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuO3B,CAAC"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * @fileoverview Tool definition for searching earthquakes via USGS or EMSC FDSN query API.
3
+ * @module mcp-server/tools/definitions/earthquake-search.tool
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ import { getServerConfig } from '../../../config/server-config.js';
8
+ import { EarthquakeEventSchema, formatEvent } from '../../../mcp-server/tools/schemas.js';
9
+ import { getEmscService } from '../../../services/emsc/emsc-service.js';
10
+ import { getUsgsService } from '../../../services/usgs/usgs-service.js';
11
+ export const earthquakeSearch = tool('earthquake_search', {
12
+ title: 'Search Earthquakes',
13
+ description: 'Search earthquakes by time range, magnitude, depth, location radius, PAGER alert level, or felt reports. ' +
14
+ 'Supports USGS (global, richer metadata: PAGER, DYFI, ShakeMap) and EMSC (European-Mediterranean, independent catalog). ' +
15
+ 'For location-based queries, provide latitude, longitude, and radius_km together. ' +
16
+ 'USGS-specific filters (alert_level, min_felt, min_significance) are ignored when source=emsc. ' +
17
+ 'Use earthquake_count first to gauge result size before requesting large result sets. ' +
18
+ 'Results are capped at 20,000 events per query.',
19
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
20
+ input: z.object({
21
+ start_time: z
22
+ .string()
23
+ .optional()
24
+ .describe('Start of time range as ISO 8601 (e.g. "2026-01-01" or "2026-05-23T00:00:00"). ' +
25
+ 'Defaults to 30 days before end_time if omitted.'),
26
+ end_time: z
27
+ .string()
28
+ .optional()
29
+ .describe('End of time range as ISO 8601. Defaults to current time if omitted.'),
30
+ min_magnitude: z
31
+ .number()
32
+ .min(-1)
33
+ .max(10)
34
+ .optional()
35
+ .describe('Minimum magnitude (Richter or equivalent). ' +
36
+ 'M2.5+ is felt by some people; M5+ can cause damage; M7+ is major.'),
37
+ max_magnitude: z.number().min(-1).max(10).optional().describe('Maximum magnitude.'),
38
+ latitude: z
39
+ .number()
40
+ .min(-90)
41
+ .max(90)
42
+ .optional()
43
+ .describe('Latitude for radius search. Requires longitude and radius_km.'),
44
+ longitude: z
45
+ .number()
46
+ .min(-180)
47
+ .max(180)
48
+ .optional()
49
+ .describe('Longitude for radius search. Requires latitude and radius_km.'),
50
+ radius_km: z
51
+ .number()
52
+ .min(0)
53
+ .max(20002)
54
+ .optional()
55
+ .describe('Search radius in kilometers from the lat/lon point. ' +
56
+ '100 km covers a metro region; 500 km covers a large country. ' +
57
+ 'Converted to degrees for EMSC (1° ≈ 111.2 km).'),
58
+ min_depth_km: z
59
+ .number()
60
+ .optional()
61
+ .describe('Minimum depth in kilometers. ' +
62
+ 'Shallow quakes (0–70 km) typically cause more surface damage than deep quakes (>300 km).'),
63
+ max_depth_km: z.number().optional().describe('Maximum depth in kilometers.'),
64
+ alert_level: z
65
+ .enum(['green', 'yellow', 'orange', 'red'])
66
+ .optional()
67
+ .describe('Minimum PAGER alert level. PAGER estimates economic loss and casualties. ' +
68
+ '"green" = minimal impact; "red" = extreme. Only available from USGS.'),
69
+ min_felt: z
70
+ .number()
71
+ .int()
72
+ .min(1)
73
+ .optional()
74
+ .describe('Minimum number of DYFI (Did You Feel It?) reports. ' +
75
+ 'Use to find events with confirmed public impact. Only available from USGS.'),
76
+ min_significance: z
77
+ .number()
78
+ .int()
79
+ .optional()
80
+ .describe('Minimum USGS significance score (0–2000+). ' +
81
+ 'Combines magnitude, felt reports, and PAGER estimates. ' +
82
+ 'Significant events typically score 600+. Only available from USGS.'),
83
+ source: z
84
+ .enum(['usgs', 'emsc'])
85
+ .default('usgs')
86
+ .describe('Data source. ' +
87
+ '"usgs" covers global events with PAGER, DYFI, and ShakeMap metadata. ' +
88
+ '"emsc" covers the European-Mediterranean region with an independent catalog — ' +
89
+ 'useful for cross-verification or European-focused queries.'),
90
+ limit: z
91
+ .number()
92
+ .int()
93
+ .min(1)
94
+ .max(20000)
95
+ .optional()
96
+ .describe('Maximum events to return. Default 100. ' +
97
+ 'Large limits (>1000) may result in slow responses. Max 20000.'),
98
+ order_by: z
99
+ .enum(['time', 'time-asc', 'magnitude', 'magnitude-asc'])
100
+ .default('time')
101
+ .describe('Sort order. "time" returns newest first; "magnitude" returns largest first.'),
102
+ }),
103
+ output: z.object({
104
+ count: z.number().describe('Number of events returned.'),
105
+ total_count: z
106
+ .number()
107
+ .optional()
108
+ .describe('Total events matching the query before the limit was applied. ' +
109
+ 'Absent when all results fit in the response.'),
110
+ source: z.enum(['usgs', 'emsc']).describe('Data source used.'),
111
+ events: z
112
+ .array(EarthquakeEventSchema.describe('A single earthquake event.'))
113
+ .describe('Matching earthquake events.'),
114
+ }),
115
+ errors: [
116
+ {
117
+ reason: 'query_too_broad',
118
+ code: JsonRpcErrorCode.InvalidParams,
119
+ when: 'Query matches more than 20,000 events — exceeds USGS search limit.',
120
+ recovery: 'Narrow the time range, raise min_magnitude, or add a location radius filter. ' +
121
+ 'Use earthquake_count first to gauge result size.',
122
+ },
123
+ {
124
+ reason: 'invalid_radius',
125
+ code: JsonRpcErrorCode.InvalidParams,
126
+ when: 'latitude or longitude provided without radius_km, or vice versa.',
127
+ recovery: 'Provide latitude, longitude, and radius_km together for a location-based search.',
128
+ },
129
+ {
130
+ reason: 'source_unavailable',
131
+ code: JsonRpcErrorCode.ServiceUnavailable,
132
+ when: 'Selected source API returns non-2xx or times out.',
133
+ recovery: 'Try the other source (usgs or emsc) or retry after a short delay.',
134
+ },
135
+ ],
136
+ async handler(input, ctx) {
137
+ // Validate radius params — all three must be provided together
138
+ const latProvided = input.latitude != null;
139
+ const lonProvided = input.longitude != null;
140
+ const radiusProvided = input.radius_km != null;
141
+ if ((latProvided || lonProvided || radiusProvided) &&
142
+ !(latProvided && lonProvided && radiusProvided)) {
143
+ throw ctx.fail('invalid_radius', 'Radius search requires latitude, longitude, and radius_km — provide all three together.', { ...ctx.recoveryFor('invalid_radius') });
144
+ }
145
+ const config = getServerConfig();
146
+ const limit = input.limit ?? config.defaultLimit;
147
+ ctx.log.info('Searching earthquakes', {
148
+ source: input.source,
149
+ limit,
150
+ start_time: input.start_time,
151
+ min_magnitude: input.min_magnitude,
152
+ });
153
+ // Use conditional spreads to satisfy exactOptionalPropertyTypes
154
+ const params = {
155
+ limit,
156
+ orderBy: input.order_by,
157
+ ...(input.start_time != null ? { startTime: input.start_time } : {}),
158
+ ...(input.end_time != null ? { endTime: input.end_time } : {}),
159
+ ...(input.min_magnitude != null ? { minMagnitude: input.min_magnitude } : {}),
160
+ ...(input.max_magnitude != null ? { maxMagnitude: input.max_magnitude } : {}),
161
+ ...(input.latitude != null ? { latitude: input.latitude } : {}),
162
+ ...(input.longitude != null ? { longitude: input.longitude } : {}),
163
+ ...(input.radius_km != null ? { radiusKm: input.radius_km } : {}),
164
+ ...(input.min_depth_km != null ? { minDepthKm: input.min_depth_km } : {}),
165
+ ...(input.max_depth_km != null ? { maxDepthKm: input.max_depth_km } : {}),
166
+ ...(input.alert_level != null ? { alertLevel: input.alert_level } : {}),
167
+ ...(input.min_felt != null ? { minFelt: input.min_felt } : {}),
168
+ ...(input.min_significance != null ? { minSignificance: input.min_significance } : {}),
169
+ };
170
+ const result = input.source === 'emsc'
171
+ ? await getEmscService().searchEvents(params, ctx)
172
+ : await getUsgsService().searchEvents(params, ctx);
173
+ ctx.log.info('Search completed', { source: input.source, count: result.count });
174
+ return {
175
+ count: result.count,
176
+ ...(result.totalCount != null ? { total_count: result.totalCount } : {}),
177
+ source: input.source,
178
+ events: result.events,
179
+ };
180
+ },
181
+ format: (result) => {
182
+ const lines = [
183
+ `**Source:** ${result.source.toUpperCase()} | **Count:** ${result.count}${result.total_count != null ? ` of ${result.total_count} total` : ''}`,
184
+ '',
185
+ ];
186
+ if (result.count === 0) {
187
+ lines.push('_No events matched the query. ' +
188
+ 'Try broadening the time range, lowering min_magnitude, or expanding the radius._');
189
+ }
190
+ else {
191
+ for (const event of result.events) {
192
+ lines.push(...formatEvent(event));
193
+ lines.push('');
194
+ }
195
+ }
196
+ return [{ type: 'text', text: lines.join('\n') }];
197
+ },
198
+ });
199
+ //# sourceMappingURL=earthquake-search.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"earthquake-search.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/earthquake-search.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,EAAE;IACxD,KAAK,EAAE,oBAAoB;IAC3B,WAAW,EACT,2GAA2G;QAC3G,yHAAyH;QACzH,mFAAmF;QACnF,gGAAgG;QAChG,uFAAuF;QACvF,gDAAgD;IAClD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;IAE9E,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,gFAAgF;YAC9E,iDAAiD,CACpD;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,qEAAqE,CAAC;QAClF,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC,CAAC;aACP,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CACP,6CAA6C;YAC3C,mEAAmE,CACtE;QACH,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QACnF,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,EAAE,CAAC;aACR,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,EAAE;aACV,QAAQ,CAAC,+DAA+D,CAAC;QAC5E,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,GAAG,CAAC;aACT,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,+DAA+D,CAAC;QAC5E,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,KAAK,CAAC;aACV,QAAQ,EAAE;aACV,QAAQ,CACP,sDAAsD;YACpD,+DAA+D;YAC/D,gDAAgD,CACnD;QACH,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,+BAA+B;YAC7B,0FAA0F,CAC7F;QACH,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QAC5E,WAAW,EAAE,CAAC;aACX,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;aAC1C,QAAQ,EAAE;aACV,QAAQ,CACP,2EAA2E;YACzE,sEAAsE,CACzE;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CACP,qDAAqD;YACnD,4EAA4E,CAC/E;QACH,gBAAgB,EAAE,CAAC;aAChB,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,CACP,6CAA6C;YAC3C,yDAAyD;YACzD,oEAAoE,CACvE;QACH,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;aACtB,OAAO,CAAC,MAAM,CAAC;aACf,QAAQ,CACP,eAAe;YACb,uEAAuE;YACvE,gFAAgF;YAChF,4DAA4D,CAC/D;QACH,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,KAAK,CAAC;aACV,QAAQ,EAAE;aACV,QAAQ,CACP,yCAAyC;YACvC,+DAA+D,CAClE;QACH,QAAQ,EAAE,CAAC;aACR,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;aACxD,OAAO,CAAC,MAAM,CAAC;aACf,QAAQ,CAAC,6EAA6E,CAAC;KAC3F,CAAC;IAEF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QACxD,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,gEAAgE;YAC9D,8CAA8C,CACjD;QACH,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAC9D,MAAM,EAAE,CAAC;aACN,KAAK,CAAC,qBAAqB,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;aACnE,QAAQ,CAAC,6BAA6B,CAAC;KAC3C,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,iBAAiB;YACzB,IAAI,EAAE,gBAAgB,CAAC,aAAa;YACpC,IAAI,EAAE,oEAAoE;YAC1E,QAAQ,EACN,+EAA+E;gBAC/E,kDAAkD;SACrD;QACD;YACE,MAAM,EAAE,gBAAgB;YACxB,IAAI,EAAE,gBAAgB,CAAC,aAAa;YACpC,IAAI,EAAE,kEAAkE;YACxE,QAAQ,EAAE,kFAAkF;SAC7F;QACD;YACE,MAAM,EAAE,oBAAoB;YAC5B,IAAI,EAAE,gBAAgB,CAAC,kBAAkB;YACzC,IAAI,EAAE,mDAAmD;YACzD,QAAQ,EAAE,mEAAmE;SAC9E;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,+DAA+D;QAC/D,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC;QAC3C,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC;QAC5C,MAAM,cAAc,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC;QAE/C,IACE,CAAC,WAAW,IAAI,WAAW,IAAI,cAAc,CAAC;YAC9C,CAAC,CAAC,WAAW,IAAI,WAAW,IAAI,cAAc,CAAC,EAC/C,CAAC;YACD,MAAM,GAAG,CAAC,IAAI,CACZ,gBAAgB,EAChB,yFAAyF,EACzF,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAAE,CACzC,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,MAAM,CAAC,YAAY,CAAC;QAEjD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,uBAAuB,EAAE;YACpC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,KAAK;YACL,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,aAAa,EAAE,KAAK,CAAC,aAAa;SACnC,CAAC,CAAC;QAEH,gEAAgE;QAChE,MAAM,MAAM,GAA0B;YACpC,KAAK;YACL,OAAO,EAAE,KAAK,CAAC,QAAQ;YACvB,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7E,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7E,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/D,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,KAAK,CAAC,gBAAgB,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvF,CAAC;QAEF,MAAM,MAAM,GACV,KAAK,CAAC,MAAM,KAAK,MAAM;YACrB,CAAC,CAAC,MAAM,cAAc,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC;YAClD,CAAC,CAAC,MAAM,cAAc,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAEvD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAEhF,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,KAAK,GAAa;YACtB,eAAe,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,iBAAiB,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,WAAW,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE;YAC/I,EAAE;SACH,CAAC;QAEF,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CACR,gCAAgC;gBAC9B,kFAAkF,CACrF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClC,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;gBAClC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;QACH,CAAC;QAED,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @fileoverview Shared Zod schemas for earthquake event output fields used across tool definitions.
3
+ * @module mcp-server/tools/schemas
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ /** Zod schema for a normalized earthquake event returned by feeds and search results. */
7
+ export declare const EarthquakeEventSchema: z.ZodObject<{
8
+ id: z.ZodString;
9
+ title: z.ZodString;
10
+ magnitude: z.ZodNumber;
11
+ magnitude_type: z.ZodString;
12
+ time: z.ZodString;
13
+ updated: z.ZodString;
14
+ place: z.ZodString;
15
+ latitude: z.ZodNumber;
16
+ longitude: z.ZodNumber;
17
+ depth_km: z.ZodNumber;
18
+ felt: z.ZodNullable<z.ZodNumber>;
19
+ cdi: z.ZodNullable<z.ZodNumber>;
20
+ mmi: z.ZodNullable<z.ZodNumber>;
21
+ alert: z.ZodNullable<z.ZodEnum<{
22
+ green: "green";
23
+ yellow: "yellow";
24
+ orange: "orange";
25
+ red: "red";
26
+ }>>;
27
+ tsunami: z.ZodNumber;
28
+ significance: z.ZodNullable<z.ZodNumber>;
29
+ status: z.ZodEnum<{
30
+ automatic: "automatic";
31
+ reviewed: "reviewed";
32
+ deleted: "deleted";
33
+ }>;
34
+ event_url: z.ZodOptional<z.ZodString>;
35
+ detail_url: z.ZodOptional<z.ZodString>;
36
+ }, z.core.$strip>;
37
+ export type EarthquakeEventOutput = {
38
+ id: string;
39
+ title: string;
40
+ magnitude: number;
41
+ magnitude_type: string;
42
+ time: string;
43
+ updated: string;
44
+ place: string;
45
+ latitude: number;
46
+ longitude: number;
47
+ depth_km: number;
48
+ felt: number | null;
49
+ cdi: number | null;
50
+ mmi: number | null;
51
+ alert: 'green' | 'yellow' | 'orange' | 'red' | null;
52
+ tsunami: number;
53
+ significance: number | null;
54
+ status: 'automatic' | 'reviewed' | 'deleted';
55
+ event_url?: string | undefined;
56
+ detail_url?: string | undefined;
57
+ };
58
+ /** Format a single earthquake event as markdown lines. Renders all schema fields for format-parity. */
59
+ export declare function formatEvent(event: EarthquakeEventOutput): string[];
60
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/tools/schemas.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,yFAAyF;AACzF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoDhC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,IAAI,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;IAE7C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,uGAAuG;AACvG,wBAAgB,WAAW,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAgClE"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @fileoverview Shared Zod schemas for earthquake event output fields used across tool definitions.
3
+ * @module mcp-server/tools/schemas
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ /** Zod schema for a normalized earthquake event returned by feeds and search results. */
7
+ export const EarthquakeEventSchema = z.object({
8
+ id: z.string().describe('USGS or EMSC event identifier.'),
9
+ title: z
10
+ .string()
11
+ .describe('Human-readable event summary, e.g. "M 6.0 - 13 km S of Honaunau-Napoopoo, Hawaii".'),
12
+ magnitude: z.number().describe('Preferred magnitude value.'),
13
+ magnitude_type: z.string().describe('Magnitude type (ml, mww, mw, mb, etc.).'),
14
+ time: z.string().describe('ISO 8601 UTC origin time.'),
15
+ updated: z.string().describe('ISO 8601 UTC time this record was last updated.'),
16
+ place: z.string().describe('Nearest named location.'),
17
+ latitude: z.number().describe('Epicenter latitude in decimal degrees.'),
18
+ longitude: z.number().describe('Epicenter longitude in decimal degrees.'),
19
+ depth_km: z
20
+ .number()
21
+ .describe('Hypocenter depth in kilometers. Shallow (<70 km), intermediate (70–300 km), or deep (>300 km).'),
22
+ felt: z
23
+ .number()
24
+ .nullable()
25
+ .describe('Number of DYFI (Did You Feel It?) responses. Null if no reports. USGS only.'),
26
+ cdi: z
27
+ .number()
28
+ .nullable()
29
+ .describe('Maximum reported intensity (Community Decimal Intensity, 0–12 scale). USGS only.'),
30
+ mmi: z
31
+ .number()
32
+ .nullable()
33
+ .describe('Maximum ShakeMap instrumental intensity (Modified Mercalli, 0–12 scale). USGS only.'),
34
+ alert: z
35
+ .enum(['green', 'yellow', 'orange', 'red'])
36
+ .nullable()
37
+ .describe('PAGER estimated impact alert level. Null if not computed. USGS only.'),
38
+ tsunami: z
39
+ .number()
40
+ .describe('1 if a tsunami warning was issued; 0 otherwise. USGS only; 0 for EMSC events.'),
41
+ significance: z
42
+ .number()
43
+ .nullable()
44
+ .describe('USGS significance score (0–2000+). Combines magnitude, felt reports, PAGER. USGS only.'),
45
+ status: z
46
+ .enum(['automatic', 'reviewed', 'deleted'])
47
+ .describe('Review status. Automatic detections may be revised.'),
48
+ event_url: z.string().optional().describe('USGS event page URL. Present for USGS events only.'),
49
+ detail_url: z
50
+ .string()
51
+ .optional()
52
+ .describe('URL to fetch the full GeoJSON detail record. Present in USGS list responses.'),
53
+ });
54
+ /** Format a single earthquake event as markdown lines. Renders all schema fields for format-parity. */
55
+ export function formatEvent(event) {
56
+ const lines = [];
57
+ lines.push(`## ${event.title}`);
58
+ lines.push(`**ID:** ${event.id} | **Magnitude:** ${event.magnitude} (${event.magnitude_type}) | **Depth:** ${event.depth_km} km`);
59
+ lines.push(`**Place:** ${event.place}`);
60
+ lines.push(`**Time:** ${event.time} | **Updated:** ${event.updated} | **Status:** ${event.status}`);
61
+ lines.push(`**Location:** ${event.latitude.toFixed(4)}°, ${event.longitude.toFixed(4)}°`);
62
+ // Impact fields (USGS-specific; render explicitly for format-parity compliance)
63
+ lines.push(`**PAGER Alert:** ${event.alert !== null ? event.alert.toUpperCase() : 'Not computed'}`);
64
+ // Render tsunami as its raw value so the linter's format-parity sentinel check passes
65
+ lines.push(`**Tsunami (warning flag):** ${event.tsunami}${event.tsunami !== 0 ? ' ⚠️ Warning issued' : ''}`);
66
+ const impactParts = [];
67
+ if (event.felt !== null)
68
+ impactParts.push(`Felt by ${event.felt} (DYFI)`);
69
+ if (event.mmi !== null)
70
+ impactParts.push(`ShakeMap MMI: ${event.mmi}`);
71
+ if (event.cdi !== null)
72
+ impactParts.push(`CDI: ${event.cdi}`);
73
+ if (event.significance !== null)
74
+ impactParts.push(`Significance: ${event.significance}`);
75
+ if (impactParts.length > 0)
76
+ lines.push(`**Impact:** ${impactParts.join(' | ')}`);
77
+ if (event.event_url)
78
+ lines.push(`**USGS page:** ${event.event_url}`);
79
+ if (event.detail_url)
80
+ lines.push(`**Detail URL:** ${event.detail_url}`);
81
+ return lines;
82
+ }
83
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/mcp-server/tools/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @fileoverview EMSC (European-Mediterranean Seismological Centre) FDSN event API client.
3
+ * @module services/emsc/emsc-service
4
+ */
5
+ import type { Context } from '@cyanheads/mcp-ts-core';
6
+ import type { AppConfig } from '@cyanheads/mcp-ts-core/config';
7
+ import type { StorageService } from '@cyanheads/mcp-ts-core/storage';
8
+ import type { EarthquakeEvent, EarthquakeQueryParams } from '../usgs/types.js';
9
+ export declare class EmscService {
10
+ private readonly baseUrl;
11
+ private readonly timeoutMs;
12
+ constructor(_config: AppConfig, _storage: StorageService, emscBaseUrl: string, timeoutMs: number);
13
+ /** Query EMSC FDSN event API. */
14
+ searchEvents(params: EarthquakeQueryParams, ctx: Context): Promise<{
15
+ events: EarthquakeEvent[];
16
+ count: number;
17
+ totalCount?: number;
18
+ }>;
19
+ /** Count events matching a query. */
20
+ countEvents(params: EarthquakeQueryParams, ctx: Context): Promise<{
21
+ count: number;
22
+ maxAllowed: number | null;
23
+ exceedsLimit: boolean;
24
+ }>;
25
+ /** Build FDSN query string from params, converting km radius to degrees for EMSC. */
26
+ private buildFdsnQuery;
27
+ }
28
+ export declare function initEmscService(config: AppConfig, storage: StorageService, emscBaseUrl: string, timeoutMs: number): void;
29
+ export declare function getEmscService(): EmscService;
30
+ //# sourceMappingURL=emsc-service.d.ts.map