Skip to main content

MuckRock & DocumentCloud Model Context Protocol (MCP) Server

Python Version MCP Version License

A stateless Model Context Protocol (MCP) server providing structured access to MuckRock Requests and DocumentCloud APIs — eight read-only tools, six resource templates, and dual stdio/HTTP transports (see Features).


Overview: LLMs & Public Records (FOIA/PRA)

MuckRock is an open-government platform that helps journalists, researchers, and anyone seeking to hold public institutions accountable file, track, and share public records requests. DocumentCloud is an open repository and analysis tool for primary source documents released by government agencies.

This Model Context Protocol (MCP) server bridges AI agents (such as Goose, OpenCode, Hermes Agent, Claude Code, Codex, or custom local LLM pipelines) with MuckRock and DocumentCloud data. Rather than requiring models to parse arbitrary web pages, this server provides structured, machine-readable access to:

  • Investigative Discovery: Searching dockets, tracking communication logs between requesters and agencies, and inspecting responsive records.
  • Document Analysis: Searching released document corpuses, fetching clean page-level extracted plain text, and extracting identified entities (people, organizations, locations).
  • Automated Workflows: Resolving agency identifiers, monitoring docket status changes, and auditing statutory response deadlines.

All interactions adhere to the standardized Model Context Protocol, allowing AI hosts to dynamically discover tools, resolve URI resources directly into model context, and autocomplete request parameters.


Architecture Overview

                         ┌──────────────────────────────┐
                         │    LLM Client / MCP Host     │
                         │ (OpenCode, Goose, Codex etc) │
                         └──────────────┬───────────────┘
                                        │
                         ┌──────────────┴───────────────┐
                         │       Transport Layer        │
                         │  StdioServerTransport (CLI)  │
                         │   StreamableHTTPTransport    │
                         └──────────────┬───────────────┘
                                        │
                         ┌──────────────┴───────────────┐
                         │      JSONRPCDispatcher       │
                         │  (MCP 2026-07-28, Discover)  │
                         └──────────────┬───────────────┘
                                        │
         ┌──────────────────────────────┼──────────────────────────────┐
         │                              │                              │
┌────────┴────────┐            ┌────────┴────────┐            ┌────────┴────────┐
│ CatalogManager  │            │ Tools & Registry│            │Resources/Resolve│
│ • Deterministic │            │ • 8 FOIA Tools  │            │ • 6 Templates   │
│   Sorted Lists  │            │ • Structured Out│            │ • RFC 6570 Match│
│ • Cache Direct. │            │ • ResourceLinks │            │ • Autocomplete  │
└─────────────────┘            └────────┬────────┘            └─────────────────┘
                                        │
                               ┌────────┴────────┐
                               │ Upstream Client │
                               │ MuckRockClient  │
                               │ DocumentCloud   │
                               └────────┬────────┘
                                        │
                               ┌────────┴────────┐
                               │   Auth & Rate   │
                               │ TokenStore(JWT) │
                               │ TokenBucket 15/5│
                               │ Jitter Backoff  │
                               └─────────────────┘

