Skip to content

Latest commit

 

History

History
201 lines (165 loc) · 11.1 KB

File metadata and controls

201 lines (165 loc) · 11.1 KB

PanelAgent MCP

PanelAgent exposes its SQLite inventory and deterministic panel computations as ten read-only MCP tools. A compatible MCP host can discover the laboratory's libraries and instruments, inspect available antibodies, generate candidate panels, and diagnose conflicts. The server does not call an LLM, import inventory, annotate antibodies, or save panel history.

This integration uses stdio and the official Python MCP SDK, with the supported dependency range mcp>=1.29.1,<2. A host that requires a remote HTTP URL cannot connect directly to this stdio server. The Web workbench uses a Next.js server-side MCP client to bridge browser requests to this process.

Install and initialize

From a PanelAgent checkout, install into a dedicated environment:

python3 -m venv .venv
.venv/bin/python -m pip install -e '.[mcp]'

Or install the release wheel with the same extra (pip install "panelagent-<version>-py3-none-any.whl[mcp]"); the packaged seed data ships inside the wheel, so no checkout is needed. See distribution.md for artifacts and verification.

Use an explicit database path. This example creates a separate demonstration database and imports the small repository fixture as the Mouse library:

.venv/bin/python -m panelagent init --db /tmp/panelagent-mcp-demo.db --config-dir config --csv Mouse=tests/fixtures/panel_inventory.csv
.venv/bin/python -m panelagent db stats --db /tmp/panelagent-mcp-demo.db --json

For laboratory use, substitute the intended persistent database path, instrument configuration, and --csv Library=/absolute/path/inventory.csv. A library name is an arbitrary inventory label, not a required species code. Initialization without an inventory import provides seed data but no antibody libraries.

MCP uses path precedence --db > PANELAGENT_DB > ~/.local/share/panelagent/panelagent.db. It opens an existing schema-version-1 database read-only; missing, uninitialized, or unsupported databases produce tool errors. Starting the server does not create tables, seed data, or import files. Each call closes its database connection even when it fails.

Connect a client

For hosts using a mcpServers configuration object, adapt examples/mcp-client.json:

{
  "mcpServers": {
    "panelagent": {
      "command": "/absolute/path/PanelAgent/.venv/bin/python",
      "args": [
        "-m", "panelagent", "mcp",
        "--db", "/absolute/path/lab.db"
      ]
    }
  }
}

Replace both absolute paths before use and point to the interpreter where the package and its MCP extra were installed. With this installation, the client can launch the server from any working directory; it does not need PYTHONPATH or a shell activation command. The host launches the process and communicates through stdin/stdout. Configuration file locations vary by host.

For a manually launched process, the equivalent command is:

/absolute/path/PanelAgent/.venv/bin/python -m panelagent mcp --db /absolute/path/lab.db

Waiting silently for protocol input is expected. This is not an HTTP service and has no page to open in a browser. Do not add shell banners, print statements, or logging to stdout; diagnostics belong on stderr. No API key is required for the server. Model credentials, if needed, belong to the MCP host.

Tool reference

All tools are read-only or pure computation. Their MCP annotations describe this behavior; no write tool is exposed. Tool discovery supplies JSON input and output schemas, descriptions, and parameter bounds.

Tool Parameters Result
db_stats None Row counts for each core table.
list_libraries None Library names and antibody_count, ordered by library.
list_instruments None Instrument id, vendor, model, and channel_count (including blocked channels), ordered by ID.
list_markers Required library; limit=100, offset=0 Target names and antibody_count in that library; excludes missing/placeholder targets.
list_fluorochromes Optional laser, instrument_id Known dye information and available mapping/brightness data.
get_fluorochrome Required name; optional instrument_id Exact name or configured alias resolution, or null if unknown.
list_channels Optional laser, instrument_id Instrument channel rows, laser metadata, and blocked status.
search_antibodies Optional library, target, keyword, flag; limit=100, offset=0 Matching inventory rows, including quality fields.
generate_panel Required library, markers; max_solutions=10, include_bad=false; optional instrument_id Candidate assignments or a completed no-solution result with diagnosis; includes selected instrument_id.
diagnose_panel Required library, markers; include_bad=false; optional instrument_id Missing markers and detected channel conflicts, with selected instrument_id.

Instrument-dependent tools select the sole instrument automatically. When the database contains multiple instruments, first call list_instruments and pass an explicit instrument_id; the server must not merge mappings across instruments. An unknown instrument ID or missing instrument configuration is an error. Use laser names from list_channels, such as Blue or Violet, when filtering. Channels with blocked=true are visible for inspection but excluded from panel generation and usable laser capacity.

