MCP Server Reference¶
BioMCP exposes one execution tool (biomcp) and a current resource inventory
centered on the help guide. This page documents the stable MCP contract and
executes lightweight checks against the source tree.
Runtime Surface¶
BioMCP exposes two MCP entrypoints:
- stdio:
biomcp serve - remote Streamable HTTP:
biomcp serve-http
The canonical remote endpoint is /mcp. Lightweight probe routes are /health,
/readyz, and /.
from pathlib import Path
repo_root = Path.cwd()
shell = (repo_root / "src/mcp/shell.rs").read_text()
assert "StreamableHttpService" in shell
assert '.nest_service("/mcp", service)' in shell
assert '.route("/health", get(health_handler))' in shell
assert '.route("/readyz", get(health_handler))' in shell
assert '.route("/", get(index_handler))' in shell
Capability Advertisement¶
The server must advertise both tools and resources.
| Capability | Required |
|---|---|
tools |
enabled |
resources |
enabled |
from pathlib import Path
repo_root = Path.cwd()
shell = (repo_root / "src/mcp/shell.rs").read_text()
assert "enable_tools()" in shell
assert "enable_resources()" in shell
Tool Description Contract¶
The runtime biomcp description is generated from
src/cli/list_reference.md, but the build step emits an MCP-safe read-only
subset. That sanitized description keeps the catalog-only
study download --list form, but it must not advertise
study download <study_id> or the combined CLI syntax
study download [--list] [<study_id>]. CLI-only packaging or mutating
commands such as skill install, ema sync, update, and uninstall
must not appear in the MCP tool description. CLI-only cache commands such as
cache path, cache stats, cache clean, and cache clear reveal workstation-local paths and filesystem context, so they also stay out of the MCP tool description.
from pathlib import Path
repo_root = Path.cwd()
build = (repo_root / "build.rs").read_text()
tests = (repo_root / "tests/test_mcp_contract.py").read_text()
assert "MCP_SHELL_INTRO" in build
assert "read-only biomedical MCP tool" in build
assert "BLOCKED_MCP_DESCRIPTION_TERMS" in build
assert "`skill install`" in build
assert "`ema sync`" in build
assert "`update [--check]`" in build
assert "`uninstall`" in build
assert "study download --list" in build
assert "study download [--list] [<study_id>]" in build
assert 'assert "study download --list" in description' in tests
assert 'assert "study download [--list] [<study_id>]" not in description' in tests
assert 'test_cache_stats_is_rejected_in_mcp_mode' in tests
assert 'test_cache_clean_is_rejected_in_mcp_mode' in tests
assert 'test_cache_clear_is_rejected_in_mcp_mode' in tests
Tool Response Content¶
The biomcp tool keeps non-chart calls text-only. In MCP mode, charted study
commands return two success content blocks in order:
textwith the normal markdown/table outputimagewithmimeType = "image/svg+xml"and base64-encoded SVG data
MCP chart calls do not write files. If the caller supplies --output or -o,
the tool returns a tool error instructing the caller to consume the inline image
instead.
Alias fallback is the main exception to the usual CLI stderr contract: failed
get gene / get drug alias suggestions are returned to MCP as structured JSON
text content with _meta.alias_resolution and _meta.next_commands so agents
can apply their own retry policy without parsing markdown.
from pathlib import Path
repo_root = Path.cwd()
shell = (repo_root / "src/mcp/shell.rs").read_text()
cli = (repo_root / "src/cli/mod.rs").read_text()
assert "crate::cli::execute_mcp(args)" in shell
assert "CallToolResult::success" in shell
assert 'Content::image(encoded, "image/svg+xml")' in shell
assert "MCP chart responses do not support --output/-o" in cli
assert 'annotations(title = "BioMCP", read_only_hint = true)' in shell
Read-only Allowlist¶
The MCP biomcp tool accepts read-only CLI commands, including discover
and the exact study download --list catalog lookup. Mutating commands
remain blocked. Cache-family commands such as cache path, cache stats,
cache clean, and cache clear are also rejected because they reveal workstation-local paths and filesystem context.
In particular, study download <study_id> is rejected because installation
performs network and filesystem writes into the local study directory;
operators should run study installs directly via the CLI, outside MCP.
from pathlib import Path
repo_root = Path.cwd()
shell = (repo_root / "src/mcp/shell.rs").read_text()
tests = (repo_root / "tests/test_mcp_contract.py").read_text()
assert '"discover" => true' in shell or '| "discover" => true' in shell
assert '"study" => {' in shell
assert '"download" => args.len() == 4 && args[3] == "--list"' in shell
assert "discover/skill" in shell or "discover/skill)." in shell
assert 'assert "study download --list" in description' in tests
assert 'test_mutating_study_download_is_rejected_in_mcp_mode' in tests
assert '"BioMCP allows read-only commands only" in result.content[0].text' in tests
assert 'test_cache_path_is_rejected_in_mcp_mode' in tests
assert '"CLI-only over MCP" in result.content[0].text' in tests
assert '"workstation-local filesystem paths" in result.content[0].text' in tests
Resource Catalog¶
Current builds always publish the help resource and one markdown resource per embedded skill use-case:
| URI | Name | Notes |
|---|---|---|
biomcp://help |
BioMCP Overview | Always listed |
biomcp://skill/<slug> |
Pattern: ... | Listed when the matching embedded worked example exists |
from pathlib import Path
repo_root = Path.cwd()
shell = (repo_root / "src/mcp/shell.rs").read_text()
use_cases_dir = repo_root / "skills" / "use-cases"
assert "RESOURCE_HELP_URI" in shell
assert 'RawResource::new(RESOURCE_HELP_URI, "BioMCP Overview")' in shell
assert "list_use_case_refs()" in shell
assert use_cases_dir.exists()
assert list(use_cases_dir.glob("*.md"))
Resource Read Mapping¶
biomcp://helpmaps toshow_overview().biomcp://skill/<slug>maps toshow_use_case(<slug>)when an embedded worked example exists.- All successful reads return
text/markdown.
from pathlib import Path
repo_root = Path.cwd()
shell = (repo_root / "src/mcp/shell.rs").read_text()
assert "show_overview()" in shell
assert 'if let Some(slug) = uri.strip_prefix("biomcp://skill/")' in shell
assert "show_use_case(slug)" in shell
assert 'with_mime_type("text/markdown")' in shell
Unknown URI Behavior¶
Unknown resource URIs must return an MCP resource-not-found error and include a helpful message.
from pathlib import Path
repo_root = Path.cwd()
shell = (repo_root / "src/mcp/shell.rs").read_text()
assert "resource_not_found" in shell
assert "Unknown resource:" in shell
Companion Runtime Tests¶
Protocol-level checks are implemented in Python integration tests:
tests/conftest.pytests/test_mcp_contract.pytests/test_mcp_http_surface.pytests/test_mcp_http_transport.py
These tests validate both transport modes:
biomcp servestdio initialize/resource behavior,- stdio charted-study
text+image/svg+xmlresponses and MCP--outputrejection, - Streamable HTTP
initialize/tools/list/tools/call, - Streamable HTTP charted-study
text+image/svg+xmlresponses, GET /,GET /health, andGET /readyz,- invalid URI error semantics.