Features

  • Ingress Transports:
    • Standard I/O (stdio): Fast, newline-delimited JSON-RPC 2.0 streaming over standard input/output with diagnostic logging strictly isolated to standard error.
    • Streamable HTTP (ASGI 3.0): Stateless POST /mcp command ingress (per-request JSON responses) with a strict 4MB framing safeguard. GET/DELETE on the endpoint return 405 — no server-side sessions.
  • Squarelet OAuth / JWT Authentication: Proactive token refresh when access token TTL drops below 60 seconds (POST https://accounts.muckrock.com/api/token/refresh/). Falls back gracefully to unauthenticated mode for public FOIA browsing when no credentials are configured; explicitly configured credentials that the upstream rejects fail loudly with 401 instead of silently serving public-only results.
  • Dual-Tier Sliding-Window Token Bucket:
    • General Tier: 15 req/min (0.25 tokens/s) with burst capacity up to 100 tokens.
    • Sensitive Tier: 5 req/min (~0.0833 tokens/s) with zero burst capacity (capacity 1) for agency, organization, and user endpoints.
    • Jittered Exponential Backoff: Automatically parses Retry-After (seconds or RFC 7231 / RFC 2822 HTTP-date) upon HTTP 429 and applies full jitter backoff.
  • Deterministic Prompt Cache Optimization: All catalog listings (tools/list, resources/list, resources/templates/list) are lexicographically sorted to maximize LLM prompt cache hit rates, returning ttlMs: 300000 (5 min) and cacheScope: "public".
  • Eight Core Tools (catalog below): Comprehensive FOIA search, request dockets, chronological correspondence threads, agency lookups, DocumentCloud search, full-text extracted plain-text retrieval, and categorized entity extraction. Tool responses embed typed ResourceLink objects connecting returned data to matching RFC 6570 URI templates.
  • Six RFC 6570 Resource Templates (resolvers below): Concrete URI resolvers for requests, threads, agencies, documents, pages, and entities.
  • Argument Autocompletion (details below): Fast MCP autocompletion (completion/complete) for request statuses, jurisdictions, and dynamic agency search.
  • Opt-in Ingress Authentication: Set MCP_API_TOKEN to require Authorization: Bearer <token> on HTTP ingress (unset means open); unauthenticated GET /healthz reports liveness. CORS is loopback-only by default — no wildcard.

Protocol Support Statement (Dual-Era Contract)

Requests without the MCP-Protocol-Version header are served as protocol version 2025-03-26 (legacy headerless clients are tolerated as 2025-03-26 era, spec-permitted, no elevated privilege). server/discover works with zero prior initialize — no handshake or session is required. subscriptions/listen and live list_changed notifications are not supported: the catalog is static with listChanged: false, so poll server/discover instead.

Era-by-Transport Matrix

Era / transport row Status Pinning test
HTTP modern headered (match served) Supported tests/integration/test_http_server.py::TestProtocolVersionHeader::test_match_served_normally
HTTP header/body mismatch → -32020 Supported tests/integration/test_http_server.py::TestProtocolVersionHeader::test_mismatch_yields_32020
HTTP unsupported version → -32022 + supported payload Supported tests/integration/test_http_server.py::TestProtocolVersionHeader::test_unsupported_yields_32022
HTTP legacy headerless initialize tolerated as 2025-03-26 Supported tests/integration/test_http_server.py::TestProtocolVersionHeader::test_legacy_headerless_served
HTTP legacy headerless server/discover tolerated as 2025-03-26 Supported tests/integration/test_http_server.py::TestProtocolVersionHeader::test_legacy_headerless_discover_served
HTTP legacy headerless tools/list tolerated as 2025-03-26 Supported tests/integration/test_http_server.py::TestProtocolVersionHeader::test_legacy_headerless_tools_list_served
HTTP stateless posture (no sessions, 405 on GET/DELETE, forged IDs ignored) Supported tests/integration/test_http_server.py::TestHTTPIntegration::test_full_http_stateless_workflow
Zero-handshake server/discover (no prior initialize) Supported tests/unit/test_protocol.py::TestJSONRPCDispatcher::test_no_handshake_calls_succeed
listChanged: false static catalog Supported tests/unit/test_protocol.py::TestJSONRPCDispatcher::test_no_handshake_calls_succeed
subscriptions/listen → -32601 Method not found Not supported (by design) tests/unit/test_protocol.py::TestJSONRPCDispatcher::test_subscriptions_listen_method_not_found
stdio legacy conversation (initialize → tools/call → resources/read → completion) Supported tests/integration/test_stdio_server.py::TestStdioIntegration::test_full_stdio_conversation
Goose harness Unverified as of 2026-09-08 —
OpenCode harness Unverified as of 2026-09-08 —
Hermes Agent harness Unverified as of 2026-09-08 —
Claude Code harness Unverified as of 2026-09-08 —
Codex harness Unverified as of 2026-09-08 —

Installation

For users

From PyPI

Run the server without touching source code, in an isolated environment:

# From PyPI, using uv (recommended)
uv tool install muckrock-mcp

# From PyPi, using pip
pip install muckrock-mcp

# With pipx
pipx install git+https://github.com/pmocek/muckrock-mcp

From a wheel

A wheel (.whl) is Python's installable package format — handy for air-gapped machines or pinning an exact build. Build one from a checkout, copy the single .whl file anywhere, and install it:

# In the checkout
uv build   # writes dist/muckrock_mcp-*.whl

# On the target machine (uv or pipx)
uv tool install muckrock_mcp-0.1.0-py3-none-any.whl
# or
pipx install muckrock_mcp-0.1.0-py3-none-any.whl

For contributors

Install with dev tools to run the test suite (uv run pytest tests/) or contribute code (formatting via black). The dev extras are pytest, pytest-asyncio, pytest-httpx, and black.

# Standard checkout install
uv sync

# With test and development dependencies
uv sync --extra dev

Without uv:

pip install -e .
pip install -e ".[dev]"

Configuration & Environment Variables

Set environment variables MUCKROCK_USERNAME / MUCKROCK_PASSWORD with valid credentials; without them the server cannot authenticate to MuckRock, and provides very limited utility (mainly to verify operation). For HTTP mode, also set MCP_API_TOKEN to require a bearer token on ingress.

Variable Description Default
MUCKROCK_USERNAME MuckRock / Squarelet account username None (Anonymous mode)
MUCKROCK_PASSWORD MuckRock / Squarelet account password None (Anonymous mode)
MCP_TRANSPORT Server transport mechanism (stdio or http) stdio
MCP_HOST Host interface to bind HTTP transport 127.0.0.1
MCP_PORT / PORT Port number to bind HTTP transport 8000
MCP_API_TOKEN Bearer token required on HTTP ingress (Authorization: Bearer <token>); unset means open None (open)
MCP_DEBUG Enable verbose diagnostic logging (1, true, on) false
MCP_CACHE_TTL_MS Prompt cache TTL hint in milliseconds 300000 (5 minutes)
MCP_CACHE_SCOPE Prompt cache scope hint (public/private) public
MCP_MAX_MESSAGE_SIZE Max ingress JSON-RPC bytes 4194304 (4MB)
MCP_CORS_ORIGINS Comma-separated CORS allowlist; default 127.0.0.1-only (no *) `` (loopback only)

Running the Server

Command-Line Interface (muckrock-mcp)

The server provides a unified CLI with full argument parsing:

# Run over stdio (default)
muckrock-mcp

# Run over Streamable HTTP on custom port
muckrock-mcp --transport http --host 0.0.0.0 --port 8080

# Authenticate via env vars
MUCKROCK_USERNAME="my_user" MUCKROCK_PASSWORD="my_secret" muckrock-mcp

# Enable verbose debug logging
muckrock-mcp --debug

# Show version
muckrock-mcp --version

Health Check

When running over HTTP, liveness (upstream reachability + rate-limiter state) is exposed without authentication:

# GET /healthz -> {"status": "ok", ...}
curl http://127.0.0.1:8000/healthz

Direct Python Invocation

python -m muckrock_mcp.cli --transport stdio

Client Integration

OpenCode

Add to your OpenCode configuration file (opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "muckrock": {
      "type": "local",
      "command": ["muckrock-mcp", "--transport", "stdio"],
      "environment": {
        "MUCKROCK_USERNAME": "your_muckrock_username",
        "MUCKROCK_PASSWORD": "your_muckrock_password"
      }
    }
  }
}