Library names are exact labels obtained from list_libraries. Antibody target search is case-insensitive exact matching; keyword searches target, fluorochrome, clone, brand, and catalog number, using SQL LIKE matching (% and _ act as wildcards). flag accepts good, warn, or bad; omitting it includes every quality state. Inventory rows with missing target or fluorochrome are displayed with - placeholders. Missing brightness or spectrum data remain unknown and must not be invented. list_fluorochromes starts from stored spectra; it is not an exhaustive list of inventory labels. Use antibody search and exact dye lookup to inspect labels that lack spectra.

Both paginated tools accept limit from 1 to 500 and nonnegative offset. Results remain lists, with no total-count envelope. Increase offset by limit until a page contains fewer than limit rows. Discovery counts include inventory rows regardless of quality or whether they can be used on the selected instrument; a count is not proof that a marker has a usable antibody.

Text parameters are trimmed and must contain 1–128 characters. Panel tools accept 1–64 marker strings. Marker names must be nonempty after normalization and must be unique after the core's case/punctuation normalization (for example, PD-1 and pd1 are duplicates). Generation accepts max_solutions from 1 to 100. Both generation and diagnosis exclude bad antibodies unless include_bad=true; keep this setting consistent between calls.

A complete workflow

After MCP initialization, discover tools with tools/list, then perform these tools/call operations. The ID below is illustrative: use the actual value returned by list_instruments.

  1. Call db_stats, list_libraries, and list_instruments with {} to confirm inventory availability and select a library and instrument.
  2. Call list_markers with {"library":"Mouse","limit":100,"offset":0} to inspect marker names. Read additional pages if needed.
  3. Call search_antibodies with {"library":"Mouse","target":"CD3"} to inspect matching inventory and quality notes.
  4. Call generate_panel with {"library":"Mouse","markers":["CD3","CD4","CD8"],"instrument_id":1,"max_solutions":10}.
  5. Inspect each candidate's markers assignments, brightness_summary, warnings, laser_distribution, and laser_capacity. Every assignment identifies an antibody_id, fluorochrome, and channel.
  6. When investigating limitations, call diagnose_panel with the same library, markers, instrument, and quality setting. A generation result with no candidates already includes diagnosis.

The host should preserve the user's experimental conditions between calls and explain constraints before changing them. An unavailable marker is a reason to discuss alternatives, not permission to silently drop a required target.

Results, errors, and scientific limits

Check MCP CallToolResult.isError before interpreting business fields. SDK structured results for dictionary-returning tools contain the dictionary itself; list and nullable returns are wrapped in structuredContent.result. The SDK also provides text content, which can be empty for a null result or an empty list. Use the advertised output schema rather than assuming every response has the same outer shape.

Situation MCP result Interpretation
Valid candidate found isError=false, business status="success" Read candidates; these are deterministic assignments.
Completed generation finds no panel isError=false, business status="error", candidates=[] Read diagnosis; the tool completed successfully.
Diagnosis finds missing markers/conflicts isError=false, business status="conflict" Constraints or inventory need attention.
Diagnosis finds no obvious conflict isError=false, business status="ok" This limited diagnostic does not prove that a valid assignment exists.
Unknown dye or no search matches isError=false, null or [] Valid lookup with no match.
Bad parameters, unknown library/instrument, unavailable database isError=true Correct the input or initialization problem before retrying.
Generation exhausts 100,000 search nodes isError=true Search was interrupted by its computation budget; infeasibility has not been established.

Generation enforces supported channel assignments and prevents duplicate channel use. Laser load balancing is a candidate-ordering preference. These results do not calculate a complete spillover/spreading model, optimize marker expression against dye brightness, or replace experimental validation. Diagnosis detects missing options and selected channel bottlenecks; it is not a complete feasibility solver. Neither tool provides an LLM evaluation.

If installation is missing, install the mcp extra in the configured Python environment. For missing or uninitialized databases, run pa init --db PATH explicitly and import the intended inventory. For empty discovery results, inspect db_stats and initialization/import reports. For ambiguous instruments, select an ID with list_instruments. Use the same database path for CLI updates and MCP; subsequent tool calls read the updated inventory.

Verification

The protocol tests launch a real stdio subprocess against temporary databases; they do not import fixtures into the default laboratory database. From the repository root, using an environment with the test dependencies installed:

PYTHONPATH=. python3 -m pytest tests/core/test_mcp.py -q
PYTHONPATH=. python3 -m pytest tests/ -q
python3 -m ruff check panelagent/ tests/core/