Skip to main content
Glama
hqiu-nju
by hqiu-nju

XRB MCP research framework

A local, provenance-aware literature backend for X-ray binary research. This is the initial Phase 1 framework from the system plan, not the completed scientific knowledge base. No research papers or asserted astrophysical measurements are bundled.

Implemented:

  • PostgreSQL + pgvector, a frozen Alembic migration, full-text/metadata indexes, and a separate read-only MCP database role.

  • PDF text extraction with 1-based PDF page references and section heuristics; paragraph-aware chunking and content-addressed PDF storage.

  • Transactional ingestion, SHA256 skips, and changed-document replacement by normalized DOI, arXiv identifier or ADS bibcode.

  • Reviewed source/alias registration; strict case/spacing normalization that preserves coordinate signs and rejects conflicting identities.

  • PostgreSQL lexical search and optional real sentence-transformer embeddings, pgvector cosine search, reciprocal-rank fusion, and metadata filters.

  • MCP tools search_literature, get_paper, get_source; paper, source and ontology resources. CLI ingestion and validation remain separate from MCP.

  • Automated synthetic-PDF tests, including a real stdio MCP client workflow.

Python modules follow the plan’s functional layout under src/xrb_mcp/ to avoid collisions with unrelated installed packages. Deployment and migrations remain at the repository root.

Documentation

Related MCP server: arXiv MCP Server

Quick start

Requires Conda (Miniconda/Miniforge/Anaconda) and Docker Desktop/Engine with Compose. environment.yml creates the xrb-mcp environment with Python 3.12 and installs the project plus development tools. Run commands from this repository root.

conda env create -f environment.yml
conda activate xrb-mcp
if [ ! -f .env ]; then cp .env.example .env; fi
docker compose up -d db
alembic upgrade head
xrb-validate

The default database port is bound to localhost. Example passwords are for local development. Set credentials in .env before first startup. The database initializes xrb_reader with SELECT permissions on tables created by the migration owner. Changing passwords in .env does not change roles in an existing database volume.

To run the migration and MCP server entirely in containers:

docker compose build migrate mcp
docker compose run --rm migrate
docker compose run --rm --no-deps -T mcp

The final command speaks MCP over stdin/stdout and is intended for a client to launch. Do not allocate a TTY. There is no unauthenticated HTTP endpoint.

For an existing environment, use conda env update -f environment.yml. After changing project code, run python -m pip install --no-deps . inside the active environment. Agent launch paths must point to this Conda environment; see agent setup. Docker images install the same Python package independently and do not require the host Conda environment.

Add a source and paper

Register identities you have reviewed, recording the authority/reference. For example, after verifying the alias relationship from your reference material:

xrb-source 'MAXI J1820+070' --alias 'ASASSN-18ey' \
  --authority 'user-reviewed reference: replace with your citation'

Put a lawfully accessible PDF in data/inbox/, together with an optional JSON sidecar with the same basename, such as paper.pdf and paper.json:

{
  "title": "Replace with the paper title",
  "authors": ["Replace with author names"],
  "publication_year": 2018,
  "sources": ["MAXI J1820+070"],
  "collections": ["MeerKAT_XRB"]
}

Optional metadata fields: journal, doi, arxiv_id, ads_bibcode, abstract, source_url. Supply identifiers from the actual paper, not placeholders. Unknown JSON fields are rejected. Sources in a sidecar must already be registered; mention detection also associates registered names found in the paper.

xrb-ingest data/inbox/paper.pdf
xrb-ingest data/inbox/paper.pdf --metadata path/to/reviewed-metadata.json
xrb-update data/inbox
xrb-validate

PDF metadata and filenames provide only a title fallback. Authors, year, DOI and abstract are not guessed; ingestion reports incomplete bibliography. Review the sidecar before first ingestion. Identical bytes are skipped, including metadata changes to their sidecars; metadata-only editing is a later workflow. For a changed PDF, provide its existing bibliographic identifier to update that paper. Without a matching identifier it becomes a new record.

