api() and endpoint(). Both take objects. Standard Schema infers handler inputs and checks each response against its status code. Effect runs internally; your handlers use ordinary TypeScript.
mocks/catalog.ts
item and Item into a shared fixture file to reuse them with MCP and CLI mocks.
Run an eval
catalog.eval.ts
await api.url("catalog") and pass the URL explicitly to a client. No environment variables or global fetch functions are replaced.
Requests and responses
The input schema receives{ params, query, headers, body }. Headers are lowercase. Repeated query values are arrays. Empty bodies become null; nonempty bodies must be JSON. Schema transforms handle coercion.
Handlers return { status, body, headers? }. Use null for bodyless responses such as 204. Content type and framing headers are managed by the runtime. Optional description text is included in agent discovery.
Explicit error responses, such as 404 or 429, are normal mock behavior. Unmatched routes return 404 with matched: false. Thrown handlers, invalid response schemas, and serialization failures fail the mock execution. Nothing is forwarded upstream.
Evidence
HTTP requests appear in trial Calls and are available to judges.api.calls(name?) returns typed records containing method, path, status, timing, matching outcome, input, output, handler logs, and runtime errors. Calls to api.url and api.calls appear in validator evidence.
Input, output, and log values contain text, format, state, and truncated. Inspect those fields before parsing captured JSON. These are bounded snapshots, not raw packet captures.
Authorization, cookies, and common secret fields are redacted before recording. Add case-insensitive field names with api({ redact: ["accessToken"], ... }). This does not redact secrets embedded in arbitrary strings or URL paths. Keep credentials out of fixtures.
Handlers can accept a second argument: handler(input, { signal, log }). Use log(value) for correlated evidence and signal to cancel asynchronous work.
Validator-owned servers
UsewithApi() when a validator needs fresh, hidden test data. It closes the server when the callback finishes or fails.
calls(), not the trial-wide journal. Log the evidence inside a validator to include it in that validator’s logs.