Skip to main content
Glama
just-prs-mcp
by dna-seq

just-prs-mcp: Conversational and Programmatic Polygenic Risk Scores

PyPI version Python 3.13+ Claude Plugin MCP BioContextAI Registry Core library Research use only Not medical advice

just-prs-mcp brings the just-prs bioinformatics toolbox into Claude, Cursor, Codex, and any other Model Context Protocol 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, 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

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.

Related MCP server: GeneChat MCP Server

How it fits into your workflow

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

Add structured PRS tools to Claude, Cursor, Codex, or an internal system

MCP server

Build scripts, notebooks, pipelines, or a browser UI directly

just-prs

Evaluate quickly without personal genomic data

Public test genomes

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.

"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. 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:

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

Use a pinned version in reproducible research environments:

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.

Cursor

Add to .cursor/mcp.json (project) or your user MCP config (Cursor MCP docs):

{
  "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:

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:

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

Other MCP clients and internal systems

Use the same local stdio process:

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

The server is built with FastMCP 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 registers the prs-trait-interpretation skill, while .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:

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:

claude plugin validate .
claude --plugin-dir .

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

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.

Claude Desktop (.mcpb extension)

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

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.

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:

[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 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

Quickstart (developers)

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 are built in:

Sample

Zenodo

VCF

Size

License

Parameter

Anton Kulaga

18370498

antonkulaga.vcf

~482 MB

CC0

sample="anton"

Livia Zaharia

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 and 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

See the just-prs interpretation guide.

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.

    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.

Available Tools

20 tools
absolute_riskAbsolute riskA
Read-onlyIdempotent

Estimate absolute disease risk from a PRS z-score and population prevalence.

Joins the score's trait to prevalence + effect-size data. z_score is the PRS in standard deviations from the population mean. Raises if the required prevalence / effect-size data is unavailable for this score.

Inputs: pgs_id (required), z_score (required), sex. Returns: Absolute disease risk estimate derived from PRS z-score and prevalence.

assess_qualityAssess qualityA
Read-onlyIdempotent

Classify and interpret a PRS result's quality (pure logic — no I/O).

match_rate is the fraction of scoring variants matched (0-1). Returns a quality label/color and a human-readable interpretation combining match rate, AUROC, and (optionally) the result percentile. Pass percentile_method / reliable / caveat from the percentile tool so the summary describes how the percentile was actually derived and echoes any low-coverage caveat.

Inputs: match_rate (required), auroc, caveat, reliable, +2 more. Returns: Quality classification + interpretation for a PRS result (pure logic, no I/O).

best_performanceBest performanceA
Read-onlyIdempotent

Look up the best evaluation performance for a score (largest sample, EUR-preferred).

Returns parsed effect sizes (OR/HR/Beta) and classification metrics (AUROC/C-index) plus pre-formatted display strings.

Inputs: pgs_id (required). Returns: Best evaluation performance for a score (largest sample, EUR-preferred).

build_prs_promptBuild PRS promptA
Read-onlyIdempotent

Build the reusable just-prs LLM prompt from saved by-trait results.

This is the MCP equivalent of prs prompt / the UI Ask-AI buttons. result_paths is always a list (one genome is fine; two or more becomes a comparison-first prompt). The returned prompt can be followed in this conversation or pasted into another assistant. Set include_url=True with assistant claude/chatgpt/perplexity/grok for a prefilled link.

kind: trait_results (default, full per-model panel), trait_summary (aggregated cards), or score (one PGS ID; pass pgs_id or the first scored row is used).

Inputs: result_paths (required), kind, limit, pgs_id, +5 more. Returns: Reusable LLM interpretation prompt generated by just-prs (``prs prompt``).

compare_genomesCompare genomesA
Read-onlyIdempotent

Compare saved by-trait PRS reports across two or more genomes.

result_paths — the result_paths list from compute_prs_by_trait (or any saved report JSONs). At least two paths are required. Files are grouped by trait, so a family comparison across several traits is one call.

Rankings use just-prs summarize_trait_rows: the median in-scope percentile is the headline (not a single "best" model). High percentile is not automatically good or bad — interpret direction from the trait.

When every path is the same trait, include_prompt=True (default) attaches the same multi-sample LLM prompt as prs prompt / the UI Ask-AI buttons.

Inputs: result_paths (required), ancestry, assistant, model_scope, +2 more. Returns: Structured comparison of PRS results across multiple genomes.

compute_prsCompute PRSA
Read-onlyIdempotent

Compute a polygenic risk score for one genome against one PGS model.

Pass the raw VCF directly; a separate normalize_vcf call is not needed. If this VCF has a fresh normalized cache, it is reused automatically; genotypes_path is the explicit Parquet fast path. For a trait panel — one genome or several — use compute_prs_by_trait(samples=[...]), then compare_genomes / build_prs_prompt / plot_trait_panel.

Reference restoration (F15/F22). reference_restoration fills a scoring variant's missing reference allele from the precomputed reference-allele universe (pulled from HuggingFace on first use) so a locus the sample is confidently hom-ref at scores as dose-0 instead of being dropped as unscorable-absent — recovering the ~50% coverage gap on genome-wide WGS scores. Default "auto" detects the input: whole-universe restoration for WGS, the matching chip scope for a genotyping array, off otherwise. Pass "off", "wgs", or a chip id (e.g. "gsa_v3") to force a scope. The result's variants_ref_resolved_panel / variants_ref_resolved_fasta counters show how many loci were recovered.

Set infer_ancestry=True to also infer and attach the sample's genetic ancestry (sample_ancestry). genotype_input_mode ("auto" / "variant_only" / "all_sites") controls how absent loci are read.

Set attach_performance=True to embed the score's best published performance (effect sizes, AUROC/C-index, evaluation ancestry) on the result in the same call. The result also carries detected_genome_build / build_mismatch from the VCF (F4).

Recommended follow-up: percentile then absolute_risk (disease traits), or build_prs_prompt(kind='score') for a reusable LLM write-up.

Inputs: pgs_id (required), vcf_path (required), genome_build, genotypes_path, +4 more. Returns: Result of a polygenic risk score computation.

compute_prs_batchCompute PRS (batch)A
Read-onlyIdempotent

Compute PRS for one genome against many PGS models.

Pass the raw VCF directly; a separate normalization call is not required. The tool transparently creates or reuses a collision-safe normalized cache, then uses the memory-safe DuckDB engine with spill-to-disk. It reuses the scoring caches across scores. This is still one genome × many PGS IDs. For a trait panel across people, use compute_prs_by_trait(samples=[...]) then compare_genomes / build_prs_prompt. Set attach_performance=True to embed each score's best published performance on its result in the same pass.

reference_restoration (default "auto") recovers absent-hom-ref coverage on WGS/array input — see compute_prs; the reference-allele universe is resolved once and reused across every score. genotype_input_mode ("auto" / "variant_only" / "all_sites") controls how absent loci are read.

Returns a PRSJob immediately. When done, result is the list of successful PRSResult objects. If status is queued or running, poll prs_job_status(job_id, wait_seconds=25).

Inputs: pgs_ids (required), vcf_path (required), genome_build, attach_performance, +2 more. Returns: A long compute/download job that Cursor can poll without blocking tools/call.

compute_prs_by_traitCompute PRS by trait (give user html_link)A
Idempotent

Compute the PRS scores associated with a trait for one or more genomes.

REQUIRED REPORT DELIVERY: when html_link is set, your reply MUST include it as a markdown link (for example Open the interactive trait report) and explicitly tell the user to open it. This is the primary user-facing result, not an implementation detail. Do not skip the link, merely say the report was saved, fetch it, or paste the HTML. html_link is an HTTP URL when available and a file:// URI on local stdio.

Pass a raw .vcf/.vcf.gz path directly. Do NOT call normalize_vcf first as a prerequisite: multi-score tools transparently create or reuse a safe normalized cache, and single-score tools read the VCF directly. normalize_vcf is only an optional explicit step for custom filters. If list_genomes already shows a normalized Parquet, it can be passed directly.

trait_id may be an EFO or MONDO identifier. samples is always a list (one genome is fine): each entry is Label=path or a bare path; .parquet is a normalized genotype source. Every genome is auto-saved; the return carries reports, result_paths, and (when models have percentiles) the primary html_link plus transport-specific html_url / html_path — the just-prs trait HTML report (same page as prs plot trait -o *.html). Pass result_paths to compare_genomes (2+), plot_trait_panel, or build_prs_prompt.

Profile (curation): profile="all" (default) returns the raw associated panel. profile="curated" is the interpreted shortlist — it drops toy scores (<10 variants), scores with no performance evidence, scores below the C_wt coverage floor, and de-dups score families.

interpret=True (default) attaches percentiles/quality per model. Set interpret=False for raw scores only — the report then says so. reference_restoration defaults to "auto". superpopulation may be a 1000G code or "auto". Set include_prompt=True to also attach the just-prs LLM prompt covering every genome in this call.

This tool returns a PRSJob immediately. If status is queued or running, call prs_job_status(job_id, wait_seconds=25) until done or failed. Do not start a second identical compute — the server reuses the in-flight job. When done, html_link and result (TraitPRSReports) are on the job. Native multi-score work is isolated in a child process so a DuckDB/Polars crash fails the batch without killing the MCP transport.

Inputs: samples (required), trait_id (required), build, limit, +13 more. Returns: A long compute/download job that Cursor can poll without blocking tools/call.

download_sample_genomeDownload sample genomeA
Idempotent

Download a public sample WGS VCF from Zenodo to try PRS without your own data.

Two whole-genome sequencing (WGS) datasets open-sourced by the just-dna-lite project are pre-configured — download both when you want a multi-person comparison:

  • sample="anton" — Anton Kulaga's genome (~482 MB, CC0 public domain, Zenodo record 18370498, file: antonkulaga.vcf).

  • sample="livia" — Livia Zaharia's genome (~349 MB, CC-BY-4.0, Zenodo record 19487816, file: SIMHIFQTILQ.hard-filtered.vcf.gz).

Pass record_url (e.g. 'https://zenodo.org/records/18370498') to fetch any other Zenodo record, and filename to pick a specific file when a record has several.

The downloaded VCF lands under <cache_dir>/samples/ (or output_dir) and is a drop-in path for normalize_vcf / compute_prs / compute_prs_by_trait (including samples=["Anton=<path>", ...]).

auto_normalize defaults to True: the download is normalized to a reusable Parquet in the same call, so data carries both path (the raw VCF) and normalized_path — a one-call, compute-ready genotype source with no separate normalize_vcf round-trip. (Normalization is idempotent, so a re-download of an already-staged sample is cheap.) Pass auto_normalize=False to fetch the raw VCF only.

Use list_genomes to see which genomes have already been downloaded and/or normalized.

Idempotent: if the target VCF already exists with the size Zenodo reports, the ~hundreds-of-MB download is skipped and the cached file is reused; likewise a present Parquet skips re-normalization. data echoes reused_cache (download skipped) and downloaded_bytes (bytes actually transferred, 0 on a cache hit) so the caller can tell a cache hit from a fresh fetch. Pass force=True to re-download/re-normalize regardless.

Returns a PRSJob immediately. When done, result is an OpResult whose data carries the local path. Poll prs_job_status if status is still running — the download is hundreds of MB.

Inputs: force, sample, filename, output_dir, +2 more. Returns: A long compute/download job that Cursor can poll without blocking tools/call.

list_genomesList genomesA
Read-onlyIdempotent

List genomes available in the server's cache directory.

Scans <cache_dir>/samples/ for downloaded raw VCF files and <cache_dir>/normalized/ for normalized Parquet files. Also lists the pre-configured sample genomes that can be downloaded via download_sample_genome (even if not yet downloaded).

Use this to discover genomes you can score or compare (Anton + Livia are the built-in pair):

  • Which genomes have already been downloaded (ready for direct scoring).

  • Which genomes have already been normalized (ready for compute_prs / compute_prs_by_trait as an optional reusable fast path).

  • Which pre-configured samples are available for download.

No network access required — reads the local filesystem only.

Inputs: no named parameters. Returns: Inventory of genomes present in the server's cache directory.

list_prs_jobsList PRS jobsA
Read-onlyIdempotent

List recent scoring/download jobs on this server process.

Use after a client timeout to recover the job_id instead of starting the same compute again.

Inputs: no named parameters. Returns: In-flight and recent jobs on this server process.

normalize_vcfNormalize VCFA
Idempotent

Normalize a VCF to a quality-filtered genotype Parquet.

This tool is optional preprocessing, not a prerequisite for scoring: compute_prs, compute_prs_batch, and compute_prs_by_trait accept raw VCF paths directly. Use normalization when you intentionally want a reusable Parquet for many later analyses or custom quality filters. Before normalizing, list_genomes can show whether a cached Parquet already exists.

Strips the chr prefix, renames id→rsid, computes genotype from GT, applies optional quality filters (FILTER allow-list, min DP, min QUAL), and writes zstd-compressed Parquet. The output is a drop-in genotype source for compute_prs / compute_prs_batch (genotypes_path) and for compute_prs_by_trait (a samples entry ending in .parquet), so each VCF is normalized once and reused. Normalize every genome you plan to compare; scoring still happens per genome.

Idempotent: if the target Parquet already exists it is reused and the (slow) normalization is skipped — reused_cache=True flags the hit. Custom filters (pass_filters / min_depth / min_qual / sex) always re-run, since the cached Parquet may not reflect them. Pass force=True to re-normalize unconditionally.

Normalization is the slow step (seconds to minutes depending on VCF size). Returns a PRSJob immediately; poll prs_job_status when status is running. When done, result is a NormalizeResult.

Inputs: vcf_path (required), sex, force, min_qual, +4 more. Returns: A long compute/download job that Cursor can poll without blocking tools/call.

percentilePRS percentileA
Read-onlyIdempotent

Estimate the population percentile (0-100) for a computed PRS value.

Uses the 3-tier fallback: precomputed reference-panel distributions (best), then a theoretical distribution, then an AUROC approximation. superpopulation is a 1000G code (AFR/AMR/EAS/EUR/SAS) and should match that genome's ancestry — when comparing people, call this once per score×genome (or rely on compute_prs_by_trait(interpret=True)). Pass weight_mass_coverage (C_wt) from compute_prs so a deflated low-coverage percentile is flagged reliable=False with a caveat instead of presented as authoritative. Also returns the true z-score and reference mean/std used, so absolute risk can be computed without inverting the percentile.

Important next step: for disease traits, feed the returned z_score directly into absolute_risk to get the concrete lifetime probability and risk ratio vs the population average. This is more informative than the percentile alone.

Inputs: pgs_id (required), prs_score (required), panel, superpopulation, +1 more. Returns: Estimated population percentile for a PRS score.

plot_trait_panelPlot trait panel (give user html_link)A
Idempotent

Write the just-prs trait HTML report and return a URL or file path.

REQUIRED REPORT DELIVERY: when html_link is set, your reply MUST include it as a markdown link (for example Open the interactive trait report) and explicitly tell the user to open it. This is the primary user-facing result, not an implementation detail. Do not skip the link, merely say the report was saved, fetch it, or paste the HTML. html_link is an HTTP URL when available and a file:// URI on local stdio.

This is the MCP equivalent of prs plot trait ... -o intel_o_family.html: just_prs.viz.plot_trait_scores + save_trait_report. The page has the Vega-Lite panel, median cards, model table, and Ask-AI buttons. result_paths is always a list (one genome is fine; two or more overlay people). On Streamable HTTP html_url is served from this same origin at /reports/<file> with no extra config.

Inputs: result_paths (required), panel, ancestry, model_scope, +2 more. Returns: A just-prs trait HTML report written to disk. Same standalone page as ``prs plo…

prs_job_statusPRS job statusA
Read-onlyIdempotent

Poll a long scoring/download job started by this server.

compute_prs_by_trait, compute_prs_batch, normalize_vcf, and download_sample_genome return a PRSJob instead of blocking. Call this with that job_id. wait_seconds=25 waits inside one call (safe for Cursor) and returns as soon as the job finishes. When status is done, read html_link and result.

Inputs: job_id (required), wait_seconds. Returns: A long compute/download job that Cursor can poll without blocking tools/call.

score_infoScore metadataA
Read-onlyIdempotent

Get cleaned metadata for a single PGS score by its ID (e.g. 'PGS000001').

Inputs: pgs_id (required). Returns: A row from the cleaned PGS Catalog scores metadata.

search_scoresSearch PGS scoresA
Read-onlyIdempotent

Search the PGS Catalog for polygenic scores by free text.

Case-insensitive substring match across PGS ID, score name, reported trait, and EFO trait. Optionally filter to a genome build (GRCh37 / GRCh38, harmonized cross-build scores included). Returns up to limit matches with their key metadata.

Inputs: query (required), limit, genome_build. Returns: result

search_traitsSearch traitsA
Read-onlyIdempotent

Search the PGS Catalog REST API for traits by term.

Upstream matching is exact-substring over labels and synonyms, so this wrapper retries a few punctuation/order variants when the first query is empty. By default, results include counts of directly associated PGS IDs and child-trait PGS IDs; set include_pgs_ids for the full arrays.

Inputs: term (required), limit, include_pgs_ids. Returns: result

trait_infoTrait infoA
Read-onlyIdempotent

Fetch a trait by ontology ID (EFO or MONDO) with its associated PGS IDs.

Inputs: efo_id, trait_id. Returns: Trait metadata from PGS Catalog REST API.

vcf_metainfoVCF meta-infoA
Read-onlyIdempotent

Detect a genome's build, input type (WGS/array/gVCF), and genetic ancestry.

One call that pairs WGS-vs-array/gVCF detection with population (super-population) inference, so before scoring you already know: the genome build (read from the VCF header), whether the input is whole-genome sequencing, a consumer genotyping array (and which chip), or a gVCF / all-sites callset, and the sample's inferred super-population.

Pass genotypes_path (a normalized Parquet from normalize_vcf / download_sample_genome) for the fast path, or a raw vcf_path. Genome-build detection reads the VCF header, so it is only available on the vcf_path branch.

The result carries ready-to-use recommendations: recommended_reference_restoration (feed to compute_prs / compute_prs_batch / compute_prs_by_trait as reference_restoration — though those tools default to "auto" and derive the same thing) and recommended_superpopulation (feed as superpopulation). Set infer_population=False to skip ancestry inference (it pulls a small model from HuggingFace on first use).

Inputs: panel, vcf_path, resolution, genome_build, +2 more. Returns: Detected properties of a VCF / normalized genotype set. Pairs WGS-vs-array/gVCF…

Tool Schema Changelog

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

Loading tool schema changelog…

    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

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Federates 13 gene-related MCP backends (gnomAD, GTEx, etc.) behind a single Streamable HTTP endpoint with collision-free namespacing and search-based tool discovery.
      7
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      MCP server for querying the GWAS Catalog (EBI/NHGRI), a curated catalog of genome-wide association studies. It enables AI agents to search and retrieve study data via natural language or direct tool calls.
      127 npm
      MIT