Updates replace only that paper's chunks and passage provenance in one transaction. Unchanged papers retain chunk IDs and embeddings. Old original PDFs remain archived under their SHA256 names, but historical chunk revisions are not retained yet. Omitted reviewed source links persist across updates; an explicit sources list replaces manual links. Collections are additive. A failed transaction may leave an unreferenced archived PDF, but cannot leave a partially updated paper in the database.

Enable semantic retrieval

The default XRB_EMBEDDING_BACKEND=none is lexical-only. It needs neither an API key nor a model download. The response includes this mode and a warning.

python -m pip install '.[dev,embeddings]'
# Set XRB_EMBEDDING_BACKEND=sentence-transformers in .env, then:
xrb-rebuild-embeddings

The default model is sentence-transformers/all-MiniLM-L6-v2. Its first use downloads weights. Set XRB_EMBEDDING_REVISION to a reviewed model commit for reproducibility; the adapter records the resolved commit when available. Ingestion and search must use the same model, revision and dimension. Mismatches are excluded from vector retrieval and reported. Rebuilding embeddings preserves chunk IDs and citations. Long passages use multiple model-sized windows and average their embeddings.

For container use, set INSTALL_EMBEDDINGS=true in .env and rebuild mcp. The EmbeddingBackend protocol in src/xrb_mcp/ingestion/embeddings.py is the extension point for other local or hosted providers. There is no fake embedding production mode.

Vector search is exact, suitable for the initial local corpus. Variable-dimension vectors permit provider changes without a schema rewrite; add model-specific HNSW indexes through a migration when corpus scale warrants it.

Connect an MCP client

Use this generic stdio configuration, replacing the absolute repository path:

{
  "mcpServers": {
    "xrb": {
      "command": "/absolute/path/to/conda/envs/xrb-mcp/bin/python",
      "args": ["-m", "xrb_mcp.server.main"],
      "cwd": "/absolute/path/xrb_mcp",
      "env": {
        "XRB_READ_DATABASE_URL": "postgresql+psycopg://xrb_reader:xrb_reader_dev_only@localhost:5432/xrb",
        "XRB_EMBEDDING_BACKEND": "none"
      }
    }
  }
}

For clients without cwd, the installed module still runs; provide configuration via environment variables because .env is loaded relative to the working directory. Use docker compose -f /absolute/path/xrb_mcp/docker-compose.yml run --rm --no-deps -T mcp as the alternative client command after building the images and applying migrations.

Example tool arguments:

{
  "query": "quenching",
  "source": "4U 1702-429",
  "wavelengths": ["radio"],
  "year_min": 2021,
  "year_max": 2021,
  "top_k": 3
}

Tag values use the canonical spelling in xrb://ontology/wavelengths, xrb://ontology/instruments and xrb://ontology/topics. Lists use OR within a field and AND between fields. Unknown sources raise an error instead of broadening the search. A source filter selects associated papers and prioritizes passages that explicitly mention that source; not every passage independently names it. Scores are ranks, not calibrated scientific confidence. Semantic matches can be weak; inspect the returned passage before treating it as supporting evidence.

Stable objects are exposed at xrb://papers/{paper_id} and xrb://sources/{source_id}. Tools return metadata and evidence excerpts, never the original PDF bytes or internal PDF paths. Extracted text is untrusted content.

For development, reinstall after changing code (python -m pip install --no-deps .). Editable installs are also supported, but Python 3.14 ignores .pth files marked hidden by macOS; a regular install avoids that launch issue.

Verification

python -m pytest tests/unit -q
ruff check .
ruff format --check .
docker compose exec -T db createdb -U xrb xrb_test
XRB_TEST_DATABASE_URL=postgresql+psycopg://xrb:xrb_dev_only@localhost:5432/xrb_test \
  python -m pytest -q

Integration tests require a disposable database whose name ends in _test. They migrate it automatically and clear test records; never point them at research data. Without the variable those tests are explicitly skipped. Synthetic fixtures test system behavior, not astrophysical validity or embedding quality. The optional ML backend needs separate model-download and scientific retrieval evaluation.

