Skip to main content
Strand AI runs a hosted Model Context Protocol server so any MCP-aware agent can drive the Strand AI platform. Lattice predicts spatially resolved protein-marker maps from routine H&E, delivered as virtual mIF channels. An agent can browse owned or public samples and upload an H&E whole-slide image. It can estimate or submit a job and read its status, then download the predicted marker channels. Every action is authorized against your Strand AI organization; only submitted jobs reserve its credits. It is a hosted, OAuth-authenticated service over Streamable HTTP. There is nothing to install and no API key to manage. You connect the server URL and authorize with your Strand AI account. Upload and download bytes bypass the conversational model context and MCP transport. Lattice still processes stored slide data to generate predictions.

Connect

Add a custom connector with the server URL https://mcp.strandai.com/mcp over the Streamable HTTP transport, then authorize with Strand AI and pick an organization. See Claude for the step-by-step, authorization, and data-handling details. Slide upload depends on the client’s network because the client sends bytes directly to storage. Claude Code and the SDKs work without additional setup. Claude.ai requires one network setting. ChatGPT cannot upload because its sandbox has no outbound network access; upload with the browser or another client before running markers from ChatGPT.

Tools

Research use only (RUO). Not for use in clinical or diagnostic procedures.

Browsing and reading samples

list_samples accepts scope: mine | public | all (default mine), bounded cursor pagination, and the same filter vocabulary as the /samples browser: q, status[], uploaded_from, uploaded_to, workflow[], markers[] (NAME:requested|completed), and fields[]. Filters narrow together. Repeated status/workflow values widen within their facet. Tags is the predefined tags field and uses the same field clause as every other sample field. Fields are addressed by key (or an unambiguous label), and every response carries the available field_definitions with origin, storage, and writable metadata. mine contains active, non-trashed samples owned by your organization. public contains the curated public cohort. all puts owned samples first and removes owned-public overlap in favor of the owned item. Public rows support q title search only: every non-q facet suppresses public rows under all and is rejected under public. Public records expose neither tags nor the organization’s field vocabulary. Results use items and next_cursor. Every item has an ownership discriminator, canonical privacy-safe id, and a platform-owned absolute app_url. The response itself has an app_url for the exact filtered browser view. Agents should return those values rather than constructing web routes. get_sample accepts that canonical ID for either branch. Owned detail includes up to the 50 newest jobs plus the uncapped job_count. Use get_job to read one exact known job of any age. Public detail is limited to curated public fields and carries no owned job history or internal sample, organization, creator, or storage identifiers. Sample reads are credit-free. Owned detail also includes segmentation: lifecycle status, retryability, latest job, latest materialized layer, artifact availability, and the explicit zero-credit cost.

Cell segmentation

segment_sample starts segmentation when none exists and retries failed jobs. The operation is state-idempotent and credit-free. It reuses active or completed work, and failed jobs have a 60-second retry cooldown. Only owned, ready, non-archived samples can be changed. Public samples are read-only. Poll with get_sample; its latest layer reports whether the uint32 label-mask OME-Zarr and per-cell feature tables are available. Both tool responses use the same snake-case segmentation object. Its outer keys are status, retryable, credit_cost, job, and layer. A non-null job has id, status, error_message, created_at, started_at, and completed_at. A non-null layer has id, entity_type, seg_model_version, coordinate_frame, instance_count, created_at, and artifacts; the artifact flags are mask, cells, and provenance. download_results(..., include_segmentation: true) attaches the segmentation manifest. Cell morphology/geometry and each marker-expression Parquet table join on instance_id. These are true cell observations. Python AnnData created from ordinary prediction results remains a pixel-grid matrix and is not a segmentation result.

Updating a sample

update_sample requires a sample ID and at least one of name, fields, or mpp. fields is keyed by stable field key and each supplied value is the complete value, not a delta. {"tags": ["baseline"]} replaces Tags and {"tags": []} clears it. Public is read-only in this envelope. A null or empty name reverts to the uploaded filename. mpp is isotropic microns per pixel and takes precedence over embedded slide calibration.

Estimating and submitting a job

submit_job defaults to creating a job and reserving credits. Set dry_run: true to return patch and credit estimates without creating a job or reserving credits. After upload, a sample can take about 90 seconds to resolve its dimensions, scale, and tissue-tile count. During that interval a dry run returns status: not_ready, a reason, and retry_after_seconds: 15; retry the dry run after that interval.

