Skip to content

Reference

Contract and read-back JSON

Fields of the runtime contract, the scan contract and the readback object.

View source on GitHub (opens in a new tab)

On this page

Two JSON formats matter. The runtime contract is read by fourgate guard and fourgate doctor. The scan contract is read by fourgate scan, and its cases carry the same extraction and read-back settings. fourgate init writes both, plus a standalone readback.json.

Runtime contract#

Top level:

FieldDescription
contract_version1.
toolsObject keyed by the exact MCP tool name. Only the tools listed here are protected.

Per tool, under tools.<name>:

FieldDescription
extractAn allowlist of named selectors. Only these fields reach the verifier. A missing required selector makes the evaluation UNKNOWN, never FAIL.
verifier.commandThe verifier as an argument array. {python} selects the interpreter that runs Fourgate.
verifier.cwdWorking directory, relative to the contract file.
verifier.timeout_msMandatory. Capped by Fourgate; the runtime cap is 2000 ms.
verifier.secret_envOptional. Names of environment variables only the verifier may see. fourgate guard removes them from the wrapped server's environment (case-insensitively on Windows). A name that is not a valid variable name rejects the contract file.
allowed_failure_reasonsReason codes the verifier may report with a FAIL. Any other verifier output is UNKNOWN.
recoveryCopied into the outcome_failed verdict. The documented examples use "stop".

Selectors#

Each entry in extract names a source and a path:

FieldDescription
sourcearguments or result.
pathA dot path, for example result.structuredContent.issue_id or title. List indexes are numbers, as in result.content.0.text.
parseOptional, for text in result.content.0.text: embedded_json or regex.
fieldWith embedded_json: the field to read from the embedded JSON object.
pattern, groupWith regex: the pattern (at most 256 characters) and the capture group to return.

The text read by a text selector is limited to 8192 characters. Configure text selectors for a known test-server response; text alone never confirms delivery or persistence.

JSON
{"source":"result","path":"result.content.0.text","parse":"embedded_json","field":"id"}

Verifier protocol#

The verifier receives only the extracted JSON object on stdin and writes exactly one typed JSON object to stdout:

JSON
{"status":"pass"}{"status":"fail","reason_code":"record_missing"}

A verifier may include an evidence object with a FAIL. It is available to the local scan report after redaction, and it never enters the runtime verdict or the outcome log.

Scan contract#

FieldDescription
scan_versionExactly 1.
server.transport"stdio".
server.commandThe server command as an array (no shell). It runs with the contract's directory as its working directory.
server.test_accountA non-empty label. --confirm-test-account must repeat it exactly.
server.protocol_versionOptional: 2024-11-05 or 2025-11-25.
server.call_timeout_msOptional: 1–10000, default 5000.
write_toolsUnique tool names that may be called.
cases[].toolA tool in write_tools.
cases[].argumentsThe exact test arguments.
cases[].outcome_contract.extractSelectors, as above.
cases[].outcome_contract.record_id_fieldOptional. The extracted field holding the created record's ID. If it is configured and the ID is absent, the verdict is UNKNOWN / success_without_record_id with zero read-back attempts. Scan only: at runtime a result without the ID is UNKNOWN.
cases[].outcome_contract.verifier, allowed_failure_reasons, recoveryThe command verifier protocol, as above.
cases[].readbackUse a readback object instead of a command verifier.

A case is never synthesized from tools/list, and no malformed or edge calls are generated.

Read-back object#

readback.json is a scan contract readback object.

FieldDocumented forDescription
typeboth"http" or "github_issue".
url_templatehttpA static-host HTTPS URL with {extracted_name} placeholders in the path or query.
expected_fieldsbothMaps a dot path in the response JSON to an extracted field name.
missing_statuseshttpOptional status codes that count as evidence of absence, for example [404].
repositorygithub_issueA fixed owner/name.
issue_number_fieldgithub_issueThe extracted field that holds the issue number.
missing_is_failgithub_issueDefault false: a 404 is UNKNOWN.
token_envbothEnvironment variable name of the read token.
authhttpscheme (bearer, header or basic) plus header, prefix, username, username_env, token_as or password. See HTTP read-back authentication.
headershttpFixed, non-secret headers.
attemptsboth1–5.
interval_msboth0–2000.
timeout_msbothTotal budget, 1–10000. At most 1500 for readback.json used under guard.

HTTPS only off loopback, a static host, and no redirects. The read-back sends GET requests only.

For generic HTTP read-back, an UNKNOWN / readback_unconfirmed after an HTTP response carries evidence.readback.method: "GET" and the last observed evidence.readback.status in the JSON and HTML reports. That evidence does not include response headers, authorization, URL or body, and reporting the status does not change the verdict.