@cyanheads/guardian-mcp-server
v0.1.4
Published
Search, browse, and retrieve full article text from The Guardian's journalism archive (1999–present) via MCP. STDIO or Streamable HTTP.
Downloads
223
Maintainers
Readme
Overview
The Guardian's journalism archive (1999–present), via the Guardian Open Platform API. Search full text, browse by section or tag, and fetch complete untruncated articles from any MCP client. Runs as a stdio process or a local Streamable HTTP server.
Tools
| Tool | Description |
|:-----|:------------|
| guardian_search | Full-text search across The Guardian's archive with optional section, tag, contributor, and date filters |
| guardian_get_article | Fetch a single Guardian article by ID with full untruncated body text and metadata |
| guardian_browse | Browse by section or tag, or discover available sections and tags, across four modes |
Capability reference
guardian_search tool
- Boolean query syntax (
AND/OR/NOT, quoted phrases) plus optionalsection,tag,contributor, andfrom_date/to_date(YYYY-MM-DD) filters - Sort via
order_by:relevance(default),newest, oroldest; paginated withpage+page_size(1–50, default 10) - Body text is HTML-stripped and truncated at 2,000 words with a
truncatedflag — fetch the complete text viaguardian_get_article - Typed error reasons:
unauthorized,no_results,invalid_date,api_error(retryable) - Zero-result responses carry an enrichment notice echoing the query
guardian_get_article tool
- Input:
article_id— the path-slugidfield returned byguardian_searchorguardian_browse - Returns complete untruncated body text (HTML stripped), full metadata, contributor list, and pillar/section classification
truncated: truemeans the body still exceeded 2,000 words after the full fetch- Typed error reasons:
unauthorized,not_found,api_error(retryable)
guardian_browse tool
- Four modes via
mode:section_latest(requiressection_id),tag_latest(requirestag_id),list_sections,list_tags list_tagstakes optionalqueryandtag_type(keyword,contributor,blog,series,tone,type,publication,newspaper-book,newspaper-book-section) — usetag_type=contributorto discover contributor IDs- Pagination via
page+page_size(1–50, default 10) applies to every mode - Typed error reasons:
unauthorized,missing_section_id,missing_tag_id,section_not_found,tag_not_found,api_error(retryable)
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.
Guardian-specific:
- Wraps the Guardian Open Platform API with a free non-commercial developer key
- Full body text extraction — HTML stripped, not just headlines or abstracts
- Contributor ID discovery via
guardian_browsemodelist_tagswithtag_type=contributor - Section and tag taxonomy browsing (
list_sections,list_tags) for filter discovery before searching - Free tier: 5,000 requests/day, 12 calls/second — the server applies no additional throttling
Agent-friendly output:
- Truncation flags on every article response — signal to call
guardian_get_articlefor the rest - Typed error reasons across all three tools, each paired with a recovery hint
total/page/pageson every paginated response so callers can track result scope- Zero-result enrichment notice on
guardian_searchechoing the query and suggesting how to broaden
Getting started
Add the following to your MCP client configuration file. Register for a free Guardian Open Platform API key at open-platform.theguardian.com/access.
{
"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/mcpPrerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- A free Guardian Open Platform API key — register at open-platform.theguardian.com/access. The non-commercial developer tier is free and instant.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/guardian-mcp-server.git- Navigate into the directory:
cd guardian-mcp-server- Install dependencies:
bun install- Configure environment:
cp .env.example .env
# Edit .env and set GUARDIAN_API_KEYConfiguration
| 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_SESSION_MODE | HTTP session mode: stateless, stateful, or auto (resolves to stateful). The server declares stateless; an exported value overrides it. | stateless |
| 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:httpRun 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-serverThe 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/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools in the
createApp()toolsarray insrc/index.ts - Wrap external API calls: validate raw → 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 testLicense
Apache-2.0 — see LICENSE for details.
Powered by The Guardian.
