Skip to main content
Glama
dna-seq
by dna-seq
README.md
# just-prs-mcp: Conversational and Programmatic Polygenic Risk Scores

[![PyPI version](https://badge.fury.io/py/just-prs-mcp.svg)](https://pypi.org/project/just-prs-mcp/)
[![Python 3.13+](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
[![Claude Plugin](https://img.shields.io/badge/Claude-Plugin-d97706?logo=anthropic&logoColor=white)](#claude-plugin)
[![MCP](https://img.shields.io/badge/MCP-Claude%20%7C%20Cursor%20%7C%20Codex-blueviolet.svg)](#connect-claude-cursor-or-another-mcp-client)
[![BioContextAI Registry](https://img.shields.io/badge/BioContextAI-Registry-0b7285.svg)](https://biocontext.ai/registry/dna-seq/just-prs-mcp)
[![Core library](https://img.shields.io/badge/core-just--prs-2ea44f.svg)](https://github.com/dna-seq/just-prs)
[![Research use only](https://img.shields.io/badge/use-research%20only-orange.svg)](#research-use-only)
[![Not medical advice](https://img.shields.io/badge/medical-not%20advice-red.svg)](#research-use-only)

`just-prs-mcp` brings the
**[just-prs](https://github.com/dna-seq/just-prs) bioinformatics toolbox** into
Claude, Cursor, Codex, and any other
[Model Context Protocol](https://modelcontextprotocol.io/) client. It exposes
typed tools for searching **5,000+ published polygenic scoring models**,
normalizing VCF and consumer-array data, computing PRS, comparing results with
reference populations, estimating absolute risk, and assessing result quality.

It is useful whether you are:

- a **bioinformatician** adding reproducible PRS operations to an MCP-enabled
  research environment;
- a **researcher or analyst** who wants to inspect models and evidence through a
  conversational interface;
- a **Claude or Cursor user** who wants to analyze a local genome without
  writing a pipeline; or
- a **developer** embedding PRS tools in an agent, application, or internal
  system.

The server runs locally by default, needs no API key, and does not upload your
genome. The underlying scoring, catalog, and reference-panel logic remains in
`just-prs`; this repository provides the MCP tools, Claude plugin, packaging,
prompts, and guided interpretation workflows.

The server is published in the
[BioContextAI Registry](https://biocontext.ai/registry/dna-seq/just-prs-mcp), a
community registry for agentic biomedical systems, where researchers can
discover its scientific scope, supported features, and registry metadata.

## See the evidence, not just a score

![Trait-level PRS report showing model percentiles, match rates, quality, and a consensus reference curve](images/intelligence.jpg)

Instead of hiding uncertainty behind one number, the server gives clients the
evidence needed to judge a result: PGS IDs, variant-match rates, model quality,
reference population, percentiles, absolute-risk context, and agreement or
conflict across models for the same trait.

## How it fits into your workflow

```mermaid
flowchart LR
    U["Researcher, bioinformatician,<br/>or genome owner"]
    C["Claude · Cursor · Codex<br/>or another MCP client"]
    M["just-prs-mcp<br/>typed tools + prompts + skill"]
    J["just-prs<br/>scoring and catalog engine"]
    V["Local VCF / array"]
    P["PGS Catalog metadata<br/>and reference distributions"]

    U --> C --> M --> J
    V --> J
    P --> J
    J --> M --> C
```

| Use case | Recommended interface |
|---|---|
| Ask questions and receive an evidence-aware interpretation | [Claude plugin](#claude-plugin) |
| Add structured PRS tools to Claude, Cursor, Codex, or an internal system | [MCP server](#connect-claude-cursor-or-another-mcp-client) |
| Build scripts, notebooks, pipelines, or a browser UI directly | [just-prs](https://github.com/dna-seq/just-prs) |
| Evaluate quickly without personal genomic data | [Public test genomes](#test-genomes-quick-play) |

## What can you ask?

These are queries an MCP client can resolve with the current tools. One genome
is always a one-element `samples` list; two or more people use the same tools
with a longer list. `compute_prs_by_trait` interprets percentiles by default.

```text
"Search the PGS Catalog for type 2 diabetes and explain which models are best supported."

"Download Anton's public genome and compute PRS for type 2 diabetes.
Give me the HTML report link and say which models agree."

"What's Livia's genetic predisposition for venous thromboembolism? Include
absolute risk, not just a percentile."

"Compare Anton and Livia on intelligence. Show all associated models,
use the median, check whether a high percentile is favorable, and open
the overlay HTML report."

"Detect the build and ancestry of this VCF, then score coronary artery disease
with superpopulation=auto."

"Compute BMI PRS directly from ~/data/me.vcf.gz. Do not normalize it first;
if list_genomes already has a cached Parquet for this genome, reuse that path."

"I already have result JSON from a previous run — plot the trait panel and
build the Ask-AI write-up from those result_paths."

"Score this genome against PGS000337 only, then give the percentile and quality."
```

The tool always returns `html_link`: an HTTP URL over **Streamable HTTP**
(`GET /reports/<file>` on the MCP origin) or a `file://` URI over local
**stdio**. The model must quote that exact target as a markdown link and tell
the user to open the interactive report; it must not fetch or paste the HTML.

The client chooses the tools and keeps the provenance (PGS IDs, match rates,
quality, ancestry). You can also call every tool from your own MCP application.

## Connect Claude, Cursor, or another MCP client

Local use requires [uv](https://docs.astral.sh/uv/). `uvx` creates an isolated
environment for the published package, so there is no repository clone or
project-level installation step.

### Claude Code

Add the MCP server:

```bash
claude mcp add just-prs -- uvx just-prs-mcp@latest stdio
claude mcp list
```

Use a pinned version in reproducible research environments:

```bash
claude mcp add just-prs -- uvx just-prs-mcp@0.5.0 stdio
```

For the MCP server plus the bundled trait-interpretation skill, use the
[Claude plugin](#claude-plugin).

### Cursor

Add to `.cursor/mcp.json` (project) or your user MCP config
([Cursor MCP docs](https://cursor.com/docs/mcp)):

```json
{
  "mcpServers": {
    "just-prs": {
      "command": "uvx",
      "args": ["just-prs-mcp@latest", "stdio"],
      "env": { "PRS_MCP_MODE": "essentials" }
    }
  }
}
```

From a checkout, `uv run just-prs-mcp stdio` is the same server. File log:
`<cache>/logs/mcp.log`. HTTP (`just-prs-mcp http`, then
`"url": "http://127.0.0.1:3011/mcp"`) is optional if you want a process that
outlives the Cursor session.

### Codex

Install the native plugin from the shared DNA Seq marketplace to get both the
MCP server and the evidence-aware trait-interpretation skill:

```bash
codex plugin marketplace add dna-seq/dna-seq-claude-marketplace
```

In Codex Desktop, open **Plugins**, choose **DNA Seq Genomics**, and install
**just-prs: Polygenic Risk Scores**. If no Codex CLI is installed, clone the
marketplace repository and open that checkout in Codex Desktop; its repository
marketplace is discovered automatically.

For a tools-only configuration, add this to `~/.codex/config.toml`:

```toml
[mcp_servers.just-prs]
command = "uvx"
args = ["just-prs-mcp@latest", "stdio"]
```

### Other MCP clients and internal systems

Use the same local stdio process:

```json
{
  "command": "uvx",
  "args": ["just-prs-mcp@latest", "stdio"],
  "env": {
    "PRS_MCP_MODE": "essentials"
  }
}
```

The server is built with [FastMCP](https://gofastmcp.com) and returns structured
Pydantic outputs, so it can be used interactively or orchestrated by your own
MCP client.

### Claude plugin

The repository is also packaged as a **Claude Code / Cowork plugin**.
[`.claude-plugin/plugin.json`](./.claude-plugin/plugin.json) registers the
`prs-trait-interpretation` skill, while [`.mcp.json`](./.mcp.json) launches the
MCP server through `uvx`. The skill guides Claude through model selection,
quality filtering, percentile interpretation, model agreement, and research-use
caveats rather than treating the first available score as definitive.

Install it from the shared marketplace:

```bash
claude plugin marketplace add dna-seq/dna-seq-claude-marketplace
claude plugin install just-prs@dna-seq
```

Or use the working tree directly during development:

```bash
claude plugin validate .
claude --plugin-dir .
```

Or build the minimal ZIP for manual upload in Claude Desktop / Cowork:

```bash
uv run pack plugin
# dist/just-prs-claude-plugin-<version>.zip
```

The ZIP contains only the plugin manifest, MCP configuration, skill, README, and
license. See the official
[Claude plugin documentation](https://code.claude.com/docs/en/plugins).

### Claude Desktop (`.mcpb` extension)

If you only need the MCP tools, package a Claude Desktop extension:

```bash
uv run pack mcpb
# dist/just-prs-mcp-<version>.mcpb
```

Double-click the `.mcpb` or drag it into Claude Desktop. The extension still
runs the server locally. Metadata and configurable options are declared in
[`manifest.json`](./manifest.json).

### Version pinning tip

`uvx` caches the first version it resolves for a bare package name. Prefer
`just-prs-mcp@latest` or `just-prs-mcp@<version>` — avoid the bare name.

Use `--mode extended` or `PRS_MCP_MODE=extended` for bulk downloads, HuggingFace
upload, prevalence priors, multi-method absolute risk, and reference-panel
scoring.

### From a clone (development)

The plugin's `.mcp.json` launches the pinned PyPI release. To run the working
tree while developing:

```toml
[mcp_servers.just-prs]
command = "uv"
args = ["run", "just-prs-mcp", "stdio"]
```

## What is a PRS?

Many traits and common diseases — type 2 diabetes, coronary artery disease,
height, longevity — are **polygenic**: influenced by thousands of small genetic
effects. A Polygenic Risk Score adds those effects and places the result
relative to a reference population. It is not a diagnosis; it can visualize
inherited predisposition and, where evidence allows, translate a percentile into
an absolute-risk estimate.

## What is MCP?

The [Model Context Protocol](https://modelcontextprotocol.io/) lets AI assistants
and applications call external tools through a shared protocol. Here, MCP turns
the `just-prs` Python API into discoverable, typed operations with structured
inputs and outputs. A chat client can use them conversationally; a
bioinformatics platform can orchestrate the same operations programmatically.

## Contents

- [See the evidence, not just a score](#see-the-evidence-not-just-a-score)
- [How it fits into your workflow](#how-it-fits-into-your-workflow)
- [What can you ask?](#what-can-you-ask)
- [Connect Claude, Cursor, or another MCP client](#connect-claude-cursor-or-another-mcp-client)
- [What is a PRS?](#what-is-a-prs)
- [What is MCP?](#what-is-mcp)
- [Quickstart (developers)](#quickstart-developers)
- [Test genomes (quick play)](#test-genomes-quick-play)
- [Tools](#tools)
- [Prompts and resources](#prompts-and-resources)
- [Typical MCP workflow](#typical-mcp-workflow)
- [Modes](#modes)
- [Configuration](#configuration)
- [Methodology](#methodology)
- [Research use only](#research-use-only)
- [Privacy](#privacy)
- [Deployment](#deployment)
- [Project layout](#project-layout)
- [License](#license)

## Quickstart (developers)

```bash
uv sync                                    # deps (incl. dev)
uv sync --extra reference                  # + pgenlib (Linux/WSL)

uv run just-prs-mcp stdio                  # stdio for MCP clients
uv run just-prs-mcp stdio --mode extended  # full tool surface
uv run just-prs-mcp http                   # HTTP (default :3011)
uv run fastmcp dev fastmcp.json            # MCP Inspector

uv run pytest
uv run ruff check .
uv run pyright
```

The server **boots with no environment configured** — every setting is optional.

## Test genomes (quick play)

Two public WGS datasets from
[just-dna-lite](https://github.com/dna-seq/just-dna-lite) are built in:

| Sample | Zenodo | VCF | Size | License | Parameter |
|--------|--------|-----|------|---------|-----------|
| Anton Kulaga | [18370498](https://zenodo.org/records/18370498) | `antonkulaga.vcf` | ~482 MB | CC0 | `sample="anton"` |
| Livia Zaharia | [19487816](https://zenodo.org/records/19487816) | `SIMHIFQTILQ.hard-filtered.vcf.gz` | ~349 MB | CC-BY-4.0 | `sample="livia"` |

```
"Download Anton's sample genome and compute the PRS for type 2 diabetes."
```

Typical tool chain: `download_sample_genome` → (auto-normalize) →
`compute_prs_by_trait` → `percentile` → `absolute_risk` → optional
`plot_trait_panel` / `build_prs_prompt`. Download both `anton` and `livia` for
a two-person comparison.

## Tools

### Essentials (always available)

| Tool | Description |
|------|-------------|
| `search_scores` | Search the PGS Catalog by free text |
| `score_info` | Cleaned metadata for one PGS ID |
| `best_performance` | Best evaluation metrics (OR / HR / AUROC / C-index) |
| `search_traits` | REST trait search with synonym retry |
| `trait_info` | Trait by EFO / MONDO ID + associated PGS IDs |
| `list_genomes` | Inventory of downloaded and normalized genomes in the cache |
| `download_sample_genome` | Fetch a public sample WGS VCF from Zenodo (auto-normalizes by default; can take several minutes) |
| `normalize_vcf` | Optional VCF → reusable genotype Parquet preprocessing; never required before compute |
| `vcf_metainfo` | Detect build, WGS/array/gVCF, and inferred ancestry; recommends restoration + superpopulation |
| `compute_prs` | Score one genome against one PGS model (`reference_restoration="auto"`) |
| `compute_prs_batch` | Score one genome against many PGS models |
| `compute_prs_by_trait` | Score raw VCFs or Parquets for 1+ genomes (`samples=["Label=path", ...]`); `profile="all"` by default (`curated` is the shortlist); returns a `PRSJob` |
| `prs_job_status` | Poll a long scoring/download job (`wait_seconds=25`) until `done` / `failed` |
| `list_prs_jobs` | Recover a `job_id` after a client timeout |
| `percentile` | Population percentile (reference panel / theoretical / AUROC fallback) |
| `absolute_risk` | Absolute disease risk from a PRS z-score + prevalence |
| `assess_quality` | Quality label + interpretation (pure logic, no I/O) |
| `compare_genomes` | Cross-genome comparison + optional just-prs LLM prompt |
| `build_prs_prompt` | Reusable `prs prompt` / Ask-AI text from saved reports (one or many genomes) |
| `plot_trait_panel` | just-prs trait HTML report; always returns `html_link` (HTTP URL or local `file://` URI) |

### Extended (opt-in via `--mode extended`)

| Tool | Description |
|------|-------------|
| `normalize_array` | 23andMe / AncestryDNA → Parquet |
| `download_scoring_file` | One harmonized scoring file from EBI FTP |
| `list_pgs_ids` | All PGS IDs on EBI FTP |
| `download_all_metadata` | All metadata sheets as Parquet |
| `bulk_download_scores` | Many/all scoring files |
| `prevalence_info` | Population prevalence priors for a score or trait |
| `absolute_risk_bundle` | Multi-method absolute-risk estimation |
| `push_catalog_to_hf` | Upload cleaned catalog to HuggingFace (needs token) |
| `download_reference_panel` | Fetch 1000G / HGDP+1kGP panel |
| `reference_score` / `reference_score_batch` | Score against a reference panel (needs `pgenlib`) |
| `pgen_read_pvar` / `pgen_read_psam` / `pgen_score` | PLINK2 binary ops (needs `pgenlib`) |

> **File paths:** computation tools take local paths on the **server**
> filesystem. Over stdio that is your machine. Reference / pgen tools need
> `uv sync --extra reference` (Linux/WSL).

## Prompts and resources

| Prompt | Description |
|--------|-------------|
| `compute_prs_for_trait` | Step-by-step: search → score raw VCF/Parquet inputs directly → interpret |
| `interpret_prs_for_trait` | End-to-end trait read (optional multi-genome compare) |
| `interpret_prs_result` | Interpret a single PGS result (prefer `build_prs_prompt` when you have a report) |
| `interpret_trait_results` | Interpret combined results across models / people |

| Resource | Description |
|----------|-------------|
| `resource://prs/panels` | Reference panels, genome builds, and the active cache directory |
| `resource://prs/genomes` | JSON catalog of cached VCFs / Parquets (same as `list_genomes`) |

## Typical MCP workflow

```
1. search_traits("venous thromboembolism")     → trait ID (e.g. EFO_0001645)
2. download_sample_genome(sample="anton")       → VCF (+ optional cached Parquet)
3. vcf_metainfo(vcf_path=...)                    → optional: build + ancestry
4. compute_prs_by_trait(trait_id, samples=["Anton=<raw VCF path>"],
     superpopulation="auto")                    → TraitPRSReports
5. absolute_risk / assess_quality               → as needed
6. build_prs_prompt(result_paths=...)           → reusable LLM write-up
7. plot_trait_panel(result_paths=...)           → html_link (HTTP or file://)
```

Same tools for a two-person (or family) comparison — `samples` and
`result_paths` are always lists:

```
2. download_sample_genome("anton"); download_sample_genome("livia")
3. compute_prs_by_trait(trait_id,
     samples=["Anton=<anton VCF>", "Livia=<livia VCF>"],
     superpopulation="auto")
4. compare_genomes(result_paths=...)            → 2+ genomes (median, not "best")
5. build_prs_prompt(result_paths=...)           → comparison-first prompt
6. plot_trait_panel(result_paths=...)           → overlay HTML (or html_link from step 3)
```

`compute_prs_by_trait` returns a `PRSJob` immediately. Poll
`prs_job_status(job_id, wait_seconds=25)` until `done`. Then `result` is
`TraitPRSReports` (`reports`, `result_paths`, `sample_labels`, `html_link`,
plus transport-specific `html_path` / `html_url`). The job also copies
`html_link` onto the top-level record. One genome is `n_samples=1`.
There is no `vcf_path` argument — always `samples`. `interpret` defaults to
`True`; `profile` defaults to `all` (every associated score). Pass
`profile="curated"` only for the shortlist. Pass `interpret=False` only for
raw scores.

Raw VCF input is first-class: do not call `normalize_vcf` as a prerequisite.
Normalization is only an optional optimization for intentional repeated reuse.
If a normalized Parquet already exists, `list_genomes` exposes it.
`normalize_vcf`, `download_sample_genome`, and `compute_prs_batch` are the
same job+poll pattern. Do not start a second identical compute after a
timeout — call `prs_job_status` or `list_prs_jobs` instead.

## Modes

`PRS_MCP_MODE` (env) or `--mode` (CLI), default `essentials`:

| Mode | What's registered |
|------|-------------------|
| `essentials` | Catalog + core compute/analyze + comparison. Smaller tool list for clients. |
| `extended` | Batch downloads, HF upload, prevalence, multi-method risk, reference/pgen. |

## Configuration

All settings are optional. See [`.env.example`](./.env.example) and
[`settings.py`](src/just_prs_mcp/settings.py).

| Variable | Description |
|----------|-------------|
| `PRS_MCP_MODE` | `essentials` (default) or `extended` |
| `PRS_MCP_CACHE_DIR` | Cache for catalog data, scoring files, panels, results |
| `PRS_MCP_DEFAULT_GENOME_BUILD` | Default genome build (`GRCh38`) |
| `PRS_MCP_DEFAULT_PANEL` | Default reference panel (`1000g`) |
| `PRS_MCP_DUCKDB_MEMORY_LIMIT` | DuckDB memory for batch scoring (e.g. `8GB`) |
| `PRS_MCP_HF_TOKEN` | HuggingFace token for `push_catalog_to_hf` (also `HF_TOKEN`) |
| `PRS_MCP_TRANSPORT` | `stdio` / `http` / `sse` |
| `PRS_MCP_HOST` / `PRS_MCP_PORT` | Bind address for HTTP/SSE (default `127.0.0.1:3011`) |
| `PRS_MCP_PUBLIC_BASE_URL` | Optional public origin for trait HTML (`/reports/<file>`). `http`/`sse` fill this from the bind address; set only behind a reverse proxy. |
| `PRS_MCP_AUTO_CACHE_VCF_FOR_BATCH` | Transparently normalize/cache raw VCFs once for multi-score tools (default `true`) |
| `PRS_MCP_ISOLATE_NATIVE_SCORING` | Run VCF normalization and multi-score DuckDB/Polars work in `python -m just_prs_mcp.native_worker` so a native crash does not kill MCP (default `true`). Worker failures are classified as `exception` / `protocol` / `signal` / `timeout`; only a confirmed native/signal scoring exit bisects the PGS batch. Stderr lands in `<cache>/logs/mcp.log`. |
| `PRS_MCP_MAX_CONCURRENT_SCORING_JOBS` | Native genomic workloads allowed per server process (default `1`; job tools and remaining blocking native tools share this slot) |
| `PRS_MCP_JOB_GRACE_SECONDS` | How long a submitting `tools/call` waits for a fast job before returning `running` (default `2`) |
| `PRS_MCP_LOG_LEVEL` | Logging level (`info` by default) |
| `PRS_MCP_LOG_FILE` | Rotating file log (default `<cache>/logs/mcp.log`). Set `off` to disable. |

## Methodology

### Percentile estimation

Percentiles use the **1000 Genomes Project phase 3** panel (2,504 individuals;
AFR, AMR, EAS, EUR, SAS) on GRCh38 harmonized scoring files. PRS is
`Σ(effect_weight × dosage)` for matched variants; the user sample is placed on
the same distribution.

### Quality scoring

Synthetic quality score (0–100) from four tiers:
- **T1a**: AUROC / C-index (strongest)
- **T1b**: Beta only (0.95×)
- **T2**: OR / HR only (0.90×; probit transform)
- **T3**: No performance metric (0.6× floor)

Also factors cohort size, coverage, and harmonized-score penalty. Labels: High
(≥70), Normal (≥50), Moderate (≥30), Low (<30).

### Absolute risk

For disease traits, `absolute_risk` converts a z-score into lifetime probability
and risk ratio vs population average. `risk_ratio` 1.0 = average; >1 elevated;
<1 reduced. If prevalence data is unavailable, the tool reports that explicitly.

### Interpreting results

Built-in instructions guide agents to:
- Present PRS as predisposition, not a trait measurement
- Call `absolute_risk` after `percentile` for disease traits
- Respect trait directionality
- Flag ancestry mismatches, low coverage, and model disagreement
- Cite PGS IDs with links to the [PGS Catalog](https://www.pgscatalog.org/)

See the
[just-prs interpretation guide](https://github.com/dna-seq/just-prs#research-use-only-interpreting-prs-results).

## Research use only

PRS results are for **research and educational purposes only** and do not
constitute medical advice.

- PRS models are statistical proxies, not causal readouts.
- Catalog listing does not mean clinical readiness.
- Environment, lifestyle, age, sex, and biomarkers often matter as much as or
  more than common-variant signal.
- Low match rates (common with consumer arrays) mean a noisier, less informative
  score.
- Ancestry matters: accuracy often drops outside the training population.

A high PRS is not a diagnosis; a low PRS is not a guarantee.

## Privacy

Genomic computation is designed to stay local:

- Over **stdio** / Claude Desktop / the Claude plugin, tools read paths on **your**
  machine. VCFs are not uploaded to a third-party API by this server.
- There is deliberately no client-to-server VCF upload or remote-fetch tool.
- Optional HuggingFace upload (`push_catalog_to_hf`, extended mode) sends
  **catalog metadata**, not personal genotype files, and only when you invoke it
  with a token.

## Deployment

- **Docker**: `docker build -t just-prs-mcp . && docker run -p 3011:3011 just-prs-mcp`
- **Smithery** (GitHub connect): repo is ready — `smithery.yaml` (`runtime: python`)
  + `[tool.smithery]` pointing at `just_prs_mcp.server:start_mcp_smithery`.
  1. Push this repo to GitHub.
  2. Follow the current [Smithery publishing guide](https://smithery.ai/docs/build/publish).
  3. Optional: set `PRS_MCP_MODE=extended` (or other `PRS_MCP_*`) in the Smithery
     project env if you want the full tool surface on the hosted instance.
  Local smoke-test of the same entrypoint:
  `uv run smithery dev` / `uv run playground` / `uv run start`.
- **Declarative**: `fastmcp.json` for `fastmcp run` / `fastmcp dev`

## Project layout

```
src/just_prs_mcp/
  server.py          build_server(), CLI, graceful shutdown, Smithery entrypoint
  settings.py        pydantic-settings (PRS_MCP_*), safe defaults
  client.py          shared PRSCatalog / REST-client construction + adapters
  models.py          Pydantic tool I/O models (+ reused just-prs models)
  jobs.py            PRSJob store, submit/poll, scoring semaphore
  native_worker.py   isolated native scoring / normalize subprocess
  plugin_package.py  minimal Claude plugin ZIP builder
  logging_setup.py   stdlib logging → stderr + `<cache>/logs/mcp.log`
  tools/
    catalog.py         essentials — PGS Catalog search and lookup
    compute.py         essentials — normalize, compute, compare, prompts
    extended.py        extended — batch downloads, HF upload, prevalence, multi-risk
    reference.py       extended — reference-panel / pgen scoring (pgenlib)
tests/               in-memory client tests (wiring + logic, no network)
```

## License

MIT — see [LICENSE](./LICENSE).

TDQS

A4.1/5.0

Scored across 20 tools

Disambiguation4/5

Most tools target a distinct action-resource pair: search, info, compute, post-process, report, and job handling are clearly separated. The main ambiguity is between compute_prs_batch and compute_prs_by_trait, which both handle multiple scores, though their descriptions clarify the one-genome-vs-many-genomes distinction.

Naming Consistency4/5

The majority of tools follow a snake_case verb_noun pattern (compute_prs, list_genomes, build_prs_prompt, compare_genomes). A few noun-style names (best_performance, vcf_metainfo, percentile, absolute_risk, score_info, trait_info) break the pattern, but the overall convention remains predictable.

Tool Count3/5

At 20 tools, this is on the heavy side and spans a very wide pipeline from catalog search to VCF normalization to reporting. The count is defensible for the domain, but some tools like percentile, absolute_risk, and assess_quality are narrowly scoped and could conceivably be folded into compute/interpretation results.

Completeness5/5

The tool surface covers the full PRS lifecycle: discovery, input preparation, computation, interpretation, comparison, reporting, and async job recovery. There are no obvious dead ends — job IDs feed prs_job_status, result paths feed compare_genomes/build_prs_prompt/plot_trait_panel, and computed z-scores feed absolute_risk.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive