opencode-bioresearcher 1.11.1 → 1.12.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.
@@ -5,10 +5,11 @@ Literature search and retrieval via `article_search` / `article_get`
5
5
 
6
6
  ## Overview
7
7
 
8
- `article_search` runs federated search across up to five backends with
9
- deduplication; `article_get` retrieves one article by PMID/PMCID/DOI with
10
- optional open-access full text, annotations, and citation graphs. Both tools
11
- enforce a 30-second execution timeout.
8
+ `article_search` runs federated search across up to six backends with
9
+ deduplication; `article_get` retrieves one article by PMID/PMCID/DOI (journal
10
+ or preprint DOI) with optional annotations, citation graphs, and opt-in
11
+ full text. `article_search` enforces a 30-second execution timeout,
12
+ `article_get` 60 seconds.
12
13
 
13
14
  ## Tools
14
15
 
@@ -17,10 +18,10 @@ enforce a 30-second execution timeout.
17
18
  | Parameter | Type | Notes |
18
19
  |-----------|------|-------|
19
20
  | query | string (required) | Search query (title, abstract, or keyword) |
20
- | source | enum, optional | `pubmed`, `europepmc`, `semantic_scholar`, `pubtator`, `litsense`; omit for federated search over all |
21
+ | source | enum, optional | `pubmed`, `europepmc`, `semantic_scholar`, `pubtator`, `litsense`, `preprint_only`, `arxiv`; omit for federated search (bioRxiv/medRxiv preprints are NOT included unless `preprint_only` is explicit; the default federation does include the `arxiv` leg) |
21
22
  | limit | int 1-50, default 10 | Applied to FINAL deduplicated results, not per-source |
22
23
  | offset | int >= 0, default 0 | Result offset |
23
- | dateRange | string, optional | `YYYY-MM-DD/YYYY-MM-DD`; open-ended `2020-01-01/` or `/2023-12-31`; at least one endpoint required. Only `pubmed`, `europepmc`, `semantic_scholar` support it - NOT `pubtator`/`litsense` |
24
+ | dateRange | string, optional | `YYYY-MM-DD/YYYY-MM-DD`; open-ended `2020-01-01/` or `/2023-12-31`; at least one endpoint required. Supported by `pubmed`, `europepmc`, `semantic_scholar`, `preprint_only`, `arxiv` - NOT `pubtator`/`litsense` |
24
25
 
25
26
  Federated sources at a glance:
26
27
 
@@ -31,20 +32,34 @@ Federated sources at a glance:
31
32
  | semantic_scholar | CS/ML-adjacent and citation graph (key optional) |
32
33
  | pubtator | Biomedical entity-tagged (gene/disease/drug/variant/chemical) |
33
34
  | litsense | Sentence-level semantic match to the query |
35
+ | preprint_only | bioRxiv/medRxiv preprints only (rows carry `preprint_server`, `ppr_id`) |
36
+ | arxiv | arXiv preprint server (rows carry `arxiv_id`) |
34
37
 
35
38
  ### article_get
36
39
 
37
40
  | Parameter | Type | Notes |
38
41
  |-----------|------|-------|
39
- | id | string (required) | PMID (numeric, e.g. "12345"), PMCID ("PMC1234567"), or DOI ("10.1038/s41586-021-03819-2") |
40
- | sections | enum array, optional | `core`, `oa`, `annotations`, `graph`, `citation`, `all`; omit for core metadata only |
42
+ | id | string (required) | PMID (numeric, e.g. "12345"), PMCID ("PMC1234567"), journal DOI ("10.1038/s41586-021-03819-2"), or preprint DOI ("10.1101/YYYY.MM.NN.NNNNNN", new prefix "10.64898/...") |
43
+ | sections | enum array, optional | `core`, `oa`, `fulltext`, `annotations`, `graph`, `citation`, `all`; omit for core metadata only. `["all"]` = oa+annotations+graph+citation WITHOUT fulltext - request `["fulltext"]` separately |
41
44
  | limit | int 1-100, default 20 | Max items per section (e.g. 20 citations) |
42
45
  | citation_mode | `fast` (default) / `full` | fast ~4 s, 4 providers with auto-fallback to PubMed; full ~15-30 s, all 5 providers incl. PubMed |
43
46
  | citation_direction | `forward` / `backward` / `both` (default) | forward = articles citing this one; backward = its references |
