01cb4255ef
New MCP server providing real-time global intelligence: financial markets (Yahoo Finance, CoinGecko), economic indicators (FRED, EIA, World Bank), conflict tracking (ACLED, UCDP, HDX), military flights (OpenSky), infrastructure monitoring (Cloudflare Radar, NGA cable health), maritime warnings (NGA), climate anomalies (Open-Meteo), news aggregation (RSS, GDELT), prediction markets (Polymarket), displacement data (UNHCR), aviation delays (FAA), cyber threats (Feodo, CISA KEV, SANS, URLhaus), country intelligence briefs (Ollama LLM), and HTML report generation (Jinja2 + Chart.js). Includes: SQLite TTL cache, per-source circuit breakers, async HTTP fetcher with retry/rate-limiting, Click CLI with 27 commands, 4 analysis modules (instability scoring, geo-convergence, signal aggregation, news clustering), 4 HTML report templates, and 28 unit tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
629 lines
25 KiB
Python
629 lines
25 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
World Intelligence MCP Server
|
|
==============================
|
|
|
|
Real-time global intelligence across 17 domains:
|
|
financial markets, economic indicators, earthquakes, wildfires,
|
|
conflict, military flights, infrastructure, and more.
|
|
|
|
Phase 1: Markets, Economic, Seismology, Wildfire (12 tools).
|
|
Phase 2: Conflict, Military, Infrastructure, Maritime, Climate (+10 = 22 tools).
|
|
Phase 3: News, Intelligence, Prediction, Displacement, Aviation, Cyber (+14 = 36 tools).
|
|
Phase 4: Reports — daily brief, country dossier, threat landscape (+3 = 39 tools).
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
import logging
|
|
import os
|
|
from typing import Any
|
|
|
|
from mcp.server import Server
|
|
from mcp.server.stdio import stdio_server
|
|
from mcp.types import Tool, TextContent
|
|
|
|
from .cache import Cache
|
|
from .circuit_breaker import CircuitBreaker
|
|
from .fetcher import Fetcher
|
|
from .sources import markets, economic, seismology, wildfire, conflict, military, infrastructure, maritime, climate, news, intelligence, prediction, displacement, aviation, cyber
|
|
from .reports import generator as report_gen
|
|
|
|
logging.basicConfig(
|
|
level=os.environ.get("WORLD_INTEL_LOG_LEVEL", "INFO"),
|
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
)
|
|
logger = logging.getLogger("world-intel-mcp")
|
|
|
|
server = Server("world-intel-mcp")
|
|
cache = Cache()
|
|
breaker = CircuitBreaker(failure_threshold=3, cooldown_seconds=300)
|
|
fetcher = Fetcher(cache=cache, breaker=breaker)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tool definitions
|
|
# ---------------------------------------------------------------------------
|
|
|
|
TOOLS: list[Tool] = [
|
|
# --- Markets (6 tools) ---
|
|
Tool(
|
|
name="intel_market_quotes",
|
|
description="Get real-time stock market index quotes (S&P 500, Dow, Nasdaq, FTSE, Nikkei, etc.). Optional: symbols (list of ticker symbols).",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"symbols": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
"description": "Ticker symbols (default: major indices)",
|
|
},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_crypto_quotes",
|
|
description="Get top cryptocurrency prices, market caps, and 7-day sparklines from CoinGecko. Optional: limit (int, default 20).",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"limit": {"type": "integer", "description": "Number of coins (default 20)", "default": 20},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_stablecoin_status",
|
|
description="Check stablecoin peg health (USDT, USDC, DAI, FDUSD). Flags depegs >0.5%.",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
Tool(
|
|
name="intel_etf_flows",
|
|
description="Get Bitcoin spot ETF prices and volumes (IBIT, FBTC, GBTC, ARKB, BITB).",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
Tool(
|
|
name="intel_sector_heatmap",
|
|
description="Get US equity sector performance heatmap (11 SPDR sector ETFs).",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
Tool(
|
|
name="intel_macro_signals",
|
|
description="Get 7 key macro signals: Fear & Greed, mempool fees, DXY, VIX, gold, 10Y Treasury, BTC dominance.",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
# --- Economic (3 tools) ---
|
|
Tool(
|
|
name="intel_energy_prices",
|
|
description="Get crude oil (Brent, WTI) and natural gas prices from EIA. Requires EIA_API_KEY.",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
Tool(
|
|
name="intel_fred_series",
|
|
description="Get Federal Reserve economic data series (GDP, UNRATE, CPIAUCSL, DFF, T10YIE, etc.). Requires FRED_API_KEY.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"series_id": {"type": "string", "description": "FRED series ID (e.g., 'UNRATE')"},
|
|
"limit": {"type": "integer", "description": "Number of observations", "default": 30},
|
|
},
|
|
"required": ["series_id"],
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_world_bank_indicators",
|
|
description="Get World Bank development indicators (GDP, inflation, unemployment) for a country.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"country": {"type": "string", "description": "ISO country code (default: USA)", "default": "USA"},
|
|
"indicators": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
"description": "World Bank indicator codes",
|
|
},
|
|
},
|
|
},
|
|
),
|
|
# --- Natural (2 tools) ---
|
|
Tool(
|
|
name="intel_earthquakes",
|
|
description="Get recent earthquakes from USGS. No API key needed.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"min_magnitude": {"type": "number", "description": "Minimum magnitude (default 4.5)", "default": 4.5},
|
|
"hours": {"type": "integer", "description": "Lookback hours (default 24)", "default": 24},
|
|
"limit": {"type": "integer", "description": "Max results (default 50)", "default": 50},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_wildfires",
|
|
description="Get active wildfires from NASA FIRMS (9 global regions). Requires NASA_FIRMS_API_KEY.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"region": {
|
|
"type": "string",
|
|
"description": "Specific region (north_america, europe, etc.) or omit for all 9",
|
|
"enum": [
|
|
"north_america", "south_america", "europe", "africa",
|
|
"middle_east", "south_asia", "east_asia", "southeast_asia", "oceania",
|
|
],
|
|
},
|
|
},
|
|
},
|
|
),
|
|
# --- Conflict (3 tools) ---
|
|
Tool(
|
|
name="intel_acled_events",
|
|
description="Get armed conflict events from ACLED. Optional: country (name), days (default 7), limit (default 100). Requires ACLED_ACCESS_TOKEN.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"country": {"type": "string", "description": "Country name filter"},
|
|
"days": {"type": "integer", "description": "Lookback days (default 7)", "default": 7},
|
|
"limit": {"type": "integer", "description": "Max results (default 100)", "default": 100},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_ucdp_events",
|
|
description="Get state-based violence events from UCDP GED. No API key needed. Optional: days (default 30).",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"days": {"type": "integer", "description": "Lookback days (default 30)", "default": 30},
|
|
"limit": {"type": "integer", "description": "Max results (default 100)", "default": 100},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_humanitarian_summary",
|
|
description="Get humanitarian crisis datasets from HDX. No API key needed. Optional: country code.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"country": {"type": "string", "description": "ISO country code filter"},
|
|
},
|
|
},
|
|
),
|
|
# --- Military (3 tools) ---
|
|
Tool(
|
|
name="intel_military_flights",
|
|
description="Track military aircraft via OpenSky Network (ICAO hex + callsign filtering). Optional: bbox (lamin,lomin,lamax,lomax).",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"bbox": {"type": "string", "description": "Bounding box: lamin,lomin,lamax,lomax"},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_theater_posture",
|
|
description="Get military aircraft presence across 5 theaters: European, Indo-Pacific, Middle East, Arctic, Korean Peninsula.",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
Tool(
|
|
name="intel_aircraft_details",
|
|
description="Get aircraft details from Wingbits by ICAO24 hex code. Requires WINGBITS_API_KEY.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"icao24": {"type": "string", "description": "ICAO24 hex code"},
|
|
},
|
|
"required": ["icao24"],
|
|
},
|
|
),
|
|
# --- Infrastructure (2 tools) ---
|
|
Tool(
|
|
name="intel_internet_outages",
|
|
description="Get internet outages from Cloudflare Radar (last 7 days). Optional: CLOUDFLARE_API_TOKEN for higher limits.",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
Tool(
|
|
name="intel_cable_health",
|
|
description="Assess undersea cable corridor health from NGA navigational warnings. 6 corridors scored 0-3.",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
# --- Maritime (1 tool) ---
|
|
Tool(
|
|
name="intel_nav_warnings",
|
|
description="Get active navigational warnings from NGA Maritime Safety. Optional: navarea (I-XVI).",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"navarea": {"type": "string", "description": "NAVAREA number (e.g., IV, XII)"},
|
|
},
|
|
},
|
|
),
|
|
# --- Climate (1 tool) ---
|
|
Tool(
|
|
name="intel_climate_anomalies",
|
|
description="Detect temperature and precipitation anomalies across 15 global climate zones (vs. prior year baseline).",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"zones": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
"description": "Zone keys to check (default: all 15)",
|
|
},
|
|
},
|
|
},
|
|
),
|
|
# --- Prediction (1 tool) ---
|
|
Tool(
|
|
name="intel_prediction_markets",
|
|
description="Get active prediction markets from Polymarket (questions, YES probabilities, volumes, sentiment).",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"limit": {"type": "integer", "description": "Number of markets (default 20)", "default": 20},
|
|
},
|
|
},
|
|
),
|
|
# --- Displacement (1 tool) ---
|
|
Tool(
|
|
name="intel_displacement_summary",
|
|
description="Get UNHCR refugee/displacement statistics by country of origin. No API key needed.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"year": {"type": "integer", "description": "Reporting year (default: last year)"},
|
|
},
|
|
},
|
|
),
|
|
# --- Aviation (1 tool) ---
|
|
Tool(
|
|
name="intel_airport_delays",
|
|
description="Get current US airport delays from FAA (20 major airports). No API key needed.",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
# --- Cyber (1 tool) ---
|
|
Tool(
|
|
name="intel_cyber_threats",
|
|
description="Get aggregated cyber threat intelligence from 4 feeds (Feodo, CISA KEV, SANS, URLhaus). No API key needed.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"limit": {"type": "integer", "description": "Max threats (default 50)", "default": 50},
|
|
},
|
|
},
|
|
),
|
|
# --- News (3 tools) ---
|
|
Tool(
|
|
name="intel_news_feed",
|
|
description="Get aggregated intelligence news from 20+ RSS feeds across 6 categories (geopolitics, security, tech, finance, military, science).",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"category": {
|
|
"type": "string",
|
|
"description": "Category filter",
|
|
"enum": ["geopolitics", "security", "technology", "finance", "military", "science"],
|
|
},
|
|
"limit": {"type": "integer", "description": "Max items (default 50)", "default": 50},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_trending_keywords",
|
|
description="Detect trending keywords from recent news headlines. Keyword spike detection across 20+ feeds.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"min_count": {"type": "integer", "description": "Minimum occurrences (default 3)", "default": 3},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_gdelt_search",
|
|
description="Search GDELT 2.0 for global news articles or volume timelines. No API key needed.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"query": {"type": "string", "description": "Search query (default: 'conflict')", "default": "conflict"},
|
|
"mode": {
|
|
"type": "string",
|
|
"description": "artlist (articles) or timelinevol (volume timeline)",
|
|
"enum": ["artlist", "timelinevol"],
|
|
"default": "artlist",
|
|
},
|
|
"limit": {"type": "integer", "description": "Max records (default 50)", "default": 50},
|
|
},
|
|
},
|
|
),
|
|
# --- Intelligence (4 tools) ---
|
|
Tool(
|
|
name="intel_country_brief",
|
|
description="Generate a country intelligence brief using Ollama LLM + World Bank + ACLED data. Falls back to data-only if LLM unavailable.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"country_code": {"type": "string", "description": "ISO country code (default: US)", "default": "US"},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_risk_scores",
|
|
description="Get country risk scores computed from ACLED conflict data vs historical baselines. Requires ACLED_ACCESS_TOKEN.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"limit": {"type": "integer", "description": "Top N countries (default 20)", "default": 20},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_instability_index",
|
|
description="Compute Country Instability Index (0-100) from conflict, economic, humanitarian, infrastructure, and military signals.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"country_code": {"type": "string", "description": "ISO alpha-3 code (e.g., UKR). Omit for top-10 focus countries."},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_signal_convergence",
|
|
description="Detect geographic convergence of multi-domain signals (earthquakes, conflict, military) in hotspot regions.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"lat": {"type": "number", "description": "Center latitude (omit for 5 global hotspots)"},
|
|
"lon": {"type": "number", "description": "Center longitude"},
|
|
"radius_deg": {"type": "number", "description": "Radius in degrees (default 5.0)", "default": 5.0},
|
|
},
|
|
},
|
|
),
|
|
# --- Reports (3 tools) ---
|
|
Tool(
|
|
name="intel_daily_brief",
|
|
description="Generate a daily intelligence brief HTML report (markets, conflict, cyber, natural, predictions, trending). Returns file path.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"output_dir": {"type": "string", "description": "Custom output directory (default: $STORAGE_BASE/reports/intel/)"},
|
|
},
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_country_dossier",
|
|
description="Generate a full country dossier HTML report (brief, instability index, conflict, displacement, economic). Returns file path.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"country_code": {"type": "string", "description": "ISO country code (e.g., UKR, SYR, MMR)"},
|
|
"output_dir": {"type": "string", "description": "Custom output directory"},
|
|
},
|
|
"required": ["country_code"],
|
|
},
|
|
),
|
|
Tool(
|
|
name="intel_threat_landscape",
|
|
description="Generate a threat landscape HTML report (cyber threats, conflict, military, cable health, outages). Returns file path.",
|
|
inputSchema={
|
|
"type": "object",
|
|
"properties": {
|
|
"output_dir": {"type": "string", "description": "Custom output directory"},
|
|
},
|
|
},
|
|
),
|
|
# --- System (1 tool) ---
|
|
Tool(
|
|
name="intel_status",
|
|
description="Get data source health, circuit breaker status, and cache statistics.",
|
|
inputSchema={"type": "object", "properties": {}},
|
|
),
|
|
]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tool dispatch
|
|
# ---------------------------------------------------------------------------
|
|
|
|
async def _dispatch(name: str, arguments: dict[str, Any]) -> Any:
|
|
"""Route tool call to the appropriate source function."""
|
|
match name:
|
|
# Markets
|
|
case "intel_market_quotes":
|
|
return await markets.fetch_market_quotes(fetcher, symbols=arguments.get("symbols"))
|
|
case "intel_crypto_quotes":
|
|
return await markets.fetch_crypto_quotes(fetcher, limit=arguments.get("limit", 20))
|
|
case "intel_stablecoin_status":
|
|
return await markets.fetch_stablecoin_status(fetcher)
|
|
case "intel_etf_flows":
|
|
return await markets.fetch_etf_flows(fetcher)
|
|
case "intel_sector_heatmap":
|
|
return await markets.fetch_sector_heatmap(fetcher)
|
|
case "intel_macro_signals":
|
|
return await markets.fetch_macro_signals(fetcher)
|
|
|
|
# Economic
|
|
case "intel_energy_prices":
|
|
return await economic.fetch_energy_prices(fetcher)
|
|
case "intel_fred_series":
|
|
return await economic.fetch_fred_series(
|
|
fetcher,
|
|
series_id=arguments["series_id"],
|
|
limit=arguments.get("limit", 30),
|
|
)
|
|
case "intel_world_bank_indicators":
|
|
return await economic.fetch_world_bank_indicators(
|
|
fetcher,
|
|
country=arguments.get("country", "USA"),
|
|
indicators=arguments.get("indicators"),
|
|
)
|
|
|
|
# Natural
|
|
case "intel_earthquakes":
|
|
return await seismology.fetch_earthquakes(
|
|
fetcher,
|
|
min_magnitude=arguments.get("min_magnitude", 4.5),
|
|
hours=arguments.get("hours", 24),
|
|
limit=arguments.get("limit", 50),
|
|
)
|
|
case "intel_wildfires":
|
|
return await wildfire.fetch_wildfires(fetcher, region=arguments.get("region"))
|
|
|
|
# Conflict
|
|
case "intel_acled_events":
|
|
return await conflict.fetch_acled_events(
|
|
fetcher,
|
|
country=arguments.get("country"),
|
|
days=arguments.get("days", 7),
|
|
limit=arguments.get("limit", 100),
|
|
)
|
|
case "intel_ucdp_events":
|
|
return await conflict.fetch_ucdp_events(
|
|
fetcher,
|
|
days=arguments.get("days", 30),
|
|
limit=arguments.get("limit", 100),
|
|
)
|
|
case "intel_humanitarian_summary":
|
|
return await conflict.fetch_humanitarian_summary(
|
|
fetcher, country=arguments.get("country"),
|
|
)
|
|
|
|
# Military
|
|
case "intel_military_flights":
|
|
return await military.fetch_military_flights(fetcher, bbox=arguments.get("bbox"))
|
|
case "intel_theater_posture":
|
|
return await military.fetch_theater_posture(fetcher)
|
|
case "intel_aircraft_details":
|
|
return await military.fetch_aircraft_details(fetcher, icao24=arguments["icao24"])
|
|
|
|
# Infrastructure
|
|
case "intel_internet_outages":
|
|
return await infrastructure.fetch_internet_outages(fetcher)
|
|
case "intel_cable_health":
|
|
return await infrastructure.fetch_cable_health(fetcher)
|
|
|
|
# Maritime
|
|
case "intel_nav_warnings":
|
|
return await maritime.fetch_nav_warnings(fetcher, navarea=arguments.get("navarea"))
|
|
|
|
# Climate
|
|
case "intel_climate_anomalies":
|
|
return await climate.fetch_climate_anomalies(fetcher, zones=arguments.get("zones"))
|
|
|
|
# Prediction
|
|
case "intel_prediction_markets":
|
|
return await prediction.fetch_prediction_markets(fetcher, limit=arguments.get("limit", 20))
|
|
|
|
# Displacement
|
|
case "intel_displacement_summary":
|
|
return await displacement.fetch_displacement_summary(fetcher, year=arguments.get("year"))
|
|
|
|
# Aviation
|
|
case "intel_airport_delays":
|
|
return await aviation.fetch_airport_delays(fetcher)
|
|
|
|
# Cyber
|
|
case "intel_cyber_threats":
|
|
return await cyber.fetch_cyber_threats(fetcher, limit=arguments.get("limit", 50))
|
|
|
|
# News
|
|
case "intel_news_feed":
|
|
return await news.fetch_news_feed(
|
|
fetcher,
|
|
category=arguments.get("category"),
|
|
limit=arguments.get("limit", 50),
|
|
)
|
|
case "intel_trending_keywords":
|
|
return await news.fetch_trending_keywords(fetcher, min_count=arguments.get("min_count", 3))
|
|
case "intel_gdelt_search":
|
|
return await news.fetch_gdelt_search(
|
|
fetcher,
|
|
query=arguments.get("query", "conflict"),
|
|
mode=arguments.get("mode", "artlist"),
|
|
limit=arguments.get("limit", 50),
|
|
)
|
|
|
|
# Intelligence
|
|
case "intel_country_brief":
|
|
return await intelligence.fetch_country_brief(fetcher, country_code=arguments.get("country_code", "US"))
|
|
case "intel_risk_scores":
|
|
return await intelligence.fetch_risk_scores(fetcher, limit=arguments.get("limit", 20))
|
|
case "intel_instability_index":
|
|
return await intelligence.fetch_instability_index(fetcher, country_code=arguments.get("country_code"))
|
|
case "intel_signal_convergence":
|
|
return await intelligence.fetch_signal_convergence(
|
|
fetcher,
|
|
lat=arguments.get("lat"),
|
|
lon=arguments.get("lon"),
|
|
radius_deg=arguments.get("radius_deg", 5.0),
|
|
)
|
|
|
|
# Reports
|
|
case "intel_daily_brief":
|
|
return await report_gen.generate_daily_brief(output_dir=arguments.get("output_dir"))
|
|
case "intel_country_dossier":
|
|
return await report_gen.generate_country_dossier(
|
|
country_code=arguments["country_code"],
|
|
output_dir=arguments.get("output_dir"),
|
|
)
|
|
case "intel_threat_landscape":
|
|
return await report_gen.generate_threat_landscape(output_dir=arguments.get("output_dir"))
|
|
|
|
# System
|
|
case "intel_status":
|
|
return {
|
|
"circuit_breakers": breaker.status(),
|
|
"cache": cache.stats(),
|
|
"sources": {
|
|
"markets": ["yahoo-finance", "coingecko", "alternative-me", "mempool"],
|
|
"economic": ["eia", "fred", "world-bank"],
|
|
"natural": ["usgs", "nasa-firms"],
|
|
"conflict": ["acled", "ucdp", "hdx"],
|
|
"military": ["opensky", "wingbits"],
|
|
"infrastructure": ["cloudflare-radar", "nga-msi"],
|
|
"maritime": ["nga-msi"],
|
|
"climate": ["open-meteo"],
|
|
"news": ["rss-aggregator", "gdelt"],
|
|
"intelligence": ["ollama", "acled", "world-bank", "hdx", "usgs"],
|
|
"prediction": ["polymarket"],
|
|
"displacement": ["unhcr"],
|
|
"aviation": ["faa"],
|
|
"cyber": ["feodo-tracker", "cisa-kev", "sans-dshield", "urlhaus"],
|
|
},
|
|
}
|
|
|
|
case _:
|
|
return {"error": f"Unknown tool: {name}"}
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# MCP handlers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@server.list_tools()
|
|
async def list_tools() -> list[Tool]:
|
|
return TOOLS
|
|
|
|
|
|
@server.call_tool()
|
|
async def call_tool(name: str, arguments: dict[str, Any] | None) -> list[TextContent]:
|
|
args = arguments or {}
|
|
logger.info("Tool call: %s(%s)", name, json.dumps(args, default=str)[:200])
|
|
result = await _dispatch(name, args)
|
|
return [TextContent(type="text", text=json.dumps(result, indent=2, default=str))]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Entry point
|
|
# ---------------------------------------------------------------------------
|
|
|
|
async def _run() -> None:
|
|
logger.info("World Intelligence MCP Server starting (%d tools)", len(TOOLS))
|
|
async with stdio_server() as (read_stream, write_stream):
|
|
await server.run(read_stream, write_stream, server.create_initialization_options())
|
|
|
|
|
|
def run() -> None:
|
|
asyncio.run(_run())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run()
|