Goose CLI

goose configure
# Select command-line extension and enter:
muckrock-mcp --transport stdio

Or add a stdio command extension directly to ~/.config/goose/config.yaml:

# ~/.config/goose/config.yaml
extensions:
  muckrock:
    enabled: true
    type: stdio
    # stdio command extension: launches muckrock-mcp with stdio transport
    cmd: muckrock-mcp
    args:
      - --transport
      - stdio
    envs:
      MUCKROCK_USERNAME: your_muckrock_username
      MUCKROCK_PASSWORD: your_muckrock_password

Hermes Agent

Add to your Hermes Agent configuration file (~/.hermes/config.yaml):

# ~/.hermes/config.yaml
mcp_servers:
  muckrock:
    command: muckrock-mcp
    args:
      - --transport
      - stdio
    env:
      MUCKROCK_USERNAME: your_muckrock_username
      MUCKROCK_PASSWORD: your_muckrock_password

Claude Code

Add via the Claude Code CLI:

claude mcp add muckrock \
  --env MUCKROCK_USERNAME=your_muckrock_username \
  --env MUCKROCK_PASSWORD=your_muckrock_password \
  -- muckrock-mcp --transport stdio

Or add to your project's .mcp.json:

{
  "mcpServers": {
    "muckrock": {
      "command": "muckrock-mcp",
      "args": ["--transport", "stdio"],
      "env": {
        "MUCKROCK_USERNAME": "your_muckrock_username",
        "MUCKROCK_PASSWORD": "your_muckrock_password"
      }
    }
  }
}

Claude Desktop

Add to your Claude Desktop configuration file (claude_desktop_config.json):

{
  "mcpServers": {
    "muckrock": {
      "command": "muckrock-mcp",
      "args": ["--transport", "stdio"],
      "env": {
        "MUCKROCK_USERNAME": "your_muckrock_username",
        "MUCKROCK_PASSWORD": "your_muckrock_password"
      }
    }
  }
}

Codex

Add to your Codex configuration file (~/.codex/config.toml):

[mcp_servers.muckrock]
command = "muckrock-mcp"
args = ["--transport", "stdio"]

[mcp_servers.muckrock.env]
MUCKROCK_USERNAME = "your_muckrock_username"
MUCKROCK_PASSWORD = "your_muckrock_password"

Tool Catalog

The server exposes eight idempotent, read-only tools:

