Skip to main content
Glama
cyanheads

@cyanheads/gdelt-mcp-server

by cyanheads

Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework

Public Hosted Server: https://gdelt.caseyjhand.com/mcp


Overview

News and TV coverage analysis from the GDELT Project: 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 spread across languages and countries.

Tools

Tool

Description

gdelt_search_articles

Search the last 3 months of global news coverage (65+ languages) with full-text and filter operators. Fetches up to 250 articles, returns as many as fit a 48,000-byte response, and hands back the date windows to re-query for the rest.

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 get named timesteps' full article lists. Pages by offset within a 48,000-byte response.

gdelt_get_tone_distribution

Get a tone histogram (bins ~−30 to +30) showing whether coverage is uniformly negative, bimodal, or clustered near neutral. Pages by offset within a 48,000-byte response.

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. Pages by offset within a 48,000-byte response.

gdelt_search_themes

Find GKG theme identifiers for the theme: operator the DOC tools accept — drought finds NATURAL_DISASTER_DROUGHT, cyberattack finds CYBER_ATTACK — ranked by the count GDELT's theme lookup lists.

gdelt_search_tv

Search US television news closed captions (2009–Oct 2024) and return per-station airtime time series.

gdelt_get_tv_clips

Retrieve matching TV clips with transcript excerpts and Internet Archive viewing links — up to 3,000 fetched, as many as fit a 48,000-byte response returned — and the date windows to re-query for the rest.

gdelt_get_tv_context

Get the most frequent co-occurring words and phrases from GDELT's relevance-ranked sample of TV clips matching a query.

gdelt_list_tv_stations

List TV stations with market, network, and monitoring date ranges — all of them, or filtered by station ID, network, or market — to verify station availability before querying.

Related MCP server: news-monitor-mcp

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:) — gdelt_search_themes finds the identifiers theme: takes

  • Configurable sort (relevance, dateDesc, dateAsc, toneDesc, toneAsc, hybridRel) and fetch count, up to 250 per call — a maxRecords up to 2,500 runs at 250 and reports the clamp in limitClamp; above 2,500 the call is rejected

  • Returns URL, title, publication date, domain, language, source country, and social image URL

  • Responses carry as many articles as fit a 48,000-byte budget; the rest are counted in withheldCount, and continuationWindows gives date windows to re-query for them (de-duplicate by url). 250 is a hard ceiling, not a page size, so narrowing the date window is the only way past it

  • Articles outside an explicit startDatetime/endDatetime window are dropped, and the notice counts them


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)

  • Each timestep carries its first 3 article links beside referenceCount, the true count; points: ["<date>"] returns only the named timesteps, each with every link

  • Responses hold as many whole timesteps as fit a 48,000-byte budget; a cut page returns nextOffset to pass back as offset. Each series' pointCount and peak cover the whole series on every page

  • Configurable smoothing (0–5 timesteps) and time range (timespan, or explicit startDatetime/endDatetime); date resolution (15min/hour/day) is inferred from the returned intervals

  • A points date matching no timestep, or an offset past the last timestep, is rejected with the valid values


gdelt_get_tone_distribution tool

  • Histogram bins from approximately −30 to +30; each bin carries its first 3 article links beside referenceCount, and bins: [<bin>] returns only the named bins, each with every link. A bins value matching no bin is rejected with the available bins

  • Summary fields over the whole histogram: peakNegativeBin, peakPositiveBin, neutralPct (% of articles in the −2 to +2 range)

  • Responses hold as many whole bins as fit a 48,000-byte budget; a cut page returns nextOffset to pass back as offset. A snapshot across all matching articles, unlike the tone timeline (gdelt_get_coverage_timeline mode tone)


gdelt_get_coverage_breakdown tool

  • Breaks down by language or country into a multi-series time series: the top 10 series by summed value, with every other series named in otherSeriesLabels

  • series: ["<label>"] returns only those series, complete, under selectedSeries; a label matching no series is rejected with the available labels

  • Responses hold as many whole series as fit a 48,000-byte budget; a cut page returns nextOffset to pass back as offset

  • Values are normalized shares of each source's media output, not article counts, so don't sum them across sources


gdelt_search_themes tool

  • Searches the identifiers in GDELT's GKG theme lookup (59,315 themes); each match is the identifier, its listed count, and a paste-ready operator such as theme:TAX_DISEASE_OUTBREAK

  • Case-insensitive, with no stemming or synonyms: words match parts of an identifier (cyberattack → CYBER_ATTACK, plant disease → TAX_PLANTDISEASE). If nothing matches, it retries once with a trailing s dropped (protests → PROTEST) and the notice says so

  • Ranked by exact match, then listed count (a static prevalence figure, not a live article total), then identifier

  • Pages with offset / limit (1–100, default 25; a limit up to 1,000 runs at 100 and reports the clamp in limitClamp, and above 1,000 the call is rejected); nextOffset appears only when more matches remain, and an offset past a non-empty result fails offset_out_of_range

  • Does not queue behind the DOC and TV rate limit