44
-
45
- Section contents: `core` = title/authors/journal/abstract; `oa` = open-access
46
- full text (PMC OA); `annotations` = PubTator entity annotations; `graph` =
47
- citation graph; `citation` = forward citations + backward references.
47
+ | fulltext_output | `file` (default) / `inline` | `sections:["fulltext"]` output mode - see below |
48
+ | fulltext_max_chars | int 1000-200000, default 40000 | Inline-mode only cap for `fulltext` text; ignored in file mode |
49
+
50
+ Section contents: `core` = title/authors/journal/abstract; `oa` =
51
+ license/access metadata and links ONLY - status vocabulary
52
+ `open_access | free_to_read | paywalled | not_in_pmc | unknown` (a pdf_url
53
+ does not by itself mean the text is fetchable); `fulltext` = the ACTUAL
54
+ text when freely readable in PMC/Europe PMC (opt-in, never triggered by
55
+ `"all"`); `annotations` = PubTator entity annotations; `graph` = citation
56
+ graph; `citation` = forward citations + backward references.
57
+
58
+ `fulltext` is file-first: by default the complete text is written to a
59
+ server-side markdown file and the reply carries `file_path` plus an outline
60
+ (Read/Grep the file selectively). Use `fulltext_output: "inline"` (capped by
61
+ `fulltext_max_chars`) only when the harness cannot read server-side files.
62
+ `oa`/`fulltext` do not apply to preprint DOIs.
48
63
 
49
64
  ## Worked examples
50
65
 
@@ -74,25 +89,28 @@ Full metadata plus citations for a known PMID:
74
89
  | Symptom | Cause | Fix |
75
90
  |---------|-------|-----|
76
91
  | Tool error "timed out after 30000ms" | federated fan-out exceeded 30 s | retry with a single `source`, narrower `dateRange`, or `limit` lowered |
77
- | dateRange silently ignored | `source` was pubtator or litsense | filter dates client-side, or switch source to pubmed/europepmc/semantic_scholar |
92
+ | dateRange silently ignored | `source` was pubtator or litsense | filter dates client-side, or switch source to pubmed/europepmc/semantic_scholar/arxiv/preprint_only |
78
93
  | Fewer results than limit on federated search | dedup-then-limit semantics | page with `offset`; duplicates across sources collapse into one entry |
79
94
  | citation section empty in fast mode | providers returned no items (fast auto-falls back to PubMed) | retry with `citation_mode: "full"` |
80
95
 
81
- ## Field contract (biomcp >= 1.4.0)
96
+ ## Field contract (biomcp >= 1.6.0)
82
97
 
83
98
  Article records from every article tool path (`article_search`,
84
99
  `article_get`, `batch_get`, `discover`) carry: `pmid`, `pmcid`, `doi`,
85
100
  `title`, `authors` (full "LastName ForeName" strings - Vancouver initials are
86
- computed by the evidence-ledger `bib` command), `journal`, `publication_date`
87
- (raw string), `volume`, `issue`, `pages` (null when the upstream record has
88
- none, e.g. epub-ahead-of-print), plus `mesh_headings`/`publication_types`/
89
- `keywords`/`chemicals` on PubMed paths. HTML entities are decoded to UTF-8.
101
+ computed by the evidence-ledger `bib` command), `journal`, `journal_issn`,
102
+ `publication_date` (raw string), `volume`, `issue`, `pages` (null when the
103
+ upstream record has none, e.g. epub-ahead-of-print), plus `mesh_headings`/
104
+ `publication_types`/`keywords`/`chemicals` on PubMed paths. HTML entities are
105
+ decoded to UTF-8.
90
106
 
91
107
  Backend coverage notes:
92
108
 
93
109
  - Only `pubmed` and `europepmc` return locator fields (volume/issue/pages).
94
110
  - `semantic_scholar`, `pubtator`, and `litsense` records never carry
95
111
  locators.
112
+ - `preprint_only` rows carry `preprint_server`/`ppr_id` and `arxiv` rows
113
+ carry `arxiv_id`; neither carries journal locator fields.
96
114
  - LitSense hits are HINT records: `{pmid, pmcid, score, source}` only - no
97
115
  title, no abstract. Before citing a LitSense-only PMID, enrich it with
