Version License Docker MCP SDK npm TypeScript Bun

Install in Claude Desktop Install in Cursor Install in VS Code

Framework


Prerequisites

A free Guardian Open Platform API key is required. Register at https://open-platform.theguardian.com/access — the non-commercial developer tier is free. Set it as GUARDIAN_API_KEY in your MCP client config or .env file. The server will not start without it.

Rate limits (free tier): 5,000 requests/day, 12 calls/second. The server applies no additional throttling — stay within these bounds.


Tools

Three tools for working with The Guardian's journalism archive:

Tool Description
guardian_search Full-text search across The Guardian's archive (1999–present) with optional section, tag, contributor, and date filters. Returns articles with full body text (HTML stripped, truncated at 2,000 words).
guardian_get_article Fetch a single Guardian article by its ID (path slug) with full body text and all metadata. Use after guardian_search to retrieve the complete untruncated text.
guardian_browse Browse The Guardian's content by section or tag, or discover available sections and tags. Four modes: section_latest, tag_latest, list_sections, list_tags.

guardian_search

Full-text search with structured filters across the entire Guardian archive.

  • Supports AND, OR, NOT boolean operators and exact phrases in double quotes
  • Filters: section ID, tag ID, contributor profile ID, date range (from_date, to_date)
  • Returns body text (HTML stripped) truncated at 2,000 words with a truncation flag — use guardian_get_article for complete text
  • Sort by relevance (default), newest, or oldest
  • Pagination via page + page_size (1–50 per page)

guardian_get_article

Fetch one article by its Guardian path-slug ID.

  • Input: article_id from guardian_search results — the id field, e.g. "world/2024/mar/01/ukraine-war-latest"
  • Returns complete untruncated body text (HTML stripped), full metadata, contributor list, and pillar/section classification
  • truncated: true in the response means the body still exceeded 2,000 words after fetching

guardian_browse

Browse and discover Guardian content — four modes in one tool.

  • section_latest: newest articles from a section (requires section_id)
  • tag_latest: newest articles carrying a tag (requires tag_id)
  • list_sections: returns all Guardian sections as a flat list — use to discover valid section_id values
  • list_tags: searches the tag taxonomy with optional query and tag_type filter — use to discover contributor IDs (tag_type=contributor), keyword tags, series, and more
  • Pagination applies to all modes

Features

Built on @cyanheads/mcp-ts-core:

  • Declarative tool definitions — single file per tool, framework handles registration and validation
  • Unified error handling — handlers throw, framework catches, classifies, and formats
  • Pluggable auth: none, jwt, oauth
  • Swappable storage backends: in-memory, filesystem, Supabase, Cloudflare KV/R2/D1
  • Structured logging with optional OpenTelemetry tracing
  • STDIO and Streamable HTTP transports

Guardian-specific:

  • Wraps the Guardian Open Platform API with a free developer key
  • Full body text extraction — HTML stripped, not just headlines or abstracts
  • Contributor ID discovery via guardian_browse mode list_tags + tag_type=contributor
  • Section and tag taxonomy browsing for filter discovery before searching
  • Powered by The Guardian

Agent-friendly output:

  • Truncation flags on every article — agents know whether to call guardian_get_article for the rest
  • Typed error reasons (unauthorized, no_results, not_found, invalid_date, api_error) with recovery hints for each case
  • total, page, and pages on all paginated responses so agents can communicate result scope
  • Zero-result enrichment notice on guardian_search — echoes the query and suggests how to broaden

Getting started

A GUARDIAN_API_KEY is required. Register for the free non-commercial developer key at https://open-platform.theguardian.com/access.

Add the following to your MCP client configuration file:

{
  "mcpServers": {
    "guardian-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/guardian-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "GUARDIAN_API_KEY": "your-api-key"
      }
    }
  }
}

Or with npx (no Bun required):

{
  "mcpServers": {
    "guardian-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/guardian-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info",
        "GUARDIAN_API_KEY": "your-api-key"
      }
    }
  }
}

Or with Docker:

{
  "mcpServers": {
    "guardian-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "-e", "GUARDIAN_API_KEY=your-api-key",
        "ghcr.io/cyanheads/guardian-mcp-server:latest"
      ]
    }
  }
}

For Streamable HTTP, set the transport and start the server:

MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 GUARDIAN_API_KEY=your-api-key bun run start:http
# Server listens at http://localhost:3010/mcp

Prerequisites

Installation

  1. Clone the repository:
git clone https://github.com/cyanheads/guardian-mcp-server.git
  1. Navigate into the directory:
cd guardian-mcp-server
  1. Install dependencies:
bun install
  1. Configure environment:
cp .env.example .env
# Edit .env and set GUARDIAN_API_KEY

Configuration

Variable Description Default
GUARDIAN_API_KEY Required. Free developer key from open-platform.theguardian.com/access.
MCP_TRANSPORT_TYPE Transport: stdio or http. stdio
MCP_HTTP_PORT Port for HTTP server. 3010
MCP_AUTH_MODE Auth mode: none, jwt, or oauth. none
MCP_LOG_LEVEL Log level (RFC 5424). info
LOGS_DIR Directory for log files (Node.js only). <project-root>/logs
STORAGE_PROVIDER_TYPE Storage backend. in-memory
OTEL_ENABLED Enable OpenTelemetry instrumentation (spans, metrics, completion logs). 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
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
    

Docker

docker build -t guardian-mcp-server .
docker run --rm -e GUARDIAN_API_KEY=your-api-key -p 3010:3010 guardian-mcp-server

The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/guardian-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 initializes the Guardian service.
src/config Server-specific environment variable parsing (GUARDIAN_API_KEY).
src/mcp-server/tools Tool definitions (*.tool.ts): guardian_search, guardian_get_article, guardian_browse.
src/services/guardian Guardian Open Platform API client, normalization, and type definitions.
tests/ Unit and integration tests.
docs/ Design document and directory tree.

Development guide

See CLAUDE.md / AGENTS.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 barrel in src/mcp-server/tools/definitions/index.ts
  • Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields

Contributing

Issues and pull requests are welcome. Run checks and tests before submitting:

bun run devcheck
bun run test

License

Apache-2.0 — see LICENSE for details.


Powered by The Guardian.