opencode-bioresearcher 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +103 -0
  3. package/agents/bioresearcher-dr-worker.md +54 -0
  4. package/connector-meta.json +23 -0
  5. package/index.js +77 -0
  6. package/loader.js +3 -0
  7. package/package.json +42 -0
  8. package/skill-bundle.json +12 -0
  9. package/skills/bioresearcher-deep-research/SKILL.md +330 -0
  10. package/skills/bioresearcher-deep-research/references/analysis-methods.md +90 -0
  11. package/skills/bioresearcher-deep-research/references/article-literature.md +89 -0
  12. package/skills/bioresearcher-deep-research/references/best-practices.md +102 -0
  13. package/skills/bioresearcher-deep-research/references/citations.md +146 -0
  14. package/skills/bioresearcher-deep-research/references/clinical-trials.md +87 -0
  15. package/skills/bioresearcher-deep-research/references/diseases.md +94 -0
  16. package/skills/bioresearcher-deep-research/references/drugs.md +88 -0
  17. package/skills/bioresearcher-deep-research/references/ensembl-pdb.md +134 -0
  18. package/skills/bioresearcher-deep-research/references/functional-genomics.md +118 -0
  19. package/skills/bioresearcher-deep-research/references/genes.md +93 -0
  20. package/skills/bioresearcher-deep-research/references/optional-analysis.md +108 -0
  21. package/skills/bioresearcher-deep-research/references/patents.md +92 -0
  22. package/skills/bioresearcher-deep-research/references/rate-limiting-auth.md +95 -0
  23. package/skills/bioresearcher-deep-research/references/report-template.md +117 -0
  24. package/skills/bioresearcher-deep-research/references/tool-selection.md +142 -0
  25. package/skills/bioresearcher-deep-research/references/utility-config.md +116 -0
  26. package/skills/bioresearcher-deep-research/references/variants.md +109 -0
  27. package/skills/bioresearcher-deep-research/references/worker-protocol.md +110 -0
  28. package/skills/bioresearcher-deep-research/scripts/markdown-to-html.py +86 -0
  29. package/skills/bioresearcher-plot-making/SKILL.md +97 -0
  30. package/skills/bioresearcher-plot-making/references/literature-search-method-summary.md +163 -0
  31. package/skills/bioresearcher-plot-making/references/qa-gates-and-gotchas.md +156 -0
  32. package/skills/bioresearcher-plot-making/references/structural-biology-binder-visualization.md +206 -0
  33. package/skills/bioresearcher-plot-making/scripts/audit_figure_collisions.py +742 -0
  34. package/skills/bioresearcher-plot-making/scripts/audit_panel_alignment.py +935 -0
  35. package/skills/bioresearcher-plot-making/scripts/audit_pdf_text.py +152 -0
  36. package/skills/bioresearcher-plot-making/scripts/plot_helpers.py +177 -0
  37. package/skills/bioresearcher-pubmed-weekly/SKILL.md +223 -0
  38. package/skills/bioresearcher-pubmed-weekly/scripts/parse_updatefiles.py +272 -0
  39. package/skills/bioresearcher-pubmed-weekly/scripts/pubmed_weekly.py +493 -0
  40. package/skills/bioresearcher-python-setup-uv/SKILL.md +184 -0