Result formats

download_results requires format: ome-zarr | ome-zarr-zip | ome-tiff. Native ome-zarr returns stored data without conversion. OME-Zarr ZIP and OME-TIFF are cached asynchronous exports. Repeat the same invocation to poll or retry a failed export. H&E is off by default for every format. Setting include_he: true selects a separately cached H&E-inclusive OME-TIFF, and for OME-Zarr and OME-Zarr ZIP it returns the processed, registered H&E as its own artifacts.he link. include_segmentation adds the latest mask plus the per-cell geometry, morphology, and marker-expression manifest. When the completed layer has its required provenance and morphology objects, download_results also emits 15-minute, generation-pinned resource links for that provenance JSON, instances.parquet, and each exact marker Parquet that exists. These links are authorized through the owned job and organization; they do not expose the caller’s OAuth token or an internal storage URI. A connector showing a resource link does not prove that the connector can fetch or analyze binary Parquet. include_original_upload: true separately requests the potentially multi-GB source file stored by Strand, not processed/registered H&E. If ingest de-identification ran, it returns the stored de-identified copy; Strand does not reconstruct pre-de-identification bytes. Original retrieval is fail-closed while the runtime original-retrieval flag is disabled or the permanent source is unavailable. The option defaults to false and is currently disabled in production. The returned URL is a 15-minute bearer link: anyone holding it can download the file until expiry, so do not share it. Refresh or resume workflows may request a new link and are subject to authenticated issuance limits. Pixel-grid marker arrays are not cell expressions. Responses report the selected contents, status, expiration, retryability, and whether the prediction artifact was converted.

Reading job status

get_job makes one status request for an exact job_id and returns immediately. It works for jobs of any age, including jobs omitted from get_sample’s capped history. A nonterminal response does not schedule another check or wake the conversation. In conversational clients, call it again only when the user asks or returns. A host with a real scheduler may poll outside the model transcript and trigger one model turn when the job becomes terminal; do not tight-loop status checks through the model.

Uploading a slide

Slides must be de-identified before upload. See Security and data handling. upload_sample does not take a file. It immediately creates the canonical owned sample and a presigned, resumable transfer bound to your organization’s storage. The returned upload_id is that sample’s ID for get_sample and submit_job; upload_url receives the bytes outside the conversational model context and MCP transport. Lattice later processes the stored slide. Your agent then:
  1. Sends the slide bytes directly to upload_url with an HTTP PUT. One request works for a typical slide. Larger files can be sent as sequential chunks (each a multiple of 256 KiB except the last). The tool result provides structured transfer metadata for content ranges, ordering, alignment, and success statuses; network metadata identifies the required egress host and browser fallback.
  2. Uses submit_job with dry_run: true as the readiness check. GCS automatically starts ingest preprocessing when it commits the final PUT. Automated de-identification is off by default and runs during ingest only when enabled for your organization. While ingest is running, the dry run returns a structured not_ready result with a retry interval. No finalize tool or REST request is required.
Because the agent performs the PUT itself, upload_sample suits agents that can execute HTTP requests and reach storage.googleapis.com. Agents in a sandboxed client usually need a one-time setting to allow that traffic: on claude.ai web and desktop, add storage.googleapis.com under your organization’s “Settings → Capabilities → Allow network egress” before the first upload, then start a new chat so the sandbox picks the change up. See Claude for the per-client setup. For a multi-GB whole-slide image, or to skip the egress step entirely, upload in your browser at app.strandai.com/samples/upload. The browser uploader runs on your machine and does not require an egress setting. It runs independently from MCP upload sessions. Discover its resulting owned sample with list_samples or get_sample. For scripted or bulk uploads, the Python SDK and REST API stream slides for you end to end.

Example prompts

Upload this H&E slide to Strand AI, estimate a CD3e, CD8, and Ki67 job without reserving credits, show me the estimate, and ask before submitting it.
Read sample SAMPLE_ID and summarize its job history. Read the latest status of job JOB_ID; if it is complete, export its results as an OME-TIFF.

See also

  • Claude: connect, authorize, and data handling.
  • ChatGPT: connection prerequisites and upload limitations.
  • Python SDK: the client library for programmatic uploads and pipelines.
  • REST API overview: the underlying HTTP surface.
  • Pricing: how retained model-grid tissue positions and markers determine credits.