tom2025b

document-catalog-mcp

Community tom2025b
Updated

Local MCP server for metadata-only discovery, recording, and querying of Markdown and PDF documents.

document-catalog-mcp

Private local stdio MCP server for metadata-only discovery, recording, and querying of Markdown and PDF documents.

Scope

document-catalog-mcp scans configured Git repositories plus an optional journal tree. It stores paths, hashes, file metadata, classification, local Git tracking state, and optional print job IDs in SQLite. It never stores or returns document contents.

flowchart LR
    Host[Codex or MCP host] -->|stdio| Server[FastMCP server]
    Server --> Service[Catalog service]
    Service --> Git[Configured Git repositories]
    Service --> Journal[Optional journal PDFs]
    Service --> DB[(SQLite metadata catalog)]

Requirements and development install

  • Python 3.11 or newer
  • Git
cd /home/tom/projects/document-catalog-mcp-codex-build
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'

Current verified executable:

/home/tom/projects/document-catalog-mcp-codex-build/.venv/bin/document-catalog-mcp

For a stable install after review, clone the preserved implementation branch into a non-worktree source directory and install it into a dedicated venv:

git clone --branch codex/standalone-catalog --single-branch \
  https://github.com/tom2025b/document-catalog-mcp.git \
  /home/tom/.local/share/document-catalog-mcp/source
python3 -m venv /home/tom/.local/share/document-catalog-mcp/venv
/home/tom/.local/share/document-catalog-mcp/venv/bin/pip install \
  /home/tom/.local/share/document-catalog-mcp/source

Configuration

Create $XDG_CONFIG_HOME/document-catalog-mcp/config.toml, or ~/.config/document-catalog-mcp/config.toml when XDG_CONFIG_HOME is unset:

journal_dir = "~/Documents/journals"

[[repos]]
name = "project-a"
path = "~/projects/project-a"

[[repos]]
name = "notes"
path = "~/notes"

Repository names and resolved paths must be unique. _journal and _external are reserved names. Unknown keys and malformed values fail with concise configuration errors. Missing configuration is valid and produces an empty catalog scan.

SQLite data lives at $XDG_DATA_HOME/document-catalog-mcp/catalog.db, or ~/.local/share/document-catalog-mcp/catalog.db when XDG_DATA_HOME is unset.

Register with Codex

Development worktree:

codex mcp add document-catalog -- \
  /home/tom/projects/document-catalog-mcp-codex-build/.venv/bin/document-catalog-mcp

Stable venv:

codex mcp add document-catalog -- \
  /home/tom/.local/share/document-catalog-mcp/venv/bin/document-catalog-mcp

These commands use the installed codex mcp add <name> -- <command> stdio syntax. Registration is manual; installation does not modify global MCP configuration.

Tools

Tool Arguments Effect Annotations
catalog_scan none Scan configured repositories and journal; upsert metadata read-only false, destructive false, open-world false
catalog_query optional repo, doc_kind, file_type, printed, since Query all 13 metadata fields with filters combined by SQL AND read-only true, destructive false, open-world false
catalog_record_generated required file_path Record one existing generated PDF read-only false, destructive false, open-world false
catalog_record_printed required file_path; optional printed_job_id Record one existing printed PDF and optional job ID read-only false, destructive false, open-world false

Example requests:

  • “Use catalog_scan to refresh my local document catalog.”
  • “Use catalog_query for PDFs classified as reports since 2026-07-01T00:00:00-04:00.”
  • “Record /tmp/output.pdf with catalog_record_generated.”
  • “Record /tmp/printed.pdf with print job ID job-42.”

Scan returns:

{
  "files_found": {"tracked": 1, "local": 2, "journal": 1},
  "files_added": 4,
  "files_updated": 0,
  "repos_skipped": 0,
  "skipped_repos": []
}

Record tools return status, repo, path, and the complete stored metadata row. Query returns matching rows ordered by repository and path. printed=true means printed_job_id is non-null; an empty job ID normalizes to null.

Scanner behavior

  • Repository scan includes tracked, untracked, and ignored .md and .pdf files, case-insensitively.
  • Local Git index membership controls tracked_in_git; remote presence is not checked.
  • Common dependency, build, cache, and VCS directories are excluded at any depth.
  • Journal scan includes PDFs only, stores resolved absolute paths, and never follows directory symlinks.
  • Missing or failing repositories and individual unreadable candidates are skipped while other sources continue.
  • Configuration and SQLite failures propagate to the caller.

Privacy and non-goals

Only bounded SHA-256 hashing reads file bytes. Contents are never parsed, stored, indexed, or returned. Git runs with argument arrays, no shell, deterministic locale, captured output, and a 30-second timeout. Server makes no network calls.

First release intentionally has no printpdf-mcp dependency, hooks, renderer, CUPS integration, watcher, scheduler, deletion pruning, full-text search, GitHub tracking check, remote HTTP, OAuth, UI, MCP App, or MCPB package. MCPB remains a possible distribution upgrade.

Known specification debt: scan has no unchanged counter; printed state requires a non-null job ID; local Git tracking does not prove remote presence; generators and print systems must call explicit record tools themselves.

Verify

.venv/bin/python -m pytest -q
.venv/bin/python -m compileall -q src tests
.venv/bin/python -c "from document_catalog_mcp.server import mcp; print(mcp.name)"
git diff --check

Disable or uninstall

Disable Codex registration without deleting catalog data:

codex mcp remove document-catalog

Removing a venv or source checkout does not delete the SQLite database. Delete ~/.local/share/document-catalog-mcp/catalog.db only when you explicitly want to erase catalog metadata.

MCP Server · Populars

MCP Server · New