Connect
Add a custom connector with the server URLhttps://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:
- Sends the slide bytes directly to
upload_urlwith an HTTPPUT. 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 structuredtransfermetadata for content ranges, ordering, alignment, and success statuses;networkmetadata identifies the required egress host and browser fallback. - Uses
submit_jobwithdry_run: trueas 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 structurednot_readyresult with a retry interval. No finalize tool or REST request is required.
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 sampleSAMPLE_IDand summarize its job history. Read the latest status of jobJOB_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.