---
title: "Get the pre-run disclosure for a suite launch plan"
method: GET
path: "/projects/{projectId}/eval-suites/{suiteId}/run-disclosure"
tags: ["Eval runs"]
---

# Get the pre-run disclosure for a suite launch plan

`GET /projects/{projectId}/eval-suites/{suiteId}/run-disclosure`

What happens to a run's content BEFORE you launch it: which models it calls and where they route, which LLM analyzers/judges can fire and where their evidence goes, capture/retention/region facts, and the subprocessors engaged. Read-only — never launches or gates a run. Keyed by the SAME destination-affecting subset a launch selects (`caseIds`/`environmentId`/`environmentIds`); pass the selectors you would pass to a run so what this discloses is what that run would do. `run_eval_suite` already fetches this itself and returns it on the receipt's `disclosure` field — call this route directly when you need the disclosure BEFORE deciding to launch. A deployment that predates this contract answers 422 `FEATURE_NOT_SUPPORTED` with `details.reason: "contract_unavailable"`, never a partial payload — this is a GUARANTEE only when the deployment's missing-function error reaches this route unredacted. Production Convex can redact that same failure to a generic "Server Error" indistinguishable from a genuine handler crash on a suite the caller CAN see; this route has no independent way to tell the two apart in that one case, so it answers 502 instead of guessing 422 — a caller cannot rely on this code alone to detect an old production deployment, and a 502 does not imply the contract is available either. `projectId` is positional only, for REST consistency with sibling routes — this endpoint authorizes per-suite, not per-project, so any `projectId` returns the same disclosure for a `suiteId` you can reach.

## Path parameters

- `projectId` string, required
- `suiteId` string, required

## Query parameters

- `caseIds` string
- `environmentId` string
- `environmentIds` string
- `host` string

## Response `200`

The pre-run disclosure.

- EvalRunDisclosure — What happens to a run's content: computed once by the backend and projected identically by the pre-run dialog, the CLI, MCP tools, and the `eval.run.launched` audit row. `execution` is present ONLY when a launch plan resolved; `executionAbsence` exactly when it is absent, naming WHICH of two reasons (`ingested-run` — MCPJam did not execute this; `plan-unresolved` — a run that WILL execute and WILL call models, just not derivable yet). `analysis` is ALWAYS present, even without `execution`: stored evidence still reaches the judges.
  - `contractVersion` integer, required
  - `computedAt` integer, required — Epoch ms. Excluded from `digest`, so identical facts digest identically regardless of when they were computed.
  - `digest` string, required — SHA-256 hex over the canonical JSON of the facts (excluding `digest`/`computedAt` and each managed rail's `observedAt`).
  - `execution` object — Present exactly when a launch plan resolved.
    - `engine` string — `emulated`, `mixed`, or `harness:<id>`.
    - `engines` string[] — Present only when `engine` is `mixed` — the per-plan detail it summarizes.
    - `sandbox` object
      - `engaged` boolean
      - `vendor` string
      - `because` string
    - `locus` object — Whether this run executes MCPJam-hosted or on the caller's own machine — a fact only the executing process (the inspector) can answer, composed onto the backend's contract.
      - `known` boolean
      - `hosted` boolean
      - `reason` string
    - `models` object[]
    - `modelsUnresolved` object — Present when the plan resolved but its models did not.
      - `reason` string
  - `executionAbsence` object — Present exactly when `execution` is absent.
    - `kind` 'ingested-run' | 'plan-unresolved', required
    - `reason` string, required
  - `analysis` object[], required
  - `capture` object, required — Capture level, reporting mode, and redaction facts (fixed for this contract version).
  - `retention` object, required — Plan retention policy, whether it is actually enforced, and what that means today (`kept-indefinitely` vs `swept-after-policy-days`).
  - `region` object, required — `{ stated: false, reason }` unless a BYOK base URL carries a derivable region token.
  - `subprocessors` object[], required

## Other responses

- `400` — Malformed body or parameters.
- `401` — Missing, invalid, revoked, or orphaned key (`UNAUTHORIZED`) — or the **target MCP server** needs an OAuth grant (`OAUTH_REQUIRED`), which is a property of the server, not your key.
- `404` — Unknown project, server, or resource.
- `422` — This deployment predates the pre-run disclosure contract (`details.reason: "contract_unavailable"`). Guaranteed only when the missing-function failure reaches this route unredacted; an ambiguous production-redacted failure on a suite the caller can see surfaces as 502 instead — see the operation description.
- `429` — Per-key rate limit exceeded (60 requests/minute sustained, bursts up to 10). Honor `Retry-After` and back off with jitter.
- `500` — Something failed on MCPJam's side.
- `502` — Could not connect to the target MCP server.

## Changes

- **2026-08-25** `38732556ace4` — 1 info
  - added the new optional `query` request parameter `host`
- **2026-08-25** `def218ffb1a5` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/mcpjam/apis/mcpjam-api/changes/projects/:projectId/eval-suites/:suiteId/run-disclosure/get.md)

---

[API](https://skmtc.dev/mcpjam/apis/mcpjam-api.md) · [All operations](https://skmtc.dev/mcpjam/apis/mcpjam-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/mcpjam/mcpjam-api/revisions/7584cc19e5ff/schema)
