Skip to main content
Glama
tom2025b
by tom2025b
README.md
# 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.

```mermaid
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

```bash
cd /home/tom/projects/document-catalog-mcp-codex-build
python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
```

Current verified executable:

```text
/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:

```bash
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:

```toml
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:

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

Stable venv:

```bash
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:

```json
{
  "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

```bash
.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:

```bash
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.

TDQS

A3.7/5.0

Scored across 4 tools

Disambiguation5/5

Each tool targets a distinct action: scanning repositories, querying metadata, recording generated PDFs, and recording printed PDFs with job IDs. No overlap in purpose.

Naming Consistency5/5

All tool names follow a consistent 'catalog_verb' pattern (catalog_scan, catalog_query, catalog_record_generated, catalog_record_printed), making naming predictable.

Tool Count5/5

4 tools is well-scoped for a document catalog server; each tool provides a necessary function without redundancy.

Completeness4/5

Covers core operations: scan, query, and two types of record creation. Missing update or delete functionality, but the domain appears focused on recording metadata, so only minor gaps.

Maintenance

ActivityMaintained
ResponsivenessSyncing