Shared tool-layer infrastructure for the Skene Lab — MCP servers, CLIs, and Python clients that agents and scripts can depend on.
One canonical Python client per external system (Labstep now, more to follow), with three thin surfaces on top:
- Python library —
from lab_mcp.labstep import LabstepClient - CLI —
labstep experiments -s "lysis buffer" - MCP server —
claude mcp add labstep labstep-mcp
Everyone downstream (Claude Code, OpenCode, Claude Desktop, cron jobs, one-off scripts, Jay's completeness-checker, Hiru's tipseq agents) reads from the same client, so a bug fixed once propagates everywhere.
Before lab-mcp there were three parallel Labstep implementations:
| Origin | What it was | Problems |
|---|---|---|
neurogenomics/lab-agents/lab_agents/connectors/labstep.py + labstep_mirror.py |
Jay's SDK wrapper + bulk export | count=BATCH_SIZE=1000 silently caps at 1000 items |
~/.claude/mcp-servers/labstep/ (local only) |
MCP server with 21 tools | Default count=20 silently truncates; wrong URL shape in docs |
neurogenomics/bulk-tipseq-summary/scripts/labstep-query.py |
Hand-rolled read-only CLI | Disables TLS verification (CERT_NONE) — dangerous on Zscaler |
Each had bugs the other two did not. lab-mcp consolidates them and fixes:
- TLS verification stays on. If Zscaler intercepts, the preflight says so; we do not silently trust MITM.
- Pagination is explicit.
count=Nonefetches everything;count=Nis a hard upper bound — no silent truncation at 20/50/1000. - URL format is correct.
https://app.labstep.com/experiment-workflow/{id}(the/experiment/{id}form 404s). - One credential resolution path — env var, then
~/.config/lab-mcp/credentials.json, then the legacy~/Projects/lab-agents/.env.
git clone https://github.com/neurogenomics/lab-mcp.git
cd lab-mcp
pip install -e ".[dev]"Then provide credentials (any one of the following):
export LABSTEP_API_KEY=lsp_...
# or
mkdir -p ~/.config/lab-mcp
echo '{"api_key": "lsp_..."}' > ~/.config/lab-mcp/credentials.jsonGenerate a key at https://app.labstep.com → profile → API.
Verify with the structured health check:
labstep-preflightExit 0 and "stage": "ready" means you're good.
labstep experiments # list ALL experiments (auto-paginates)
labstep experiments -s "lysis buffer" # search
labstep experiments -n 20 # cap at 20
labstep experiment SK592 # detail by SK number
labstep experiment 12345 # detail by numeric ID
labstep reagents SK592 # inventory fields on an experiment
labstep protocols -s "TIP-seq"
labstep resources -s antibody
labstep preflight # structured JSON health check
labstep --json experiments # machine-readable outputclaude mcp add labstep labstep-mcpOr via JSON config (Claude Desktop, OpenCode, etc.):
{
"mcpServers": {
"labstep": { "command": "labstep-mcp" }
}
}Tools exposed (≈ 22): session (whoami, list_workspaces, set_workspace), experiments (list, get, find-by-SK, list-reagents, create, edit, complete, lock, add-comment, add-tag, attach-protocol, add-file, list-files), protocols (list, get, create, edit, new-version), resources (list, get).
from lab_mcp.labstep import LabstepClient
client = LabstepClient()
rows = client.list_experiments(search_query="lysis", count=None) # all pages
detail = client.find_experiment_by_sk("SK592")labstep-mirror # mirror to ~/labstep-mirror
labstep-mirror -o /data/eln-backup
labstep-mirror --skip resources --skip protocols
labstep-mirror --limit 5 # smoke test ┌─────────────────┐
Claude ──┤ mcp_server.py │
OpenCode │ │
Desktop └────────┬────────┘
│
┌────────▼────────┐ ┌──────────────┐
CLI ───┤ cli.py │ │ preflight │
humans │ │ │ .py │
└────────┬────────┘ └──────┬───────┘
│ │
┌────────▼────────┐ │
Jay's │ │ │
checker │ client.py ├───────────────┘
Scripts ─┤ (labstepPy) │
Mirror │ │
└────────┬────────┘
│
┌──────▼──────┐
│ bodies │ ProseMirror helpers
│ .py │
└─────────────┘
All entry points converge on client.py. client.py wraps labstepPy. Bug fixes land once.
lab_mcp/sharepoint/— OneDrive/SharePoint tooling (Jay already works with it)lab_mcp/slack/— Lab Orchestrator alerts + ELN completeness pingslab_mcp/hpc/— Imperial CX3 job submission / queue inspection
Each follows the same pattern: one client.py, a cli.py, an mcp_server.py when it makes sense, tests, preflight.
MIT. See LICENSE.
PRs welcome from anyone in the lab. Run tests before pushing:
pytestNo network access is required for the test suite — everything that would hit Labstep is mocked.