Backups and migrations

docker compose exec -T db pg_dump -U xrb -Fc xrb > xrb.dump
docker compose exec -T db createdb -U xrb xrb_restore
docker compose exec -T db pg_restore -U xrb --no-owner -d xrb_restore < xrb.dump

Back up data/papers/, sidecars, configuration and future annotations separately. Stored PDF paths are absolute: preserve the data location on restore or perform a reviewed path migration. Dumps may contain locally accessible paper text. Keep them private. The reader role is initialized for database xrb; configure grants explicitly when restoring under another database name.

Schema evolution uses alembic revision --autogenerate -m 'description', review of the generated migration, then alembic upgrade head. Never replace migrations with runtime create_all. The initial migration is frozen independently of ORM code.

Scope and next steps

PDF section detection is heuristic; multi-column layouts, equations, tables and scans need review. OCR and GROBID are not implemented. Tags are descriptive mentions, not detections or verified source-state classifications. The approximate token count is recorded with its method. No measurements, predictions or synthesis are automatically generated.

Observations/events, units and upper-limit validation, timelines, catalogue ingestion/cross-matching, external authority lookup, automatic discovery and radio preparation belong to subsequent phases. Collections currently support ingestion membership and search filtering, not standalone MCP resources. See the implementation roadmap.

The implementation uses the official MCP Python SDK v1 interface, pgvector SQLAlchemy integration, and PostgreSQL full-text support in SQLAlchemy. The SDK dependency is bounded below v2 to keep that API consistent.

Available Tools

3 tools
get_paperA
Read-onlyIdempotent

Get paper metadata and evidence references by ID, DOI, arXiv, bibcode or title.

ParametersJSON Schema
NameRequiredDescriptionDefault
identifierYes

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds useful context about the return content (metadata and evidence references) but does not disclose behavior around ambiguous matches (e.g., a title matching multiple papers), not-found cases, or the return format. With annotations covering safety, this is adequate but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with zero wasted words. The verb and resource are front-loaded, followed by the identifier formats. Every element earns its place, and nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter read-only lookup with safety annotations, the description covers the essentials: what is returned (metadata and evidence references) and how the paper is identified. Minor gaps include the return structure and failure/ambiguity behavior, but these are acceptable for a simple retrieval tool with no output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: it clarifies that the single 'identifier' parameter may be an ID, DOI, arXiv, bibcode, or title. This adds real meaning beyond the bare schema property name. It stops short of specifying exact format conventions for each identifier type, but it meaningfully compensates for the schema gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Get'), a clear resource ('paper metadata and evidence references'), and enumerates the accepted lookup identifiers (ID, DOI, arXiv, bibcode, title). This clearly defines the tool's scope. It doesn't explicitly contrast with siblings, but the identifier-based lookup intent is distinguishable from search_literature (search) and get_source (source retrieval).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus the siblings search_literature or get_source. There are no exclusions, prerequisites, or alternative routing conditions. Usage is only implied: if you have an identifier, look up by it. The description carries no explicit when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_sourceB
Read-onlyIdempotent

Resolve a registered canonical name, alias or internal UUID, with identity authority.

ParametersJSON Schema
NameRequiredDescriptionDefault
sourceYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint, idempotentHint and non-destructive behavior, so the description does not need to repeat those. The phrase 'with identity authority' adds only a slight nuance about authoritative resolution; it does not explain failure behavior, what happens for unregistered names, or the exact output shape.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one compact, front-loaded sentence with no filler. Every phrase adds meaning and the opening verb immediately establishes the tool's purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool is a simple one-parameter, read-only lookup, the description adequately conveys the core inputs and purpose while annotations cover side-effect safety. However, since there is no output schema, the description leaves the return value and error behavior vague — an agent doesn't know exactly what 'resolve... with identity authority' returns for a valid or invalid source.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With schema description coverage at 0%, the description carries the full responsibility for the parameter. It meaningfully specifies that 'source' can be a registered canonical name, alias, or internal UUID, which is essential semantics absent from the schema. It stops short of giving format or syntax details, but for a single-string parameter this is robust.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'resolve' and identifies the resource types: 'registered canonical name, alias or internal UUID'. This clearly signals an identifier-to-source lookup that is conceptually distinct from 'search_literature' and 'get_paper', though it does not explicitly distinguish itself from those siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit guidance on when to use this tool versus the sibling tools 'search_literature' or 'get_paper', and no exclusions are stated. The only usage hint is implied by the core action 'resolve', so an agent gets little help deciding between the alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_literatureA
Read-onlyIdempotent