Tool Name Parameters Description
search_requests query (str, optional), agency (int/str, optional), jurisdiction (int/str, optional), status (str, optional), has_files (bool, optional), page (int, default 1) Search public records requests across MuckRock by keyword, agency, jurisdiction, or status.
get_request_docket request_id (int, required) Retrieve top-level docket data, filing dates, jurisdiction, and status for a FOIA request.
get_request_thread request_id (int, required) Retrieve chronological correspondence, communications, sender directions, and attached files.
search_agencies query (str, optional), jurisdiction (int/str, optional), page (int, default 1) Locate government agencies, unique identifiers, and jurisdictional mappings.
get_agency_profile agency_id (int, required) Retrieve agency details, contact email, portal existence, and historical disposition statistics.
search_documents query (str, required), page (int, default 1), per_page (int, default 10) Query public documents on DocumentCloud matching keywords or queries.
get_document_text document_id (str/int, required), page_number (int, optional), max_chars (int, default 20000) Retrieve full or page-specific extracted plain text from DocumentCloud, capped with truncation hints.
get_document_entities document_id (str/int, required) Retrieve categorized entities (people, organizations, locations) identified in DocumentCloud.

Resource Templates

The server provides six RFC 6570 Resource Templates with URI resolvers:

URI Template MIME Type Resolver Description
muckrock://requests/{request_id} application/json Request metadata, dates, status, and agency info.
muckrock://requests/{request_id}/thread application/json Complete communication thread and correspondence history.
muckrock://agencies/{agency_id} application/json Agency details, contacts, and statistical disposition metrics.
doccloud://documents/{document_id} application/json DocumentCloud document metadata, title, pages, and source.
doccloud://documents/{document_id}/pages/{page_number}/text text/plain Extracted plain text of an individual document page.
doccloud://documents/{document_id}/entities application/json Extracted entities (people, organizations, locations).

Autocompletion (completion/complete)

The server implements dynamic argument autocompletion for:

  • status: Matches against valid MuckRock lifecycle states (submitted, processing, done, rejected, appealed, no_docs, etc.).
  • jurisdiction: Matches against standard Federal, State, and Territorial jurisdictions.
  • agency: Queries MuckRock dynamically and formats results as "{name} (ID: {id})".

Testing & Verification

The test harness provides comprehensive, 100% offline verification across unit, integration, end-to-end tiers, and challenger suites:

# Run the complete test suite
uv run pytest tests/

# Run specific tiers
uv run pytest tests/unit/              # Unit tests (protocol, auth, ratelimit, tools, etc.)
uv run pytest tests/integration/       # Multi-turn transport integration tests
uv run pytest tests/e2e/               # End-to-end multi-tier test suites
uv run pytest tests/e2e/test_tier5_adversarial.py  # Tier 5 Adversarial hardening tests

Test Suite Structure

Tier Focus
Unit Serialization, models, transports, auth TTL, sliding buckets, tools, lifecycle, auth edges
Integration Stdio & Streamable HTTP multi-turn protocol conversations
Tier 1 (Features) Happy-path nominal coverage (>=5 tests per feature F01–F22)
Tier 2 (Boundaries) Edge cases, limits, and boundary error conditions
Tier 3 (Combinations) Pairwise cross-subsystem interactions
Tier 4 (Scenarios) 6 Real-world investigative user journeys
Tier 5 (Adversarial) Malformed payloads, 4MB overflow, session forgery, path escape, egress caps, burst recovery
Challengers Stress, tools/resources cross-checks

Metadata

Release files for muckrock-mcp 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for muckrock-mcp 0.4.3
File Size Uploaded Provenance Actions
muckrock_mcp-0.4.3.tar.gz 621.5 kB With provenance Details for muckrock_mcp-0.4.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for muckrock-mcp 0.4.3
File Interpreter ABI Platform Actions
muckrock_mcp-0.4.3-py3-none-any.whl Python 3 none any Details for muckrock_mcp-0.4.3-py3-none-any.whl

Total release size: 713.0 kB

Release files / muckrock_mcp-0.4.3.tar.gz

Download URL muckrock_mcp-0.4.3.tar.gz
Size 621.5 kB
Tags Source
SHA-256 checksum
How to use checksums
a01d5e2d6838a8882ff34a9e14becc6d5224d218a1c30babea3db8f3e651d33e
BLAKE2b-256 checksum
How to use checksums
551dc0fc861ea431118742b8c665a0b821fd74cf1ca341d89dfdf0f09911c07c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Release files / muckrock_mcp-0.4.3-py3-none-any.whl

Download URL muckrock_mcp-0.4.3-py3-none-any.whl
Size 91.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f30d53ede0e487deeba30f23286f94db30023d32a4083f2697dfdfdbfd133f94
BLAKE2b-256 checksum
How to use checksums
b36ec44ffd6d26972e2064d7b0d6238913b53080c52bc50518df4c83e9959508
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

Security for muckrock-mcp 0.4.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for muckrock_mcp-0.4.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page