MCP Tools Reference Generated by AI
MockMotor exposes a Model Context Protocol (MCP) server at /console/api/mcp (JSON-RPC 2.0 over HTTP POST), so AI agents and other MCP clients can inspect and manage mock environments, services, reactions, accounts, and more. This page is generated live from the server's own tools/list response, so it always matches exactly what's currently available — every tool below, with its parameters and result shape, is what you'd get by connecting an MCP client to this instance right now.
Read-only tools (list/get) work without authentication. Tools that change something require an API key, sent as either the Authorization: Bearer <key> or X-MockMotor-API-Key: <key> header — find your key on your account page.
Lessons learned
Field notes from real agent sessions against this server — things that aren't obvious from the schema alone.
"Authentication required. Pass the X-MockMotor-API-Key header."means the key itself is missing/invalid — a header-format problem is not the likely cause if you already sentX-MockMotor-API-Key:orAuthorization: Bearer; the key value itself is wrong or stale."Access denied: you are not an owner of this environment."means the key is valid and authenticates correctly, but that user isn't in the environment's owner list. Checklist_owners.- Read-only calls (
list_*,get_*) succeed even fully unauthenticated, so a successful read does not confirm a key works — only a write call (e.g.create_reaction) proves authentication. - User accounts can be recreated with a new internal ID over time, silently dropping them from an environment's owner list even though the username is unchanged. If a previously-working key suddenly gets "Access denied," re-check
list_ownersbefore assuming the key is wrong.
For SOAP/XML payloads, use XQuery instead: $input//*:fieldName (wildcard-namespace match) reliably extracts fields regardless of the request's namespace prefixes, e.g. $input//*:ban[starts-with(.,'6')].
$accounts variable is a single wrapper element, not a sequenceIn a payload/response script it has the shape <accounts><account>...</account><account>...</account></accounts>. Iterate with for $a in $accounts/account, not for $a in $accounts (the latter silently loops exactly once, over the wrapper). Each <account> exposes its properties as direct child elements ($a/BAN, $a/SUB, ...) plus an <ID> element. This differs from the singular $account bound per-candidate inside accountsSelectorScript during selection.
maxAccounts defaults to 1If a reaction needs to bind more than one matching account (e.g. multiple subscriber rows per key), explicitly raise maxAccounts, or only the first match is ever used regardless of how many accounts actually match.
matchByScript whitelist...when a reaction's response is generated from mock account data. A hardcoded OR-chain of known keys requires editing the reaction every time mock data changes, and silently drifts out of sync (new accounts added via create_account won't be served until the reaction is manually updated). Instead:
- Leave
matchByScriptempty; rely onmatchByFirstElement/matchByRelativeURIfor base routing. - Use
accountsSelectorScriptto select by key, e.g.$account/BAN = $input//*:ban. - Set
ifAccountNotFound: skipso the reaction only fires when a matching account exists, falling through to the next reaction (e.g. a default stub) otherwise. - For a "known key, legitimately zero results" case, use a real sentinel account (key present, other fields blank) plus a payload filter (e.g.
$accounts/account[normalize-space(SUB) != '']), rather than encoding that case into the match script.
debug_reaction is the primary diagnostic toolIt returns a step-by-step trace (Match by HTTP Method, Match by FirstPayloadElement, Script XQ/Script JS, Match by Script, Executed/Skipped reaction) that pinpoints exactly which stage failed and why. When a variable's structure is unclear, dump it directly as a temporary diagnostic payload (e.g. <Debug>{ for $a in $accounts return <acc>{$a}</acc> }</Debug>) rather than guessing.
create_reaction places them before all existing reactions. This is useful for overriding a generated default, but means an overly broad matcher will shadow every request matching its base criteria — scope it precisely with matchByScript/accountsSelectorScript rather than relying on order alone.
/console/api/mcp…