98
116
  `article_get(pmid)` (one sequential call; standard retry ladder on
@@ -80,7 +80,7 @@ Trial landscape directly (name accepted):
80
80
 
81
81
  | Symptom | Cause | Fix |
82
82
  |---------|-------|-----|
83
- | `_error: Disease ... not found` from disease_trials | invalid/unresolvable ID | call `disease_search` first and copy the exact ID; supported formats are MONDO/DOID/OMIM (message text) plus EFO/Orphanet/CUI accepted by the resolver |
83
+ | `_error: Disease 'X' not found. Try disease_search...` from disease_trials | invalid/unresolvable ID | call `disease_search` first and copy the exact ID; supported formats are MONDO/DOID/OMIM/UMLS CUI (message text) plus EFO/Orphanet accepted by the resolver |
84
84
  | disease_get 0 hits for a raw name | the tool wants an ID, not a name | resolve via `disease_search`, or use `disease_trials`/`disease_drugs` which accept names |
85
85
  | Sections empty | over-narrow section set or sparse annotation for rare diseases | try `sections: ["all"]` and note data sparsity in the report |
86
86
 
@@ -6,7 +6,7 @@ Drug identity, regulatory status, labels, adverse events, and targets via
6
6
  ## Overview
7
7
 
8
8
  `drug_search` finds drugs by name/mechanism/keyword (MyChem-backed);
9
- `drug_get` returns per-drug detail with sections spanning US/EU/WHO
9
+ `drug_get` returns per-drug detail with sections spanning US/WHO
10
10
  regulatory data, FDA labels (safety), FAERS adverse events, targets, and
11
11
  indications; `drug_trials` cross-links to clinical trials.
12
12
 
@@ -25,7 +25,7 @@ indications; `drug_trials` cross-links to clinical trials.
25
25
  | Parameter | Type | Notes |
26
26
  |-----------|------|-------|
27
27
  | name | string (required) | Drug name, e.g. "imatinib", "aspirin" |
28
- | sections | enum array, optional | `core`, `us_regulatory`, `eu_regulatory`, `who_regulatory`, `safety`, `targets`, `indications`, `adverse_events`, `all` |
28
+ | sections | enum array, optional | `core`, `us_regulatory`, `who_regulatory`, `safety`, `targets`, `indications`, `adverse_events`, `all` |
29
29
  | limit | int 1-100, default 20 | For `adverse_events`, caps the number of ranked reaction rows |
30
30
 
31
31
  Section semantics (important - commonly confused):
@@ -34,7 +34,7 @@ Section semantics (important - commonly confused):
34
34
  |---------|----------|
35
35
  | core | identity, identifiers, description |
36
36
  | us_regulatory | US brand name + `fda_status` (e.g. approved) - NOT full labels, NOT approval history |
37
- | eu_regulatory / who_regulatory | EMA / WHO regulatory summaries |
37
+ | who_regulatory | WHO Prequalification products: `{prequalified, products, note}` - prequalification listing, not regulatory summaries |
38
38
  | safety | FDA LABEL TEXT: box_warning, warnings, adverse_reactions - this is where label prose lives |
39
39
  | adverse_events | FDA FAERS adverse reactions RANKED by report count - no filters (no patient age/sex/date/reaction filtering) |
40
40
  | targets | drug targets |
@@ -65,7 +65,7 @@ Regulatory snapshot + targets + indications in one call:
65
65
 
66
66
  ```json
67
67
  {"name": "trastuzumab",
68
- "sections": ["us_regulatory", "eu_regulatory", "targets", "indications"]}
68
+ "sections": ["us_regulatory", "who_regulatory", "targets", "indications"]}
69
69
  ```
70
70
 
71
71
  ## Failure modes
@@ -75,6 +75,7 @@ Regulatory snapshot + targets + indications in one call:
75
75
  | us_regulatory is surprisingly thin | it only carries brand name + fda_status | label text (warnings, box warning, adverse reactions) is in `safety` |
76
76
  | Wanting FAERS filtered by age/sex/date | `adverse_events` exposes ranked counts only - no filters | take the ranked list and note the limitation in the report; do not claim subgroup-level FAERS results |
77
77
  | 0 hits for a trade name | search index prefers generic/mechanism terms | `drug_search` by generic name or mechanism, then `drug_get` by the matched name |
78
+ | `sections: ["eu_regulatory"]` rejected (MCP -32602) | `eu_regulatory` was removed in biomcp 1.6.0 | drop it; US status is `us_regulatory`, WHO prequalification is `who_regulatory` |
78
79
  | Payload too large | `sections: ["all"]` on a heavily annotated drug | request only the needed sections; lower `limit` for reaction rows |
79
80
 
80
81
  ## Integration notes
@@ -44,9 +44,13 @@ not index them; the error points at ENA (https://www.ebi.ac.uk/ena).
44
44
  `format` (`genbank` default / `fasta`), `seq_start`/`seq_stop` (1-based
45
45
  inclusive region), `strand` (1 plus; 2 minus, allows seq_start > seq_stop for
46
46
  reverse slices), `max_response_bytes` (default 30,000,000; oversized errors
47
- rather than truncates). Caps: whole-record fetches max 2,000,000 bp - larger
48
- records REQUIRE a seq_start/seq_stop region (up to 10 Mb span); output
49
- `sequence_text` is truncated to its first 200,000 characters when oversized.
47
+ rather than truncates), `sequence_output` (`file` default / `inline`). Caps:
48
+ whole-record fetches max 2,000,000 bp - larger records REQUIRE a
49
+ seq_start/seq_stop region (up to 10 Mb span). Sequences over 1,000 characters
50
+ default to FILE mode: the full text is written to a server-side cache file
51
+ and the reply carries `file_path` + char counts (never truncated) - Read/Grep
52
+ the file selectively. `sequence_output: "inline"` opts back into inline
53
+ `sequence_text`, capped at its first 200,000 characters.
50
54
 
51
55
  `genbank_genes`: maps a nucleotide accession to NCBI Gene IDs (elink
52
56
  nuccore->gene) usable directly with gene_get/gene_search (entrezgene IDs) -
@@ -40,11 +40,11 @@ Protein Atlas - see pacing note below), `druggability` (DGIdb),
40
40
 
