docs/mcp-quickstart.mdx
WorldMonitor exposes 63 live tools — markets, conflict events, maritime chokepoints, aviation, climate, AI briefs, and China decision signals — over the Model Context Protocol. This page is the shortest path from zero to a useful response inside Claude. Everything else in the MCP Server reference is optional reading once this works.
Free accounts can't reach the MCP server — the OAuth flow returns 403 INSUFFICIENT_TIER. You need one of:
wm_… key in your client, or use the same OAuth flow as Pro. wm_… MCP calls are throttled at 60 requests/minute/key in this handler; REST/API plan allowances are separate from the Pro/OAuth MCP daily counter.Upgrade or generate a key at worldmonitor.app/pro. The rest of this guide assumes Claude Desktop + OAuth (the simplest path); if you'd rather paste a wm_… key into a curl script, jump to Server-side curl at the bottom.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the Windows equivalent at %APPDATA%\Claude\claude_desktop_config.json and add the worldmonitor entry:
{
"mcpServers": {
"worldmonitor": {
"url": "https://worldmonitor.app/mcp"
}
}
}
Restart Claude Desktop. The first time you mention WorldMonitor in a chat, Claude pops the OAuth consent screen — click Sign in with WorldMonitor Pro, authenticate in your browser, and the token is stored locally by Claude. No API key ever touches your filesystem.
<Tip> Cursor, Claude web, and MCP Inspector use the same URL. See [client setup](/mcp-overview#client-setup) for the exact config field per client. </Tip>mcp-remote bridgeOlder Claude Desktop builds — and any stdio-only MCP client — connect through the mcp-remote bridge instead of the native url field:
{
"mcpServers": {
"worldmonitor": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://worldmonitor.app/mcp", "--header", "X-WorldMonitor-Key:wm_YOUR_KEY"]
}
}
}
Two things matter with this setup:
mcp-remote never sees a 401 challenge at connect time and does not start its OAuth flow on its own. Without the header, the connection looks healthy but every tools/call fails with 401. Use the single-argument form X-WorldMonitor-Key:wm_… with no space after the colon — it sidesteps client/npx argument-escaping bugs with spaces inside args (documented by mcp-remote for Cursor and Claude Desktop on Windows).--header: your first tool call returns the 401 challenge that triggers mcp-remote's browser consent flow (dynamic client registration works on both worldmonitor.app and www.worldmonitor.app). Older mcp-remote versions handle this mid-session flow less reliably than the connect-time one, so if the consent window never appears, the explicit key header above is the deterministic path.Open a new chat in Claude Desktop and try:
What's the current US equity market sentiment and which sectors are leading or lagging today?
Claude will pick get_market_data from the WorldMonitor toolset, call it with no arguments, and answer in plain English. The raw tool response is a single bootstrap bundle covering quotes, sector ETFs, crypto, gulf quotes, ETF flows, and the WorldMonitor fear-greed composite. Because cache tools default-cap list/map fields at 30 items when limit is omitted, this first response is intentionally compact; pass limit: 0 only when you genuinely need the full 200+ quote / ~100 KB market bundle. Typical latency: 300–800 ms (cache read from Redis, no upstream API call).
Behind the scenes, the tool call looks like this:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "get_market_data", "arguments": {} }
}
And the response is a standard MCP content block — a single text block whose text field is the JSON payload:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{ "type": "text", "text": "{\"cached_at\":\"2026-05-17T10:34:00.852Z\",\"stale\":false,\"data\":{\"stocks-bootstrap\":{...},\"sectors\":{...},\"fear-greed\":{...}}}" }
],
"isError": false
}
}
Two payload-level fields you'll see on every cache tool:
cached_at — ISO timestamp of the oldest contributing data point. Use this to reason about how fresh the answer is.stale — true when any contributing seed exceeded its freshness budget. Tells the model when to caveat its answer.Broad cache calls can still be large even with their default list caps. That's fine for one call, but if you're chaining several reads inside a longer conversation, you'll burn context fast. Every tool accepts an optional jmespath argument that projects the response server-side before it crosses the wire:
{
"name": "get_market_data",
"arguments": {
"jmespath": "data.\"stocks-bootstrap\".quotes[?symbol=='AAPL' || symbol=='MSFT'].{s:symbol,p:price,chg:change}"
}
}
Same call, ~120 bytes of response instead of the broader default-capped market bundle. JMESPath cuts payload by 80–95% for typical projections. If you disable the default cap with limit: 0, projection becomes even more important because get_market_data can return the full 200+ quote / ~100 KB bundle.
Don't try to memorise the grammar from scratch — head to the JMESPath guide for the 12 worked examples covering filters, projections, multiselect-hash, and the rest of the slices you'll actually use.
get_market_data is one of 63 tools. The rest cover:
get_conflict_events, get_country_risk, get_military_posture, get_cyber_threats, get_sanctions_data, get_news_intelligence.get_chokepoint_status, get_maritime_activity, get_airspace, get_aviation_status, search_flights.get_energy_intelligence, get_economic_data, get_country_macro, get_tariff_trends, get_eu_housing_cycle, get_eu_quarterly_gov_debt, get_eu_industrial_production.get_climate_data, get_natural_disasters, get_radiation_data, get_health_signals.get_world_brief (citation-grounded dashboard snapshot; refreshed by the insights seeder).get_country_brief, analyze_situation, generate_forecasts.Full per-tool parameters, freshness budgets, and curl examples are in the MCP Tools Reference. When the compressed tools/list description is ambiguous about a specific tool, call describe_tool with tool_name: "<name>" for the full uncompressed definition — it's exempt from the Pro daily quota, so use it freely while exploring.
If an endpoint appears in the REST OpenAPI docs but does not appear as an MCP tool, that is usually intentional. MCP exposes curated agent-safe tools, not every REST operation. Some REST routes are excluded because they mutate state, invoke per-call LLM work, fetch paid or high-cardinality upstream data on cache miss, or need manual cache-key mapping.
To discover what MCP can call from your client:
tools/list for the current tool names and compressed descriptions.describe_tool with tool_name when a tools/list entry is too short to choose confidently._apiPaths mapping exists.The MCP handshake is invisible from the chat side, but here's the sequence so you know where to look if something breaks:
claude_desktop_config.json, sees the WorldMonitor server, and on first use POSTs initialize to https://worldmonitor.app/mcp. The server responds with its capabilities, the negotiated protocol version (default 2025-06-18, matching the static server card; clients pinned to 2025-03-26 still get 2025-03-26), and a session-level instructions string that tells the model about the universal jmespath argument. Clients that advertise text/event-stream may receive this response as SSE with a resumable Mcp-Session-Id / Last-Event-ID cursor; clients that do not advertise SSE receive JSON. See protocol negotiation and Streamable HTTP responses for the rollout details.tools/list and receives 63 compressed tool descriptions (≤120 bytes per tool). The compressed form keeps tools/list cheap; describe_tool returns the full definition on demand.tools/call, and inlines the response into its reply. Cache-backed tools, including get_world_brief, return the accepted snapshot without a request-time LLM call; live LLM tools (analyze_situation, etc.) take 1–4 s.If you'd rather skip the OAuth dance and drive MCP from a script:
export WM_KEY="wm_0123456789abcdef0123456789abcdef01234567" # API Starter+ key from worldmonitor.app/settings
# 1. List tools (compressed descriptions)
curl -s https://worldmonitor.app/mcp \
-H "X-WorldMonitor-Key: $WM_KEY" \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# 2. Call a cache tool
curl -s https://worldmonitor.app/mcp \
-H "X-WorldMonitor-Key: $WM_KEY" \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0","id":2,
"method":"tools/call",
"params":{"name":"get_market_data","arguments":{}}
}'
# 3. Same call with a JMESPath projection (much smaller response).
# Heredoc keeps the single-quoted JMESPath string literals readable —
# wrapping the JSON in -d '...' would collide with the inner quotes.
curl -s https://worldmonitor.app/mcp \
-H "X-WorldMonitor-Key: $WM_KEY" \
-H 'Content-Type: application/json' \
--data-binary @- <<'EOF'
{
"jsonrpc":"2.0","id":3,
"method":"tools/call",
"params":{
"name":"get_market_data",
"arguments":{
"jmespath":"data.\"stocks-bootstrap\".quotes[?symbol=='AAPL' || symbol=='MSFT'].{s:symbol,p:price}"
}
}
}
EOF
The wm_… user API key goes in X-WorldMonitor-Key, not as a Bearer token — sending it as a bearer fails OAuth resolution and returns 401 invalid_token. If you already have an OAuth access token from /api/oauth/token, use Authorization: Bearer $TOKEN instead and drop the X-WorldMonitor-Key header.
curl examples for every tool.npx worldmonitor tools drives the same tools from your terminal or a script, no integration to write.pip install worldmonitor-sdk), Ruby (gem install worldmonitor), and Go (go get github.com/koala73/worldmonitor/sdk/go) call the same tools with language-native helpers.X-WorldMonitor-Key vs. OAuth vs. browser session.Every tools/call emits a structured telemetry line tagged mcp.toolcall with latency, payload bytes (pre and post JMESPath), jmespath_used, and budget_exceeded. initialize emits mcp.tools_list_emitted with tool-count and tools-list byte metrics. Pipe Vercel / log-drain consumers at these lines if you want real P95 and payload-size tracking. Caller-facing behaviour is unaffected.