chazzawarner

space-stands

Community chazzawarner
Updated

Local-first MCP server for querying authorised CCSDS and ECSS standards

space-stands

Local-first, read-only MCP retrieval for authorised CCSDS and ECSS standards.The repository contains code only. Standards files, extracted text, indexes,credentials, logs, and SANA personal data stay outside Git.

The first runnable slice supports:

  • local PDF ingestion with source-path and official-host restrictions;
  • idempotent SQLite FTS5 indexing;
  • citation-rich standards search and passage retrieval;
  • revision-aware metadata and corpus/status/document filters;
  • atomic whole-corpus rebuilds from a validated JSON manifest;
  • MCP stdio tools plus document and passage resources;
  • native uv installation and an optional Docker image.

SANA is not yet connected. Its API requires authenticated documentation and aconfirmed reuse/rate-limit policy. The server does not scrape its HTML pages.

Recommended native setup

Requirements: Python 3.11 or newer and uv.

./scripts/bootstrap.sh

The script installs locked runtime dependencies and creates these local paths:

  • ~/.local/share/space-stands/index.sqlite3
  • ~/.local/share/space-stands/corpus/

Override them before setup if required by work policy:

export SPACE_STANDS_DATA_DIR=/approved/private/index-directory
export SPACE_STANDS_CORPUS_DIR=/approved/private/standards-directory
./scripts/bootstrap.sh

Place an authorised PDF beneath the corpus directory, then index it withexplicit provenance:

uv run space-stands ingest "$SPACE_STANDS_CORPUS_DIR/131x0b6ec1.pdf" \
  --source CCSDS \
  --document-id "CCSDS 131.0-B-6" \
  --title "TM Synchronization and Channel Coding" \
  --revision "6" \
  --status active \
  --official-url "https://ccsds.org/.../131x0b6ec1.pdf"

The command rejects PDFs outside the configured corpus root. ECSS documentsmust be acquired separately under an applicable ECSS licence.

Official-source acquisition

The acquisition helper discovers files without downloading them by default:

uv run python scripts/download_official_sources.py --source all

To download the active CCSDS catalogue PDFs and the ECSS bulk archives/TMsnapshot into source-specific directories beneath the configured corpus:

uv run python scripts/download_official_sources.py \
  --source all \
  --download \
  --prepare \
  --accept-ccsds-reuse-terms \
  --accept-ecss-license

Use --list to inspect every discovered record first. Use --manifest PATH tosave a discovery plan. Repeat --ccsds-book-type or --ecss-collection toselect a subset; select --ccsds-book-type "Silver Book" explicitly forhistorical/obsolete CCSDS publications. Downloads are bounded and atomic,redirects remain on official hosts, existing files are revalidated, and theresulting local manifest records source URLs, SHA-256 hashes, sizes, andverification times. Keep the destination outside the repository.

Use --refresh on a later run to re-fetch existing filenames. The helper keepsthe existing file when its SHA-256 is unchanged and atomically replaces it whenthe publisher content changed. A partial or failed run writes a separatefailed-attempt report and does not replace the last complete manifest.

With --prepare, ZIP members are validated before extraction, archive pathsand links are rejected, decompressed sizes are bounded, and the completedarchive is published atomically beneath the corpus directory. The command thenwrites ingestion-manifest.generated.json. ECSS archive entries do not containcomplete catalogue metadata. When any values are inferred, the generated filecontains "metadata_review_required": true, which makes it invalid foringestion. Reconcile each ECSS title, identifier, revision, status, andcanonical document URL against the official catalogue. Then remove that reviewmarker before indexing:

uv run space-stands ingest-manifest \
  "$SPACE_STANDS_CORPUS_DIR/ingestion-manifest.generated.json"

An existing acquisition manifest can be prepared separately:

uv run space-stands prepare-corpus \
  "$SPACE_STANDS_CORPUS_DIR/acquisition-manifest.json"

The ECSS bulk PDF archive is a dated standards snapshot, and the handbook andtechnical-memoranda sources are not complete current catalogues. The CCSDSsite provides no documented API or all-publications ZIP; the helper reads itsofficial active-and-obsolete catalogue and will fail if that page's embeddeddata contract changes. Review the acquisition researchbefore relying on bulk synchronisation.

PDF extraction backends

pypdf remains the default. PDF Inspector is an optional, exactly pinned nativedependency. Install it before selecting that backend for a complete manifestrebuild:

uv sync --extra pdf-inspector
export SPACE_STANDS_PDF_BACKEND=pdf-inspector
uv run space-stands ingest-manifest /approved/private/manifest.json

PDF Inspector runs locally and reports OCR-risk, table, and multi-column pages.It does not perform OCR. The automated 11-document, 60-query A/B benchmarkretained pypdf as the default. pypdf indexed all 1,180 pages, achieved 100%passage hit-rate@3, 80% top-1, 0.787 nDCG@3, and took 9.7 seconds with a131.5 MiB peak. PDF Inspector indexed 1,178 pages, achieved 63.6% hit-rate@3,50.9% top-1, 0.515 nDCG@3, and took 45.8 seconds with a 210.8 MiB peak. Bothachieved 100% no-answer accuracy and citation-field completeness. PDF Inspectoridentified a vector-text CCSDS cover and an ECSS change-log page as OCR risks.A visual check confirmed those classifications, but broader sampled review ofclause boundaries, tables, symbols, and page furniture remains required.