41
41
  | Tool | Parameters | Notes |
42
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 |
43
+ | gene_diseases | symbol, limit (1-50, default 10) | DisGeNET associations NEED `DISGENET_API_KEY`; without it the tool silently returns OpenTargets gene-disease rows (source: "opentargets") |
44
44
  | gene_drugs | symbol | Drugs targeting the gene |
45
45
  | gene_trials | symbol | Clinical trials referencing the gene |
46
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 |
47
+ | gene_enrich | genes (min 3 HGNC symbols), limit (1-100, default 30) | Reactome pathway enrichment; success returns `{pathways, total_reported, truncated}`; a single `_error` row on failure |
48
48
 
49
49
  ## Worked examples
50
50
 
@@ -77,7 +77,7 @@ Enrichment on a hit list:
77
77
  | Symptom | Cause | Fix |
78
78
  |---------|-------|-----|
79
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 |
80
+ | gene_diseases returns an `_error` row | BOTH DisGeNET and OpenTargets failed - not merely a missing key | without `DISGENET_API_KEY` the tool silently returns OpenTargets rows (source: "opentargets"); add the key for DisGeNET-grade associations and retry transient backend failures |
81
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
82
  | gene_enrich single `_error` row | Reactome AnalysisService rejected the input | check symbols are valid HGNC; retry with a smaller list |
83
83
 
@@ -90,4 +90,6 @@ Enrichment on a hit list:
90
90
  gene expression questions with tissue profiles.
91
91
  - `ensembl_lookup` (references/ensembl-pdb.md) is the identifier/structure
92
92
  authority (stable IDs, coordinates, transcripts) for ANY Ensembl species.
93
+ - `gene_enrich` runs 15-45 s typically (~105 s worst case, its server-side
94
+ budget) - keep client tool timeouts generous (>= 120 s) for it.
93
95
  - MyGene is server-limited at 100 ms - no manual throttling.
@@ -29,7 +29,12 @@ the biomedical ones: search is bounded at 60 s, detail at 120 s.
29
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
30
 
31
31
  Default (no `source`) "auto" mode: queries worldwide + ppubs concurrently; if
32
- ppubs fails hard it falls back to uspto_odp once (tagged `_note`).
32
+ ppubs fails hard it falls back to uspto_odp once (noted in `warnings`). The
33
+ success payload is an envelope: `{patents, total_hits, total_hits_basis,
34
+ seminal_prior_art, mined_count, errors?, warnings?}` - backend failures
35
+ (e.g. a google_patents timeout) ride in `errors` as `{source, message}`
36
+ entries, fallback/coverage notes in `warnings`; there are no in-band marker
37
+ rows inside `patents`.
33
38
 
34
39
  ### patent_get
35
40
 
@@ -82,8 +87,9 @@ Pull claims and citations for a specific patent:
82
87
 
83
88
  ## Integration notes
84
89
 
85
- - Auto-mode `_note` fields flag backend fallbacks - mention data lineage in
86
- the report when present.
90
+ - Auto-mode envelope fields flag data lineage - `errors[]` entries
91
+ (source + message) record backend failures and `warnings[]` records
92
+ fallback/coverage notes; mention them in the report when present.
87
93
  - EPO OPS and USPTO are server-limited at ~1 s token buckets - no manual
88
94
  throttling; expect patent tools to be the slowest calls in an aspect.
