offnadir-delta-mcp 1.3.26 → 1.3.28

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/dist/catalog.js CHANGED
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * Static introspection catalog for the Off-Nadir Delta stdio MCP proxy.
3
3
  *
4
+ * AUTO-GENERATED from the Off-Nadir Delta contract registry
5
+ * (src/lib/api/toolRegistry.ts + src/lib/api/mcpResources.ts) by
6
+ * scripts/gen-contract-artifacts.mjs — DO NOT EDIT BY HAND.
7
+ *
4
8
  * These tool / resource / prompt definitions mirror the live remote MCP server
5
9
  * (https://offnadir-delta.com/api/v1/mcp) so that `tools/list`, `resources/list`,
6
10
  * and `prompts/list` answer instantly and WITHOUT credentials — this is what
@@ -8,52 +12,160 @@
8
12
  *
9
13
  * Actual `tools/call` / `resources/read` / `prompts/get` requests are forwarded
10
14
  * to the remote server with the caller's OFFNADIR_DELTA_API_KEY (see index.ts).
11
- *
12
- * Keep in sync with the source of truth: src/app/api/v1/mcp/route.ts in the
13
- * Off-Nadir Delta app. Token costs and enums are inlined from that surface.
14
15
  */
15
- const DELTA_CATEGORIES = [
16
- 'kinetic',
17
- 'armed_conflict',
18
- 'maritime',
19
- 'natural_disaster',
20
- 'infrastructure',
21
- 'aviation',
22
- 'humanitarian',
23
- 'protest',
24
- 'diplomacy',
25
- 'other',
26
- ];
27
- const MARKET_IMPACTS = [
28
- 'oil',
29
- 'natural_gas',
30
- 'grain',
31
- 'shipping',
32
- 'defense',
33
- 'metals',
34
- 'semiconductors',
35
- 'fx',
36
- 'equities',
37
- ];
38
- const IMAGERY_COLLECTIONS = [
39
- 'sentinel-1-grd',
40
- 'sentinel-1-rtc',
41
- 'sentinel-2-l2a',
42
- 'OPERA_L2_RTC-S1_V1',
43
- ];
44
- const SIGNALS_MAX_DAYS = 30;
45
- const SIGNALS_MAX_LIMIT = 500;
46
- const BBOX = {
47
- type: 'array',
48
- items: { type: 'number' },
49
- minItems: 4,
50
- maxItems: 4,
51
- };
16
+ // Generated for Off-Nadir Delta MCP 1.3.28.
52
17
  export const TOOLS = [
53
18
  {
54
- name: 'query_signals',
55
- annotations: { "readOnlyHint": false, "openWorldHint": false, "destructiveHint": true },
56
- outputSchema: {
19
+ "name": "query_signals",
20
+ "description": "Query geolocated world event signals (Delta Signals: geopolitical, security, disaster, and infrastructure events distilled from global news media, AI-enriched with severity/GEOINT scores and satellite-collection recommendations). Filter by bounding box, date window, and category. Costs 3 token(s) per call, charged to the API key owner's balance.",
21
+ "inputSchema": {
22
+ "type": "object",
23
+ "properties": {
24
+ "bbox": {
25
+ "type": "array",
26
+ "items": {
27
+ "type": "number"
28
+ },
29
+ "minItems": 4,
30
+ "maxItems": 4,
31
+ "description": "Bounding box [minLon, minLat, maxLon, maxLat] (WGS84). Omit for worldwide."
32
+ },
33
+ "date": {
34
+ "type": "string",
35
+ "description": "Window end date, YYYY-MM-DD (UTC). Defaults to today."
36
+ },
37
+ "days": {
38
+ "type": "integer",
39
+ "minimum": 1,
40
+ "maximum": 30,
41
+ "description": "Window length in days ending on `date`. Defaults to 1."
42
+ },
43
+ "categories": {
44
+ "type": "array",
45
+ "items": {
46
+ "type": "string",
47
+ "enum": [
48
+ "kinetic",
49
+ "armed_conflict",
50
+ "maritime",
51
+ "natural_disaster",
52
+ "infrastructure",
53
+ "aviation",
54
+ "humanitarian",
55
+ "protest",
56
+ "diplomacy",
57
+ "other"
58
+ ]
59
+ },
60
+ "description": "Restrict to these categories. Omit for all."
61
+ },
62
+ "markets": {
63
+ "type": "array",
64
+ "items": {
65
+ "type": "string",
66
+ "enum": [
67
+ "oil",
68
+ "natural_gas",
69
+ "grain",
70
+ "shipping",
71
+ "defense",
72
+ "metals",
73
+ "semiconductors",
74
+ "fx",
75
+ "equities"
76
+ ]
77
+ },
78
+ "description": "Restrict to signals AI-tagged as exposing these financial markets via a direct physical/supply channel (informational only, not investment advice). Omit for all."
79
+ },
80
+ "limit": {
81
+ "type": "integer",
82
+ "minimum": 1,
83
+ "maximum": 500,
84
+ "description": "Maximum rows per page. Defaults to 100."
85
+ },
86
+ "cursor": {
87
+ "type": "string",
88
+ "description": "Opaque pagination cursor from a previous response's meta.next_cursor."
89
+ },
90
+ "minSeverity": {
91
+ "type": "number",
92
+ "minimum": 0,
93
+ "maximum": 10,
94
+ "description": "Keep only signals with severity_score >= this (0-10)."
95
+ },
96
+ "escalating": {
97
+ "type": "boolean",
98
+ "description": "Keep only signals whose escalation_trend is \"escalating\"."
99
+ },
100
+ "sort": {
101
+ "type": "string",
102
+ "enum": [
103
+ "severity",
104
+ "recent",
105
+ "sources",
106
+ "geoint"
107
+ ],
108
+ "description": "Result ordering. Omit for the feed's default ranking. \"geoint\" ranks by the continuous GEOINT collection priority (intelligence.collection_priority) — an imageability gate times tasking value (severity, urgency, information gain, corroboration, escalation, market) — so imageable, decision-relevant events (e.g. a high-severity escalating strike) rise and non-observable news noise sinks. This is NOT the saturated geoint_score."
109
+ },
110
+ "updatedSince": {
111
+ "type": "string",
112
+ "description": "Differential fetch: only signals (re)enriched at/after this ISO 8601 timestamp. Ignores the date window. Response signals carry last_updated_at."
113
+ },
114
+ "createdSince": {
115
+ "type": "string",
116
+ "description": "Differential fetch: only signals first enriched at/after this ISO 8601 timestamp."
117
+ },
118
+ "observability": {
119
+ "type": "string",
120
+ "enum": [
121
+ "observable",
122
+ "not-observable"
123
+ ],
124
+ "description": "Keep only signals with this satellite observability — whether a physical mark is imageable at all (intelligence.satellite_observability)."
125
+ },
126
+ "observabilityStatus": {
127
+ "type": "string",
128
+ "enum": [
129
+ "observable",
130
+ "not_observable",
131
+ "insufficient_detail"
132
+ ],
133
+ "description": "3-state observability filter. Unlike `observability` (binary), this exposes `insufficient_detail` — signals where imageability is unknown (no RS enrichment yet, unresolved location, or an Impossible verdict rescued because the event reads kinetic). `not_observable` = a considered \"nothing to image\"; neither bucket leaks insufficient_detail."
134
+ },
135
+ "openData": {
136
+ "type": "string",
137
+ "enum": [
138
+ "sufficient",
139
+ "commercial-recommended",
140
+ "not-applicable"
141
+ ],
142
+ "description": "Keep only signals with this open-data sufficiency — free imagery is enough vs commercial tasking recommended (intelligence.open_data_sufficiency)."
143
+ },
144
+ "minInformationGain": {
145
+ "type": "number",
146
+ "minimum": 0,
147
+ "maximum": 1,
148
+ "description": "Keep only signals whose intelligence.expected_information_gain >= this (0-1)."
149
+ },
150
+ "taskableOnly": {
151
+ "type": "boolean",
152
+ "description": "Keep only signals whose coordinate is search_ready — GEO-READY ONLY: drops country centroids, ADM1 mismatches, reporting-dateline fallbacks and unresolved fixes (intelligence.geo_validation.search_ready). It does NOT imply observable or quality-passed, so not-observable / insufficient-detail / quality-failed signals can still appear. For automated imagery tasking use collectionReadyOnly (or combine with observability:\"observable\")."
153
+ },
154
+ "collectionReadyOnly": {
155
+ "type": "boolean",
156
+ "description": "STRICT tasking-candidate filter: search_ready AND observability=observable AND quality.status!=failed AND a concrete collection plan (rs_target + rs_reason present) AND an event coordinate. The safe input set for automated imagery tasking — a superset of every gate taskableOnly alone does not check."
157
+ },
158
+ "responseFormat": {
159
+ "type": "string",
160
+ "enum": [
161
+ "concise",
162
+ "detailed"
163
+ ],
164
+ "description": "Per-signal field detail. \"concise\" (default) returns the key decision + GEOINT fields (id, date, category, title, location, lat/lng, severity/geoint scores, collection_priority, escalation, market, rs_level/rs_sensor, observability, observability_status, verification_status, geo_status, search_ready, article_count, independent_source_count, information_gain) — cheaper to scan. \"detailed\" returns the full Signal object (shape per the signals://schema resource)."
165
+ }
166
+ }
167
+ },
168
+ "outputSchema": {
57
169
  "type": "object",
58
170
  "properties": {
59
171
  "meta": {
@@ -76,44 +188,59 @@ export const TOOLS = [
76
188
  "signals"
77
189
  ]
78
190
  },
79
- description: 'Query geolocated world event signals (Delta Signals: geopolitical, security, disaster, and ' +
80
- 'infrastructure events distilled from global news media, AI-enriched with severity/GEOINT scores ' +
81
- 'and satellite-collection recommendations). Filter by bounding box, date window, and category. ' +
82
- "Costs 3 token(s) per call, charged to the API key owner's balance.",
83
- inputSchema: {
84
- type: 'object',
85
- properties: {
86
- bbox: { ...BBOX, description: 'Bounding box [minLon, minLat, maxLon, maxLat] (WGS84). Omit for worldwide.' },
87
- date: { type: 'string', description: 'Window end date, YYYY-MM-DD (UTC). Defaults to today.' },
88
- days: { type: 'integer', minimum: 1, maximum: SIGNALS_MAX_DAYS, description: 'Window length in days ending on `date`. Defaults to 1.' },
89
- categories: { type: 'array', items: { type: 'string', enum: [...DELTA_CATEGORIES] }, description: 'Restrict to these categories. Omit for all.' },
90
- markets: {
91
- type: 'array',
92
- items: { type: 'string', enum: [...MARKET_IMPACTS] },
93
- description: 'Restrict to signals AI-tagged as exposing these financial markets via a direct ' +
94
- 'physical/supply channel (informational only, not investment advice). Omit for all.',
95
- },
96
- limit: { type: 'integer', minimum: 1, maximum: SIGNALS_MAX_LIMIT, description: 'Maximum rows per page. Defaults to 100.' },
97
- cursor: { type: 'string', description: "Opaque pagination cursor from a previous response's meta.next_cursor." },
98
- minSeverity: { type: 'number', minimum: 0, maximum: 10, description: 'Keep only signals with severity_score >= this (0-10).' },
99
- escalating: { type: 'boolean', description: 'Keep only signals whose escalation_trend is "escalating".' },
100
- sort: { type: 'string', enum: ['severity', 'recent', 'sources', 'geoint'], description: "Result ordering. Omit for the feed's default ranking. \"geoint\" ranks by the continuous GEOINT collection priority (intelligence.collection_priority) — an imageability gate times tasking value (severity, urgency, information gain, corroboration, escalation, market) — so imageable, decision-relevant events (e.g. a high-severity escalating strike) rise and non-observable news noise sinks. This is NOT the saturated geoint_score." },
101
- updatedSince: { type: 'string', description: 'Differential fetch: only signals (re)enriched at/after this ISO 8601 timestamp. Ignores the date window. Response signals carry last_updated_at.' },
102
- createdSince: { type: 'string', description: 'Differential fetch: only signals first enriched at/after this ISO 8601 timestamp.' },
103
- observability: { type: 'string', enum: ['observable', 'not-observable'], description: 'Keep only signals with this satellite observability — whether a physical mark is imageable at all (intelligence.satellite_observability).' },
104
- observabilityStatus: { type: 'string', enum: ['observable', 'not_observable', 'insufficient_detail'], description: '3-state observability filter. Unlike `observability` (binary), this exposes `insufficient_detail` — signals where imageability is unknown (no RS enrichment yet, unresolved location, or an Impossible verdict rescued because the event reads kinetic). `not_observable` = a considered "nothing to image"; neither bucket leaks insufficient_detail.' },
105
- openData: { type: 'string', enum: ['sufficient', 'commercial-recommended', 'not-applicable'], description: 'Keep only signals with this open-data sufficiency — free imagery is enough vs commercial tasking recommended (intelligence.open_data_sufficiency).' },
106
- minInformationGain: { type: 'number', minimum: 0, maximum: 1, description: 'Keep only signals whose intelligence.expected_information_gain >= this (0-1).' },
107
- taskableOnly: { type: 'boolean', description: 'Keep only signals whose coordinate is search_ready — GEO-READY ONLY: drops country centroids, ADM1 mismatches, reporting-dateline fallbacks and unresolved fixes (intelligence.geo_validation.search_ready). It does NOT imply observable or quality-passed, so not-observable / insufficient-detail / quality-failed signals can still appear. For automated imagery tasking use collectionReadyOnly (or combine with observability:"observable").' },
108
- collectionReadyOnly: { type: 'boolean', description: 'STRICT tasking-candidate filter: search_ready AND observability=observable AND quality.status!=failed AND a concrete collection plan (rs_target + rs_reason present) AND an event coordinate. The safe input set for automated imagery tasking — a superset of every gate taskableOnly alone does not check.' },
109
- responseFormat: { type: 'string', enum: ['concise', 'detailed'], description: 'Per-signal field detail. "concise" (default) returns key decision + GEOINT fields (incl. collection_priority, the corrected 0-100 ranking value); "detailed" returns the full Signal object.' },
110
- },
111
- },
191
+ "annotations": {
192
+ "readOnlyHint": false,
193
+ "openWorldHint": false,
194
+ "destructiveHint": true
195
+ }
112
196
  },
113
197
  {
114
- name: 'query_stats',
115
- annotations: { "readOnlyHint": false, "openWorldHint": false, "destructiveHint": true },
116
- outputSchema: {
198
+ "name": "query_stats",
199
+ "description": "Aggregate statistics over the signal corpus — total event count plus per-category and per-day breakdown (trend) for a bounding box and date window. Cheaper than query_signals (returns roll-ups, not rows). NOTE the unit: `total` counts article-deduped events (meta.population = article_deduped_events), which is NOT cluster-collapsed, so it is >= the query_signals count for the same window. Costs 1 token(s) per call.",
200
+ "inputSchema": {
201
+ "type": "object",
202
+ "properties": {
203
+ "bbox": {
204
+ "type": "array",
205
+ "items": {
206
+ "type": "number"
207
+ },
208
+ "minItems": 4,
209
+ "maxItems": 4,
210
+ "description": "Bounding box [minLon, minLat, maxLon, maxLat] (WGS84). Omit for worldwide."
211
+ },
212
+ "date": {
213
+ "type": "string",
214
+ "description": "Window end date, YYYY-MM-DD (UTC). Defaults to today."
215
+ },
216
+ "days": {
217
+ "type": "integer",
218
+ "minimum": 1,
219
+ "maximum": 30,
220
+ "description": "Window length in days. Defaults to 1."
221
+ },
222
+ "categories": {
223
+ "type": "array",
224
+ "items": {
225
+ "type": "string",
226
+ "enum": [
227
+ "kinetic",
228
+ "armed_conflict",
229
+ "maritime",
230
+ "natural_disaster",
231
+ "infrastructure",
232
+ "aviation",
233
+ "humanitarian",
234
+ "protest",
235
+ "diplomacy",
236
+ "other"
237
+ ]
238
+ },
239
+ "description": "Restrict to these categories. Omit for all."
240
+ }
241
+ }
242
+ },
243
+ "outputSchema": {
117
244
  "type": "object",
118
245
  "properties": {
119
246
  "meta": {
@@ -133,25 +260,77 @@ export const TOOLS = [
133
260
  "stats"
134
261
  ]
135
262
  },
136
- description: 'Aggregate statistics over the signal corpus — total event count plus per-category and per-day ' +
137
- 'breakdown (trend) for a bounding box and date window. Cheaper than query_signals (returns ' +
138
- 'roll-ups, not rows). NOTE the unit: `total` counts article-deduped events (meta.population = ' +
139
- 'article_deduped_events), which is NOT cluster-collapsed, so it is >= the query_signals count ' +
140
- 'for the same window. Costs 1 token(s) per call.',
141
- inputSchema: {
142
- type: 'object',
143
- properties: {
144
- bbox: { ...BBOX, description: 'Bounding box [minLon, minLat, maxLon, maxLat] (WGS84). Omit for worldwide.' },
145
- date: { type: 'string', description: 'Window end date, YYYY-MM-DD (UTC). Defaults to today.' },
146
- days: { type: 'integer', minimum: 1, maximum: SIGNALS_MAX_DAYS, description: 'Window length in days. Defaults to 1.' },
147
- categories: { type: 'array', items: { type: 'string', enum: [...DELTA_CATEGORIES] }, description: 'Restrict to these categories. Omit for all.' },
148
- },
149
- },
263
+ "annotations": {
264
+ "readOnlyHint": false,
265
+ "openWorldHint": false,
266
+ "destructiveHint": true
267
+ }
150
268
  },
151
269
  {
152
- name: 'query_hotspots',
153
- annotations: { "readOnlyHint": false, "openWorldHint": false, "destructiveHint": true },
154
- outputSchema: {
270
+ "name": "query_hotspots",
271
+ "description": "Geographic hotspots — signal density grid-binned into cells, ranked by event count, each with peak severity, the categories present, and up to 5 representative event_ids (trace a cell back to its signals). Use to find WHERE activity is concentrating. NOTE the unit: cells count satellite-observable points (meta.population = rs_observable_points); meta reports source_point_count and dropped_by_geo_count / dropped_by_severity_count so point_count is fully accountable. Costs 1 token(s) per call.",
272
+ "inputSchema": {
273
+ "type": "object",
274
+ "properties": {
275
+ "bbox": {
276
+ "type": "array",
277
+ "items": {
278
+ "type": "number"
279
+ },
280
+ "minItems": 4,
281
+ "maxItems": 4,
282
+ "description": "Bounding box [minLon, minLat, maxLon, maxLat] (WGS84). Omit for worldwide."
283
+ },
284
+ "date": {
285
+ "type": "string",
286
+ "description": "Window end date, YYYY-MM-DD (UTC). Defaults to today."
287
+ },
288
+ "days": {
289
+ "type": "integer",
290
+ "minimum": 1,
291
+ "maximum": 30,
292
+ "description": "Window length in days. Defaults to 1."
293
+ },
294
+ "categories": {
295
+ "type": "array",
296
+ "items": {
297
+ "type": "string",
298
+ "enum": [
299
+ "kinetic",
300
+ "armed_conflict",
301
+ "maritime",
302
+ "natural_disaster",
303
+ "infrastructure",
304
+ "aviation",
305
+ "humanitarian",
306
+ "protest",
307
+ "diplomacy",
308
+ "other"
309
+ ]
310
+ },
311
+ "description": "Restrict to these categories. Omit for all."
312
+ },
313
+ "precision": {
314
+ "type": "number",
315
+ "minimum": 0.1,
316
+ "maximum": 5,
317
+ "description": "Grid cell size in decimal degrees. Defaults to 1."
318
+ },
319
+ "minSeverity": {
320
+ "type": "number",
321
+ "minimum": 0,
322
+ "maximum": 10,
323
+ "description": "Keep only points with severity_score >= this."
324
+ },
325
+ "limit": {
326
+ "type": "integer",
327
+ "minimum": 1,
328
+ "maximum": 500,
329
+ "description": "Max source points sampled before grid-binning — NOT the number of cells returned. Defaults to 500 (the max). Lower values sample fewer events and fragment clusters (each cell trends toward count 1), so leave at the default for a representative density map."
330
+ }
331
+ }
332
+ },
333
+ "outputSchema": {
155
334
  "type": "object",
156
335
  "properties": {
157
336
  "meta": {
@@ -174,29 +353,25 @@ export const TOOLS = [
174
353
  "hotspots"
175
354
  ]
176
355
  },
177
- description: 'Geographic hotspots — signal density grid-binned into cells, ranked by event count, each with ' +
178
- 'peak severity, the categories present, and up to 5 representative event_ids (trace a cell back ' +
179
- 'to its signals). Use to find WHERE activity is concentrating. NOTE the unit: cells count ' +
180
- 'satellite-observable points (meta.population = rs_observable_points); meta reports ' +
181
- 'source_point_count and dropped_by_geo_count / dropped_by_severity_count so point_count is fully ' +
182
- 'accountable. Costs 1 token(s) per call.',
183
- inputSchema: {
184
- type: 'object',
185
- properties: {
186
- bbox: { ...BBOX, description: 'Bounding box [minLon, minLat, maxLon, maxLat] (WGS84). Omit for worldwide.' },
187
- date: { type: 'string', description: 'Window end date, YYYY-MM-DD (UTC). Defaults to today.' },
188
- days: { type: 'integer', minimum: 1, maximum: SIGNALS_MAX_DAYS, description: 'Window length in days. Defaults to 1.' },
189
- categories: { type: 'array', items: { type: 'string', enum: [...DELTA_CATEGORIES] }, description: 'Restrict to these categories. Omit for all.' },
190
- precision: { type: 'number', minimum: 0.1, maximum: 5, description: 'Grid cell size in decimal degrees. Defaults to 1.' },
191
- minSeverity: { type: 'number', minimum: 0, maximum: 10, description: 'Keep only points with severity_score >= this.' },
192
- limit: { type: 'integer', minimum: 1, maximum: SIGNALS_MAX_LIMIT, description: 'Max source points sampled before grid-binning — NOT the number of cells returned. Defaults to 500 (the max). Lower values sample fewer events and fragment clusters (each cell trends toward count 1), so leave at the default for a representative density map.' },
193
- },
194
- },
356
+ "annotations": {
357
+ "readOnlyHint": false,
358
+ "openWorldHint": false,
359
+ "destructiveHint": true
360
+ }
195
361
  },
196
362
  {
197
- name: 'get_world_brief',
198
- annotations: { "readOnlyHint": true, "openWorldHint": false, "destructiveHint": false },
199
- outputSchema: {
363
+ "name": "get_world_brief",
364
+ "description": "Fetch the Daily World Brief — an AI-synthesized OSINT/GEOINT digest of the previous UTC day's worldwide event signals (headline, executive summary, top developments with why-it-matters and what-to-watch, per-theme roll-up, ranked signals). Free of token charges. The result includes a freshness object (brief_date, age_hours, is_stale) — if is_stale is true this is the latest published brief and a newer day is not yet available, so relay it as possibly out of date.",
365
+ "inputSchema": {
366
+ "type": "object",
367
+ "properties": {
368
+ "date": {
369
+ "type": "string",
370
+ "description": "Brief date, YYYY-MM-DD (UTC). Defaults to the latest available."
371
+ }
372
+ }
373
+ },
374
+ "outputSchema": {
200
375
  "type": "object",
201
376
  "properties": {
202
377
  "brief": {
@@ -211,20 +386,20 @@ export const TOOLS = [
211
386
  "brief"
212
387
  ]
213
388
  },
214
- description: "Fetch the Daily World Brief — an AI-synthesized OSINT/GEOINT digest of the previous UTC day's " +
215
- 'worldwide event signals (headline, executive summary, top developments with why-it-matters and ' +
216
- 'what-to-watch, per-theme roll-up, ranked signals). Free of token charges.',
217
- inputSchema: {
218
- type: 'object',
219
- properties: {
220
- date: { type: 'string', description: 'Brief date, YYYY-MM-DD (UTC). Defaults to the latest available.' },
221
- },
222
- },
389
+ "annotations": {
390
+ "readOnlyHint": true,
391
+ "openWorldHint": false,
392
+ "destructiveHint": false
393
+ }
223
394
  },
224
395
  {
225
- name: 'get_usage',
226
- annotations: { "readOnlyHint": true, "openWorldHint": false, "destructiveHint": false },
227
- outputSchema: {
396
+ "name": "get_usage",
397
+ "description": "Check the calling key's remaining token balance and plan capabilities — monthly allocation, tokens used this period, tokens remaining, and whether the plan includes AI tools over the API (assess_signal / ask_analyst). Use this to pre-flight a metered call: decide whether enough balance is left before spending. Free of token charges.",
398
+ "inputSchema": {
399
+ "type": "object",
400
+ "properties": {}
401
+ },
402
+ "outputSchema": {
228
403
  "type": "object",
229
404
  "properties": {
230
405
  "tokens": {
@@ -267,16 +442,99 @@ export const TOOLS = [
267
442
  "plan"
268
443
  ]
269
444
  },
270
- description: "Check the calling key's remaining token balance and plan capabilities — monthly allocation, " +
271
- 'tokens used this period, tokens remaining, and whether the plan includes AI tools over the API ' +
272
- '(assess_signal / ask_analyst). Use this to pre-flight a metered call: decide whether enough ' +
273
- 'balance is left before spending. Free of token charges.',
274
- inputSchema: { type: 'object', properties: {} },
445
+ "annotations": {
446
+ "readOnlyHint": true,
447
+ "openWorldHint": false,
448
+ "destructiveHint": false
449
+ }
275
450
  },
276
451
  {
277
- name: 'search_imagery',
278
- annotations: { "readOnlyHint": false, "openWorldHint": false, "destructiveHint": true },
279
- outputSchema: {
452
+ "name": "search_imagery",
453
+ "description": "Search the satellite imagery catalog (Sentinel-1/2, OPERA RTC-S1) for scenes over an area and date window — the natural follow-up to a signal (find imagery over the event location). Returns scene metadata (id, datetime, footprint, cloud cover, platform, orbit geometry, coverage, catalog link) — no imagery bytes. Pass eventDate to classify each scene timing=pre/post/same_day_unknown (a same-day scene is same_day_unknown, never post, without a real event time) and get pre/post bracketing + window_status + SAR sar_pair_status in meta. Pass eventPoint [lon,lat] and/or eventAoi [minLon,minLat,maxLon,maxLat] to get each scene's target_relation (covers_event_geometry = pure geometry gate; usable_for_analysis additionally requires acceptable cloud for optical, so a 99%-cloud scene is geometry-covering but not analysis-usable) — so a scene that only clips the wide bbox is not mistaken for covering the event. Costs 2 token(s) per call.",
454
+ "inputSchema": {
455
+ "type": "object",
456
+ "properties": {
457
+ "bbox": {
458
+ "type": "array",
459
+ "items": {
460
+ "type": "number"
461
+ },
462
+ "minItems": 4,
463
+ "maxItems": 4,
464
+ "description": "Bounding box [minLon, minLat, maxLon, maxLat] (WGS84). Required."
465
+ },
466
+ "collection": {
467
+ "type": "string",
468
+ "enum": [
469
+ "sentinel-1-grd",
470
+ "sentinel-1-rtc",
471
+ "sentinel-2-l2a",
472
+ "OPERA_L2_RTC-S1_V1"
473
+ ],
474
+ "description": "Catalog collection. Defaults to sentinel-2-l2a."
475
+ },
476
+ "date": {
477
+ "type": "string",
478
+ "description": "Window end date, YYYY-MM-DD (UTC). Defaults to today."
479
+ },
480
+ "days": {
481
+ "type": "integer",
482
+ "minimum": 1,
483
+ "maximum": 30,
484
+ "description": "Window length in days. Defaults to 7."
485
+ },
486
+ "eventDate": {
487
+ "type": "string",
488
+ "description": "Event date, YYYY-MM-DD (UTC). When set, each scene is tagged timing=pre/post/same_day_unknown and the search window is widened to the canonical pre/post span, so meta reports has_pre_baseline / has_post / bracketing_available / window_status; for sentinel-1-grd it also reports sar_pair_status (ready | not_ready | indeterminate_event_time) + orbit_note."
489
+ },
490
+ "eventPoint": {
491
+ "type": "array",
492
+ "items": {
493
+ "type": "number"
494
+ },
495
+ "minItems": 2,
496
+ "maxItems": 2,
497
+ "description": "Event point [lon, lat] (WGS84). When set, each scene reports target_relation.covers_event_point / usable_for_event so a scene that only clips the wide bbox is not presented as covering the event."
498
+ },
499
+ "eventAoi": {
500
+ "type": "array",
501
+ "items": {
502
+ "type": "number"
503
+ },
504
+ "minItems": 4,
505
+ "maxItems": 4,
506
+ "description": "Event AOI bbox [minLon, minLat, maxLon, maxLat] (WGS84). Drives target_relation.intersects_event_aoi / event_aoi_coverage_ratio."
507
+ },
508
+ "eventTimestamp": {
509
+ "type": "string",
510
+ "description": "Full event timestamp (ISO 8601) when known — promotes same-day scenes from same_day_unknown to pre/post by time."
511
+ },
512
+ "cloudCoverMax": {
513
+ "type": "number",
514
+ "minimum": 0,
515
+ "maximum": 100,
516
+ "description": "Sentinel-2 only: max cloud cover %."
517
+ },
518
+ "limit": {
519
+ "type": "integer",
520
+ "minimum": 1,
521
+ "maximum": 100,
522
+ "description": "Max scenes to return. Defaults to 25."
523
+ },
524
+ "responseFormat": {
525
+ "type": "string",
526
+ "enum": [
527
+ "concise",
528
+ "detailed"
529
+ ],
530
+ "description": "Per-scene field detail. \"concise\" (default) returns id, collection, datetime, timing, cloud_cover, platform, orbit_state, relative_orbit, instrument_mode, product_type, coverage_ratio, covers_event_point, usable_for_event, stac_item_url, preview. \"detailed\" adds the full footprint bbox/geometry, the complete target_relation, constellation, polarizations, absolute_orbit, incidence_angle, and non-signed asset hrefs."
531
+ }
532
+ },
533
+ "required": [
534
+ "bbox"
535
+ ]
536
+ },
537
+ "outputSchema": {
280
538
  "type": "object",
281
539
  "properties": {
282
540
  "meta": {
@@ -299,38 +557,36 @@ export const TOOLS = [
299
557
  "scenes"
300
558
  ]
301
559
  },
302
- description: 'Search the satellite imagery catalog (Sentinel-1/2, OPERA RTC-S1) for scenes over an area and ' +
303
- 'date window — the natural follow-up to a signal (find imagery over the event location). Returns ' +
304
- 'scene metadata (id, datetime, footprint, cloud cover, platform, orbit geometry, coverage, catalog ' +
305
- 'link) — no imagery bytes. Pass eventDate to classify each scene timing=pre/post/same_day_unknown ' +
306
- '(a same-day scene is same_day_unknown, never post, without a real event time) and get pre/post ' +
307
- 'bracketing + window_status + SAR sar_pair_status in meta. Pass eventPoint [lon,lat] and/or eventAoi ' +
308
- '[minLon,minLat,maxLon,maxLat] to get each scene\'s target_relation (covers_event_geometry = pure ' +
309
- 'geometry gate; usable_for_analysis additionally requires acceptable cloud for optical, so a ' +
310
- '99%-cloud scene is geometry-covering but not analysis-usable) — so a scene that only clips the wide ' +
311
- 'bbox is not mistaken for covering the event. Costs 2 token(s) per call.',
312
- inputSchema: {
313
- type: 'object',
314
- properties: {
315
- bbox: { ...BBOX, description: 'Bounding box [minLon, minLat, maxLon, maxLat] (WGS84). Required.' },
316
- collection: { type: 'string', enum: [...IMAGERY_COLLECTIONS], description: 'Catalog collection. Defaults to sentinel-2-l2a.' },
317
- date: { type: 'string', description: 'Window end date, YYYY-MM-DD (UTC). Defaults to today.' },
318
- days: { type: 'integer', minimum: 1, maximum: SIGNALS_MAX_DAYS, description: 'Window length in days. Defaults to 7.' },
319
- eventDate: { type: 'string', description: 'Event date, YYYY-MM-DD (UTC). When set, each scene is tagged timing=pre/post/same_day_unknown and the search window is widened to the canonical pre/post span, so meta reports has_pre_baseline / has_post / bracketing_available / window_status; for sentinel-1-grd it also reports sar_pair_status (ready | not_ready | indeterminate_event_time) + orbit_note.' },
320
- eventPoint: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2, description: 'Event point [lon, lat] (WGS84). When set, each scene reports target_relation.covers_event_point / usable_for_event so a scene that only clips the wide bbox is not presented as covering the event.' },
321
- eventAoi: { type: 'array', items: { type: 'number' }, minItems: 4, maxItems: 4, description: 'Event AOI bbox [minLon, minLat, maxLon, maxLat] (WGS84). Drives target_relation.intersects_event_aoi / event_aoi_coverage_ratio.' },
322
- eventTimestamp: { type: 'string', description: 'Full event timestamp (ISO 8601) when known — promotes same-day scenes from same_day_unknown to pre/post by time.' },
323
- cloudCoverMax: { type: 'number', minimum: 0, maximum: 100, description: 'Sentinel-2 only: max cloud cover %.' },
324
- limit: { type: 'integer', minimum: 1, maximum: 100, description: 'Max scenes to return. Defaults to 25.' },
325
- responseFormat: { type: 'string', enum: ['concise', 'detailed'], description: 'Per-scene field detail. "concise" (default) returns id, collection, datetime, timing, cloud_cover, platform, orbit_state, relative_orbit, instrument_mode, product_type, coverage_ratio, covers_event_point, usable_for_event, stac_item_url, preview. "detailed" adds the full footprint bbox/geometry, the complete target_relation, constellation, polarizations, absolute_orbit, incidence_angle, and non-signed asset hrefs.' },
326
- },
327
- required: ['bbox'],
328
- },
560
+ "annotations": {
561
+ "readOnlyHint": false,
562
+ "openWorldHint": false,
563
+ "destructiveHint": true
564
+ }
329
565
  },
330
566
  {
331
- name: 'assess_signal',
332
- annotations: { "readOnlyHint": false, "openWorldHint": false, "destructiveHint": true, "idempotentHint": true },
333
- outputSchema: {
567
+ "name": "assess_signal",
568
+ "description": "Run an AI RS (remote-sensing) deep-dive assessment for a specific signal: what to observe, recommended sensors, and a collection window. `eventId` is the `id` from query_signals. The result also carries a deterministic `context` block (event id/date, normalized target, AOI bbox, observability + quality verdict, and an `imagery_handoff` giving the exact bbox + event_date to pass to search_imagery for REAL pre/post scene candidates) — turning the assessment into an actionable collection plan. Costs 5 (quick) or 15 (deep) tokens, charged to the key owner's balance. A prior assessment for the same signal is cached (no re-charge). The exact charge and remaining balance are in the result meta.tokens. Signals that are not satellite-observable (observability:\"not-observable\" — e.g. political statements or broad-area events with no imageable physical mark) are rejected BEFORE any charge, so pre-filter with query_signals observability:\"observable\" to spend only where imagery helps.",
569
+ "inputSchema": {
570
+ "type": "object",
571
+ "properties": {
572
+ "eventId": {
573
+ "type": "integer",
574
+ "description": "Signal id (global_event_id) from query_signals."
575
+ },
576
+ "kind": {
577
+ "type": "string",
578
+ "enum": [
579
+ "quick",
580
+ "deep"
581
+ ],
582
+ "description": "Assessment depth. Defaults to quick."
583
+ }
584
+ },
585
+ "required": [
586
+ "eventId"
587
+ ]
588
+ },
589
+ "outputSchema": {
334
590
  "type": "object",
335
591
  "properties": {
336
592
  "kind": {
@@ -356,30 +612,42 @@ export const TOOLS = [
356
612
  "meta"
357
613
  ]
358
614
  },
359
- description: 'Run an AI RS (remote-sensing) deep-dive assessment for a specific signal: what to observe, ' +
360
- 'recommended sensors, and a collection window. `eventId` is the `id` from query_signals. ' +
361
- 'The result also carries a deterministic `context` block (event id/date, normalized target, AOI ' +
362
- 'bbox, observability + quality verdict, and an `imagery_handoff` giving the exact bbox + event_date ' +
363
- 'to pass to search_imagery for REAL pre/post scene candidates) — turning the assessment into an ' +
364
- 'actionable collection plan. ' +
365
- "Costs 5 (quick) or 15 (deep) tokens, charged to the key owner's balance. A prior assessment for " +
366
- 'the same signal is cached (no re-charge). The exact charge and remaining balance are in meta.tokens. ' +
367
- 'Signals that are not satellite-observable (observability:"not-observable" — e.g. political statements ' +
368
- 'or broad-area events with no imageable physical mark) are rejected BEFORE any charge, so pre-filter ' +
369
- 'with query_signals observability:"observable" to spend only where imagery helps.',
370
- inputSchema: {
371
- type: 'object',
372
- properties: {
373
- eventId: { type: 'integer', description: 'Signal id (global_event_id) from query_signals.' },
374
- kind: { type: 'string', enum: ['quick', 'deep'], description: 'Assessment depth. Defaults to quick.' },
375
- },
376
- required: ['eventId'],
377
- },
615
+ "annotations": {
616
+ "readOnlyHint": false,
617
+ "openWorldHint": false,
618
+ "destructiveHint": true,
619
+ "idempotentHint": true
620
+ }
378
621
  },
379
622
  {
380
- name: 'ask_analyst',
381
- annotations: { "readOnlyHint": false, "openWorldHint": false, "destructiveHint": true },
382
- outputSchema: {
623
+ "name": "ask_analyst",
624
+ "description": "Ask the Delta Analyst an OSINT/GEOINT question. Runs an agentic multi-step analysis over the signal corpus and returns a structured brief (summary, findings with collection recommendations, assessment, citations). Costs 5–123 tokens (usage-based, metered by the compute the question actually uses; charged ONCE, when the run completes; the exact charge and remaining balance are in the result meta.tokens). Durable async: the run is ENQUEUED and returns {status:\"processing\", job_id} immediately, then completes in a background worker — so it is never lost to a client timeout. Timing: most questions finish in ~30–90s; a complex brief (satellite-imagery lookups or many sources) can take 2–3 minutes. Fetch the finished brief by calling get_analyst_job with the job_id (poll every ~10–20s), or ask_analyst again with the SAME idempotencyKey (no second charge).",
625
+ "inputSchema": {
626
+ "type": "object",
627
+ "properties": {
628
+ "question": {
629
+ "type": "string",
630
+ "description": "The analytic question (≤ 500 chars)."
631
+ },
632
+ "bbox": {
633
+ "type": "array",
634
+ "items": {
635
+ "type": "number"
636
+ },
637
+ "minItems": 4,
638
+ "maxItems": 4,
639
+ "description": "Optional focus bounding box [minLon, minLat, maxLon, maxLat] (WGS84)."
640
+ },
641
+ "idempotencyKey": {
642
+ "type": "string",
643
+ "description": "Optional at-most-once key. Re-sending the SAME key resolves to the SAME run: if it finished you get the brief with NO second charge; if it is still running you get its processing status. Strongly recommended — it makes a timeout recoverable. Use a fresh key to ask again."
644
+ }
645
+ },
646
+ "required": [
647
+ "question"
648
+ ]
649
+ },
650
+ "outputSchema": {
383
651
  "type": "object",
384
652
  "properties": {
385
653
  "brief": {
@@ -397,34 +665,95 @@ export const TOOLS = [
397
665
  "type": "string",
398
666
  "description": "Id of the analyst run — pass to get_analyst_job (also at GET /api/v1/analyst/{job_id})."
399
667
  },
668
+ "progress": {
669
+ "type": "object",
670
+ "description": "Pipeline progress while the job is processing. completed_steps reaches total_steps ONLY when status is \"done\".",
671
+ "properties": {
672
+ "stage": {
673
+ "type": "string",
674
+ "enum": [
675
+ "queued",
676
+ "retrieval",
677
+ "imagery_reconciliation",
678
+ "synthesis",
679
+ "final_validation",
680
+ "persistence",
681
+ "complete"
682
+ ],
683
+ "description": "Current pipeline stage."
684
+ },
685
+ "completed_steps": {
686
+ "type": "integer",
687
+ "description": "Completed pipeline steps (0-6)."
688
+ },
689
+ "total_steps": {
690
+ "type": "integer",
691
+ "description": "Always 6."
692
+ },
693
+ "agent_progress": {
694
+ "type": "object",
695
+ "description": "The model's internal step counter (an upper bound on the steps a run may take), or null.",
696
+ "properties": {
697
+ "completed_steps": {
698
+ "type": "integer"
699
+ },
700
+ "total_steps": {
701
+ "type": "integer"
702
+ }
703
+ }
704
+ }
705
+ },
706
+ "required": [
707
+ "stage",
708
+ "completed_steps",
709
+ "total_steps"
710
+ ]
711
+ },
712
+ "estimated_charge": {
713
+ "type": "object",
714
+ "description": "The charge ceiling quoted for THIS run, fixed at enqueue (統合改善指示書 P1-1). The completed run reports the actual charge in meta.tokens.charged and echoes this ceiling as meta.tokens.maximum_promised; actual never exceeds it.",
715
+ "properties": {
716
+ "minimum": {
717
+ "type": "integer",
718
+ "description": "Floor charge for any completed run."
719
+ },
720
+ "maximum": {
721
+ "type": "integer",
722
+ "description": "Ceiling this run may be charged."
723
+ }
724
+ },
725
+ "required": [
726
+ "minimum",
727
+ "maximum"
728
+ ]
729
+ },
400
730
  "message": {
401
731
  "type": "string"
402
732
  }
403
733
  }
404
734
  },
405
- description: 'Ask the Delta Analyst an OSINT/GEOINT question. Runs an agentic multi-step analysis over the ' +
406
- 'signal corpus and returns a structured brief (summary, findings with collection recommendations, ' +
407
- 'assessment, citations). Costs 5–123 tokens (usage-based, metered by the compute the question actually ' +
408
- 'uses; charged ONCE, when the run completes; the exact charge and remaining balance are in meta.tokens). ' +
409
- 'Durable async: the run is ENQUEUED and returns {status:"processing", job_id} immediately, then completes ' +
410
- 'in a background worker — so it is never lost to a client timeout. Timing: most questions finish in ~30–90s; ' +
411
- 'a complex brief (satellite-imagery lookups or many sources) can take 2–3 minutes. Fetch the finished brief ' +
412
- 'by calling get_analyst_job with the job_id (poll every ~10–20s), or ask_analyst again with the SAME ' +
413
- 'idempotencyKey (no second charge).',
414
- inputSchema: {
415
- type: 'object',
416
- properties: {
417
- question: { type: 'string', description: 'The analytic question (≤ 500 chars).' },
418
- bbox: { ...BBOX, description: 'Optional focus bounding box [minLon, minLat, maxLon, maxLat] (WGS84).' },
419
- idempotencyKey: { type: 'string', description: 'Optional at-most-once key. Re-sending the SAME key resolves to the SAME run: if it finished you get the brief with NO second charge; if it is still running you get its processing status. Strongly recommended — it makes a timeout recoverable. Use a fresh key to ask again.' },
420
- },
421
- required: ['question'],
422
- },
735
+ "annotations": {
736
+ "readOnlyHint": false,
737
+ "openWorldHint": false,
738
+ "destructiveHint": true
739
+ }
423
740
  },
424
741
  {
425
- name: 'get_analyst_job',
426
- annotations: { "readOnlyHint": true, "openWorldHint": false, "destructiveHint": false },
427
- outputSchema: {
742
+ "name": "get_analyst_job",
743
+ "description": "Fetch the status and result of an ask_analyst run by job_id. Job status is ONLY \"processing\" (still running — poll again in ~10-20s), \"done\" (with the finished brief and meta.tokens), or \"error\". When done, result_quality.status (\"complete\" | \"partial\", with any issues[]) reports whether the structured output is fully populated — this is SEPARATE from the job status (a done job can carry a partial result). Free of token charges — the run itself is charged once on completion. A job is visible only to the API key owner that created it.",
744
+ "inputSchema": {
745
+ "type": "object",
746
+ "properties": {
747
+ "job_id": {
748
+ "type": "string",
749
+ "description": "The job_id returned by ask_analyst."
750
+ }
751
+ },
752
+ "required": [
753
+ "job_id"
754
+ ]
755
+ },
756
+ "outputSchema": {
428
757
  "type": "object",
429
758
  "properties": {
430
759
  "job_id": {
@@ -434,6 +763,50 @@ export const TOOLS = [
434
763
  "type": "string",
435
764
  "description": "\"processing\" | \"done\" | \"error\"."
436
765
  },
766
+ "progress": {
767
+ "type": "object",
768
+ "description": "Pipeline progress while the job is processing. completed_steps reaches total_steps ONLY when status is \"done\".",
769
+ "properties": {
770
+ "stage": {
771
+ "type": "string",
772
+ "enum": [
773
+ "queued",
774
+ "retrieval",
775
+ "imagery_reconciliation",
776
+ "synthesis",
777
+ "final_validation",
778
+ "persistence",
779
+ "complete"
780
+ ],
781
+ "description": "Current pipeline stage."
782
+ },
783
+ "completed_steps": {
784
+ "type": "integer",
785
+ "description": "Completed pipeline steps (0-6)."
786
+ },
787
+ "total_steps": {
788
+ "type": "integer",
789
+ "description": "Always 6."
790
+ },
791
+ "agent_progress": {
792
+ "type": "object",
793
+ "description": "The model's internal step counter (an upper bound on the steps a run may take), or null.",
794
+ "properties": {
795
+ "completed_steps": {
796
+ "type": "integer"
797
+ },
798
+ "total_steps": {
799
+ "type": "integer"
800
+ }
801
+ }
802
+ }
803
+ },
804
+ "required": [
805
+ "stage",
806
+ "completed_steps",
807
+ "total_steps"
808
+ ]
809
+ },
437
810
  "brief": {
438
811
  "type": "object"
439
812
  },
@@ -456,54 +829,106 @@ export const TOOLS = [
456
829
  }
457
830
  }
458
831
  },
459
- description: 'Fetch the status and result of an ask_analyst run by job_id. Returns status "processing" (still ' +
460
- 'running — poll again in ~10-20s), "done" (with the finished brief and meta.tokens), or "error". ' +
461
- 'Free of token charges — the run itself is charged once on completion. A job is visible only to the ' +
462
- 'API key owner that created it. Use this to retrieve the brief after ask_analyst returned a job_id.',
463
- inputSchema: {
464
- type: 'object',
465
- properties: {
466
- job_id: { type: 'string', description: 'The job_id returned by ask_analyst.' },
467
- },
468
- required: ['job_id'],
469
- },
470
- },
832
+ "annotations": {
833
+ "readOnlyHint": true,
834
+ "openWorldHint": false,
835
+ "destructiveHint": false
836
+ }
837
+ }
471
838
  ];
472
839
  export const RESOURCES = [
473
- { uri: 'brief://latest', name: 'Daily World Brief (latest)', description: 'The most recent AI-synthesized Daily World Brief (JSON). Free.', mimeType: 'application/json' },
474
- { uri: 'signals://schema', name: 'Signal object schema', description: 'JSON Schema of the public Signal shape returned by query_signals / /api/v1/signals.', mimeType: 'application/json' },
475
- { uri: 'usage://current', name: 'API usage & quota', description: 'Remaining token balance and plan capabilities for the calling key. Free.', mimeType: 'application/json' },
476
- { uri: 'imagery://collections', name: 'Imagery collections', description: 'The satellite catalog collections searchable via search_imagery. Free.', mimeType: 'application/json' },
477
- { uri: 'status://current', name: 'Data freshness & pipeline status', description: 'How current the data is (ingestion/enrichment frontier), the Daily World Brief status, and an Operational/Delayed/Degraded roll-up. Free.', mimeType: 'application/json' },
840
+ {
841
+ "uri": "brief://latest",
842
+ "name": "Daily World Brief (latest)",
843
+ "description": "The most recent AI-synthesized Daily World Brief (JSON). Free.",
844
+ "mimeType": "application/json"
845
+ },
846
+ {
847
+ "uri": "signals://schema",
848
+ "name": "Signal object schema",
849
+ "description": "JSON Schema of the public Signal shape returned by query_signals / /api/v1/signals.",
850
+ "mimeType": "application/json"
851
+ },
852
+ {
853
+ "uri": "usage://current",
854
+ "name": "API usage & quota",
855
+ "description": "Remaining token balance and plan capabilities for the calling key. Free.",
856
+ "mimeType": "application/json"
857
+ },
858
+ {
859
+ "uri": "imagery://collections",
860
+ "name": "Imagery collections",
861
+ "description": "The satellite catalog collections searchable via search_imagery. Free.",
862
+ "mimeType": "application/json"
863
+ },
864
+ {
865
+ "uri": "status://current",
866
+ "name": "Data freshness & pipeline status",
867
+ "description": "How current the data is (ingestion/enrichment frontier), the Daily World Brief status, and an Operational/Delayed/Degraded roll-up. Free.",
868
+ "mimeType": "application/json"
869
+ }
478
870
  ];
479
871
  export const RESOURCE_TEMPLATES = [
480
- { uriTemplate: 'brief://{date}', name: 'Daily World Brief by date', description: 'The Daily World Brief for a specific UTC date (YYYY-MM-DD). Free.', mimeType: 'application/json' },
872
+ {
873
+ "uriTemplate": "brief://{date}",
874
+ "name": "Daily World Brief by date",
875
+ "description": "The Daily World Brief for a specific UTC date (YYYY-MM-DD). Free.",
876
+ "mimeType": "application/json"
877
+ }
481
878
  ];
482
879
  export const PROMPTS = [
483
880
  {
484
- name: 'daily-situation-briefing',
485
- description: 'Summarize the current world situation from the Daily World Brief.',
486
- arguments: [{ name: 'date', description: 'UTC date YYYY-MM-DD (optional; defaults to latest).', required: false }],
881
+ "name": "daily-situation-briefing",
882
+ "description": "Summarize the current world situation from the Daily World Brief.",
883
+ "arguments": [
884
+ {
885
+ "name": "date",
886
+ "description": "UTC date YYYY-MM-DD (optional; defaults to latest).",
887
+ "required": false
888
+ }
889
+ ]
487
890
  },
488
891
  {
489
- name: 'assess-top-signal',
490
- description: 'Find the highest-severity recent signal in an area/category and run an RS assessment.',
491
- arguments: [
492
- { name: 'bbox', description: 'Bounding box "minLon,minLat,maxLon,maxLat" (optional).', required: false },
493
- { name: 'category', description: 'Category filter (optional).', required: false },
494
- ],
892
+ "name": "assess-top-signal",
893
+ "description": "Find the highest-severity recent signal in an area/category and run an RS assessment.",
894
+ "arguments": [
895
+ {
896
+ "name": "bbox",
897
+ "description": "Bounding box \"minLon,minLat,maxLon,maxLat\" (optional).",
898
+ "required": false
899
+ },
900
+ {
901
+ "name": "category",
902
+ "description": "Category filter (optional).",
903
+ "required": false
904
+ }
905
+ ]
495
906
  },
496
907
  {
497
- name: 'aoi-watch',
498
- description: 'Scan an area of interest for recent escalations and recommend collection.',
499
- arguments: [{ name: 'bbox', description: 'Bounding box "minLon,minLat,maxLon,maxLat".', required: true }],
908
+ "name": "aoi-watch",
909
+ "description": "Scan an area of interest for recent escalations and recommend collection.",
910
+ "arguments": [
911
+ {
912
+ "name": "bbox",
913
+ "description": "Bounding box \"minLon,minLat,maxLon,maxLat\".",
914
+ "required": true
915
+ }
916
+ ]
500
917
  },
501
918
  {
502
- name: 'market-exposure-check',
503
- description: 'Find recent events that could plausibly move a given market (oil, grain, shipping, ...) and explain each transmission channel. Informational only — not investment advice.',
504
- arguments: [
505
- { name: 'market', description: `Market to check: ${MARKET_IMPACTS.join(', ')}.`, required: true },
506
- { name: 'days', description: 'Lookback window in days (optional; default 3).', required: false },
507
- ],
508
- },
919
+ "name": "market-exposure-check",
920
+ "description": "Find recent events that could plausibly move a given market (oil, grain, shipping, ...) and explain each transmission channel. Informational only — not investment advice.",
921
+ "arguments": [
922
+ {
923
+ "name": "market",
924
+ "description": "Market to check: oil, natural_gas, grain, shipping, defense, metals, semiconductors, fx, equities.",
925
+ "required": true
926
+ },
927
+ {
928
+ "name": "days",
929
+ "description": "Lookback window in days (optional; default 3).",
930
+ "required": false
931
+ }
932
+ ]
933
+ }
509
934
  ];
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
21
21
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
22
22
  import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
23
23
  import { PROMPTS, RESOURCES, RESOURCE_TEMPLATES, TOOLS } from './catalog.js';
24
- const VERSION = '1.3.26';
24
+ const VERSION = '1.3.28';
25
25
  const REMOTE_URL = new URL(process.env.OFFNADIR_DELTA_MCP_URL ?? 'https://offnadir-delta.com/api/v1/mcp');
26
26
  /** Lazily-connected client to the hosted remote MCP server. */
27
27
  let remote = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "offnadir-delta-mcp",
3
- "version": "1.3.26",
3
+ "version": "1.3.28",
4
4
  "description": "Local (stdio) MCP server for Off-Nadir Delta — live, geolocated world-event intelligence, a Daily World Brief, satellite-imagery search, and an OSINT/GEOINT analyst. Forwards to the hosted server with your API key.",
5
5
  "type": "module",
6
6
  "bin": {