mcpjam command. For guides and recipes, see the individual command pages.
Account-bound Cloud commands live under mcpjam cloud. Local MCP testing stays at the top level (mcpjam server, mcpjam oauth login, …). Credential flags --api-key / --api-url are declared on mcpjam cloud and work before or after descendants. Hosted readiness stays at the root and still takes leaf --api-key. See Migrating to CLI 4.0.
Global flags
server commands
All server commands accept the shared connection flags below, plus command-specific options.
Shared connection flags
Transport selection is inferred from
--url vs --command when
--transport is omitted. Use --transport http|stdio when you want an
explicit validation step.
For stdio targets, child processes inherit the parent shell environment by
default. -e/--env adds or overrides child env values, and structured debug
artifacts only record the explicit env keys you passed on the command line.
--credentials-file cannot be combined with individual token flags
(--access-token, --oauth-access-token, --refresh-token, --client-id,
--client-secret). The CLI rejects conflicting auth sources upfront.
server probe
No additional flags beyond shared connection flags.
server doctor
server info
No additional flags.
server validate
No additional flags.
server ping
No additional flags.
server capabilities
No additional flags.
server export
No additional flags.
tools commands
tools list
Uses shared connection flags, plus:
When
--host is set, the output includes a host field and a toolsDroppedVisibility count. Hosts that opt out of visibility filtering (e.g. cursor) keep all tools.
tools call
Plus shared connection flags.
Without
--ui, tools call returns the raw tool result. When that result is a JSON object (the usual MCP CallToolResult), the default JSON output also includes _durationMs — wall-clock milliseconds spent in the tool call itself, excluding connection setup and the --host visibility probe, so it measures the same window as the durationMs returned by POST /v1/projects/{projectId}/servers/{serverId}/tools/call. Arrays and non-objects are left unchanged so a list-shaped payload is not rewritten. --reporter keeps its own durationMs, which is end-to-end (connection setup plus the call, stopped before validation, Inspector render, and debug I/O), and does not get _durationMs. With --ui, it opens Inspector by default in a TTY and returns a compact envelope with result, inspectorBrowserUrl, and inspectorRender status. Object-shaped result values carry _durationMs; the envelope root does not. inspectorRender.status is rendered when Inspector accepted the render, skipped when the tool succeeded but Inspector had no active browser client, an unsatisfied render precondition, or a render timeout, and error for non-recoverable render command failures. inspectorRender.remediation is always present and is one of open_browser, retry, reconnect_server, or none. Skipped renders are emitted as a stable root warning plus inspectorRender.warning, both with the shape { code, message, remediation, browserUrl?, hasActiveClient?, inspectorStarted? }. Stable skipped-render codes are no_active_client, timeout, disconnected_server, and unsupported_in_mode. Skipped renders keep the tool-call exit code unless --require-render is set; tool failures, validation failures, non-skippable render command errors, and --require-render skipped renders all exit nonzero. --attach-only is an exception to the skipped-render rule for no_active_client: by default a missing browser client yields inspectorRender.status = "skipped" with inspectorRender.remediation = "open_browser", but when --attach-only is set, no_active_client is treated as non-skippable, surfaces as a root error (not a downgraded warning), and exits nonzero like other non-skippable render failures. --inspector-url points to the Inspector backend/API; pass --frontend-url when you already know the browser/client URL and want to skip health-advertised frontend checks and local dev port discovery. Use --no-open when browser automation already opened inspectorBrowserUrl; use --attach-only when startup, browser opening, and discovery should all be disallowed. Default non-TTY --ui runs do not open a browser unless --open is passed. When --open is in effect (default in TTYs, opt-in elsewhere), the App Builder URL and the initial browser-client wait progress are emitted to stderr unless --quiet is set, regardless of whether stderr is a TTY; only the elapsed-seconds heartbeat is gated on stderr being a TTY. The Inspector path injects the completed tool result through renderToolResult; it does not call the tool a second time. Fresh tabs do not hydrate the injected render state; use the active Inspector client that received the render. Use --debug-out for the full render envelope including params and command responses. --ui cannot be combined with --reporter.
Reading tools call --ui output as an agent
Treat the tool result and the Inspector render as separate outcomes. An exit code of 0 means the tool call succeeded and no hard render error occurred; it does not, by itself, prove the UI rendered. Confirm UI delivery with inspectorRender.status === "rendered". If inspectorRender.status === "skipped", branch on inspectorRender.remediation or the stable root warning.code. If --require-render is set, the same skipped-render issue moves from root warning to root error and the command exits with code 1.
resources commands
resources list
Uses shared connection flags, plus:
resources read
Plus shared connection flags.
resources templates
Uses shared connection flags, plus:
prompts commands
prompts list
Uses shared connection flags, plus:
prompts get
Plus shared connection flags.
xaa commands
xaa run
Run the Cross-App Access (ID-JAG) debugger: self-issue an ID-JAG, redeem it at the target authorization server (RFC 7523), and call the MCP server with the resulting access token. See the XAA Debugger guide for the trust setup, registration strategies, and CI usage.
Registration strategies
Confidential CIMD (--client-auth private-key-jwt)
When --registration cimd --client-auth private-key-jwt is used, the CLI loads or generates a local EC P-256 key pair (stored in ~/.mcpjam). The public key is encoded into a reflector URL on app.mcpjam.com, which becomes the client_id. The CLI signs a client_assertion with the private key at token-redemption time; the private key never leaves the machine.
--issuer-base-url — see making the issuer reachable.
Key rotation: the key is the identity. Deleting ~/.mcpjam/xaa-client-private.pem or changing the XAA_CLIENT_PRIVATE_KEY environment variable generates a new client_id; any RAS-side allowlisting must be updated after rotation.
oauth commands
oauth login
oauth conformance
oauth conformance-suite
oauth metadata
oauth proxy / oauth debug-proxy
protocol commands
protocol conformance
Use
--format json|human for raw output and --reporter json-summary|junit-xml for CI reports.
protocol conformance-suite
apps commands
Shared connection flags
Apps commands share the same transport inference rules as the rest of the CLI:
--url implies HTTP, --command implies stdio, and --transport is an
optional explicit override.
apps conformance
MCP Apps server-side conformance checks. Uses shared connection flags plus:
Use
--format json|human for raw output and --reporter json-summary|junit-xml for CI reports.
apps conformance-suite
compat command
Check whether an MCP server’s tools and widgets work on each AI host. Uses shared server connection flags (see server commands) plus:
verdict (works, degraded, blocked, or unknown), a findings list explaining each verdict, and a top-level summary count. When the tool list is truncated (more than 50 pages), verdicts that would otherwise be works are downgraded to unknown.
cloud clients commands
Manage the clients saved in your hosted MCPJam projects — the named, reusable
configurations that define how MCPJam connects to and talks to your MCP servers.
Every clients command that contacts Cloud requires an sk_ API key (via
--api-key or the MCPJAM_API_KEY environment variable) or a prior
mcpjam cloud login. clients templates is the exception: it prints the
built-in template list from the bundled SDK and needs no credential.
mcpjam cloud hosts … still works as a command alias, and every command accepts
--host as a deprecated spelling of --client. Passing both --client and
--host is a usage error rather than a silent precedence rule.
Editing safely: configId and expectedConfigId
A client’s config is immutable and content-addressed: configId identifies the
exact settings, so the same id means byte-identical settings. Every config edit
takes the configId you last read as expectedConfigId, and a rename takes the
name you last read as expectedName. If someone else edited the client since
you read it, the write is refused with a 409 naming the current value instead
of silently reverting their edit.
The loop is always the same:
get and retry with the fresh value.
Shared platform flags
cloud clients templates
List the built-in templates usable with mcpjam cloud clients create --template. No additional flags.
cloud clients list
Clients that exist only as the private backing of a User Testing scenario are
omitted, matching the Clients tab.
cloud clients get
Returns the resolved config, the
configId every edit takes, and impact — the
live environments, scenario attachments and active legacy journeys a config edit
would follow.
cloud clients create
Provide either
--template or --file/--json, not both.
cloud clients update
Use either
--set/--unset or --file/--json, not both. Prefer --set: a
whole-config replacement composed from a stale read reverts anything that landed
in between.
--set field types
Values are parsed by the FIELD, never guessed from what the value looks like —
so --set systemPrompt='{"a":1}' sets that literal string, and a
--set temperature=0.2x typo fails locally instead of reaching the API as a
string.
Object-valued fields are whole-object replacements, not merges. To change a deep
knob, read the client, overlay the sub-object, and send the whole object back.
cloud clients servers
This REPLACES the server set: every server you leave out is detached.
cloud clients duplicate
cloud clients delete
cloud environments commands
Manage project environments in your hosted MCPJam projects. A project environment is a named, live-editable execution bundle — one host, optionally a standalone server group, optionally a pinned skill selection and pinned plugin versions — that eval suites and journeys run against.
A project environment is not a Computer sandbox image (those are
mcpjam cloud images), and not the STDIO environment variables you pass with --env.environments commands require an sk_ API key (via --api-key or the MCPJAM_API_KEY environment variable) or a prior mcpjam cloud login. Reading requires project membership; creating, updating, archiving, and restoring require project admin — a key bound to a non-admin gets a FORBIDDEN error on those.
Shared platform flags
The revision workflow
Environments use optimistic concurrency. Every write takes--expected-revision, the revision you last read:
CONFLICT error (HTTP 409) instead of overwriting their edit — re-read it and retry. CONFLICT also covers a duplicate name and archive-state errors (archiving something already archived, editing something archived), so read the message.
cloud environments list
cloud environments get
cloud environments resolve
Preview what the environment resolves to right now: the host’s current config, the closed server set, and the pinned plugin versions. Fails with CONFLICT when the environment can’t currently produce a runnable configuration (for example a pinned plugin was disabled); details.code carries the specific reason.
cloud environments create
*
--name and --host-id may instead be supplied inside --file/--json; explicit flags override the same key in the JSON body. Use the JSON body for the structured fields that have no flag — serverAttachmentId, skillSelection, and pluginVersionIds:
cloud environments update
Only the fields you pass change. To clear
serverAttachmentId, skillSelection, or pluginVersionIds, send an explicit null in the JSON body — an empty array is rejected, it is not a way to clear:
cloud environments archive
Archiving is reversible and frees the name for a new environment; the row is kept.
cloud environments restore
Fails with CONFLICT if another live environment took the name while this one was archived. Plugin pins whose version no longer exists at all are dropped on restore — compare the returned pluginVersionIds against what you archived.
cloud environments ensure-adhoc
Get or create an unnamed environment for a composed stack. Deduplicated by content: the same stack always returns the same environment, with created: false on the second call. Ad-hoc environments do not appear in environments list — they exist so a one-off combination can be run and reproduced without adding a name to the project’s list.
Requires project membership, not admin (pinning plugin versions still requires admin).
cloud environments name
Promote an ad-hoc environment to a named one in place — the same id every existing run already points at, so history stays attached. Fails with CONFLICT if the environment already has a name.
What can be pinned
Both pin fields are narrower than they look:skillSelectionaccepts project-shared skills only. Personal skills, skills with supporting files or extra frontmatter, and plugin-component skills are all rejected.pluginVersionIdsaccepts a plugin version only when its plugin is installed and enabled, the version isready, at most one version per plugin is pinned, and none of the version’s skills carry supporting files.
cloud images commands
Manage custom Computer sandbox images in your hosted MCPJam projects. An image is defined by a blueprint — YAML with a digest-pinned base image, initialize steps baked into the image at build time, and maintenance / knowledge text delivered to the agent at runtime (never executed automatically):
images commands require an sk_ API key (via --api-key or the MCPJAM_API_KEY environment variable) or a prior mcpjam cloud login.
Shared platform flags
cloud images list
cloud images get
cloud images validate
Lint a blueprint without saving it. Prints ok plus the resolved base digest, or structured errors with the YAML path of each violation.
cloud images create
cloud images edit
cloud images build
Trigger an image build for the sandbox image (async). Poll images logs to check build status.
cloud images logs
Show a sandbox image’s builds (newest first) with their log preview.
cloud images use
Boot your computer from this sandbox image. This rebuilds the computer — installed files are wiped.
cloud images reset
Reset your computer to its current image, wiping mutable state.
cloud images promote
Share a personal-draft sandbox image with the whole project. Requires project admin permissions.
cloud images delete
Permanently delete a sandbox image from a project.
cloud skills commands
List and read the Cloud Skills in your hosted MCPJam projects. These commands exist to close a gap: three flags across the CLI take a skill ID (eval run --compose-skill, eval cases run --compose-skill, environments ensure-adhoc --skill) and until now there was no way to discover those IDs without opening the web app. Authoring stays in the app — these commands are read-only.
All skills commands require an sk_ API key (via --api-key or the MCPJAM_API_KEY environment variable) or a prior mcpjam cloud login.
Shared platform flags
cloud skills list
List the skills visible to you in a project — the project-shared ones plus your own personal drafts. Each row includes a pinnability field that says whether the skill’s ID is usable with --compose-skill and environment skillSelection, and why not if it isn’t.
cloud skills get
Show one skill, including its SKILL.md body.
inspector commands
inspector open
Start or attach to the local Inspector and open the UI.
inspector start
Start the local Inspector in the background without opening a browser.
inspector stop
Stop the local Inspector if it is running.
cloud tunnel
Expose a local MCP server through an MCPJam relay tunnel and register it as a server in your hosted project, so evals and scenarios can target it. Requires an sk_ API key or a prior mcpjam cloud login. The tunnel stays up until Ctrl-C; the server record outlives the session (calls fail fast at the edge until you re-run, which revives the same URL slug with a fresh secret).
With
--format json, a single machine-readable startup object (public URL, server ID, slug, project) is written to stdout; ongoing status goes to stderr in both formats.
readiness hosted commands
Grade a saved server against a publisher’s directory as the platform reaches it — through the saved server row and the authorize exchange. This is the hosted half of readiness check: it answers a different question (what the platform sees, not what your machine sees), can optionally spend credits for model observations, and leaves a persistent record.
All readiness hosted commands require an sk_ API key (via --api-key or the MCPJAM_API_KEY environment variable) or a prior mcpjam cloud login.
Shared platform flags
readiness start claude
Start a hosted readiness run that grades a saved server against Anthropic’s connector-directory rules. Returns immediately with a run id; poll with readiness status.
readiness start openai
Start a hosted readiness run that grades a saved server against OpenAI’s app-directory rules. --submission-mode is required and never inferred — omitting it would silently report the package lane as not-applicable.
readiness status
Read one hosted readiness run. The response carries three independent axes: status (whether the run finished), overallStatus (the grade — a completed run can be not-ready), and llmObservations (whether the optional model pass ran).
readiness list
List hosted readiness runs, newest first.
readiness cancel
Stop a hosted readiness run that is still going. The run’s real terminal state arrives on a later readiness status — this response reports the request, not the outcome.
readiness report
Read a finished run’s findings, ordered most-consequential-first and capped. truncated and totalFindings indicate when you are seeing a subset.
cloud eval commands
All eval commands accept the shared platform flags below.
Shared platform flags
cloud eval create
Create a runnable eval suite from authored test cases (does not run it).
cloud eval list
List the eval suites saved in a project.
cloud eval run
Start an eval run of an existing suite, or upload a versioned suite file and run it. Provide either --suite or --file, not both.
By default the command prints a launch receipt and returns immediately. --wait polls every launched run to a terminal state.
Exit codes (--wait only). Without --wait this command’s exit code is unchanged: 0 on any launch, 1 on a partial or wholly failed fan-out. --wait owns a separate six-code contract — a caller who asked this process to sit and watch a run to completion is asking it to say how the run went:
No infrastructure condition ever maps to
1 — see the same rule under eval gate below. A multi-target launch merges these worst-of across every waited run, in the order 1 > 3 > 4 > 5 > 0: a real verdict failure is never masked by a sibling’s infrastructure noise, and a credential failure (which may be why other targets show no verdict) outranks a plain connection failure.
This six-code contract is new and deliberately different from eval gate’s four codes below — see that command’s own doc for why the two are not unified. An invalid suite file exits 2 either way — eval validate still exits 1 for the same contract failure, because it is a verdict on the file and this command is not.
Composing a target instead of naming one
--compose-host <id-or-name> builds an execution stack for this run instead of
naming a saved environment, refined by --compose-computer, --compose-model,
--compose-server-group and --compose-skill. The stack becomes an unnamed,
content-addressed environment (the same one environments ensure-adhoc
produces), so composing the same stack twice reuses one environment.
Any --compose-* flag alongside --environment, --host, --server or
--all-targets is a usage error: compose builds the stack the run uses, so
naming a target alongside it describes two different runs.
Which target runs
Fan-out is explicit and never inferred. Choosing for you would be choosing how much to spend, so:- nothing attached → the suite’s saved server selection runs (unchanged);
- exactly one attached environment or host → that one runs automatically, and the run is stamped with its configuration;
- several attached → the run fails with
TARGET_REQUIRED, listing every choice. Name one with--environment/--host, several by repeating the flag, or run all of them with--all-targets.
--all-targets expands one axis: attached environments if the suite has
any, otherwise attached hosts — never a cross product, because an environment
already resolves a host. It starts one paid run per target, launched as a
single group that occupies one concurrency slot rather than N.
--environment / --host and --server are mutually exclusive: an
environment or host supplies a closed server set that an override cannot
change.
Output and exit codes
With--format json, stdout is exactly one JSON document — the launch
receipt, with nothing appended — so CI can parse it directly. In human format
the CLI prints a View: link per started run, a Started N/M runs (group …)
summary when several launched, and a Failed: <target> — <code>: <message>
line per failure.
With --wait, the default output contains the launch receipt and completed
runs. --reporter replaces that output with the canonical structured report.
--out writes the same report atomically, including on failed-run and
post-completion reporting-error paths, before the command sets its exit code.
Without --wait, a partial or wholly failed fan-out exits 1; with
--wait it exits 4 (see the exit-code table above). A per-target failure
does not abort its siblings, so exiting 0 would let a pipeline read “1 of 3
runs never started” as a clean launch.
--file: upload and run a suite file
eval run --file reads the versioned suite file (schemaVersion: "1"),
authenticates, then validates. A contract-invalid file exits 2 after the
auth request — it does not start a run. eval validate on the same bytes
still exits 1: that command is a verdict on the file; this one is not.
The file’s suite.id is the declared suite identity. The first run creates a
file-owned suite stamped with that id; later runs of the same id in the same
project update that suite rather than creating a second one. A UI-authored
suite has no declared id, so no file can claim it. Resolve is never by name.
File passThreshold is a fraction; the hosted suite grades on a percent. The
conversion refuses rather than approximates. File repetitions above 10
are refused by name (REPETITIONS_CAP) and are not clamped.
Cases are synced in batches of at most 100 (create_eval_cases). Every
declared case is created or updated, including disabled: true rows. A case
the file no longer declares is deleted from the hosted suite before
launch. A case the file still declares but marks disabled: true is kept,
with its history — it is simply left out of the launch, so parking a flaky
test does not destroy its past results and re-enabling it later resumes the
same case.
The run is scoped to the enabled cases either way. A file with no enabled
cases is refused (NO_ENABLED_CASES) rather than launching the whole
persisted suite. --case may only name an enabled case. A later run updates
existing cases by declared id and creates new ones. An enabled case that
overrides passThreshold is refused: hosted grading is suite-wide. A
disabled case with the same override is ignored, matching how repetitions
are checked. Authored
defaults.toolPolicy and non-empty defaults.validity gates are refused at
hosted CLI launch (TOOL_POLICY_UNSUPPORTED / the corresponding validity
refusal). Hosted platform-authored suites do not currently have a backend
tool-policy field or enforcement path, so the CLI does not upload a suite that
would claim those guarantees. When supported by an eval runner, toolPolicy
is enforced at execution time with denied tools kept visible but blocked;
server annotations are advisory and UNTRUSTED. File defaults.repetitions is
inherited per case and is not uploaded as a suite minIterations floor.
Authored defaults.systemPrompt and defaults.temperature are uploaded as
execution defaults; omitted fields stay omitted so the platform applies its
own defaults. target.hosts and target.environment are attached before
launch. A file environment takes precedence over file hosts for that launch,
while an explicit CLI target takes precedence over both. When an explicit CLI
target is provided (for example --host), the file’s target.hosts are
not synchronized to the suite’s persisted host attachments — the suite
keeps whatever hosts it already has. Host attachment synchronization only
runs when no explicit CLI target overrides the file. Environment attachment
synchronization is unaffected and always runs.
Without --idempotency-key, the CLI derives one from the file’s SHA-256,
declared suite id, project, target, and every run-affecting knob
(--iterations, --case, --min-pass-rate, --exclude-skills,
--match-options, --environment / --host / --server / --all-targets,
--refresh-snapshot, compose flags, and the normalized
--allow-approximated set with its --approval-reason). Repeating the same
file with the same knobs returns the run it already started; changing a knob
starts a new one. The approval set is sorted and keyed by AUTHORED case id, so
--allow-approximated a b and --allow-approximated b a are the same run
while approving nothing is a different one. --notes is not part of the key.
Imported cases: live tool resolution, and per-run approval
Every file run performs the same live checkeval validate --project performs,
before it writes anything. It is not opt-in and there is no flag to skip
it. A file with no deterministic toolCall steps asks no question and pays no
round trip.
What happens when a deterministic reference does not resolve depends on the
case:
Each target is checked on its own server set.
--host is checked against
that host’s configured servers rather than the file’s, because that is the set
the run connects — validating target.servers would approve a tool the host
cannot reach. A host the FILE declares uses its own servers list when it
declares one (those are attached to the host before launch) and the host’s
configured set when the field is omitted. An explicitly empty servers: []
is a real, empty set — it clears the attachment before launch — and is
validated as such, never as an omitted field. A step that pins serverId is resolved by id;
serverName is a display fallback and never overrides it.
If the run’s target set cannot be enumerated before the suite exists
(--all-targets, --compose-*), or a host does not report a server set, or a
host pins a server the project no longer has, the launch refuses rather than
assuming the references are fine.
--case accepts a hosted row id, which does not exist yet when this check
runs. A selector this stage cannot map is therefore treated as possibly naming
any enabled case, so an unresolved reference still refuses; the launcher
resolves the selector itself a moment later.
A selected approximated case refuses unless this invocation approves it:
--suite: a
hosted suite’s cases are not the ones this invocation authored, so an
authored-id selector has nothing to resolve against.
The approval belongs to the run, never to the case. You supply an id and a
reason and nothing else — the approver and the timestamp are derived by the
server and frozen into that run’s own snapshot, because a caller-supplied
approver would file one person’s approval under another’s name and a
caller-supplied timestamp could be backdated past the edit that invalidated the
claim. Nothing persists: edit the suite, re-sync, or launch again, and the flags
are required again.
Scheduled runs and GitHub-App runs cannot approve anything. A scheduled suite
containing a selected approximation is refused by platform policy, which is the
intended behaviour — an unattended job is exactly the caller that must not be
able to wave one through.
--file pointing at create-API JSON (no schemaVersion) is a usage error
that names eval create --file. The converse is also true: eval create --file
on a versioned suite file names eval run --file.
Export of a file-owned suite writes declaredId as suite.id. Export of a
UI suite still writes the Convex id; running that file back is the ownership
refusal.
When the run targets an attached project environment (eval environments set), it executes against that environment’s resolved host config, closed
server set, and pinned plugin versions instead of the suite’s saved selection.
Every run records the environment and the exact revision it used, so eval status can answer “which configuration did this run actually execute against?”
long after the environment has been edited.
cloud eval status
Get the status and summary of an eval run.
The response carries a
judges block with each advisory grader’s state and
per-case grades. status: null means that judge was never requested for the
run — different from a judge that ran and graded nothing. In --format human,
each judge that actually graded gets a one-line summary.
cloud eval judge
Grade a finished eval run with LLM as Judge. Spends your organization’s model
budget. Returns a pending receipt; read the grades from eval status.
A run’s grading config is pinned when the run starts, so turning the judge on
for the suite does not reach a run that was already recorded —
--enable is
what grades it, and it changes nothing beyond that run. Passing neither
--judge-model nor --judge-threshold grades with the suite’s own config,
clearing any override a previous request left on the run.
cloud eval iterations
List per-iteration results for an eval run (pass/fail, tool calls, tokens, latency). Results are paginated.
--project is optional. Selection follows --project → input selector → MCPJAM_PROJECT → nearest project link → automatic newest accessible project.
cloud eval gate
Apply a pass/fail policy to an eval run. Add --wait to poll an in-progress
run before evaluating it.
Report files are flushed before gate exit codes are set, including failed and
incomplete gate outcomes.
--baseline / --baseline-sha. Either flag fetches the same run
comparison cloud eval compare uses and folds a regression verdict into the
same report and exit code as the threshold flags above — either one alone
enables the pass-rate regression gate with its default tuning; the four tuning
flags need a baseline to mean anything and are a usage error without one. A
case set that changed, was added or removed, or ran an unequal iteration count
between the two runs makes the whole-run pass-rate and p95-latency gates
non-gateable (exit 3) rather than a silent pass or a misread regression;
the deterministic per-case regression gate is exempt and can still fail
(exit 1) on a matching case.
The two are mutually exclusive — passing both is a usage error (exit 2).
There is deliberately no single flag that guesses which kind you meant: a
Convex run ID is an opaque string with no documented format, and an
abbreviated commit SHA is indistinguishable from one by construction, so the
kind is named by the flag rather than inferred. A commit SHA passed to
--baseline is rejected with a pointer to --baseline-sha instead of being
sent as a doomed run lookup.
A SHA that matches no completed run in the suite is not an error: it is the
ordinary “no baseline” outcome, incomplete (exit 3), which means the
comparison established nothing — never a regression. When the SHA matched more
than one eligible run, or the lookup was truncated before it could prove
uniqueness, the gate report’s baseline provenance records baselineMatchCount
alongside baselineMatchCountTruncated; the count is a floor, not a total,
so the two are always read together. An absent count means the match was
unambiguous.
Baseline provenance records both what was requested and what it resolved to —
requestedBaselineKind, requestedBaselineRunId or
requestedBaselineCommitSha, the backend-echoed resolvedBaselineCommitSha,
and the resolved baseRunId — so an archived report can answer “which run did
commit X compare against?” without the invocation that produced it. There is no
automatic baseline selection: a baseline is compared only when one is pinned.
Gate waivers. A run whose gate failed can be overridden by an authorized
user, on the record, until an expiry they name — see
cloud eval gate waive below. When a waiver is in
force, eval gate reports the outcome as waived and exits 0.
waived is deliberately not the same as passed. The run keeps its own failed
result, the failing verdicts stay in the report, and the waiver — who granted
it, why, and until when — is named in every output format: the human
report, json-summary, junit-xml (as a <skipped> element on the gate
testcase, which does not fail the build and does not render as a clean green
row), and html (its own badge and section, neither green nor red).
Only a real verdict failure can be waived. An incomplete gate — a cancelled
run, a --wait timeout, a network failure, non-gateable score evidence — keeps
exit 3 no matter what waiver is on the run: a waiver granted because the evals
regressed is not consent to ship on an infrastructure failure. A usage_error
keeps exit 2 for the same reason.
The CLI also re-derives the waiver’s expiry itself rather than trusting the
platform’s active flag, so a lapsed waiver cannot keep a gate green.
Exit codes. eval gate is the command that fails a build, so it is the one
that maps a verdict onto an exit code. It keeps four:
Incomplete import evidence is exit
3, decided first. When the platform
reports the run’s importEligibility as incomplete (or gateable: false
under any status), eval gate returns 3 before any verdict is computed
and before a waiver is considered. That ordering is the point: import
completeness is evidence ELIGIBILITY, not a measurement of the server, so it is
never exit 1 — the run has not said the server regressed, it has said its own
evidence cannot be relied on. A waiver cannot override it either, for the same
reason it cannot override a cancelled run: a waiver granted because the evals
regressed is not consent to ship on evidence nobody finished reviewing. Fix it
by re-running with the approvals the cases need, or with the unsupported cases
excluded.
The baseline is checked too. A --baseline / --baseline-sha gate rests
on two runs, so eval gate reads the resolved baseline run’s own
importEligibility and returns 3 when the baseline cannot gate — the compare
response reports counters, not provenance, so the baseline is fetched by id
rather than assumed sound. Without that, a baseline whose own approximations
were never approved could still produce a confident “no regression”. A baseline
run that cannot be read at all is also 3: “we could not look” is not “it is
fine”.
A run whose eligibility is legacy (no imported cases at all — every native
run) or eligible goes through the ordinary verdict logic unchanged. A server
that reports no eligibility at all behaves exactly as it did before the field
existed.
No infrastructure condition ever maps to 1. A job that fails a release because
a network call flaked, and reports it as a regression, teaches people to ignore
the gate — so retry on 3, and treat 1 as a real finding about the server.
These four are deliberately not the same set eval run --wait uses (see
that command above): gate’s exit 3 means “incomplete / non-gateable”, and
remapping it to the six-code scheme would invert pipelines that already
retry on 3. This is a deliberate compatibility exception for v1 — a
six-code migration for gate is deferred behind a future opt-in flag, kept
here so the exception stays documented rather than silently diverging.
cloud eval gate waive
Override a failing run’s gate until an expiry you name. Requires the manage
tier, enforced by the platform — whoever launched the run gets no exception for
having launched it.
This does not make the run pass. The run keeps its result, and the waiver
is reported by both things that read the gate: the GitHub Check Run and
eval gate itself.
--expires-in 7 is ambiguous between seven minutes
and seven days, and the difference is a gate that reopens before lunch or three
weeks later. The 30-day cap is enforced by the platform, so the refusal names
the cap and what to do instead.
Waiving a run that already has a waiver in force is a conflict, not a second
waiver: the existing one is reported back and is left untouched, because two
active waivers would make “which reason is on the check” a race.
cloud eval gate unwaive
Revoke a waiver, putting the gate and the GitHub Check Run back.
cloud eval trace
Fetch the full trace for one eval iteration (complete message history and spans). Can be large.
--project is optional. Selection follows --project → input selector → MCPJAM_PROJECT → nearest project link → automatic newest accessible project.
cloud eval get
Show an eval suite’s full settings.
cloud eval validate
Validate a local eval suite file — the versioned declarative document that
describes a suite, its defaults and its cases (schemaVersion: "1", YAML
canonical, JSON accepted, conventionally .mcpjam/evals/*.yaml).
Offline by default: without --project this command builds no API client, reads
no API key and never touches the network. Passing --project is the only thing
that changes that, and it is keyed off the FLAG — a linked directory or an
MCPJAM_PROJECT in the environment never turns the offline command into a
networked one.
Input is capped at 1,048,576 bytes (1 MiB) of UTF-8 and is never truncated —
a file over the cap is rejected outright.
Under
--format json, stdout carries this envelope whether the file is valid or
not:
--project. The offline check judges
the file against the suite-file contract. It does not re-resolve tool names,
server references or fixtures against a project’s live discovery, so a file that
validates here can still fail to run.
--project: resolving the names against a real project
With --project, the command authenticates, resolves the named project, and
checks every deterministic toolCall step against the live tool inventory of
the targets the file would run on. Structural findings are unchanged and the
live half is additive, under its own key:
- Only
toolCallsteps count. A tool named in prompt text is a hint the model may or may not act on, and anassertstep is an expectation a case may legitimately fail at run time. Treating either as a deterministic reference would make a negative test unwritable. - Per target, never over their union. A file that runs against several targets must resolve in all of them; a union would green-light a case that fails on two targets out of three.
- Auth and network failures are command errors, not findings. “Your file names a tool that does not exist” and “we could not look” send you to two different places, so they are never reported as the same thing.
1, like any other contract failure. A failure to authenticate,
reach the project, or list a server’s tools is a command error on stderr.
cloud eval export
Write a hosted eval suite to a local suite file.
The default path uses the suite’s id, not its display name: an id is stable
and path-safe, so a rename does not leave a second file behind.
Fail-closed. A suite file cannot express everything a hosted suite can, and
this command refuses rather than writing a file that describes a different test
than the dashboard runs. When any part of a suite is not representable it emits
UNSUPPORTED_SUITE_EXPORT findings, exits 1, and writes no file at all —
not a partial one, not one with a warning comment. Every finding names the field
it is about, so the command’s output is the authoritative list; the constructs
that refuse today include:
- several attached project environments, or legacy servers combined with an attached environment (the suite file can name one environment);
- a pinned sandbox image;
- automatic LLM-as-judge grading, non-default match options, and an iterations floor that raises a case above its own count;
- a compare-across-models case, a scenario-bound case, and cases that name different model providers (a suite file carries one suite-level provider);
replace/extendcheck overrides, a case that inherits the suite’s checks while also carrying its own, and any suite check the predicate contract does not recognise;- a suite with no execution model, no minimum accuracy, no name, no runnable server or environment target, or no cases; a case with no steps; and a suite or case id that is not an opaque id;
- a suite that serializes past the 1 MiB suite-file limit — the size is a property of the suite, and this never truncates.
The file is written through a sibling temp file and a rename, so an interrupted
write leaves the previous file exactly as it was.
cloud eval update
Edit an eval suite’s settings (only the flags you pass change).
cloud eval checks list
List the repositories whose pull requests run an eval suite, plus the
repositories the MCPJam GitHub App can reach.
available: false means GitHub Checks is not enabled for the organization at
all, so connecting a repository will not help. connectable: null means the
App could not be asked (GitHub unavailable, or no installation) — different
from an empty list, which would mean it reaches nothing.
cloud eval checks connect
Run this suite on every pull request to a repository. Affects everyone who
opens a pull request on that repository, and with fail-closed it can block
their merges.
--outage-policy has no default on purpose: it decides what happens to other
people’s pull requests during an MCPJam outage, and it is not editable from
this command afterwards. Retargeting a repository at a different suite, pausing
it, and disconnecting all live in the app’s Settings → Integrations, where every
connected repository is visible at once.
cloud eval delete
Permanently delete an eval suite (and its cases and runs).
cloud eval schedule
Enable or disable scheduled runs for a suite.
Pass either
--enable or --disable (not both).
A scheduled run launches exactly one run, so a suite with several attached environments
must pin one with --environment; a suite with exactly one defaults to it. --environment
is rejected with --disable: disabling preserves the existing pin, so accepting one there
would silently do nothing.
cloud eval environments subcommands
Attach or detach the project environments an eval suite runs against. Attaching is what
makes eval run --environment available for the suite.
cloud eval environments set
Replace the suite’s attached environments (this sets the whole list, in order).
eval schedule --enable --environment ...) or disable it first.
cloud eval environments clear
Detach every environment, reverting the suite to its saved server selection.
Subject to the same schedule guard as
set: rejected if the suite has an
enabled schedule pinned to one of the environments being removed. Repoint the
schedule or disable it first.
cloud eval cases subcommands
cloud eval cases list
List a suite’s test cases.
cloud eval cases get
Show one test case.
cloud eval cases run
Run a single case as a persisted, fully-queryable run — inspect it with eval iterations /
eval steps like any other run.
Every
--compose-* flag behaves exactly as it does for eval run — see
Composing a target instead of naming one.
Target selection follows the same rules (Which target runs),
except that a single case run targets ONE thing — there is no --all-targets here.
cloud eval cases create
Add a test case to a suite (definition via --file/--json).
cloud eval cases update
Edit a test case (definition via --file/--json).
cloud eval cases delete
Permanently delete a test case.
cloud eval cases generate
AI-generate test cases from the suite’s tools (spends credits).
mcp command
mcp
Run MCPJam as an MCP server over stdio so MCP clients (Claude Desktop, Claude Code, Cursor, …) can connect to, exercise, and debug other MCP servers. See MCPJam as an MCP server for the exposed tools and client setup.
--timeout <ms> flag sets the default per-request timeout against target servers, and --quiet suppresses the startup notice on stderr. Stdout carries only JSON-RPC; never pipe other output into it.
telemetry commands
Telemetry commands inspect and configure anonymous CLI telemetry. They never emit telemetry events themselves.
telemetry status
Shows the effective telemetry state, install ID state, state file path, debug mode, and disable reason when disabled. This command does not create an install ID.
telemetry disable
Persistently disables anonymous CLI telemetry by writing enabled: false to the telemetry state file. If no install ID exists yet, this command does not create one.
telemetry enable
Persistently enables anonymous CLI telemetry. If no install ID exists yet, this command creates a random install UUID.
cloud workspace
mcpjam cloud is the account-bound namespace. Log in, link a project, then run evals, tunnels, and the rest of the Cloud groups.
Cloud account session
Seecloud login / logout / whoami below.
cloud link
Pin the current Git worktree (or --here cwd) to a Cloud project by writing .mcpjam/project.json. No secrets. Bare link ignores an existing file when choosing what to pin.
cloud status
Zero-network. Prints credential source, deployment URL, and the project selector that Cloud commands would use (flag / env / link / automatic). API keys are redacted.
The report includes credential.valid (true / false / null) and deployment.valid. null means no credential is configured and is a successful informational status. An invalid explicit --api-key or --api-url still emits the complete JSON report, sets ok: false, includes an error string, and exits 1. Other Cloud commands reject those same values with exit 2 and no report.
cloud organizations list
List organizations and their ids. An sk_ key sees only its own. Use the id with mcpjam cloud projects list --org <id>.
cloud projects list
cloud sessions list
List Playground chat sessions in the selected project. Same project-selection rule as other Cloud commands.
cloud sessions send
Send one message to a project’s MCP servers and print the reply plus the raw tool calls, per-call latency and token usage — the telemetry a participant in the conversation cannot see.
This spends model credits on every call.
--idempotency-key is required and must be stable for the intent, not regenerated per attempt. It is what makes a retry safe: with the same key, a turn that already completed is replayed rather than re-run and re-billed. A fresh key per attempt deduplicates nothing.
Omit --session to start a conversation; pass the sessionId the command returns to continue one. Configuration is fixed at the first turn, so --model, --environment, --server, --system-prompt and --tool-mode are refused alongside --session rather than silently repinning the session.
read_only filters on a hint the SERVER asserts, so it is a policy this host applies rather than a guarantee it can verify. A server is free to annotate a mutating tool as read-only.
cloud sessions show
Print a session’s metadata and a window of its raw messages. Message index values are absolute transcript positions — the same indices cloud sessions trace spans reference, so the two outputs join on that number.
A transcript that could not be read reports transcriptUnavailable: true and a null messageCount — never 0, which would claim the conversation is empty.
cloud sessions trace
Print a session’s per-turn execution spans: per-tool-call latency, token usage, and indices into the transcript.
Returns the latest turn by default rather than the whole session — a session’s spans are the largest thing the API emits, and the turn you just took is the one you are debugging.
A turn whose spans could not be read reports spansUnavailable: true rather than an empty spans array: “made no calls” and “could not fetch” are opposite conclusions.
cloud login / logout / whoami
These commands manage your MCPJam platform session. login opens a browser for OAuth and stores the session locally; logout removes it; whoami shows the account behind the current credentials.
cloud login
The
MCPJAM_API_URL environment variable is equivalent to --api-url. An invalid value in either source is a hard error (exit 2).
URL resolution order for cloud commands after login:
- Explicit
--api-urlflag MCPJAM_API_URLenvironment variable- The
apiUrlstored with the OAuth session (only when the stored login is the credential;sk_API keys do not inherit the stored URL) - Production default (
https://app.mcpjam.com/api/v1)
Account details (
email and plan) are fetched from the platform after the OAuth exchange completes. If the lookup fails, login still succeeds and a warning is printed to stderr (suppressed with --quiet).
cloud logout
No additional flags. Removes the stored MCPJam session.
When MCPJAM_API_KEY is set to an active sk_ key, logout prints a warning to stderr (human format only) noting that the CLI remains authenticated via the environment variable even after the stored session is cleared. JSON output is unaffected.
cloud whoami
Exit codes
Codes above
2 are reserved for outcomes a script should act on differently — not merely for naming a failure. See MCP Tasks for the full tasks watch mapping.
