Validate MCP output against policies
Validate MCP response data against configured policies without having executed the query through AxonFlow.
This endpoint enables external orchestrators to apply AxonFlow's output-side policy enforcement (PII redaction, exfiltration limits, SQLi response scanning) to data they fetched from MCP connectors independently.
Policy Evaluation
The following checks are applied in order:
- SQLi response scanning: Detects SQL injection artifacts in response data
- Static response policies: PII detection and redaction (SSN, credit card, Aadhaar, etc.)
- Exfiltration limits (query-style only): Row count and byte size limits
If PII is detected, the response includes redacted_data with masked values. If exfiltration limits are exceeded, the response returns allowed: false.
Query vs Execute Responses
- Query responses (response_data): Full policy evaluation including exfiltration checks
- Execute responses (message): SQLi scanning and PII checks only (no exfiltration limits)
Audit Logging
All check-output evaluations are logged to the mcp_query_audits table with operation: "check-output" for compliance tracking.
Request
- Base URLhttps://agent.getaxonflow.com
- Authnone declared
- TypeScriptA function with typed inputs. Its response is checked against the schema.
Headers
Optional client-version telemetry header (<client>/<version>, e.g. mcp-proxy/0.3.1 or claude-code/1.9.1). Enterprise deployments with the client_version_telemetry capability count validated values in the axonflow_client_version_requests_total metric on the decide and MCP check-output planes. Telemetry only — never used for authentication or authorization; invalid values are ignored.
base64url (padding optional) of the PEPHandshake document.
The ADR-065 PEP capability handshake: base64url of a compact JSON document in which an external enforcement point declares what it is and which obligations it can discharge. See PEPHandshake for the document.
Absent is the default and changes nothing. A caller that omits the header takes byte-for-byte the path it took before this header existed.
What an absent header means for a redaction depends on the plane, by design (PRD v11 section 1 item 16, #4257). The MCP passes discharge a redaction of the content they hand back: the request pass (check-input, check_policy) masks the statement, and a redaction that masks nothing in the statement is refused unsupported_obligation to every caller, and one that masks a request parameter to every caller that has not declared field_redact at version 2 (on Community, to every caller) (#4264); the response passes (check-output, the MCP server's check_output) mask the rows or the message. /api/v1/decide and the gateway pre-check return a decision rather than content, so a required redaction is a field_redact obligation for the enforcement point, and a caller that has not declared field_redact is refused unsupported_obligation. A caller that declares NO redaction (capabilities: []) is refused on each of these planes; on Community the MCP passes still return a checksum validator's masked content to it (reachable only through a directly inserted detection_action_overrides row) until #4122.
A header that is PRESENT and cannot be read is refused, never treated as absent: degrading a malformed declaration to "legacy caller" would go on handing an enforcement point obligations it had just said it cannot discharge. The refusal is 400 and its message names this header, which matters on /api/v1/access/evaluation where the refusal is rendered through that surface's existing incomplete_evaluation code and the message is the only thing distinguishing a malformed HEADER from a malformed body ENVELOPE.
Present more than once is refused: RFC 7230 permits an intermediary to join repeated field lines with a comma, and a comma is outside the base64 alphabet, so a joined pair can only decode to malformed. That is why the document is base64 rather than raw JSON, which would join into something a lenient parser might accept.
When a decision carries a mandatory obligation the declared set does not cover, the request is answered 200 with verdict: deny and the reason unsupported_obligation (ADR-065 invariant 8) - a decision about the request, not a transport error. That holds on every edition. An Enterprise deployment adds a second reason beginning pep_capability_unsupported naming the gap, and refuses a checksum validator's mask on the MCP passes; a Community deployment hands that masked content over (#4257 split 2, #4122).
Request body
Response
Output passed all policy checks (may include redacted data)
Changes
No recorded changes to this operation across all 1 revision of this API.