Skip to main content
POST
Send one agent Playground message

Authorizations

Authorization
string
header
required

MCPJam API key (sk_…). Create one at Settings → API keys. Guest sessions cannot use the API, and API keys cannot manage other API keys.

Body

application/json
idempotencyKey
string
required

STABLE identity for this turn's intent — reuse it when retrying. A fresh key per attempt deduplicates nothing and will bill the turn twice. Printable ASCII only.

Required string length: 1 - 200
message
string
required

The message to send, as the user.

Required string length: 1 - 8000
projectId
string

Required to START a session; ignored when continuing one.

sessionId
string

Continue this session. Omit to start a new one.

modelId
string

Provider-prefixed model id, e.g. anthropic/claude-sonnet-5. Required on a first turn. A BARE id is rejected with details.reason: "MODEL_AMBIGUOUS" rather than guessed — an unprefixed id is indistinguishable from a local Ollama model, and guessing would spend on the wrong rail.

hostId
string

The saved host (client) this turn executes AS — it decides which ENGINE runs. A host that declares an agent harness (Claude Code, Codex, Cursor CLI) runs the real runtime; without one the turn runs MCPJam's emulated engine. The server re-fetches that host's own runtime config, so harness and computer are NEVER read from the request body — a body carrying either is a 400. PER-TURN, not pinned to the session: re-send it on every turn, and read engine on the response to confirm what ran. A continuation of a session that named ONLY a host must re-send it — omitting it is refused with details.reason: "HOST_TARGET_REQUIRED" rather than run on the emulated engine. Alongside environmentId it is an assertion only — a host contradicting the environment's own is rejected with details.reason: "HOST_TARGET_CONFLICT". Alone, the turn connects the host's own selected servers. A harness turn additionally requires toolMode: "auto" with no allowedTools/maxToolCalls: a harness builds its own tool set inside its sandbox, so the narrowing could not be applied, and the combination is refused rather than run with it silently dropped. It also cannot be combined with serverIds, because hostId cannot be pinned beside them and a later turn that omitted it would run the emulated engine on a session established on the harness (422, details.kind: "surface-unpinnable-host") — target an environmentId, or send hostId alone and narrow per turn with allowedServerIds.

environmentId
string

Target this environment's servers. Mutually exclusive with serverIds. First turn only.

serverIds
string[]

Target these project servers. Mutually exclusive with environmentId. First turn only. Server CONFIGS are never accepted — only ids the project already holds.

Maximum array length: 20
systemPrompt
string

First turn only.

Maximum string length: 8000
temperature
number

First turn only — pinned to the session and reused on every continuation.

Required range: 0 <= x <= 2
maxSteps
integer
Required range: 1 <= x <= 16
toolMode
enum<string>
default:read_only

read_only advertises only tools annotated readOnlyHint: true. auto advertises everything and MAY CAUSE REAL EXTERNAL SIDE EFFECTS. First turn only.

Available options:
read_only,
auto
allowedServerIds
string[]

Narrow THIS TURN to a subset of the target's servers. An empty array narrows to none and is rejected — omit the field to use the whole target. Per-turn, not pinned.

Maximum array length: 20
allowedTools
string[]

Advertise only these tool names, for THIS TURN. An empty array advertises no tools at all — the same request as maxToolCalls: 0. Per-turn, not pinned.

Maximum array length: 100
maxToolCalls
integer

Cap the tool calls this turn may make, enforced at DISPATCH rather than by bounding steps (one step can emit several parallel calls). 0 advertises no tools at all.

Required range: 0 <= x <= 16

Response

The turn ran. persisted.outcome reports whether the transcript landed — a turn that ran but failed to persist still spent, so this is a 200 with an honest persisted block rather than an error.

sessionId
string | null
required

The one public session id. Pass it back to continue, and to the trace/detail reads. NULL only when the turn ran but its transcript did not persist — which persisted.outcome reports, and which must not be read as "nothing happened": the turn already spent.

turnId
string
required

Minted by the turn lease and used by the ingest dedupe, so it names the same turn in both.

projectId
string
required

The project this turn ran in. On a continuation the caller never sent it — it comes off the session row — so this is the only place the response names the session's project.

persisted
object
required
origin
enum<string>
required
Available options:
api
reply
string
finishReason
string | null
toolCalls
object[]
trace
object

This turn's spans, inline.

usage
object
model
object
toolMode
enum<string>
Available options:
read_only,
auto
engine
string

WHICH ENGINE RAN: emulated, or harness:<id> such as harness:claude-code. Present on every turn. Read it rather than infer it from model. hostId is per-turn: a continuation of a host-only session is refused without it, and one that pinned its own serverIds runs the emulated engine — this is the field that says which.

hostId
string

The saved host this turn executed as — the pointer the caller sent, or the host the targeted environment pins. Absent when the turn named no host.

advertisedToolCount
integer

Tools the model could see this turn.

excludedToolCount
integer

Tools the tool policy withheld.

replay
boolean

Set when this idempotencyKey replayed an already-completed turn. Nothing was spent.

message
string