gdelt-mcp-server
Health Warn
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Search and analyze global news coverage and US television transcripts via the GDELT Project's real-time APIs via MCP. STDIO or Streamable HTTP.
@cyanheads/gdelt-mcp-server
Search and analyze global news coverage and US television transcripts via the GDELT Project's real-time APIs via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://gdelt.caseyjhand.com/mcp
Overview
News and television coverage analysis from the GDELT Project's DOC and TV APIs — the last 3 months of global news in 65+ languages, and US TV transcripts from 2009 through October 2024 across 150+ stations. Search articles and clips, track coverage spikes, analyze tone, and trace how a story propagated across languages and countries. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
Tools
| Tool | Description |
|---|---|
gdelt_search_articles |
Search the last 3 months of global news coverage (65+ languages) with full-text and filter operators. Returns up to 250 articles, and hands back the date windows to re-query when that ceiling is hit. |
gdelt_get_coverage_timeline |
Retrieve a time series of coverage volume or average tone for a query. volume_with_articles mode includes top articles per spike timestep, with points to render a timestep's full article list. |
gdelt_get_tone_distribution |
Get a tone histogram (bins ~−30 to +30) showing whether coverage is uniformly negative, bimodal, or clustered near neutral. |
gdelt_get_coverage_breakdown |
Break down coverage volume by source language or source country — a multi-series time series showing geographic propagation. Values are normalized shares of media output, not article counts. |
gdelt_search_tv |
Search US television news closed captions (2009–Oct 2024) and return per-station airtime time series. |
gdelt_get_tv_clips |
Retrieve up to 3,000 matching TV clips with transcript excerpts and Internet Archive viewing links, and the date windows to re-query when that ceiling is hit. |
gdelt_get_tv_context |
Get the most frequent co-occurring words and phrases from TV clips matching a query. |
gdelt_get_tv_trending |
Retrieve trending topics currently dominating US television news (updated every 15 minutes; no query required). |
gdelt_list_tv_stations |
List all TV stations with market, network, and monitoring date ranges to verify station availability before querying. |
Capability reference
gdelt_search_articles tool
- Full GDELT query syntax: phrases, boolean OR, exclusion, filter operators (
sourcecountry:,sourcelang:,domain:,theme:,tone</tone>), proximity (near20:) and repetition (repeat3:) - Configurable sort (
relevance,dateDesc,dateAsc,toneDesc,toneAsc,hybridRel) and result count, up to 250 per call - Returns URL, title, publication date, domain, language, source country, and social image URL
- 250 is a hard per-call ceiling, not a page size — GDELT exposes no cursor. At the ceiling, the response returns
continuationWindows: the queried window halved and overlapping by a second so nothing falls through the seam; de-duplicate byurl
gdelt_get_coverage_timeline tool
- Three modes:
volume(normalized % per timestep),volume_with_articles(volume plus top articles per spike — signal detection in one call),tone(average sentiment per timestep) - Every article reference is always in
structuredContent; the text surface renders the first 3 links per timestep beside that timestep's true count, andpoints: ["<date>"]renders named timesteps in full - Configurable smoothing (0–5 timesteps) and time range (
timespan, or explicitstartDatetime/endDatetime) - Date resolution (
15min/hour/day) is inferred from the returned intervals - A
pointsdate matching no timestep is rejected with the available timestep list, rather than silently ignored
gdelt_get_tone_distribution tool
- Histogram bins from approximately −30 to +30; each bin includes representative article URLs
- Summary fields:
peakNegativeBin,peakPositiveBin,neutralPct(% of articles in the −2 to +2 range) - A snapshot across all matching articles — distinct from the tone timeline (
gdelt_get_coverage_timelinemodetone), which is a time series
gdelt_get_coverage_breakdown tool
- Breaks down by
languageorcountryinto a multi-series time series - Top 10 series by total volume; the rest aggregate into
otherAggregated, with every folded-in label named inotherSeriesLabels - Pass any label to
series: ["<label>"]to retrieve that series complete underselectedSeries, ranked or not - Values are normalized shares of media output, not article counts — a high value means the topic dominated that source's coverage, not that it published the most articles
- A
serieslabel matching no series is rejected with the available label list, rather than silently skipped
gdelt_search_tv tool
- Up to 10 structured
stations(e.g.["CNN", "FOXNEWS"]), or astation:selector embedded in the query — the TV API requires at least one, either way normalizetoggles relative airtime % (default) vs. raw matching 15-second clip counts; optionaldateresaggregation (hour/day/week/month/year)- Responses page at most 500 points per call in deterministic date-then-station order; use
nextOffsetwith the same inputs to retrieve the next page - TV-specific operators:
station:,network:,market:,show:,context: - Verify station active date ranges with
gdelt_list_tv_stationsbefore querying recent events
gdelt_get_tv_clips tool
- Up to 3,000 clips per call, sorted by relevance, date descending, or date ascending
- Each clip: show name, station, air timestamp, 15-second transcript excerpt, direct Archive.org link, and optional thumbnail
- 3,000 is a hard per-call ceiling, not a page size — GDELT exposes no cursor. At the ceiling, the response returns
continuationWindows: the queried window halved and overlapping by a second; de-duplicate byarchiveUrl
gdelt_get_tv_context tool
- Returns the most frequent non-stopword terms co-occurring with the query across matching clips
- Relative frequency scores 0–100, where the query term itself scores 100
- Use to identify narrative framing, related concepts, or follow-up search terms
gdelt_get_tv_trending tool
- No arguments — zero-input entry point for the current TV news cycle
- Returns trending topics, keywords, and phrases across national networks, updated every 15 minutes
- Reflects the frozen October 2024 TV archive, not a live feed
gdelt_list_tv_stations tool
- Returns every station with market, network, monitoring start date, and end date
isActiveis true when the end date is within the last 24 hours- Use to verify a station was active during a target time period, or to discover valid station IDs for the
stationsparameter on other TV tools
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
GDELT-specific:
- Shared outbound pacer across all tools — one request in flight at 1 req/5s, plus a cooldown gate that any GDELT rate-limit response closes for every queued caller (5s, doubling to 60s, reset by the next success)
- Two service layers (
GdeltDocService,GdeltTvService) mapping clean tool parameters to the DOC and TV API URL conventions - TV station filter operators embedded in query strings internally — callers pass structured
stationsarrays, not raw query syntax
Agent-friendly output:
- Query echo on every response — searches return the original query and applied timespan so agents can chain calls without re-deriving parameters
- Discriminated series labels — timeline and breakdown responses carry typed
labelfields ("Volume Intensity","Average Tone", language/country names) rather than positional arrays - Structured station metadata —
isActiveboolean and ISO 8601 date fields let agents reason about TV station availability without parsing date strings - Partial-coverage signals in distribution output —
neutralPct,peakNegativeBin,peakPositiveBinsummary fields let agents branch on sentiment without histogramming the raw bins themselves
Getting started
Public Hosted Instance
A public instance is available at https://gdelt.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"gdelt-mcp-server": {
"type": "streamable-http",
"url": "https://gdelt.caseyjhand.com/mcp"
}
}
}
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"gdelt-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/gdelt-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"gdelt-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/gdelt-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"gdelt-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/gdelt-mcp-server:latest"
]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No API key required — GDELT is a free public API.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/gdelt-mcp-server.git
- Navigate into the directory:
cd gdelt-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env if you need to override defaults
Configuration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
| Variable | Description | Default |
|---|---|---|
GDELT_BASE_URL |
Override the GDELT API base URL for both DOC and TV APIs. | https://api.gdeltproject.org/api/v2 |
GDELT_REQUEST_DELAY_MS |
Minimum milliseconds between GDELT requests (enforces 1 req/5s limit). | 5300 |
MCP_TRANSPORT_TYPE |
Transport: stdio or http. |
stdio |
MCP_HTTP_PORT |
Port for the HTTP server. | 3010 |
MCP_HTTP_ENDPOINT_PATH |
HTTP endpoint path where the MCP server is mounted. | /mcp |
MCP_PUBLIC_URL |
Public origin override for TLS-terminating reverse-proxy deployments. | none |
MCP_AUTH_MODE |
Auth mode: none, jwt, or oauth. |
none |
MCP_SESSION_MODE |
HTTP session mode: auto, stateful, or stateless. createApp() declares stateless in code — this server holds no per-session state — and setting this variable overrides that declaration. |
stateless |
MCP_LOG_LEVEL |
Log level (debug, info, warning, error, etc.). |
info |
MCP_GC_PRESSURE_INTERVAL_MS |
Opt-in Bun-only forced-GC pressure loop in ms. Try 60000 if heap growth is observed under sustained HTTP load. |
0 (disabled) |
LOGS_DIR |
Directory for log files (Node.js only). Absolute paths are used verbatim; a relative path resolves against the application root. | <app-root>/logs |
STORAGE_PROVIDER_TYPE |
Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. |
in-memory |
OTEL_ENABLED |
Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
Running the server
Local development
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security audit bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t gdelt-mcp-server .
docker run --rm -p 3010:3010 gdelt-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/gdelt-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts |
createApp() entry point — registers tools and inits services. |
src/config |
Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools |
Tool definitions (*.tool.ts). Nine tools across DOC and TV APIs. |
src/services/gdelt |
GdeltDocService and GdeltTvService wrapping the DOC and TV APIs, plus the shared outbound pacer every call queues behind. |
tests/ |
Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools via the barrels in
src/mcp-server/tools/definitions/index.ts - Wrap GDELT API calls: validate raw JSON → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found