ecfr-cartography-mcp

ecfr-cartography-mcp

An MCP server that turns the US Code of Federal Regulations into an agent-navigable citation graph, enabling traversal of regulatory references and detection of stale citations via structured tools.

Category
Visit Server

README

ecfr-cartography-mcp

An MCP server that turns the US Code of Federal Regulations into an agent-navigable citation graph — so agents can traverse the regulatory graph instead of skimming PDFs. Point Claude at 45 CFR part 170 and ask "which section is the hub? which citations are stale?"; you get structured, edge-by-edge answers grounded in the live eCFR API instead of best-effort text search.

Under the hood: a small pure-Python citation extractor (regex + reference graph), a FastMCP server that wires six tools over stdio, and a D3 visualizer for the README hero. All three share the same graph code so the picture can't drift from what the model sees.

45 CFR part 170 as a citation graph

45 CFR part 170 rendered by python visualize.py 45 170. Node size scales with in-degree; the blue cluster centers on the twin hubs § 170.315 and § 170.299; orphans (definitions, one-off subparts) sit orange on the periphery; and the red dashed ghost is § 170.503 — a citation target § 170.599 still points at, even though § 170.503 was removed in the 2020 ONC final rule.


Tools

Tool What it does When to reach for it
search_regulations(query, per_page) Full-text search across all 50 CFR titles. Discover which title/part governs a topic.
get_part_structure(title, part) Ordered list of every section + its heading. Get a table of contents cheaply.
get_section_text(title, part, section, date?) Full section text + every citation extracted from it. Read one section and see where it points.
map_part_references(title, part) Flagship. Builds the intra-part citation graph — nodes, edges, top-10 hubs, orphans, external refs, statutory authorities. Ask "which section anchors this part?" or "what other parts does this part depend on?"
find_stale_references(title, part) Same-part citations whose target section doesn't exist in the fetched part. Surface likely-broken cross-references for a compliance-review workflow.
get_section_history(title, part, section) Every amendment version recorded for a section. Point-in-time questions ("what did this look like before 2020?").

Every tool returns a JSON string. Errors come back as {"error": "..."} rather than exceptions, so an LLM caller never sees a raw traceback.


Install

Requires Python 3.11+.

git clone https://github.com/apraba05/ecfr-cartography-mcp
cd ecfr-cartography-mcp
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

Run the offline test suite:

pytest -q               # 18 tests, all pure — no network
pytest -m integration -q  # 5 tests, hits the live eCFR API

Confirm the server registers all six tools:

python server.py --list
# search_regulations
# get_section_text
# get_part_structure
# map_part_references
# find_stale_references
# get_section_history

Wire it up to Claude Desktop / Claude Code

Add this to your MCP client's config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, or .claude/mcp.json for Claude Code):

{
  "mcpServers": {
    "ecfr-cartography": {
      "command": "python",
      "args": ["/absolute/path/to/ecfr-cartography-mcp/server.py"]
    }
  }
}

Restart the client. The six tools show up under the ecfr-cartography server.


Three-minute demo (45 CFR part 170 — ONC health-IT certification)

Copy-paste these into a Claude conversation with the server connected. The narrative shows an agent walking the graph rather than word-searching PDFs.

1. Discover the part with search.

Tool: search_regulations Args: query="electronic health records certification API", per_page=5

Every result surfaces its title + part. Expect 45 CFR 170 (ONC Health IT Certification) at the top for this query.

2. Map the entire part in one call.

Tool: map_part_references Args: title="45", part="170"

Returns ~51 sections and ~63 intra-part edges. The top_referenced list identifies § 170.315 (Certification criteria) and § 170.299 (Incorporation by reference) as the twin hubs — each with in-degree 9. Roughly a third of the sections are orphans (definitions, purpose statements, one-off subparts).

3. Ask the model to spot broken cross-references.

Tool: find_stale_references Args: title="45", part="170"

Returns one candidate: § 170.599 → § 170.503. Section 170.599 ("Incorporation by reference") says "IBR approved for § 170.503" — but 170.503 isn't in the current part.

4. Prove it with the versioner (the point-in-time story).

Tool: get_section_history Args: title="45", part="170", section="170.503"

Response: three versions, the last one on 2020-06-30 with "removed": true. The ISO/IEC standard incorporated by reference in § 170.599 is anchored to a section that was retired six years ago. That's a real regulatory-graph defect surfaced without a human reading the whole part.

5. Optional flourish — recover the removed text.

Tool: get_section_text Args: title="45", part="170", section="170.503", date="2020-05-01"

Fetches the part as it stood before the removal so the model can quote the old language back to you.


Honest limitations

  • Recall isn't perfect. Citation extraction is regex-based. It handles the common forms exhaustively — § 170.404, §§ 170.401 through 170.404, 45 CFR 164.512, 42 CFR part 2, part 171 of this title, 42 U.S.C. 300jj-11, 42 U.S.C. §§ 1301 et seq. — but obscure phrasings ("the regulation at Title 45, Section 170.315") will slip through. A statistical extractor would push recall higher at the cost of the "reproducible, offline unit-testable" property that made regex the right call for a portfolio piece.
  • find_stale_references returns candidates, not conclusions. A dangling target may be a reserved section, an intentional cross-title cite, or a paragraph-level reference the extractor misread. The tool response says so explicitly. Always verify against the source before acting.
  • Large parts pull a lot of XML. 40 CFR part 60 is ~13 MB of XML and yields 1,800+ sections and 5,600+ edges. map_part_references handles it, but the D3 visualizer starts to strain — the tool is happier on chunks the size of 45 CFR 170.
  • In-memory caching only. The httpx client caches within one server process. There's no on-disk cache; a restart re-fetches.
  • Titles-list resolution is authoritative for dates. The versioner is point-in-time. If you don't pass a date, we use the title's up_to_date_as_of — which may lag reality by a business day or two.

Next steps

  • Statute → regulation authorization graph. The statutory_refs field already collects USC citations. Cross-link them against uscode.house.gov to build the "which statute authorizes this rule?" graph — the reverse of what agencies publish.
  • State administrative codes. Same shape, different sources — Cornell's LII and per-state SoS APIs. A search_state_regulations tool + a map_state_part_references tool would drop straight in beside these six.
  • Diff two point-in-time snapshots. get_section_history already exposes version dates; a diff_section(section, date_a, date_b) tool would surface what changed between rulemakings.
  • Federal Register cross-linking. Each amendment date maps back to a Federal Register notice; adding a get_amendment_notice tool would connect the graph to the rulemaking record.

Files

server.py       FastMCP server — six tools over stdio
citations.py    Pure citation extractor + ReferenceGraph (no HTTP)
visualize.py    CLI: python visualize.py 45 170 → graph.html
tests/
  test_citations.py     18 offline tests
  test_integration.py    5 live-API smoke tests

MIT licensed. Contributions welcome.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured