search_genes
Search marker genes by name (case-insensitive) to find which clusters they mark.
Instructions
Case-insensitive search across marker genes. Returns matching genes and which cluster they mark.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| limit | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/millimap_mcp/server.py:191-216 (handler)The `search_genes` tool handler function. It loads the snapshot, does a case-insensitive substring search over marker genes, and returns matching genes with their cluster ID, annotation, score, and log2fc. Uses `_load_snapshot()` and `_fmt_json()` helpers, and is registered as an MCP tool via the `@mcp.tool()` decorator on line 191.
@mcp.tool() def search_genes(query: str, limit: int = 20) -> str: """Case-insensitive search across marker genes. Returns matching genes and which cluster they mark. """ snap = _load_snapshot() if "error" in snap: return _fmt_json(snap) needle = query.strip().lower() hits: list[dict] = [] for cid, entries in snap.get("markers", {}).items(): for entry in entries: gene = str(entry.get("gene", "")) if needle and needle in gene.lower(): hits.append({ "gene": gene, "cluster_id": cid, "annotation": snap.get("annotations", {}).get(cid), "score": entry.get("score"), "log2fc": entry.get("log2fc"), }) if len(hits) >= max(1, min(limit, 100)): break if len(hits) >= max(1, min(limit, 100)): break return _fmt_json({"query": query, "hits": hits}) - src/millimap_mcp/server.py:191-191 (registration)The `@mcp.tool()` decorator on line 191 registers `search_genes` as an MCP tool via the FastMCP instance (`mcp = FastMCP("millimap")` on line 22).
@mcp.tool() - src/millimap_mcp/server.py:61-75 (helper)`_load_snapshot()` helper function that reads the MilliMap session snapshot from `~/.millimap/mcp_session.json`. Called by `search_genes` to get marker gene data.
def _load_snapshot() -> dict[str, Any]: if not SNAPSHOT_PATH.exists(): return { "error": "no_snapshot", "message": ( f"No MilliMap snapshot found at {SNAPSHOT_PATH}. " "Is MilliMap running with a dataset loaded?" ), } try: with SNAPSHOT_PATH.open("r") as f: return json.load(f) except Exception as exc: return {"error": "read_failed", "message": str(exc)} - src/millimap_mcp/server.py:77-79 (helper)`_fmt_json()` helper function that serializes a payload to pretty-printed JSON. Called by `search_genes` to format its return value.
def _fmt_json(payload: Any) -> str: return json.dumps(payload, indent=2, default=str)