Agent-first command-line tool for the National Archives Catalog API v2, with a shared Python API and optional MCP server.
The CLI is designed for research agents and humans who need scan-friendly search results, structured JSON, direct digital-object workflows, and preservation-safe source packets without hand-inspecting nested API responses.
This project is read-only against NARA and is not affiliated with the National Archives and Records Administration.
Keywords: NARA, National Archives, archival research, historical research, genealogy, digital humanities, research agents, AI agents, Model Context Protocol, MCP, Python CLI.
- Compact terminal output by default; JSON when agents need structured data.
- One shared service layer for CLI, Python API, and MCP tools.
- Explicit safeguards for downloads, filesystem writes, and API-key handling.
- Source-packet and negative-search helpers for auditable research workflows.
- Offline-first tests so behavior is not coupled to live NARA responses.
NARA Catalog records can support many historical and genealogical research workflows, including:
- finding historical passport applications and travel records;
- locating military service, pension, draft, and veterans' records;
- researching immigration, naturalization, and border-crossing records;
- finding federal court, land, census, and agency records;
- tracing record groups, series, file units, and archival hierarchy around a known NAID;
- listing and downloading available digital object images for source review;
- preserving catalog metadata, source URLs, hashes, and negative searches for later citation.
git clone https://github.com/chrishart0/nara-catalog-api.git
cd nara-catalog-api
python -m pip install -e '.[test]'For the optional MCP server:
python -m pip install -e '.[mcp]'Get a NARA Catalog API key by emailing Catalog_API@nara.gov. A short request
is usually enough; see the API key request template.
In project use, NARA has typically responded within about one business day. Keys are normally issued with a default limit of 10,000 API calls per month.
After you receive a key, use one of:
export NARA_API_KEY=your-key
# or, from the directory where you run commands:
printf 'NARA_API_KEY=your-key\n' > .env
# or:
nara-api --secret-file /path/to/nara.env check-key --liveCredential lookup order is environment, --secret-file, current working
directory .env, then ~/.hermes/secrets/nara.env. The tool never prints the
key.
# Readable compact search results
nara-api search --query '"SEARCH TERMS"' --online
# Normalized JSON for agents
nara-api search --query '"SEARCH TERMS"' --online --json
# Count-only scoping, optionally with a negative-search draft
nara-api search --query '"SEARCH TERMS"' --online --count
nara-api search --query '"SEARCH TERMS"' --online --count --negative-search-draft
# Fetch a record and create a preservation draft
nara-api record --naid NAID
nara-api record --naid NAID --save /tmp/nara-NAID.json
nara-api source-packet --naid NAID --source-id S001 --archive-root /path/to/archive-root
# List or download digital objects
nara-api images --naid NAID
nara-api images --naid NAID --status-dir /tmp/nara-NAID
nara-api images --naid NAID --download-dir /tmp/nara-NAID --range 1-5
# Browse hierarchy and related records
nara-api browse --naid NAID --siblings
nara-api related --naid NAID --mode same-seriesUse --json for normalized JSON and --full for raw NARA API JSON. Run
nara-api COMMAND --help for command-specific options.
Saved JSON from search, record, images, browse, related,
source-packet, and negative-search can be re-read with summarize-file.
searchdefaults to compact terminal output.recordalso defaults to compact terminal output; use--jsonfor normalized JSON or--fullfor raw NARA API JSON.images --status-dir PATHmarks expected files as already downloaded when listing digital objects.--start-dateand--end-datemap to NARAstartDateandendDate.- Date filters are catalog constraints, not proof of event dates.
- Downloads never overwrite unless
--forceis passed. - Downloads stream to temporary files, compute SHA-256, and write
nara-{naid}-download-manifest.json. --rangeis inclusive, e.g.1,3-5. Out-of-range indexes are skipped. Open-ended ranges such as5-are not supported.- Search-result downloads enforce
--download-record-limitand--download-object-limit; use--rangeor--yesfor explicit bulk intent. - Use
--quieton download commands when scripts only need the final summary. - Source IDs must match
S###,R###,C###, orN###with an optional alphanumeric, underscore, or dash suffix. source-packetcreatesarchive/nara/SOURCE_IDunder--archive-rootwhen needed and refuses to overwrite existing packet files.
NARA documents a default Catalog API limit of 10,000 queries per month per API
key. Keep searches small and prefer --count for scoping.
from pathlib import Path
from nara_catalog.models import SearchRequest
from nara_catalog.service import NaraCatalogService
service = NaraCatalogService.from_environment(project_dir=Path.cwd())
result = service.search_records(SearchRequest(
query='"SEARCH TERMS"',
online=True,
limit=10,
))nara-mcpThe MCP server is local stdio-first and targets the MCP 2025-11-25
specification with the stable mcp Python SDK v1 line. Write tools are disabled
unless NARA_MCP_WRITE_ROOT is set; paths outside that root are rejected and MCP
responses scrub local filesystem details and key-source labels. Use the CLI when
you need full local path output.
python -m pip install -e '.[test]'
pytest
RUN_NARA_INTEGRATION=1 pytest tests/integrationUnit tests are offline. Live NARA tests are opt-in and assert broad API shape only.
MIT. See LICENSE.