Re-run the benchmark after changing the corpus or either parser:

uv run --extra pdf-inspector python scripts/benchmark_extractors.py \
  --manifest /approved/private/manifest.json

Aggregate results are recorded inbenchmarks/extractor-results.json; nostandards text is written to that file.

For repeatable whole-corpus setup, copyexamples/manifest.example.json outside therepository, edit it, and run:

uv run space-stands ingest-manifest /approved/private/manifest.json

Each file is relative to SPACE_STANDS_CORPUS_DIR. Manifest ingestion buildsand validates a complete staged database before replacing the current index. Ifany document fails, the previous index remains available. Stop the MCP serverbefore rebuilding the index.

Run a diagnostic query:

uv run space-stands search "attached sync marker"
uv run space-stands search "interface requirement" --source ECSS --status active
uv run space-stands document "CCSDS 131.0-B-6" --revision 6

MCP client configuration

Use the installed executable directly. Replace /absolute/path/to/space-standsand the data paths with real absolute paths:

{
  "mcpServers": {
    "space-stands": {
      "command": "/absolute/path/to/space-stands/.venv/bin/space-stands",
      "args": ["serve"],
      "env": {
        "SPACE_STANDS_DATA_DIR": "/approved/private/index-directory",
        "SPACE_STANDS_CORPUS_DIR": "/approved/private/standards-directory"
      }
    }
  }
}

The exact configuration file depends on the MCP host used at work. The serverwrites protocol messages only to stdout; diagnostics from the SDK use stderr.

For Codex, register the native server with the CLI. Use absolute paths:

codex mcp add space-stands \
  --env SPACE_STANDS_DATA_DIR=/approved/private/index-directory \
  --env SPACE_STANDS_CORPUS_DIR=/approved/private/standards-directory \
  -- /absolute/path/to/space-stands/.venv/bin/space-stands serve
codex mcp get space-stands

Codex stores this user-level configuration in ~/.codex/config.toml. RestartCodex after adding the server, then use /mcp to confirm that its tools areavailable. See the official Codex MCP configuration guide.

The MCP surface is:

  • search_standards(query, source?, document_id?, revision?, status?, limit?)
  • get_document(document_id, revision?, source?)
  • get_passage(passage_id)
  • space-stands://documents/{document_key}
  • space-stands://passages/{passage_id}

Optional Docker setup

Docker is supported but is not required. Native execution is usually simplerfor a desktop MCP client. Build the image once:

docker build -t space-stands:local .
docker volume create space-stands-data

Initialise it, mounting the authorised corpus read-only:

docker run --rm \
  --mount source=space-stands-data,target=/data \
  --mount type=bind,source=/approved/private/standards-directory,target=/corpus,readonly \
  space-stands:local ingest-manifest /corpus/manifest.json

For MCP stdio, retain stdin with -i:

docker run --rm -i \
  --mount source=space-stands-data,target=/data \
  --mount type=bind,source=/approved/private/standards-directory,target=/corpus,readonly \
  space-stands:local serve

Use that docker run command and arguments in the MCP host if native executionis prohibited.

Development checks

UV_CACHE_DIR=/tmp/space-stands-uv-cache uv sync --frozen --extra dev
UV_CACHE_DIR=/tmp/space-stands-uv-cache uv run pytest
UV_CACHE_DIR=/tmp/space-stands-uv-cache uv run ruff check .
UV_CACHE_DIR=/tmp/space-stands-uv-cache uv run mypy

Run the local-corpus retrieval benchmark after ingestion:

uv run python scripts/evaluate_retrieval.py \
  --output benchmarks/retrieval-results.json

The checked corpus passes all 55 graded positive questions at passagehit-rate@3 and correctly abstains on all five no-answer questions. Passage-leveltop-1 accuracy is 80%, MRR is 0.888, nDCG@3 is 0.787, and every returned resulthas a page, section, official source URL, and stable MCP resource URI. The casessupport multiple graded passages for valid cross-standard answers. Seebenchmarks/retrieval.json,benchmarks/retrieval-results.json, andbenchmarks/coverage-gaps.json.

See the proposal, corpus policy,MCP research, andacquisition research.

MCP Server ยท Populars

MCP Server ยท New

    onehumanbeing

    ESP32 iPhone Agent

    Let an AI model use a real iPhone with a $7 ESP32: AirPlay eyes, USB HID hands, any OpenAI-compatible vision model. No Mac, no developer account, no jailbreak.

    Community onehumanbeing
    qubrics

    Email Inbox API + Sending by Sendmux

    Official monorepo of SDKs, CLI, and MCP servers for Sendmux email APIs across TypeScript, Python, Go, PHP, Rust, and Ruby.

    Community qubrics
    Twigpine

    openrecall

    Open-source, self-hostable, zero-knowledge memory for AI agents. End-to-end encrypted โ€” the server stores only ciphertext and can't read your agent's memory. Works with any MCP agent .

    Community Twigpine
    customermates

    customermates

    Open-source CRM for people and AI agents, with MCP, a company knowledge base and a self-hostable core.

    Community customermates
    alessandro-afloarei

    ShadowGit MCP server

    A Model Context Protocol (MCP) server that provides AI assistants with secure, read-only access to your ShadowGit repositories. This enables powerful debugging and code analysis capabilities by giving AI access to your project's fine-grained git history.