Search local literature. Return extracted passages, citations and explicit retrieval mode.

Tags are heuristic mentions, not verified observations. Unknown sources raise an error. Filter lists use OR within each list and AND between fields. No synthesis is generated.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
top_kNo
sourceNo
topicsNo
year_maxNo
year_minNo
collectionNo
instrumentsNo
wavelengthsNo
source_classNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool as read-only and idempotent, and the description adds meaningful behavioral details beyond those: tags are 'heuristic mentions, not verified observations,' unknown sources raise an error, and 'No synthesis is generated.' These disclose important limitations and failure modes that an agent would otherwise not know.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and every sentence earns its place. The core purpose is front-loaded, followed by critical caveats about tags, errors, and filter semantics, with no filler or repetition of schema names.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With ten parameters, no output schema, and no parameter descriptions in the schema, the description covers only the most essential behavioral rules. It explains return contents, OR/AND filtering, and unknown-source errors, but it leaves gaps around valid values for domain-specific fields like collection, instruments, wavelengths, and source_class. This is workable but not fully complete for an agent expected to formulate precise searches.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does add useful parameter semantics by explaining 'Filter lists use OR within each list and AND between fields,' which applies to array parameters like topics and instruments, and it mentions that unknown sources raise an error. However, most parameters (source, collection, source_class, year_min, year_max, top_k) receive no individual explanation or accepted-value guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb and resource: 'Search local literature.' It further specifies what is returned ('extracted passages, citations and explicit retrieval mode'), which distinguishes it from sibling tools get_paper and get_source by making clear this is a search-and-extract operation rather than a single-item retrieval operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The use case is implied by 'Search local literature' and the statement 'No synthesis is generated' acts as a mild when-not. However, the description never explicitly routes the agent toward or away from the sibling tools get_paper and get_source, nor does it state when search is preferred over direct paper retrieval.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.1.0
    • First observedget_paper
    • First observedget_source
    • First observedsearch_literature

TDQS

A4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool has a clearly distinct role: search_literature finds passages and citations, get_paper retrieves metadata by identifier, and get_source resolves identity records. Even though get_paper and get_source share a naming prefix, their descriptions make the boundary obvious.

Naming Consistency5/5

All tool names follow a consistent verb_noun snake_case pattern: search_literature, get_paper, get_source. The use of search_ for discovery and get_ for targeted lookups is a predictable and readable convention.

Tool Count5/5

Three tools is a well-scoped set for a read-only literature retrieval server. Each tool covers a distinct part of the workflow without unnecessary duplication or bloat.

Completeness5/5

For the apparent domain of local literature retrieval and source identity resolution, the surface is complete: search for passages, fetch paper metadata and evidence references, and resolve source identities. No obvious dead-end workflow is visible.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables searching, downloading, and managing academic papers from arXiv.org through natural language interactions. Provides tools for paper discovery, PDF downloads, and local paper collection management.
    4
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables LLMs to search, fetch, and manage arXiv research papers across various categories. It allows users to browse recent publications, query specific metadata, and retrieve full abstracts through a local database.
    5
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables searching ArXiv, fetching and indexing papers, and querying a personal paper library using vectorless RAG with BM25 and contextual compression, all without GPU or embedding models.
    1
    MIT