89
95
  - Cite patents by publication number with a Google Patents or Espacenet URL
@@ -49,7 +49,11 @@ Everything else: call sequentially, no timers.
49
49
 
50
50
  | Tool | Budget |
51
51
  |------|--------|
52
- | article_search / article_get | 30 s |
52
+ | article_search / journal_metrics | 30 s |
53
+ | article_get | 60 s |
54
+ | gene_get / disease_get / drug_get / variant_get / pdb | 40 s |
55
+ | trial_get / variant_trials | 45 s |
56
+ | gene_enrich | up to ~105 s (keep client tool timeouts >= 120 s) |
53
57
  | patent_search | 60 s |
54
58
  | patent_get | 120 s |
55
59
  | Per-source HTTP timeout (most sources) | 15 s |
@@ -75,6 +79,7 @@ Everything else: call sequentially, no timers.
75
79
  | `CROSSREF_EMAIL` | Crossref polite pool - faster citation metadata |
76
80
  | `EPO_OPS_CONSUMER_KEY` + `EPO_OPS_CONSUMER_SECRET` | EPO OPS patent backend: worldwide search + EP/WO claims (BOTH must be set together) |
77
81
  | `USPTO_API_KEY` | USPTO Open Data Portal application search backend |
82
+ | `OPENALEX_API_KEY` | `journal_metrics`: private per-key daily budget instead of the shared keyless OpenAlex pool (free key at openalex.org) |
78
83
 
79
84
  Set keys in the MCP client's env block (opencode: `environment`; Claude/
80
85
  Codex: `env`), then restart the client - config changes never apply live.
@@ -84,7 +89,7 @@ Codex: `env`), then restart the client - config changes never apply live.
84
89
  - Patents: US search works keyless via USPTO Public Search (ppubs default US
85
90
  backend); Google Patents is a best-effort fallback.
86
91
  - Drug regulatory/FAERS data works keyless (lower limits).
87
- - Literature works keyless across all five federated sources.
92
+ - Literature works keyless across all six federated sources.
88
93
 
89
94
  ## Integration notes
90
95
 
@@ -5,10 +5,11 @@ Route a research question to the correct biomcp tool, then shape the call with
5
5
 
6
6
  ## Overview
7
7
 
8
- biomcp (npm `biomcp`, pinned `biomcp@1.4`) 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.
8
+ biomcp (npm `biomcp`, pinned `biomcp@1.6`) exposes 58 tools: 43 core plus 15
9
+ environment-gated optional tools (3 database, 4 R analysis, 8 biowasm). The
10
+ 1.6 core set adds `journal_metrics` and `preprint_fulltext` to the article
11
+ family. This file routes question types to tools; per-domain parameter
12
+ detail lives in the domain reference files.
12
13
 
13
14
  > In MCP clients that prefix server tools (e.g. opencode with server name
14
15
  > 'biomcp'), tools appear as biomcp_article_search etc.
@@ -20,6 +21,8 @@ QUESTION TYPE
20
21
  ├─ Literature / papers / PubMed
21
22
  │ → article_search (query, source?, dateRange?, limit, offset)
22
23
  │ → article_get (id: PMID/PMCID/DOI, sections?, citation_mode?)
24
+ │ → preprint_fulltext (bioRxiv/medRxiv preprint DOI, version?) # on-demand full text; license disclosed
25
+ │ → journal_metrics (journal name / NLM abbreviation / ISSN, limit <= 25) # OpenAlex venue quality (2-yr citedness, h-index, i10, OA) before citing
23
26
  │ → details: references/article-literature.md
24
27
  │
25
28
  ├─ Clinical trials / NCT IDs
@@ -131,7 +134,7 @@ Question: "What evidence links BRAF V600E to melanoma drug resistance?"
131
134
  |---------|-------|-----|
