offnadir-delta-mcp 1.3.28 → 1.5.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/dist/catalog.js CHANGED
@@ -13,7 +13,7 @@
13
13
  * Actual `tools/call` / `resources/read` / `prompts/get` requests are forwarded
14
14
  * to the remote server with the caller's OFFNADIR_DELTA_API_KEY (see index.ts).
15
15
  */
16
- // Generated for Off-Nadir Delta MCP 1.3.28.
16
+ // Generated for Off-Nadir Delta MCP 1.5.0.
17
17
  export const TOOLS = [
18
18
  {
19
19
  "name": "query_signals",
@@ -563,6 +563,299 @@ export const TOOLS = [
563
563
  "destructiveHint": true
564
564
  }
565
565
  },
566
+ {
567
+ "name": "plan_event_imagery",
568
+ "description": "Plan the imagery evidence for ONE event in a single call, instead of guessing collections one at a time. Give the event_id and what you are trying to establish (damage_assessment | flood_mapping | wildfire_assessment) and the SERVER runs the deterministic plan for that goal: it always checks BOTH in-app sensors — sentinel-1-grd (SAR: all-weather, the only look that survives cloud and night) and sentinel-2-l2a (optical, human-legible) — exactly once each, against the event’s own footprint and a pre/post window around its date. The result carries, per search, why it was made, how many scenes came back, how many actually COVER the event and are usable (cloud-obscured optical does not count), the SAR pair status, and whether a pre/post bracket exists. It also states screening / detection / identification capability: Sentinel-1/2 screen and detect at facility scale, and only object-level identification needs commercial VHR — a VHR recommendation NEVER invalidates what the free catalog already showed. Prefer this over several search_imagery calls for the same event: it cannot miss the SAR look and cannot repeat a search. An event with no resolvable footprint is refused rather than planned against a guess. Costs 4 token(s) per call (it deliberately issues two catalog searches).",
569
+ "inputSchema": {
570
+ "type": "object",
571
+ "properties": {
572
+ "event_id": {
573
+ "type": "integer",
574
+ "description": "The `id` from query_signals. The server resolves its authoritative point + AOI."
575
+ },
576
+ "analysis_goal": {
577
+ "type": "string",
578
+ "enum": [
579
+ "damage_assessment",
580
+ "flood_mapping",
581
+ "wildfire_assessment"
582
+ ],
583
+ "description": "What the imagery must establish — decides which collection leads and how cloud is gated."
584
+ },
585
+ "event_date": {
586
+ "type": "string",
587
+ "description": "Event date YYYY-MM-DD. Optional — the event row supplies it when known."
588
+ }
589
+ },
590
+ "required": [
591
+ "event_id",
592
+ "analysis_goal"
593
+ ]
594
+ },
595
+ "outputSchema": {
596
+ "type": "object",
597
+ "properties": {
598
+ "meta": {
599
+ "type": "object",
600
+ "description": "Query echo, token charge/balance (meta.tokens), and pagination where applicable."
601
+ },
602
+ "summary": {
603
+ "type": "string",
604
+ "description": "One-line natural-language summary of the result, ready to relay to a user."
605
+ },
606
+ "plan": {
607
+ "type": "object"
608
+ }
609
+ },
610
+ "required": [
611
+ "meta",
612
+ "plan"
613
+ ]
614
+ },
615
+ "annotations": {
616
+ "readOnlyHint": false,
617
+ "openWorldHint": false,
618
+ "destructiveHint": true
619
+ }
620
+ },
621
+ {
622
+ "name": "rank_imaging_priority",
623
+ "description": "WHERE — and with what class (and therefore cost) of satellite — is observation most worthwhile right now? Crosses each event’s composite IMPORTANCE (severity × source breadth × market relevance) with the SPEC CLASS its required resolution demands: coarse (≤100 m), hr (≤10 m, Sentinel-class free data) or vhr (sub-metre, commercial tasking). Returns how many imageable events fall in each class with their mean importance, plus the top targets with importance, required class and AOI. Use it to triage a theatre before spending on imagery: a high-importance event that only needs hr is answerable with free Sentinel data, while a vhr one is what a paid order is for. Deterministic — no LLM, no per-event cost. Costs 1 token(s) per call.",
624
+ "inputSchema": {
625
+ "type": "object",
626
+ "properties": {
627
+ "bbox": {
628
+ "type": "array",
629
+ "items": {
630
+ "type": "number"
631
+ },
632
+ "minItems": 4,
633
+ "maxItems": 4,
634
+ "description": "Area [west, south, east, north] in WGS84. Omit for a global survey."
635
+ },
636
+ "start_date": {
637
+ "type": "string",
638
+ "description": "Inclusive start date YYYY-MM-DD. Defaults to today; clamped to your plan history floor."
639
+ },
640
+ "end_date": {
641
+ "type": "string",
642
+ "description": "Inclusive end date YYYY-MM-DD. Defaults to today. The window is capped at 30 days."
643
+ },
644
+ "categories": {
645
+ "type": "array",
646
+ "items": {
647
+ "type": "string"
648
+ },
649
+ "description": "Restrict to these Delta categories (kinetic, armed_conflict, maritime, natural_disaster, infrastructure, aviation, humanitarian, protest, diplomacy)."
650
+ },
651
+ "min_geoint_score": {
652
+ "type": "number",
653
+ "description": "Drop events below this GEOINT score before ranking."
654
+ },
655
+ "top_n": {
656
+ "type": "number",
657
+ "minimum": 1,
658
+ "maximum": 50,
659
+ "description": "How many top targets to return (default 12)."
660
+ }
661
+ },
662
+ "required": []
663
+ },
664
+ "outputSchema": {
665
+ "type": "object",
666
+ "properties": {
667
+ "meta": {
668
+ "type": "object",
669
+ "description": "Query echo, token charge/balance (meta.tokens), and pagination where applicable."
670
+ },
671
+ "summary": {
672
+ "type": "string",
673
+ "description": "One-line natural-language summary of the result, ready to relay to a user."
674
+ },
675
+ "priority": {
676
+ "type": "object"
677
+ }
678
+ },
679
+ "required": [
680
+ "meta",
681
+ "priority"
682
+ ]
683
+ },
684
+ "annotations": {
685
+ "readOnlyHint": false,
686
+ "openWorldHint": false,
687
+ "destructiveHint": true
688
+ }
689
+ },
690
+ {
691
+ "name": "survey_observable_events",
692
+ "description": "Which events in a window can a given in-app sensor actually RESOLVE? Evaluates the FULL set (not just the top few) against each event’s precomputed required resolution, and returns how many are observable vs not, the breakdown by required resolution, and the top observable events with the ready-made imaging rationale. Observability here is resolvability — whether the physical mark is large enough for the sensor: Sentinel-2 is ~10 m optical (needs daylight and clear sky), Sentinel-1 is SAR (all-weather, day or night). Prefer this over asking about events one at a time: it is exhaustive AND cheap, and it is the honest way to answer \"what can we actually see\" before committing collection effort. Deterministic — no LLM. Costs 1 token(s) per call.",
693
+ "inputSchema": {
694
+ "type": "object",
695
+ "properties": {
696
+ "sensor": {
697
+ "type": "string",
698
+ "enum": [
699
+ "sentinel-2",
700
+ "sentinel-1"
701
+ ],
702
+ "description": "Which in-app sensor to evaluate against. sentinel-2 = ~10 m optical (daylight, clear sky); sentinel-1 = SAR (all-weather, day/night). Default sentinel-2."
703
+ },
704
+ "bbox": {
705
+ "type": "array",
706
+ "items": {
707
+ "type": "number"
708
+ },
709
+ "minItems": 4,
710
+ "maxItems": 4,
711
+ "description": "Area [west, south, east, north] in WGS84. Omit for a global survey."
712
+ },
713
+ "start_date": {
714
+ "type": "string",
715
+ "description": "Inclusive start date YYYY-MM-DD. Defaults to today; clamped to your plan history floor."
716
+ },
717
+ "end_date": {
718
+ "type": "string",
719
+ "description": "Inclusive end date YYYY-MM-DD. Defaults to today. The window is capped at 30 days."
720
+ },
721
+ "categories": {
722
+ "type": "array",
723
+ "items": {
724
+ "type": "string"
725
+ },
726
+ "description": "Restrict to these Delta categories."
727
+ },
728
+ "min_geoint_score": {
729
+ "type": "number",
730
+ "description": "Drop events below this GEOINT score before surveying."
731
+ },
732
+ "top_n": {
733
+ "type": "number",
734
+ "minimum": 1,
735
+ "maximum": 50,
736
+ "description": "How many observable events to return (default 20)."
737
+ }
738
+ },
739
+ "required": []
740
+ },
741
+ "outputSchema": {
742
+ "type": "object",
743
+ "properties": {
744
+ "meta": {
745
+ "type": "object",
746
+ "description": "Query echo, token charge/balance (meta.tokens), and pagination where applicable."
747
+ },
748
+ "summary": {
749
+ "type": "string",
750
+ "description": "One-line natural-language summary of the result, ready to relay to a user."
751
+ },
752
+ "survey": {
753
+ "type": "object"
754
+ }
755
+ },
756
+ "required": [
757
+ "meta",
758
+ "survey"
759
+ ]
760
+ },
761
+ "annotations": {
762
+ "readOnlyHint": false,
763
+ "openWorldHint": false,
764
+ "destructiveHint": true
765
+ }
766
+ },
767
+ {
768
+ "name": "predict_satellite_passes",
769
+ "description": "WHEN can this place next be imaged, and by WHAT — the timing half of collection planning. Propagates current orbital elements (SGP4 over day-cached CelesTrak two-line elements) for seven families and returns the access windows over a target: Sentinel-1 (SAR), Sentinel-2 and Landsat (free, SYSTEMATIC — scheduled acquisitions you will get), plus WorldView, ICEYE, Capella and SkySat (commercial, AGILE — taskable ACCESS opportunities that require a paid order and are NOT guaranteed collects). Each pass carries acquisition/loss times, the closest-approach instant, peak elevation, OFF-NADIR angle, ground distance, ascending/descending, solar elevation and whether the target is sunlit (optical needs light; SAR does not), and the age of the element set it was computed from. Use it to answer \"when is the next chance to see this\", to choose between waiting for a free systematic pass and paying to task an agile one, and to time a pre/post change-detection pair. Give lat/lon, or a bbox whose centre is used. Horizon is capped at 7 days. If elements cannot be retrieved the result says so (retrieval_ok:false) — that means timing is UNAVAILABLE, never \"no passes\". Costs 2 token(s) per call.",
770
+ "inputSchema": {
771
+ "type": "object",
772
+ "properties": {
773
+ "lat": {
774
+ "type": "number",
775
+ "minimum": -90,
776
+ "maximum": 90,
777
+ "description": "Target latitude (-90..90; positive = North). Required unless bbox is given."
778
+ },
779
+ "lon": {
780
+ "type": "number",
781
+ "minimum": -180,
782
+ "maximum": 180,
783
+ "description": "Target longitude (-180..180; positive = East). Required unless bbox is given."
784
+ },
785
+ "bbox": {
786
+ "type": "array",
787
+ "items": {
788
+ "type": "number"
789
+ },
790
+ "minItems": 4,
791
+ "maxItems": 4,
792
+ "description": "Area [west, south, east, north] in WGS84. The CENTRE is used as the target when lat/lon are omitted."
793
+ },
794
+ "start_date": {
795
+ "type": "string",
796
+ "description": "Inclusive start date YYYY-MM-DD (UTC). Defaults to today."
797
+ },
798
+ "end_date": {
799
+ "type": "string",
800
+ "description": "Inclusive end date YYYY-MM-DD (UTC). Defaults to start+2 days; the window is capped to a 7-day horizon."
801
+ },
802
+ "satellites": {
803
+ "type": "array",
804
+ "items": {
805
+ "type": "string",
806
+ "enum": [
807
+ "sentinel-1",
808
+ "sentinel-2",
809
+ "landsat",
810
+ "worldview",
811
+ "iceye",
812
+ "capella",
813
+ "skysat"
814
+ ]
815
+ },
816
+ "description": "Families to consider. Omit for all seven. Use this to compare \"free systematic only\" against \"what could I task\"."
817
+ },
818
+ "max_passes": {
819
+ "type": "number",
820
+ "minimum": 1,
821
+ "maximum": 100,
822
+ "description": "Maximum passes to return, soonest first (default 40)."
823
+ }
824
+ },
825
+ "required": []
826
+ },
827
+ "outputSchema": {
828
+ "type": "object",
829
+ "properties": {
830
+ "meta": {
831
+ "type": "object",
832
+ "description": "Query echo, token charge/balance (meta.tokens), and pagination where applicable."
833
+ },
834
+ "summary": {
835
+ "type": "string",
836
+ "description": "One-line natural-language summary of the result, ready to relay to a user."
837
+ },
838
+ "passes": {
839
+ "type": "array",
840
+ "items": {
841
+ "type": "object"
842
+ }
843
+ },
844
+ "freshness": {
845
+ "type": "object"
846
+ }
847
+ },
848
+ "required": [
849
+ "meta",
850
+ "passes"
851
+ ]
852
+ },
853
+ "annotations": {
854
+ "readOnlyHint": false,
855
+ "openWorldHint": false,
856
+ "destructiveHint": true
857
+ }
858
+ },
566
859
  {
567
860
  "name": "assess_signal",
568
861
  "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.",
@@ -638,6 +931,14 @@ export const TOOLS = [
638
931
  "maxItems": 4,
639
932
  "description": "Optional focus bounding box [minLon, minLat, maxLon, maxLat] (WGS84)."
640
933
  },
934
+ "mode": {
935
+ "type": "string",
936
+ "enum": [
937
+ "fast",
938
+ "deep"
939
+ ],
940
+ "description": "fast (default) or deep. Deep enables extended reasoning and wider evidence-gathering budgets — for forecasting, collection trade-offs and market-implication questions where step-by-step reasoning materially helps. It is slower and the ceiling rises from 123 to 415 tokens; charging stays metered by what the run actually consumes, so a light deep question does not cost the ceiling."
941
+ },
641
942
  "idempotencyKey": {
642
943
  "type": "string",
643
944
  "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."
@@ -834,6 +1135,162 @@ export const TOOLS = [
834
1135
  "openWorldHint": false,
835
1136
  "destructiveHint": false
836
1137
  }
1138
+ },
1139
+ {
1140
+ "name": "create_standing_order",
1141
+ "description": "Put an area under CONTINUOUS watch: save a question plus a bounding box and Delta re-answers it on a schedule, notifying only when the answer actually changed. Creating one is FREE. Each time it fires it runs ask_analyst and is metered like any Analyst question, so the cost is per CHANGE, not per check: a deterministic pass over the corpus decides whether anything new crossed the reporting bar, and quiet periods never invoke the model or charge anything. Returns projected_monthly_tokens_max — the ceiling if every single check fired — so the cost is visible before committing. Cadence and how many orders you may hold are set by your plan; the error says which limit you hit. Use it when the question is \"tell me when this changes\" rather than \"what is happening right now\".",
1142
+ "inputSchema": {
1143
+ "type": "object",
1144
+ "properties": {
1145
+ "bbox": {
1146
+ "type": "array",
1147
+ "items": {
1148
+ "type": "number"
1149
+ },
1150
+ "minItems": 4,
1151
+ "maxItems": 4,
1152
+ "description": "Area to watch, [west, south, east, north] in WGS84. Required — a global standing order would fire on everything."
1153
+ },
1154
+ "question": {
1155
+ "type": "string",
1156
+ "description": "The question to re-answer each time something changes. Omit for \"what changed in this area, and what does it mean?\"."
1157
+ },
1158
+ "name": {
1159
+ "type": "string",
1160
+ "description": "Label for the order (default \"Standing order\")."
1161
+ },
1162
+ "cadence": {
1163
+ "type": "string",
1164
+ "enum": [
1165
+ "daily",
1166
+ "weekly",
1167
+ "monthly"
1168
+ ],
1169
+ "description": "How often to CHECK (checking is free; only a fired check costs tokens). Default weekly. Faster cadences may require a higher plan."
1170
+ },
1171
+ "categories": {
1172
+ "type": "array",
1173
+ "items": {
1174
+ "type": "string"
1175
+ },
1176
+ "description": "Restrict the watch to these Delta categories (kinetic, armed_conflict, maritime, natural_disaster, infrastructure, aviation, humanitarian, protest, diplomacy)."
1177
+ },
1178
+ "min_geoint_score": {
1179
+ "type": "number",
1180
+ "description": "Reporting bar (0-10, default 6). Raise it to be told only about major developments."
1181
+ },
1182
+ "min_new_events": {
1183
+ "type": "number",
1184
+ "description": "How many new qualifying events must appear before a run is triggered (default 1)."
1185
+ },
1186
+ "notify_email": {
1187
+ "type": "boolean",
1188
+ "description": "Email the result when it fires (default true). Results are readable via list_standing_orders either way."
1189
+ }
1190
+ },
1191
+ "required": [
1192
+ "bbox"
1193
+ ]
1194
+ },
1195
+ "outputSchema": {
1196
+ "type": "object",
1197
+ "properties": {
1198
+ "summary": {
1199
+ "type": "string",
1200
+ "description": "One-line natural-language summary of the result, ready to relay to a user."
1201
+ },
1202
+ "order": {
1203
+ "type": "object"
1204
+ },
1205
+ "projected_monthly_tokens_max": {
1206
+ "type": "number"
1207
+ }
1208
+ },
1209
+ "required": [
1210
+ "order"
1211
+ ]
1212
+ },
1213
+ "annotations": {
1214
+ "readOnlyHint": false,
1215
+ "openWorldHint": false,
1216
+ "destructiveHint": false
1217
+ }
1218
+ },
1219
+ {
1220
+ "name": "list_standing_orders",
1221
+ "description": "List the standing orders on this key, with each one’s cadence, watched area, when it last checked, when it last actually fired, and how many consecutive checks found nothing (quiet_checks — a high number means the watch is not earning its place). Also returns how many orders the plan allows and how many remain. Free of token charges.",
1222
+ "inputSchema": {
1223
+ "type": "object",
1224
+ "properties": {},
1225
+ "required": []
1226
+ },
1227
+ "outputSchema": {
1228
+ "type": "object",
1229
+ "properties": {
1230
+ "summary": {
1231
+ "type": "string",
1232
+ "description": "One-line natural-language summary of the result, ready to relay to a user."
1233
+ },
1234
+ "orders": {
1235
+ "type": "array",
1236
+ "items": {
1237
+ "type": "object"
1238
+ }
1239
+ },
1240
+ "limits": {
1241
+ "type": "object"
1242
+ }
1243
+ },
1244
+ "required": [
1245
+ "orders"
1246
+ ]
1247
+ },
1248
+ "annotations": {
1249
+ "readOnlyHint": true,
1250
+ "openWorldHint": false,
1251
+ "destructiveHint": false
1252
+ }
1253
+ },
1254
+ {
1255
+ "name": "delete_standing_order",
1256
+ "description": "Delete a standing order by id, or pause/resume it instead by passing active=false/true. Pausing keeps the order and its history; deleting removes both. Neither costs tokens. A paused order still counts against the plan limit, so delete rather than pause when you want the slot back.",
1257
+ "inputSchema": {
1258
+ "type": "object",
1259
+ "properties": {
1260
+ "order_id": {
1261
+ "type": "string",
1262
+ "description": "The id returned by create_standing_order or list_standing_orders."
1263
+ },
1264
+ "active": {
1265
+ "type": "boolean",
1266
+ "description": "Omit to DELETE. Pass false to pause and true to resume, keeping the order."
1267
+ }
1268
+ },
1269
+ "required": [
1270
+ "order_id"
1271
+ ]
1272
+ },
1273
+ "outputSchema": {
1274
+ "type": "object",
1275
+ "properties": {
1276
+ "summary": {
1277
+ "type": "string",
1278
+ "description": "One-line natural-language summary of the result, ready to relay to a user."
1279
+ },
1280
+ "deleted": {
1281
+ "type": "string"
1282
+ },
1283
+ "order": {
1284
+ "type": "object"
1285
+ }
1286
+ }
1287
+ },
1288
+ "annotations": {
1289
+ "readOnlyHint": false,
1290
+ "openWorldHint": false,
1291
+ "destructiveHint": true,
1292
+ "idempotentHint": true
1293
+ }
837
1294
  }
838
1295
  ];
839
1296
  export const RESOURCES = [
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.28';
24
+ const VERSION = '1.5.0';
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,7 +1,7 @@
1
1
  {
2
2
  "name": "offnadir-delta-mcp",
3
- "version": "1.3.28",
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.",
3
+ "version": "1.5.0",
4
+ "description": "Local (stdio) MCP server for Off-Nadir Delta \u2014 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": {
7
7
  "offnadir-delta-mcp": "dist/index.js"