Skip to content

MCP ​

MCP is a thin optional adapter over the Python SDK. Decoding, scientific layer creation, validation, queries, rendering, revision checks, and persistence are Python API features. The adapter adds tool schemas, root-scoped paths, response formatting, and stdio transport.

From a clone:

sh
pip install -e './[mcp]'
pip install openslide-bin  # or install native OpenSlide through the OS
microscope mcp --root /data/study

After publication: pip install 'microscope-io[mcp]'. The official MCP Python SDK stable 1.x is constrained to a supported major. The plain SDK is sufficient; its separate developer CLI extra is not required. No network service, listening HTTP port, hosted backend, or foundation-model runtime is introduced.

An MCP client launches this command as a subprocess:

json
{
  "mcpServers": {
    "microscope": {
      "command": "/absolute/path/to/venv/bin/microscope",
      "args": ["mcp", "--root", "/data/study"]
    }
  }
}

All tools accept slide_path and optional project="default". Absolute or relative paths must resolve inside the configured root; symlink escapes through slide workspaces, inputs, assets, or outputs are refused. This is application-level path enforcement, not an OS sandbox against concurrent hostile filesystem changes. Use a trusted local study directory. Local paths/explicit bounded tool data go to the MCP client and potentially its model provider; local server execution does not imply that the model is local. Images are never automatically inlined.

ToolAdditional inputsStructured result
inspect_slide—Dimensions, actual X/Y MPP, levels, counts, layer catalog, annotation/layer revisions
render_regionrequired output; optional region, layers, annotations, size, target_mpp{output,width,height,transform}; image stays on disk
read_annotationsoptional region, offset, limit, max_vertices{items,classes,revision,offset,next_offset}
update_annotationsrequired expected_revision; optional upsert, remove, classes{count,revision}
read_layerrequired layer; optional query controlsDescriptor/artifact for rasters; bounded items and descriptor for points/geometry
add_layerrequired data_path, kind, expected_revision; optional name, boundsSaved descriptor, revision, local asset path
update_layerrequired layer, expected_revision; optional settings, positionSaved descriptor, revision, local asset path

kind is an enum: points, polygons, geojson, raster, mask, labels. NPY inputs use the restricted float32 format; polygons use MPOLY001; ordinary GeoJSON uses a FeatureCollection. Editable geometry is exposed through the annotation tools because the current viewer has a single per-project editable ROI collection. No model output is forced into it. Large centroid collections generally suit points; generated boundaries suit packed polygons; ordinary GeoJSON is convenient for moderate sets. Users choose another supported representation explicitly when desired.

The checked-in tool schemas include the exact JSON input/output schemas, nested ROI/class/appearance fields, enums, and query budgets. Regenerate them with python scripts/export_mcp_schema.py after changing tool signatures. Scientific format validation remains in the Python API.

Regions/bounds are (x,y,width,height) level-0 pixels. Query defaults: offset 0, limit 100, max_vertices 10,000. Maximum limit 1000, vertices 100,000, offset 1m; pages bound JSON to ~512 KiB. Annotation mutations accept at most 500 upserts/removals and a 512 KiB payload; bulk pipelines should use Python/local artifacts. Render bounds match the Python API. Full source arrays are not serialized into tool responses.

Reads are declared read-only. Rendering is declared a write because it saves a local artifact. Every mutation requires a token returned by the corresponding read/inspection. Missing/stale revisions and external index changes refuse commits. Tokens are separate for annotations and layer stacks. Writes retain the existing backup/index-last semantics; no multi-file transaction or viewer live synchronization is claimed.

json
{
  "slide_path": "case.svs",
  "region": [12000, 8000, 2048, 2048],
  "size": [1600, 1600],
  "layers": ["cells", "tumor_mask"],
  "output": "previews/roi-17.png"
}

Response shape:

json
{
  "output": "/data/study/previews/roi-17.png",
  "width": 1600,
  "height": 1600,
  "transform": {"region": [12000,8000,2048,2048], "scale_x": 0.78125, "scale_y": 0.78125}
}

The actual transform also reports level, coordinates, selected layers, annotation visibility, and any approximation warnings. Clients can inspect the returned local file through their own artifact mechanism; this server does not implicitly transmit it as an image.

Workflow authoring through the existing server ​

Configure your MCP client to run the installed microscope command with:

json
{"mcpServers":{"microscope":{"command":"microscope","args":["mcp","--root","/data/workflows","--runtime-root","/home/researcher/.local/share/microscope/companion"]}}}

Use actual paths on your workstation. --root is the explicitly authorized artifact/slide scope. Optional --runtime-root permits reading cached approved pack metadata, not session tokens or WSI files. It does not pair the agent to a live browser. Omit it to discover only core source schemas. Install the optional MCP extra in the SDK environment; processing packs remain in their own environments. Configuration alone does not install packages.

The six additive workflow tools are:

ToolBehavior
discover_workflow_nodes(node_type?)Cached installed nodes/packs/composites, typed ports, parameters/defaults, execution requirements, pinned revisions; no imports or execution
create_workflow(name)Empty version-1 portable graph in the response
edit_workflow(workflow, operations)Atomic in-response authoring batch; typed edges, parameter and cycle checks; temporarily unwired inputs allowed
validate_workflow(workflow, tiled=false)Actual engine/composite validator, complete required wiring, missing pack/version/commit checks, optional tile-local compatibility
load_workflow(path)Root-scoped bounded JSON and its content revision
save_workflow(path, workflow, expected_revision?)Portable JSON export, atomic local write; existing file requires its current revision