@@ -0,0 +1,93 @@
1
+ # Gene Research
2
+
3
+ Gene discovery, annotation, cross-links, and pathway enrichment via
4
+ `gene_search` / `gene_get` and the `gene_*` family.
5
+
6
+ ## Overview
7
+
8
+ `gene_search` finds genes by symbol/name/keyword (MyGene-backed);
9
+ `gene_get` returns rich per-gene annotation with selectable sections;
10
+ cross-link tools connect a gene to diseases, drugs, trials, and articles;
11
+ `gene_enrich` runs Reactome pathway enrichment on a gene list.
12
+
13
+ ## Tools
14
+
15
+ ### gene_search
16
+
17
+ | Parameter | Type | Notes |
18
+ |-----------|------|-------|
19
+ | query | string (required) | Gene symbol, name, or keyword |
20
+ | chromosome | string, optional | e.g. "7", "X" |
21
+ | limit | int 1-50, default 10 | Maximum results |
22
+ | offset | int >= 0, default 0 | Result offset |
23
+
24
+ ### gene_get
25
+
26
+ | Parameter | Type | Notes |
27
+ |-----------|------|-------|
28
+ | symbol | string (required) | OFFICIAL HGNC symbol only (e.g. "BRAF", "TP53", "ERBB2"); aliases like "HER2"/"NEU" rejected unless `smart: true` |
29
+ | sections | enum array, optional | `core`, `pathways`, `ontology`, `diseases`, `protein`, `go`, `interactions`, `clinical_evidence`, `expression`, `protein_atlas`, `druggability`, `dosage_sensitivity`, `constraint`, `disease_associations`, `funding`, `all` |
30
+ | limit | int 1-100, default 20 | Caps array lengths per section |
31
+ | smart | boolean, default false | When true, resolves aliases/common names to the official HGNC symbol first (e.g. "HER2" -> "ERBB2"); zero overhead for valid symbols |
32
+
33
+ Section highlights: `protein` (UniProt), `pathways` (Reactome),
34
+ `clinical_evidence` (CIViC variants), `expression` + `protein_atlas` (Human
35
+ Protein Atlas - see pacing note below), `druggability` (DGIdb),
36
+ `disease_associations` (DisGeNET - needs key), `dosage_sensitivity` (ClinGen),
37
+ `constraint` (gnomAD pLI), `funding` (NIH Reporter grants).
38
+
39
+ ### Cross-link and enrichment tools
40
+
41
+ | Tool | Parameters | Notes |
42
+ |------|-----------|-------|
43
+ | gene_diseases | symbol, limit (1-50, default 10) | DisGeNET associations NEED `DISGENET_API_KEY`; without it the tool falls back to OpenTargets gene-disease associations |
44
+ | gene_drugs | symbol | Drugs targeting the gene |
45
+ | gene_trials | symbol | Clinical trials referencing the gene |
46
+ | gene_articles | symbol | Articles about the gene (relevance search, no recency sort) |
47
+ | gene_enrich | genes (list of HGNC symbols) | Reactome pathway enrichment; returns `_error` row on failure |
48
+
49
+ ## Worked examples
50
+
51
+ Resolve an alias and pull focused annotation:
52
+
53
+ ```json
54
+ {"symbol": "HER2", "smart": true, "sections": ["core", "druggability", "clinical_evidence"]}
55
+ ```
56
+
57
+ Search by chromosome:
58
+
59
+ ```json
60
+ {"query": "kinase", "chromosome": "7", "limit": 15}
61
+ ```
62
+
63
+ Disease associations via the fallback path (no DisGeNET key):
64
+
65
+ ```json
66
+ {"symbol": "BRCA1", "limit": 10}
67
+ ```
68
+
69
+ Enrichment on a hit list:
70
+
71
+ ```json
72
+ {"genes": ["BRAF", "NRAS", "MAP2K1", "MAPK1"]}
73
+ ```
74
+
75
+ ## Failure modes
76
+
77
+ | Symptom | Cause | Fix |
78
+ |---------|-------|-----|
79
+ | gene_get error: not a valid HGNC symbol | alias or outdated name used | pass the official symbol, or set `smart: true` |
80
+ | gene_diseases returns `_error` re DisGeNET | `DISGENET_API_KEY` missing | the tool already fell back to OpenTargets data; add the key for DisGeNET-grade associations |
81
+ | HPA sections slow/erroring when iterating many genes | `protein_atlas`/`expression` use an unthrottled raw fetch | pace these calls manually; other sections are server-limited |
82
+ | gene_enrich single `_error` row | Reactome AnalysisService rejected the input | check symbols are valid HGNC; retry with a smaller list |
83
+
84
+ ## Integration notes
85
+
86
+ - Typical chain: `gene_search` (discovery) -> `gene_get` (annotation) ->
87
+ `gene_diseases`/`gene_drugs`/`gene_trials` (cross-links) -> `trial_get` /
88
+ `article_get` for depth.
89
+ - `gtex_expression`/`gtex_eqtl` (references/functional-genomics.md) extend
90
+ gene expression questions with tissue profiles.
91
+ - `ensembl_lookup` (references/ensembl-pdb.md) is the identifier/structure
92
+ authority (stable IDs, coordinates, transcripts) for ANY Ensembl species.
93
+ - MyGene is server-limited at 100 ms - no manual throttling.
@@ -0,0 +1,108 @@
1
+ # Optional Analysis Tools
2
+
3
+ Environment-gated analysis: SQL database access (3 tools), R/Bioconductor
4
+ differential expression (4 tools), and biowasm BAM/VCF/BED pipelines
5
+ (8 tools). All register ONLY when their env gate is set at server start.
6
+
7
+ ## Overview
8
+
9
+ These 15 tools extend biomcp beyond retrieval into local-data analysis. They
10
+ are optional: without `DB_TYPE`, `ANALYSIS_R=1`, or `ANALYSIS_BIOWASM=1` set
11
+ in the client env block, they do not exist (calls return `no_such_tool`).
12
+
13
+ ## Database tools (gate: DB_TYPE=mysql or sqlite)
14
+
15
+ | Tool | Parameters | Notes |
16
+ |------|-----------|-------|
17
+ | db_list_tables | none | Lists databases/aliases, tables, row counts; call FIRST |
18
+ | db_describe_table | table_name | Column schema; qualify attached SQLite dbs as `alias.table` |
19
+ | db_query | sql, params? | READ-ONLY: only SELECT/SHOW/DESCRIBE/EXPLAIN/WITH allowed; named params `:name` passed via `params` |
20
+
21
+ ```json
22
+ {"sql": "SELECT gene_symbol, COUNT(*) AS n FROM variants
23
+ WHERE significance = :sig GROUP BY gene_symbol LIMIT 20",
24
+ "params": {"sig": "pathogenic"}}
25
+ ```
26
+
27
+ MySQL additionally needs DB_HOST/DB_USER/DB_PASSWORD/DB_DATABASE and the
28
+ `mysql2` peer dependency (`-p mysql2@3` in the client command); SQLite needs
29
+ DB_SQLITE_PATH (comma-separated; first = main, rest attached read-only,
30
+ enabling `alias.table` cross-database JOINs).
31
+
32
+ ## R analysis tools (gate: ANALYSIS_R=1, needs webr peer `-p webr@0.6`)
33
+
34
+ | Tool | Purpose |
35
+ |------|---------|
36
+ | analysis_r_deseq2 | DESeq2 negative-binomial DE (params: alpha, fit_type, shrink) |
37
+ | analysis_r_edger | edgeR TMM + quasi-likelihood/exact (param: test=qlm/exact) |
38
+ | analysis_r_limma | limma-voom precision-weighted linear models |
39
+ | analysis_r_session_info | Runtime diagnostics (R/Wasm versions, package versions, memory) |
40
+
41
+ Shared input schema: `counts` (genes x samples integer matrix), `coldata`
42
+ (per-sample metadata), `design` (R formula, e.g. "batch + condition"),
43
+ `contrast` {variable, numerator, denominator} or `coef`, `top_n`
44
+ (default 50), `include_full`, `format` ("json" for structured output).
45
+
46
+ COLD START: the first call starts a ~1 GB WebAssembly R worker and downloads
47
+ a ~62 MB package bundle - MINUTES, not seconds. Set the client MCP timeout to
48
+ 120000 (ms) once R analysis is enabled, or pre-warm from bash before asking
49
+ the client. Later calls reuse the warm worker (seconds).
50
+
51
+ ## Biowasm tools (gate: ANALYSIS_BIOWASM=1; npx-only, nothing to install)
52
+
53
+ | Tool | Purpose |
54
+ |------|---------|
55
+ | analysis_bam_summary | Alignment triage: contigs, flagstat, idxstats |
56
+ | analysis_bam_view_region | Reads/depth/pileup in a region (mode=count/depth/pileup/reads) |
57
+ | analysis_bcf_summary | VCF/BCF triage: counts, samples, INFO/FORMAT inventory |
58
+ | analysis_bcf_view_region | Region variant projection (column pick, sample subset, filter) |
59
+ | analysis_bed_op | bedtools intersect/merge/subtract/coverage/jaccard/sort |
60
+ | analysis_biowasm_convert | Format plumbing: SAM/BAM/CRAM/VCF/BCF/TSV conversion |
61
+ | analysis_biowasm_session_info | Runtime report (tool versions, cache, artifacts) |
62
+ | analysis_biowasm_cli | Escape hatch: allowlisted samtools/bedtools/bcftools subcommand (max 32 args, no shell) |
63
+
64
+ Source inputs accept inline `content`, a prior `artifact_id`, or a
65
+ `host_path` under `ANALYSIS_BIOWASM_DATA_DIR` (unset = host files denied).
66
+ Output `format`: "table" (markdown, `top_n` rows, 2 MB cap), "json", or
67
+ "artifact" (handle + preview; reusable as the next call's `artifact_id`).
68
+ `top_n` max is 200 (default 50).
69
+
70
+ ARTIFACT THREADING: multi-step pipelines pass `artifact_id` between calls,
71
+ e.g. bam_view_region(format="artifact") -> biowasm_convert(to="SAM") ->
72
+ bam_summary. This keeps bulky data server-side and out of context.
73
+
74
+ ## Worked examples
75
+
76
+ ```json
77
+ {"sql": "SELECT * FROM gene_effect WHERE gene_symbol = :g LIMIT 50",
78
+ "params": {"g": "KRAS"}}
79
+ ```
80
+
81
+ ```json
82
+ {"source": {"artifact_id": "art_abc123"}, "mode": "count", "region": "chr7:140453000-140453500"}
83
+ ```
84
+
85
+ ```json
86
+ {"source": {"content": "chr1\t10\t20\nchr1\t100\t200\n"}, "op": "merge"}
87
+ ```
88
+
89
+ ## Failure modes
90
+
91
+ | Symptom | Cause | Fix |
92
+ |---------|-------|-----|
93
+ | `no_such_tool` | env gate unset, or set after server start | set DB_TYPE/ANALYSIS_R/ANALYSIS_BIOWASM, restart client |
94
+ | First R call fails client-side despite healthy machine | cold bootstrap runs minutes; client timeout too low | raise client timeout to 120000 or pre-warm from bash |
95
+ | R bundle download times out | slow link vs download budget | raise `features.analysis_r.asset_timeout_ms` via biomcp_configure or self-fetch the bundle (see ENV-VARS docs) |
96
+ | db_query rejected | non-SELECT statement | only SELECT/SHOW/DESCRIBE/EXPLAIN/WITH are allowed |
97
+ | host_path denied | ANALYSIS_BIOWASM_DATA_DIR unset | set it to the allowlisted root directory |
98
+ | webr/mysql2 missing while install_mode is npx-cache | peers invisible to npx cache | use a client command carrying `-p webr@0.6` and/or `-p mysql2@3` |
99
+
100
+ ## Integration notes
101
+
102
+ - GEO workflow: `geo_get(download=true)` -> load counts -> `analysis_r_*`.
103
+ - Large-input guards: estimate-gated tools return guidance; re-run with
104
+ `proceed_on_large_input: true` to stream (progress reported).
105
+ - Worker pool: `ANALYSIS_BIOWASM_WORKERS` (default 1 = serial); memory limits
106
+ default 2048 MB RSS watermark.
107
+ - Full guides: R-ANALYSIS.md / BIOWASM-ANALYSIS.md / DATABASE.md in the
108
+ biomcp-ts docs.
@@ -0,0 +1,92 @@
1
+ # Patent Research
2
+
3
+ Worldwide patent search and detail via `patent_search` / `patent_get`
4
+ (USPTO Public Search, USPTO ODP, EPO OPS, Google Patents backends).
5
+
6
+ ## Overview
7
+
8
+ `patent_search` runs multi-backend patent search with automatic seminal
9
+ prior-art mining; `patent_get` retrieves one patent by publication number with
10
+ claims, citations, family, and classifications. These tools are slower than
11
+ the biomedical ones: search is bounded at 60 s, detail at 120 s.
12
+
13
+ ## Tools
14
+
15
+ ### patent_search
16
+
17
+ | Parameter | Type | Notes |
18
+ |-----------|------|-------|
19
+ | query | string (required) | Free text; QUOTE exact multi-word concepts, e.g. "\"mRNA display\"" - unquoted phrases drift off-topic |
20
+ | assignee | string, optional | Assignee/applicant org, e.g. "Moderna" |
21
+ | inventor | string, optional | Inventor name |
22
+ | cpc | string, optional | Full CPC symbol, e.g. "C12N15/11" |
23
+ | status | enum, optional | `granted` / `application` |
24
+ | date_range | string, optional | `YYYY-MM-DD/YYYY-MM-DD`, either side may be empty |
25
+ | limit | int 1-50, default 10 | Maximum results |
26
+ | offset | int >= 0, default 0 | Pagination |
27
+ | source | enum, optional | Force backend: `ppubs` (USPTO Public Search, US full-text, keyless, default US), `ops` (EPO OPS worldwide bibliographic; needs EPO keys), `uspto_odp` (US application metadata; needs USPTO_API_KEY), `google_patents` (best-effort, often unavailable) |
28
+ | sort_by | enum, optional | `relevance` (default) / `recency` - currently affects the ppubs backend only |
29
+ | seminal | boolean, optional, default true | Co-citation mining of top results to surface foundational prior art in `seminal_prior_art`; adds ~5-30 s - set `false` for the fastest bibliographic lookups |
30
+
31
+ Default (no `source`) "auto" mode: queries worldwide + ppubs concurrently; if
32
+ ppubs fails hard it falls back to uspto_odp once (tagged `_note`).
33
+
34
+ ### patent_get
35
+
36
+ | Parameter | Type | Notes |
37
+ |-----------|------|-------|
38
+ | patent_id | string (required) | Publication number, e.g. "US11027025B2", "EP3904939B1", "US20260240819A1" |
39
+ | sections | enum array, optional | `core`, `abstract`, `claims`, `citations`, `family`, `classifications`, `all`; default core only |
40
+ | limit | int 1-100, default 20 | Max entries per section array |
41
+
42
+ Claims detail: US full text via USPTO Public Search; EP/WO claims via EPO OPS
43
+ which REQUIRES `EPO_OPS_CONSUMER_KEY` + `EPO_OPS_CONSUMER_SECRET` (both, set
44
+ together).
45
+
46
+ ## Worked examples
47
+
48
+ Fast bibliographic landscape (skip seminal mining):
49
+
50
+ ```json
51
+ {"query": "\"mRNA display\" peptide library", "assignee": "Moderna",
52
+ "seminal": false, "limit": 20}
53
+ ```
54
+
55
+ Foundational prior-art discovery (default behavior):
56
+
57
+ ```json
58
+ {"query": "CRISPR base editing", "date_range": "2015-01-01/", "limit": 15}
59
+ ```
60
+
61
+ Force worldwide search via EPO OPS (keys set):
62
+
63
+ ```json
64
+ {"query": "chimeric antigen receptor", "source": "ops", "limit": 20}
65
+ ```
66
+
67
+ Pull claims and citations for a specific patent:
68
+
69
+ ```json
70
+ {"patent_id": "US11027025B2", "sections": ["abstract", "claims", "citations"]}
71
+ ```
72
+
73
+ ## Failure modes
74
+
75
+ | Symptom | Cause | Fix |
76
+ |---------|-------|-----|
77
+ | Search exceeds 60 s budget / times out | seminal mining + multi-backend fan-out on a broad query | set `seminal: false`, quote multi-word concepts, narrow with `assignee`/`cpc`/`date_range` |
78
+ | patent_get exceeds 120 s / times out | claims fetch across slow backends | request fewer sections (drop `family`/`citations` if unneeded), retry once |
79
+ | EP/WO claims missing or error mentioning EPO | EPO OPS keys absent | set `EPO_OPS_CONSUMER_KEY` + `EPO_OPS_CONSUMER_SECRET` together, or accept abstract-only detail |
80
+ | google_patents source fails | backend often unavailable | rely on ppubs (US) or ops (worldwide with keys) |
81
+ | Off-topic results | unquoted multi-word concepts | quote the exact phrase in `query` |
82
+
83
+ ## Integration notes
84
+
85
+ - Auto-mode `_note` fields flag backend fallbacks - mention data lineage in
86
+ the report when present.
87
+ - EPO OPS and USPTO are server-limited at ~1 s token buckets - no manual
88
+ throttling; expect patent tools to be the slowest calls in an aspect.
89
+ - Cite patents by publication number with a Google Patents or Espacenet URL
90
+ (references/citations.md).
91
+ - Link patents to literature: `seminal_prior_art` entries often carry patent
92
+ and paper citations that map to `article_get` inputs.
@@ -0,0 +1,95 @@
1
+ # Rate Limiting & Auth
2
+
3
+ biomcp enforces server-side per-source rate limiters, so workers do NOT need
4
+ manual sleep timers between calls. This file lists the limiters, the
5
+ exceptions that DO need pacing, and every auth variable.
6
+
7
+ ## Overview
8
+
9
+ Every ConnectionManager-backed source has a token-bucket limiter applied
10
+ inside the server (src/connections/registry.ts). Sequential calls from a
11
+ worker are automatically paced. Manual `sleep`/timer logic between biomcp
12
+ calls is unnecessary and slows research down - drop the old 0.3 s/0.5 s
13
+ worker rules from earlier agent generations.
14
+
15
+ ## Server-side limiter table (per source)
16
+
17
+ | Source (tools affected) | Interval | Notes |
18
+ |------------------------|----------|-------|
19
+ | eutils - SHARED by PubMed/GEO/SRA/GenBank (article_search, geo_*, sra_*, genbank_*) | 334 ms keyless; 100 ms with NCBI_API_KEY | One budget across ALL NCBI E-utilities databases (conditional limiter); server also retries 4x |
20
+ | pubtator (article_search source=pubtator) | 334 ms keyless; 100 ms keyed | |
21
+ | MyGene (gene_search/gene_get) | 100 ms | |
22
+ | MyVariant (variant_*) | 100 ms | |
23
+ | MyChem (drug_*) | 100 ms | |
24
+ | MyDisease (disease_*) | 100 ms | |
25
+ | OpenTargets (disease_drugs, gene_diseases fallback) | 500 ms | |
26
+ | ClinicalTrials.gov (trial_search/trial_get, *_trials) | 100 ms | |
27
+ | Ensembl REST (ensembl_*) | 100 ms | Server retries transient 500/503s 3x |
28
+ | RCSB PDB (pdb) | 100-200 ms | |
29
+ | Semantic Scholar (article_search source=semantic_scholar) | 2000 ms keyless; 1000 ms keyed (S2_API_KEY) | |
30
+ | LitSense / OpenCitations / NIH Reporter | 1000 ms | |
31
+ | Crossref (citation data) | 100 ms | Polite pool with CROSSREF_EMAIL |
32
+ | Google Patents (patent fallback backend) | 2000 ms | |
33
+ | EPO OPS (patent_search/patent_get ops backend) | ~1 s token bucket | |
34
+ | USPTO PPUBS + ODP (patent US backends) | ~1 s token bucket | |
35
+ | GTEx (gtex_*) | 100 ms | |
36
+
37
+ ## Exceptions - pace these manually
38
+
39
+ 1. **HPA raw fetch**: the `protein_atlas` and `expression` sections of
40
+ `gene_get` call proteinatlas.org via a raw (unthrottled) fetch. When
41
+ iterating these sections over many genes, space the calls yourself.
42
+ 2. **GEO supplementary downloads**: `geo_get(download=true)` fetches files
43
+ via raw fetch (not the limiter). Pace repeated downloads; each is also
44
+ capped by `max_bytes` (default 50 MB).
45
+
46
+ Everything else: call sequentially, no timers.
47
+
48
+ ## Timeout reference
49
+
50
+ | Tool | Budget |
51
+ |------|--------|
52
+ | article_search / article_get | 30 s |
53
+ | patent_search | 60 s |
54
+ | patent_get | 120 s |
55
+ | Per-source HTTP timeout (most sources) | 15 s |
56
+ | R analysis first call | minutes (cold start) - set client MCP timeout 120000 |
57
+
58
+ ## Auth table
59
+
60
+ ### Required (tool fails without them)
61
+
62
+ | Variable | Unlocks | Without it |
63
+ |----------|---------|-----------|
64
+ | `ONCOKB_TOKEN` | `variant_oncokb` precision-oncology annotations | Tool errors; use variant_get clinical section instead (register: oncokb.org/account/register) |
65
+ | `DISGENET_API_KEY` | DisGeNET disease-gene associations | `gene_diseases` falls back to OpenTargets associations (soft degradation, note lineage in reports) |
66
+
67
+ ### Optional (higher limits / extra backends)
68
+
69
+ | Variable | Effect |
70
+ |----------|--------|
71
+ | `NCBI_API_KEY` | NCBI E-utilities rate: 3 -> 10 req/s (eutils limiter 334 -> 100 ms). Recommended for literature-heavy research |
72
+ | `NCBI_EMAIL` | Polite tool/email parameters on E-utilities requests |
73
+ | `S2_API_KEY` | Semantic Scholar higher limits (2 s -> 1 s interval) |
74
+ | `OPENFDA_API_KEY` | openFDA higher upstream limits (drug_get regulatory/FAERS sections; unlike NCBI_API_KEY this does not change the in-process limiter interval) |
75
+ | `CROSSREF_EMAIL` | Crossref polite pool - faster citation metadata |
76
+ | `EPO_OPS_CONSUMER_KEY` + `EPO_OPS_CONSUMER_SECRET` | EPO OPS patent backend: worldwide search + EP/WO claims (BOTH must be set together) |
77
+ | `USPTO_API_KEY` | USPTO Open Data Portal application search backend |
78
+
79
+ Set keys in the MCP client's env block (opencode: `environment`; Claude/
80
+ Codex: `env`), then restart the client - config changes never apply live.
81
+
82
+ ## Keyless fallback behavior
83
+
84
+ - Patents: US search works keyless via USPTO Public Search (ppubs default US
85
+ backend); Google Patents is a best-effort fallback.
86
+ - Drug regulatory/FAERS data works keyless (lower limits).
87
+ - Literature works keyless across all five federated sources.
88
+
89
+ ## Integration notes
90
+
91
+ - The worker rule is simply: sequential calls, no sleep timers; pace only the
92
+ HPA and GEO-download exceptions.
93
+ - If a client ever reports HTTP 429 despite the limiters, back off for a few
94
+ seconds and retry once (see worker-protocol.md retry ladder).
95
+ - Keys live in the client env block, never in reports or committed files.
@@ -0,0 +1,117 @@
1
+ # Report Template
2
+
3
+ Mandatory structure for `final_report.md` (and the per-aspect files, in
4
+ lighter form). Ported from the bioresearcher agent's report standard.
5
+
6
+ ## Overview
7
+
8
+ Every report has exactly SIX mandatory sections, in this order. Every claim
9
+ carries provenance: a citation [N], a documented data source, or a described
10
+ analysis method.
11
+
12
+ ## Mandatory sections
13
+
14
+ ```markdown
15
+ # [Research Topic Title]
16
+
17
+ Generated: [YYYY-MM-DD] | TOPIC: <TOPIC> | Scope: [1-2 sentence research question]
18
+
19
+ ## Executive Summary
20
+ [2-3 sentence overview of key findings with the most critical citations [1, 2]]
21
+
22
+ Key findings:
23
+ - [Finding 1 [1]]
24
+ - [Finding 2 [2, 3]]
25
+ - [Finding 3 [4]]
26
+
27
+ ## Data Sources
28
+ [Table: source | type | query/accession | date accessed]
29
+ [Scope: records retrieved, date range, filters applied]
30
+ [Quality notes: gaps, known biases]
31
+
32
+ ## Analysis Methodology
33
+ [Aspects researched and how (worker/sequential mode)]
34
+ [Tools used per aspect with key query parameters]
35
+ [Validation steps and error handling (retries, fallbacks)]
36
+
37
+ ## Findings
38
+ [Organized by research question; each subsection = one theme]
39
+ [Key data points with confidence and citation: metric | value | confidence | source]
40
+ [Evidence tables where numeric comparisons exist]
41
+
42
+ ## Limitations
43
+ [Data gaps: what could not be found and why]
44
+ [Methodological constraints: source coverage, date windows, auth-gated tools skipped]
45
+ [Generalizability: where findings apply and where they may not]
46
+
47
+ ## References
48
+ [Numbered bibliography in references/citations.md format, ordered by first appearance]
49
+ ```
50
+
51
+ ## Per-aspect file structure (lighter)
52
+
53
+ ```markdown
54
+ # [Aspect Name] (TOPIC: <TOPIC>)
55
+
56
+ Scope: [1 paragraph from the worker ABSTRACT]
57
+
58
+ ## Findings
59
+ [Findings with in-text citations [1], [2, 3]]
60
+
61
+ ## Tool / Query Log
62
+ [tool + key arguments, e.g. article_search(query="...", dateRange="2021-01-01/", limit=15)]
63
+
64
+ ## Evidence Gaps
65
+ [queries that failed after retries, with reasons]
66
+
67
+ ## References
68
+ [numbered bibliography]
69
+ ```
70
+
71
+ ## Citation placement rules
72
+
73
+ - In-text: [1] single; [2, 3] list; [1-5] range - numbered by ORDER OF
74
+ APPEARANCE across the document.
75
+ - The Executive Summary cites only the most critical sources.
76
+ - Every table row with a number has a Source column.
77
+ - Bibliography is ordered by number, not alphabetized.
78
+
79
+ ## Provenance standard
80
+
81
+ BAD (no provenance):
82
+
83
+ ```markdown
84
+ BRAF V600E is found in 50% of melanomas.
85
+ ```
86
+
87
+ GOOD:
88
+
89
+ ```markdown
90
+ BRAF V600E mutations occur in approximately 50% of cutaneous melanomas [1],
91
+ consistent with earlier estimates of 40-60% prevalence [2, 3].
92
+ ```
93
+
94
+ Where the claim derives from an analysis rather than a document, name the
95
+ method and input: "based on trial_search(query='melanoma', phase='Phase 3')
96
+ conducted 2026-09-04, 42 recruiting trials of which 28 list a BRAF/MEK
97
+ combination [4]."
98
+
99
+ ## Quality checklist (before finalizing)
100
+
101
+ - [ ] All six sections present, in order
102
+ - [ ] Every claim has provenance (citation / source / method)
103
+ - [ ] All in-text [N] present in References; no orphan references
104
+ - [ ] Identifiers included in references (PMIDs, DOIs, NCT IDs, patent IDs, accessions)
105
+ - [ ] Access dates for web/official-site sources
106
+ - [ ] Limitations honest about gaps and auth-gated tools not used
107
+ - [ ] Findings re-numbered into one bibliography in final_report.md
108
+ - [ ] Conflicting findings surfaced, not silently dropped
109
+
110
+ ## Common mistakes
111
+
112
+ | Mistake | Fix |
113
+ |---------|-----|
114
+ | Missing Data Sources section | Document every tool query and accession |
115
+ | "We analyzed the data" methodology | Name tools + parameters + steps |
116
+ | Absolute-truth tone in Findings | Mark confidence; hedge appropriately |
117
+ | No Limitations | Always include coverage gaps and constraints |
@@ -0,0 +1,142 @@
1
+ # Tool Selection
2
+
3
+ Route a research question to the correct biomcp tool, then shape the call with
4
+ `sections` / `limit` / pagination so payloads stay small.
5
+
6
+ ## Overview
7
+
8
+ biomcp (npm `biomcp`, pinned `biomcp@1.1`) exposes 56 tools: 41 core plus 15
9
+ environment-gated optional tools (3 database, 4 R analysis, 8 biowasm). This
10
+ file routes question types to tools; per-domain parameter detail lives in the
11
+ domain reference files.
12
+
13
+ > In MCP clients that prefix server tools (e.g. opencode with server name
14
+ > 'biomcp'), tools appear as biomcp_article_search etc.
15
+
16
+ ## Domain routing decision tree
17
+
18
+ ```
19
+ QUESTION TYPE
20
+ ├─ Literature / papers / PubMed
21
+ │ → article_search (query, source?, dateRange?, limit, offset)
22
+ │ → article_get (id: PMID/PMCID/DOI, sections?, citation_mode?)
23
+ │ → details: references/article-literature.md
24
+
25
+ ├─ Clinical trials / NCT IDs
26
+ │ → trial_search (query, status?, phase?, intervention_type?, page_token?)
27
+ │ → trial_get (nct_id, sections?) # no "protocol" section exists
28
+ │ → details: references/clinical-trials.md
29
+
30
+ ├─ Genes
31
+ │ → gene_search (query, chromosome?, limit, offset) # discovery
32
+ │ → gene_get (symbol, sections?, smart?) # annotation
33
+ │ → gene_diseases / gene_drugs / gene_trials / gene_articles # cross-links
34
+ │ → gene_enrich (genes[]) # Reactome pathways
35
+ │ → details: references/genes.md
36
+
37
+ ├─ Variants / mutations
38
+ │ → variant_search (gene + hgvsp as SEPARATE params - never free text)
39
+ │ → variant_get (id, sections?)
40
+ │ → variant_oncokb (gene, protein_change) # needs ONCOKB_TOKEN
41
+ │ → variant_trials (variant)
42
+ │ → details: references/variants.md
43
+
44
+ ├─ Drugs / compounds
45
+ │ → drug_search (query, limit, offset)
46
+ │ → drug_get (name, sections?) # safety = labels; adverse_events = FAERS
47
+ │ → drug_trials (drug)
48
+ │ → details: references/drugs.md
49
+
50
+ ├─ Diseases
51
+ │ → disease_search (query, limit, offset)
52
+ │ → disease_get (disease_id, sections?) # DOID/MONDO/OMIM/EFO/Orphanet/CUI
53
+ │ → disease_drugs / disease_trials
54
+ │ → details: references/diseases.md
55
+
56
+ ├─ Patents / prior art
57
+ │ → patent_search (query, assignee?, source?, seminal?, sort_by?)
58
+ │ → patent_get (patent_id, sections?)
59
+ │ → details: references/patents.md
60
+
61
+ ├─ Functional genomics datasets / sequences
62
+ │ → geo_search / geo_get # expression & sequencing studies
63
+ │ → sra_search / sra_get # sequencing runs (NCBI accessions only)
64
+ │ → genbank_search / genbank_get / genbank_genes
65
+ │ → gtex_expression / gtex_eqtl
66
+ │ → details: references/functional-genomics.md
67
+
68
+ ├─ Orthologues / consequences / regions / structures
69
+ │ → ensembl_lookup / ensembl_homology / ensembl_consequence / ensembl_region
70
+ │ → pdb (query | pdb_id | pdb_id+download)
71
+ │ → details: references/ensembl-pdb.md
72
+
73
+ ├─ Ambiguous / multi-entity free text ("BRAF V600E melanoma")
74
+ │ → discover (query) # resolves concepts to typed entities
75
+
76
+ ├─ Many entities at once
77
+ │ → batch_get (inputs: [{entity, id, sections?}])
78
+
79
+ ├─ Local SQL database (DB_TYPE set)
80
+ │ → db_list_tables → db_describe_table → db_query
81
+ │ → details: references/optional-analysis.md
82
+
83
+ └─ Differential expression / BAM/VCF/BED analysis (opt-in features)
84
+ → analysis_r_* / analysis_bam_* / analysis_bcf_* / analysis_bed_op / ...
85
+ → details: references/optional-analysis.md
86
+ ```
87
+
88
+ ## The `sections` pattern (payload trimming, part 1)
89
+
90
+ The `_get` tools for article, trial, gene, variant, drug, disease, and patent
91
+ accept `sections` (array of enum strings) plus `limit` (1-100, default 20):
92
+
93
+ - Omit `sections` -> core metadata only (smallest payload).
94
+ - Request only the sections you need, e.g. `drug_get` with
95
+ `sections: ["safety"]` instead of `["all"]`.
96
+ - `"all"` expands to every non-core section - use it only when most sections
97
+ are genuinely needed.
98
+ - `limit` caps array lengths within requested sections (e.g. top 20 citations,
99
+ top 20 adverse-event reaction rows).
100
+
101
+ Valid section enums per tool are tabulated in the domain reference files.
102
+
103
+ ## Pagination (payload trimming, part 2)
104
+
105
+ - Most search tools (`article_search`, `gene_search`, `variant_search`,
106
+ `drug_search`, `disease_search`, `patent_search`, `geo_search`,
107
+ `sra_search`, `genbank_search`): offset-based - `limit` (1-50, default 10)
108
+ plus `offset` (>= 0).
109
+ - `trial_search` is the exception: CURSOR-based only - pass the `page_token`
110
+ string from the previous response; there is no `offset` parameter.
111
+ - Stop paging when a page returns fewer than `limit` results, or when you have
112
+ enough sources for the claim at hand (typically 5-15 per aspect).
113
+
114
+ ## Worked example: routing a compound question
115
+
116
+ Question: "What evidence links BRAF V600E to melanoma drug resistance?"
117
+
118
+ 1. `discover(query="BRAF V600E")` - confirm entity types (gene + variant).
119
+ 2. `article_search(query="BRAF V600E melanoma treatment resistance",
120
+ dateRange="2018-01-01/", limit=15)` - recent literature.
121
+ 3. `variant_search(gene="BRAF", hgvsp="V600E")` - variant IDs/coordinates.
122
+ 4. `drug_get(name="vemurafenib", sections=["core","safety"])` - approved BRAF
123
+ inhibitor label data.
124
+ 5. `trial_search(query="BRAF melanoma", phase="Phase 3")` - trial landscape.
125
+
126
+ ## Failure modes
127
+
128
+ | Symptom | Cause | Fix |
129
+ |---------|-------|-----|
130
+ | `no_such_tool` for a db/analysis tool | feature not enabled, or enabled after server start (tools register at startup only) | set `DB_TYPE`/`ANALYSIS_R`/`ANALYSIS_BIOWASM` in the client env block, restart the client |
131
+ | Tool error mentioning OncoKB token | `variant_oncokb` without `ONCOKB_TOKEN` | get a token (oncokb.org registration) and set it, or skip OncoKB |
132
+ | gene_diseases returns an `_error` about DisGeNET | no `DISGENET_API_KEY` | the tool falls back to OpenTargets associations; add the key for DisGeNET data |
133
+ | variant_search returns nothing for "BRAF V600E" as `query` | compound free text is not a variant ID | use `gene="BRAF"`, `hgvsp="V600E"` as separate params (the tool also auto-splits a bare "GENE V600E" query, but explicit params are reliable) |
134
+ | Trial pages repeat or skip | offset paging used on trial_search | use `page_token` cursor paging |
135
+
136
+ ## Integration notes
137
+
138
+ - Confirm the server is connected before fan-out: any cheap call (e.g.
139
+ `gene_search(query="BRAF", limit=1)`) suffices as a smoke test.
140
+ - `biomcp_configure` with `{}` reports feature availability and config health
141
+ in one call (see `references/utility-config.md`).
142
+ - Rate limits, timeouts, and auth requirements: `references/rate-limiting-auth.md`.