gdelt_search_tv tool

  • Up to 10 structured stations (e.g. ["CNN", "FOXNEWS"]), or a station: selector embedded in the query — the TV API requires at least one, either way

  • normalize toggles relative airtime % (default) vs. raw matching 15-second clip counts; optional dateres aggregation (hour/day/week/month/year). TV operators: station:, network:, market:, show:, context:

  • Each series carries station (the ID the stations input takes, FOXNEWS) and stationName (GDELT's label, FOX News). If an ID can't be resolved, the series keeps stationName without station and the notice says so

  • Pages at most 500 points per call in date-then-station-name order; pass nextOffset with the same inputs for the next page. A limit up to 5,000 runs at 500 and reports the clamp in limitClamp; above 5,000 the call is rejected. The text surface's per-station count, sum, and peak cover only the returned page

  • Check station date ranges with gdelt_list_tv_stations before querying recent events


gdelt_get_tv_clips tool

  • Up to 3,000 clips fetched per call, sorted by relevance, date descending, or date ascending — a maxRecords up to 30,000 runs at 3,000 and reports the clamp in limitClamp; above 30,000 the call is rejected

  • Each clip: show name, station and stationName (resolved as in gdelt_search_tv, so a series' station passes straight into stations), air timestamp, 15-second transcript excerpt, direct Archive.org link, and optional thumbnail

  • The server requests whole clock hours, so any window width works; clips outside an explicit startDatetime/endDatetime window are dropped and counted in the notice (a timespan call drops nothing)

  • Responses carry as many clips as fit a 48,000-byte budget; the rest are counted in withheldCount, and continuationWindows gives date windows to re-query for them (de-duplicate by archiveUrl). 3,000 is a hard ceiling, not a page size, so narrowing the date window is the only way past it


gdelt_get_tv_context tool

  • Returns the most frequent non-stopword terms co-occurring with the query

  • Terms and scores come from GDELT's sample of the 200 most relevant matching clips, not all coverage; every non-empty response says so in notice. Compare windows or stations with a separate, narrower call for each

  • Relative frequency scores 0–100, where the query term itself scores 100


gdelt_list_tv_stations tool

  • Returns every station with market, network, monitoring start date, and end date — or only those matching the optional stations, network, and market filters

  • Filters match whole values case-insensitively and combine with AND (network: "FOX" does not match FOXNEWS); activeCount and totalCount count the returned stations

  • A filter or station ID that matches nothing is named in the notice; isActive is true when the end date is within the last 24 hours

  • Use to verify a station was active during a target period, or to find valid station IDs for the stations parameter 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 request pacer across the DOC and TV tools: one request in flight at 1 req/5s, with a backoff (5s, doubling to 60s) after any rate-limit response

  • Structured stations arrays instead of raw TV query syntax

  • GKG theme lookup held in memory after first download

Agent-friendly output:

  • Query echo on every response: the original query and applied timespan, so calls chain without re-deriving parameters

  • Typed series label fields ("Volume Intensity", "Average Tone", language/country names) instead of positional arrays

  • Station metadata with an isActive boolean and ISO 8601 dates

  • Zero matches return the normal output shape with empty arrays and a notice on how to broaden the query

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

  1. Clone the repository:

git clone https://github.com/cyanheads/gdelt-mcp-server.git
  1. Navigate into the directory:

cd gdelt-mcp-server
  1. Install dependencies:

bun install
  1. 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

GDELT_REQUEST_TIMEOUT_MS

Deadline for a single GDELT request (a call with retries is bounded at twice this).

60000

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.

stateless

MCP_LOG_LEVEL

Log level (debug, info, warning, error, etc.).

info

MCP_GC_PRESSURE_INTERVAL_MS

Opt-in Bun-only forced-GC loop interval in ms.

0 (disabled)

LOGS_DIR

Directory for log files (Node.js only).

<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:http
  • Run 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 the DOC and TV APIs and the GKG theme lookup.

src/services/gdelt

GdeltDocService and GdeltTvService wrapping the DOC and TV APIs, the shared outbound pacer every DOC and TV call queues behind, and GdeltThemeService for the GKG theme lookup.

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/catch in tool logic

  • Use ctx.log for request-scoped logging, ctx.state for 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.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    F
    maintenance
    MCP server providing access to the GNews API for fetching news articles and headlines. Supports search and top headlines with advanced filtering by language, country, category, and date.
    1
    -
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for global news monitoring, media analysis and sentiment tracking via WorldNewsAPI — full-text search across 150+ countries, German/English sentiment analysis, top headlines, GL briefings, newspaper front pages and geo-search. API key required.
    15
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables macro/geopolitical event detection by wrapping the GDELT 2.0 API, providing tools for searching events, trending actors, and sentiment timeseries from global news.
    1
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A remote, read-only MCP server for global media intelligence using GDELT DOC 2.0 API, enabling search and analysis of multilingual news coverage, tone, and attention trends.
    33 npm
    MIT