Edit actions: add_node, remove_node, set_parameters, connect, disconnect, upsert_composite, add_composite. connect accepts source/target IDs and source_port/target_port names from discovery. Nodes include stable IDs/types/versions, parameters and canvas positions. A composite's editable graph, typed boundary nodes and exposed parameter bindings use exactly the viewer's format. An edit batch is limited to 64 operations; a graph to 64 expanded nodes/256 edges, eight nested composite levels and 256 KiB JSON.

Example agent request:

Discover my installed OpenCV nodes. Create a WSI source in whole-slide mode at 0.5 MPP, connect Grayscale to fixed Threshold (Otsu off), put Threshold in an editable composite, validate tiled execution, and save tissue.workflow.json. Do not execute or install anything.

Open that JSON with Workflow → Load workflow JSON in the actual viewer. The graph remains draggable/editable, including its nested composite. Pair your browser with microscope serve, review scope and scientific settings, and click Run yourself. WSI pixels are extracted by the browser and sent directly to the paired loopback runtime.

Authority boundary ​

These tools do not run workflows, install packs, receive browser file handles, or control an active viewer session. No live command channel was added. The seven original slide/layer tools still operate on explicit paths under --root; they do not discover an open browser WSI. Offline authoring and browser-mediated execution are deliberately distinct. Future live control needs a separate per-session viewer grant and authenticated coordination mechanism; a health/discovery GET or MCP connection is not that grant.

Author a workflow with an MCP client ​

The optional workflow authoring tools use the same schemas and graph validator as the viewer/engine. The MCP server runs as a local subprocess over stdio. A client can discover installed node IDs, typed ports, parameter defaults/bounds, and pack revisions, then create/edit/validate/save portable JSON. The existing runnable example workflow-mcp.py uses the official Python MCP client and follows that exact sequence; it deliberately does not install a pack or execute a graph.

Install the SDK with the mcp extra, register the official OpenCV pack in the companion's separate runtime environment, and start/use the same runtime root for discovery. Client configuration for an agent that supports an MCP server map is:

json
{
  "mcpServers": {
    "microscope": {
      "command": "/absolute/path/to/microscope-python/.venv/bin/microscope",
      "args": [
        "mcp",
        "--root", "/data/workflows",
        "--runtime-root", "/home/researcher/.local/share/microscope/companion"
      ]
    }
  }
}

Use a real directory you intend to authorize. --root scopes slide files and saved workflow artifacts; --runtime-root permits the MCP process to read cached approved pack schemas. Neither option pairs the MCP client with an open browser. The client process receives the configured local filesystem permissions, so keep the root narrow and use a trusted agent/client.

For an executable transport example from the Python repository root, first register the local OpenCV checkout in the companion runtime, start microscope serve with that same runtime root, then run:

sh
.venv/bin/python examples/workflow-mcp.py \
  --root /data/workflows \
  --runtime-root /home/researcher/.local/share/microscope/companion \
  --output agent-threshold.workflow.json

The script initializes an actual stdio ClientSession, calls discover_workflow_nodes, creates an empty workflow, adds a built-in WSI Region source and installed Grayscale/Threshold OpenCV nodes, connects their typed ports, validates tiled compatibility, and saves the JSON under the authorized root. It refuses to continue if the expected OpenCV node schemas are not discoverable. The workflow output starts with a whole-slide 0.5 MPP source and fixed threshold; change scope/settings in the viewer to suit the slide and intended local run.

Open the viewer's Workflow editor and choose Load workflow JSON, then select the saved file. The graph remains an ordinary editable graph. Connect the browser to the local companion, review the working resolution and output, then explicitly select Run in the viewer. The browser captures the current slide region and sends the bounded data to the paired loopback companion. MCP itself does not receive that browser File handle or the pixels.

What the agent can and cannot do ​

  • discover_workflow_nodes reads installed/cached schema metadata; discovery does not import or run node code.
  • edit_workflow applies typed node/edge/parameter edits with graph checks; temporarily disconnected inputs can be left for continued authoring.
  • validate_workflow checks the current graph against available schemas and can check tile-local compatibility. A successful validation does not prove scientific validity, model availability, or success on a particular WSI.
  • save_workflow writes bounded portable JSON within --root, using a revision token when replacing an existing document.
  • MCP cannot install/uninstall packs, execute the graph, control the live viewer, or automatically accept/run user work. A JSON workflow must be loaded in the viewer; a paired viewer and user-triggered Run are required for Python execution.
  • Agent-authored arbitrary Python source and MCP-authored workflow JSON are separate tasks. A custom node must first be written in a trusted Python package, declared in a manifest, installed/registered, and discovered before an authored graph can refer to it.

The workflow MCP integration tests are in tests/test_workflow_authoring.py and exercise the actual Python tool methods, including discovery, atomic edits, validation, root-scoped load/save, and revisions. The additional examples/workflow-mcp.py script uses the external MCP stdio client transport; run it in an environment with the mcp extra installed. It does not open a browser, run algorithms, or send WSI data.

Private input IDs, layer IDs, path/weight/credential parameters and unknown node fields are omitted from workflow exports. Arbitrary human-authored scientific strings can still contain sensitive information; do not encode patient identity in configuration. Image arrays and weights are never embedded. Opening a JSON graph never installs a missing pack or runs Python.