132
135
  | `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 |
133
136
  | Tool error mentioning OncoKB token | `variant_oncokb` without `ONCOKB_TOKEN` | get a token (oncokb.org registration) and set it, or skip OncoKB |
134
- | gene_diseases returns an `_error` about DisGeNET | no `DISGENET_API_KEY` | the tool falls back to OpenTargets associations; add the key for DisGeNET data |
137
+ | gene_diseases returns an `_error` row | BOTH DisGeNET and OpenTargets failed - not merely a missing key | without `DISGENET_API_KEY` the tool silently returns OpenTargets rows (source: "opentargets"); add the key for DisGeNET-grade associations |
135
138
  | 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) |
136
139
  | Trial pages repeat or skip | offset paging used on trial_search | use `page_token` cursor paging |
137
140
 
@@ -104,13 +104,13 @@ Check a feature's parameters in detail:
104
104
  | `no_such_tool` after enabling a feature | tools register at server start only | restart the client/session, then verify with `biomcp_configure` `{}` (`running_now`) |
105
105
  | set refused: "sensitive" | sensitive key class requires confirmation | re-send identical call with `confirm_sensitive: true` |
106
106
  | `cwd_refused` | server cwd is / or $HOME | use the client env block (error carries the translation) |
107
- | batch_get item row contains `_error` | that single ID failed (typo, unknown ID) | fix the ID and re-request just that item; other items succeeded |
107
+ | batch_get item row contains `success: false` + `error` | that single ID failed (typo, unknown ID) | fix the ID and re-request just that item; the batch continues and other items succeeded |
108
108
 
109
109
  ## Integration notes
110
110
 
111
111
  - Smoke-test sequence for a fresh setup: `biomcp_configure` with `{}` ->
112
112
  confirm expected features `running_now` -> one cheap domain call.
113
- - `doctor` CLI complements this: `npx -y biomcp@1.4 doctor` (exit 0 = clear);
113
+ - `doctor` CLI complements this: `npx -y biomcp@1.6 doctor` (exit 0 = clear);
114
114
  `--client opencode` emits a paste-ready client entry.
115
115
  - Multi-entity literature pulls (e.g. 10 PMIDs from article_search) belong in
116
116
  ONE `batch_get` call, not 10 article_get calls.
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: bioresearcher-onboard
3
+ description: "Bootstraps a project-local biomcp MCP server runtime in .bioresearcher-runtime/: downloads portable Node.js 22 (if missing), vendors biomcp with fast mirror support (official or npmmirror), configures optional features (R, Biowasm, SQLite), and registers the server in OpenCode, Claude Code, Cursor, ZCode, Pi, CodeBuddy, or WorkBuddy. Use when biomcp is not installed, when biomedical tools are missing, or on requests like setup bioresearcher, install biomcp, or onboard."
4
+ license: Apache-2.0
5
+ compatibility: "Unix-like shells (Linux, macOS) and Windows (PowerShell, cmd.exe); OpenCode, Claude Code, Cursor, ZCode, Pi Coding Agent, CodeBuddy, WorkBuddy"
6
+ metadata:
7
+ version: "1.2.0"
8
+ source: "bioresearcher-skills"
9
+ allowed-tools: Bash Read Write Edit
10
+ ---
11
+
12
+ # BioMCP Project-Local Onboarding
13
+
14
+ This skill sets up a self-contained, project-local BioMCP runtime in your
15
+ working directory under `.bioresearcher-runtime/`.
16
+
17
+ ## What it does
18
+
19
+ - Checks if the host has Node.js >= 22.13. If missing, downloads a pinned,
20
+ cryptographically verified portable Node.js LTS binary into
21
+ `.bioresearcher-runtime/node/` (zero global installation, does not touch `~`
22
+ or `/usr/local`).
23
+ - Auto-detects network conditions (official distribution vs. fast npmmirror in
24
+ mainland China).
25
+ - Installs `biomcp` locally into `.bioresearcher-runtime/node_modules/` with
26
+ sub-100ms startup latency and offline resilience.
27
+ - Configures optional features (R analysis, Biowasm genomics, SQLite database)
28
+ and registers the server in your harness configuration (`opencode.json`
29
+ under the canonical `mcp.servers.biomcp` key, `.mcp.json`, etc.) without
30
+ overwriting existing settings.
31
+ - Verifies the configuration using the built-in diagnostic doctor.
32
+
33
+ ## Steps
34
+
35
+ Follow the steps below in order.
36
+
37
+ ### Step 1: Run Stage 0 Bootstrap
38
+
39
+ Execute the bootstrap script corresponding to your operating system.
40
+
41
+ **For Unix-like shells (Linux, macOS, Git Bash):**
42
+
43
+ ```bash
44
+ bash skills/bioresearcher-onboard/scripts/bootstrap.sh
45
+ ```
46
+
47
+ **For Windows (PowerShell):**
48
+
49
+ ```powershell
50
+ powershell -NoProfile -ExecutionPolicy Bypass -File skills\bioresearcher-onboard\scripts\bootstrap.ps1
51
+ ```
52
+
53
+ The script automatically:
54
+ 1. Reuses your host Node.js if version >= 22.13 is available.
55
+ 2. If missing, downloads and verifies the official portable Node.js archive into
56
+ `.bioresearcher-runtime/node/`.
57
+ 3. Installs `biomcp@1.6.0` into `.bioresearcher-runtime/node_modules/`.
58
+ 4. Updates your harness configuration (`opencode.json` or `.mcp.json`) with
59
+ absolute executable paths.
60
+
61
+ ### Step 2: Configure Optional Features (Optional)
62
+
63
+ By default, the core biomedical tools (PubMed/literature, clinical trials,
64
+ genes, variants, drugs, diseases, patents) and built-in SQLite are installed.
65
+
66
+ If the user needs specialized capabilities, pass the corresponding flags to the
67
+ bootstrap script or set environment variables before running:
68
+
69
+ - **R / Bioconductor Analysis** (DESeq2, edgeR, limma; requires ~2 GB RAM):
70
+ Pass `--with-r` to install the `webr@0.6` peer dependency and enable R
71
+ analysis in `.biomcp.json`.
72
+ - **Biowasm Analysis** (SAM/BAM/BED/BCF genomics tools):
73
+ Pass `--with-biowasm` to enable Biowasm in `.biomcp.json`.
74
+ - **Local SQLite Database**:
75
+ Pass `--sqlite-path=<path_to_db>` (e.g. `--sqlite-path=data/research.db`).
76
+ - **Client Override**:
77
+ Pass `--client=opencode`, `--client=claude-code`, `--client=cursor`,
78
+ `--client=zcode`, `--client=pi`, `--client=codebuddy`, or
79
+ `--client=workbuddy` if auto-detection should be overridden.
80
+
81
+ Example with R analysis and SQLite enabled:
82
+
83
+ ```bash
84
+ bash skills/bioresearcher-onboard/scripts/bootstrap.sh --with-r --sqlite-path=data/research.db
85
+ ```
86
+
87
+ ### Step 3: In-Session Feature Reconfiguration
88
+
89
+ Once BioMCP is registered and running, you do not need to hand-edit
90
+ configuration files. Use the built-in `biomcp_configure` tool to inspect or
91
+ adjust features dynamically:
92
+
93
+ - Inspect feature status:
94
+ `biomcp_configure(action="status")`
95
+ - Enable or disable features:
96
+ `biomcp_configure(action="set", values={"features.analysis_r.enabled": true})`
97
+ - Configure SQLite database:
98
+ `biomcp_configure(action="set", values={"features.database.enabled": true, "features.database.type": "sqlite", "features.database.sqlite_path": "data/research.db"}, confirm_sensitive=true)`
99
+
100
+ ### Step 4: Restart the Harness
101
+
102
+ MCP servers are spawned at client startup. Instruct the user to restart their
103
+ agent session or IDE to activate the newly connected BioMCP tools:
104
+
105
+ - **OpenCode**: Restart the session or open a new terminal session.
106
+ - **Claude Code**: Start a new session (`claude`).
107
+ - **Cursor / VS Code**: Reload the window or restart the application.
108
+ - **ZCode**: Reload the workspace or start a new ADE session.
109
+ - **Pi Coding Agent**: Start a new agent session (`pi`).
110
+ - **CodeBuddy**: Reload the window or restart the CLI session.
111
+ - **WorkBuddy**: Restart the application or switch workspace.
112
+
113
+ After restarting, verify connectivity by asking the agent to search for a gene
114
+ or article (e.g., `gene_search(query="BRAF")`).
@@ -0,0 +1,96 @@
1
+ # Stage 0 Zero-Dependency PowerShell Bootstrap for bioresearcher-onboard (Windows)
2
+ # Checks for existing Node >= 22.13; if missing, downloads pinned portable
3
+ # Node.js LTS into .bioresearcher-runtime\node, verifies SHA256, and hands off
4
+ # execution to onboard.mjs.
5
+ $ErrorActionPreference = "Stop"
6
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
7
+ $RuntimeRoot = if ($env:BIORESEARCHER_RUNTIME_DIR) { $env:BIORESEARCHER_RUNTIME_DIR } else { Join-Path (Get-Location).Path ".bioresearcher-runtime" }
8
+ $NodeDir = Join-Path $RuntimeRoot "node"
9
+ $NodeExe = Join-Path $NodeDir "node.exe"
10
+
11
+ $NodeVer = "v22.14.0"
12
+
13
+ # 1. Probe if host already satisfies Node >= 22.13
14
+ if (Get-Command node -ErrorAction SilentlyContinue) {
15
+ try {
16
+ $check = node -e "var v=process.versions.node.split('.');process.exit((v[0]>22||(v[0]==22&&v[1]>=13))?0:1)"
17
+ if ($LASTEXITCODE -eq 0) {
18
+ Write-Host "[bioresearcher-onboard] Found host $(node -v) on PATH"
19
+ & node "$ScriptDir\onboard.mjs" @args
20
+ exit $LASTEXITCODE
21
+ }
22
+ } catch {}
23
+ }
24
+
25
+ # If already vendored in working directory, reuse directly
26
+ if (Test-Path $NodeExe) {
27
+ $env:PATH = "$NodeDir;$env:PATH"
28
+ & "$NodeExe" "$ScriptDir\onboard.mjs" @args
29
+ exit $LASTEXITCODE
30
+ }
31
+
32
+ Write-Host "[bioresearcher-onboard] Host Node >= 22.13 not found. Bootstrapping portable Node.js $NodeVer into .bioresearcher-runtime\..."
33
+
34
+ # 2. Architecture Detection
35
+ $Arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) {
36
+ "arm64"
37
+ } else {
38
+ "x64"
39
+ }
40
+
41
+ # 3. Mirror Selection Probe (2-second integer timeout)
42
+ $MirrorBase = "https://nodejs.org/dist/$NodeVer"
43
+ $NpmRegistry = "https://registry.npmjs.org"
44
+ try {
45
+ $req = [System.Net.WebRequest]::Create("https://nodejs.org/dist/")
46
+ $req.Timeout = 2000
47
+ $res = $req.GetResponse()
48
+ $res.Close()
49
+ } catch {
50
+ Write-Host "[bioresearcher-onboard] nodejs.org unreachable; using npmmirror.com fast mirror"
51
+ $MirrorBase = "https://npmmirror.com/mirrors/node/$NodeVer"
52
+ $NpmRegistry = "https://registry.npmmirror.com"
53
+ }
54
+
55
+ $File = "node-$NodeVer-win-$Arch.zip"
56
+ $DownloadUrl = "$MirrorBase/$File"
57
+
58
+ $Checksums = @{
59
+ "x64" = "55b639295920b219bb2acbcfa00f90393a2789095b7323f79475c9f34795f217"
60
+ "arm64" = "2d71f5f9b2fffa33baa108c07d74b0d24e0c3dd8f441d567772ae0e3dd4b1a22"
61
+ }
62
+ $ExpectedSha = $Checksums[$Arch]
63
+
64
+ New-Item -ItemType Directory -Force -Path $RuntimeRoot | Out-Null
65
+ $TmpArchive = Join-Path $RuntimeRoot "node.zip"
66
+
67
+ Write-Host "[bioresearcher-onboard] Downloading $File..."
68
+ Invoke-WebRequest -Uri $DownloadUrl -OutFile $TmpArchive -UseBasicParsing
69
+
70
+ # 4. Checksum verification
71
+ $ActualSha = (Get-FileHash -Path $TmpArchive -Algorithm SHA256).Hash.ToLower()
72
+ if ($ActualSha -ne $ExpectedSha) {
73
+ Remove-Item -Force $TmpArchive -ErrorAction SilentlyContinue
74
+ Write-Error "SHA256 checksum verification failed for $File.`nExpected: $ExpectedSha`nActual: $ActualSha"
75
+ exit 1
76
+ }
77
+
78
+ # 5. Extract and flatten layout
79
+ $TmpExtract = Join-Path $RuntimeRoot "node-extract-tmp"
80
+ if (Test-Path $TmpExtract) { Remove-Item -Recurse -Force $TmpExtract }
81
+ New-Item -ItemType Directory -Force -Path $TmpExtract | Out-Null
82
+ Expand-Archive -Path $TmpArchive -DestinationPath $TmpExtract -Force
83
+ Remove-Item -Force $TmpArchive
84
+
85
+ New-Item -ItemType Directory -Force -Path $NodeDir | Out-Null
86
+ $ExtractedFolder = Get-ChildItem -Path $TmpExtract | Select-Object -First 1
87
+ Get-ChildItem -Path $ExtractedFolder.FullName | Move-Item -Destination $NodeDir -Force
88
+ Remove-Item -Recurse -Force $TmpExtract
89
+
90
+ Write-Host "[bioresearcher-onboard] Portable Node.js ready: $(& $NodeExe -v)"
91
+
92
+ # 6. Hand off to Stage 1
93
+ $env:PATH = "$NodeDir;$env:PATH"
94
+ $env:NPM_CONFIG_REGISTRY = $NpmRegistry
95
+ & "$NodeExe" "$ScriptDir\onboard.mjs" @args
96
+ exit $LASTEXITCODE