For Google Cloud · Gemini Enterprise Agent Platform (formerly Vertex AI) · Agent Development Kit · Agent Engine · Apigee · MCP & A2A

Every ADK agent action,
independently judged before it executes.

Three actions below are shaped exactly as they leave an agent on Google Cloud — an ADK tool call, an API call through Apigee, an MCP tool call from an ADK toolset — and each one goes through the live Veridect system on this page. On your side the integration is one callback on the agent, one policy on the proxy, or a URL change in the toolset. Behind it is the whole control plane: consensus from frontier models across independent vendors, deterministic policy classes, risk routing, a hash-chained ledger, and an Ed25519-signed decision record you can verify right here.

Open the full live tour
3 seams
a callback, an Apigee policy, or one MCP URL — your agents, tools, deployments and models stay exactly as they are
1 judgment
POST /pre-action — behind every path (the MCP gateway makes that call for you); the answer is a verdict plus a signed record
1 record each
every decision — pass, hold or refusal — is a signed record, exportable as newline-delimited JSON into BigQuery or Cloud Logging
0 trust required
every decision re-derives from its recorded inputs and verifies against a published key — try it below
Where it sits

Between the agent’s plan and the tool.

Google Cloud runs the agent: the Agent Development Kit builds it, Agent Engine runs and scales it, Gemini Enterprise puts it in front of employees, Apigee fronts the enterprise APIs it calls, and MCP and A2A connect it to tools and to other agents. Veridect sits at the one moment none of those were built to own: the instant before a tool call with consequences executes — a refund issued, a payment released, a dataset changed, a record rewritten — when an independent judgment — not the model that proposed the action, not the platform that hosts it — decides whether it goes, waits for a person, or never happens, and signs the record either way.

Your agent on Google Cloud

Proposes an action

  • ADK agents on Agent Engine proposing tool calls that pay, ship, change or delete
  • Enterprise APIs the agent calls through Apigee
  • Any MCP tool an ADK toolset reaches — MCP Toolbox servers, your own, or third-party
Veridect · live control plane

Judges it before it runs

  • Deterministic scope check against the agent’s configured authority
  • Policy classes in code — money thresholds, protected data, regulated data, cumulative exposure
  • Multi-vendor model consensus with calibrated confidence and a dissent register
  • Risk routing: greenlight, escalate to a named human queue, or block
  • Hash-chained, Ed25519-signed record — written whether it passes or not
Outcome

Three doors, one record

greenlightthe tool runs, the API call proceeds or the MCP call is forwarded; the verdict and record id travel with it
escalateheld for a person in the queue the policy names — the callback returns the verdict as the tool result, the proxy returns the hold, the MCP call waits
blocknever executes — and the refusal is on the ledger too
Three thin paths

The integration is thin. The system behind it is not.

Each path maps the call your agent was already making onto one judgment — POST /api/ai/consensus/pre-action, made by the callback, the Apigee policy, or the MCP gateway on your behalf: the verb, the target, the fields, which agent is asking, and what that agent is authorized to do. Nothing about the agent, the model, the tool or the deployment changes. The verdict decides whether the original action proceeds.

PATH 01 · ADK · before_tool_callback

One callback on the agent, one judgment before every tool

The ADK runs before_tool_callback before every tool an agent calls. Post the proposed call to Veridect there: return None on a greenlight and the tool runs as written; return a dict otherwise and the ADK skips the tool and hands that dict — verdict and record id — back to the model as the tool’s result, so the agent tells the user the action is waiting for a person instead of pretending it happened. Attach it to one agent, or as a plugin to every agent in the runner.

~20 lines · one callback or one plugin · tools unchanged

Fail-closed by construction: a network error, a timeout or a malformed response is a dict, never None, so the tool does not run. The Veridect key comes from Secret Manager, never from the agent’s instructions.

# the judgment before every tool call — one callback, attached to the agent (or a Plugin for the whole runner)
import os, requests
from typing import Any, Dict, Optional
from google.adk.agents import LlmAgent
from google.adk.tools.base_tool import BaseTool
from google.adk.tools.tool_context import ToolContext

AGENT_SCOPE = "may read orders and may approve replacement shipments for items reported damaged"   # its configured authority, in words

def veridect_before_tool(tool: BaseTool, args: Dict[str, Any], tool_context: ToolContext) -> Optional[Dict]:
    verdict, record_id = "unavailable", ""                                  # closed until proven open
    try:
        r = requests.post("https://<your-veridect-host>/api/ai/consensus/pre-action", timeout=60,
            headers={"Authorization": "Bearer " + os.environ["VERIDECT_API_KEY"]},   # from Secret Manager
            json={"action": tool.name, "target": "adk:" + tool.name, "parameters": args,
                  "callingAgent": tool_context.agent_name, "callingAgentScope": AGENT_SCOPE,
                  "context": "session " + tool_context.session.id, "department": "customer_operations"})
        d = r.json() if r.status_code == 200 else {}
        verdict, record_id = d.get("verdict", "unavailable"), d.get("auditBundleId", "")
    except Exception:
        pass                                                                # network, timeout, parse: all stay closed
    tool_context.state["veridect_record"] = record_id                           # the record id rides with the session
    if verdict == "greenlight":
        return None                                                         # the tool runs, as written
    return {"executed": False, "verdict": verdict, "record_id": record_id}   # tool skipped; this becomes its result

agent = LlmAgent(name="order_support_agent", model="gemini-2.5-pro", tools=[lookup_order, create_replacement_shipment],
                 before_tool_callback=veridect_before_tool)
PATH 02 · APIGEE · POLICY ON THE PROXY

A policy on the API the agent calls, no agent code

Where agents reach enterprise systems through Apigee, put the judgment on the proxy: verify the agent’s own token, look up its authority by that verified identity, then a ServiceCallout to Veridect in the request flow, an ExtractVariables for the verdict, and a RaiseFault unless it is a greenlight. Every agent that calls the API is covered, whatever built it; the target system and the agent do not change.

5 policies · one proxy · no agent code

Where the authority lives: the scope string is the agent’s configured authority, looked up on the proxy by the agent’s verified client id — a caller cannot widen it with a header. A read-only reporting agent that proposes to delete rows is a categorical no-authority action — the deterministic layer blocks it before any model is asked to weigh in. Watch it below. The policy classes work over field names; send values only for the fields your policy needs.

<!-- Apigee proxy: PreFlow request — ask Veridect, then fault unless greenlight -->
<OAuthV2 name="OA-VerifyAgent"><Operation>VerifyAccessToken</Operation></OAuthV2>   <!-- the agent's own credential; sets accesstoken.client_id -->

<KeyValueMapOperations name="KVM-AgentAuthority" mapIdentifier="agent-authority">   <!-- authority keyed by the verified client id, never a caller header -->
  <Get assignTo="agent_scope"><Key><Parameter ref="accesstoken.client_id"/></Key></Get>
</KeyValueMapOperations>
<RaiseFault name="RF-UnknownAgent"><FaultResponse><Set><StatusCode>403</StatusCode></Set></FaultResponse></RaiseFault>   <!-- Step Condition: agent_scope is null -->

<ServiceCallout name="SC-Veridect">
  <Request variable="veridectReq">
    <Set>
      <Headers><Header name="Authorization">Bearer {private.veridect_key}</Header></Headers>   <!-- KVM-backed -->
      <Payload contentType="application/json">{
        "action": "{request.verb}:{proxy.pathsuffix}",                 <!-- the operation itself, e.g. POST:/payments/release -->
        "target": "{apiproxy.name}",
        "parameters": {request.content},
        "callingAgent": "{accesstoken.client_id}",                     <!-- from the verified token -->
        "callingAgentScope": "{agent_scope}"                            <!-- its configured authority, in words -->
      }</Payload>
      <Verb>POST</Verb>
    </Set>
  </Request>
  <Response>veridectRes</Response>
  <Timeout>60000</Timeout>
  <HTTPTargetConnection><URL>https://<your-veridect-host>/api/ai/consensus/pre-action</URL></HTTPTargetConnection>
</ServiceCallout>

<ExtractVariables name="EV-Verdict">
  <Source>veridectRes</Source>
  <JSONPayload><Variable name="verdict"><JSONPath>$.verdict</JSONPath></Variable>
               <Variable name="recordId"><JSONPath>$.auditBundleId</JSONPath></Variable></JSONPayload>
</ExtractVariables>

<RaiseFault name="RF-NotGreenlit">                       <!-- Step Condition: verdict != "greenlight" (unset counts) -->
  <FaultResponse><Set><StatusCode>409</StatusCode>
    <Payload contentType="application/json">{"executed": false, "verdict": "{verdict}", "record_id": "{recordId}"}</Payload>
  </Set></FaultResponse>
</RaiseFault>
<!-- on greenlight the request continues to the target with X-Veridect-Record: {recordId} -->
PATH 03 · MCP · ADK TOOLSET

One MCP URL in the toolset

ADK agents reach MCP servers through McpToolset — MCP Toolbox for Databases servers, your own, or a third party’s. Register the real server as a Veridect upstream once and give the toolset the Veridect gateway URL instead. Every tools/call is judged in flight; tools/list, initialize and everything else pass straight through. A refused call is never forwarded.

0 lines of agent logic · one registration, one URL

Identity on the wire: the agent’s identity, session and business context ride in params._meta["veridect/…"] — unsigned, that is the caller’s own claim, and the decision record marks it as such; a tenant can require a signed Ed25519 identity envelope on every call, and an unsigned call is then refused inside the protocol. Both outcomes run live below.

# 1) once — register the real MCP server as an upstream (admin call)
POST /api/ai/consensus/mcp/upstreams/{tenant}
{ "upstreamId": "toolbox-orders-prod", "url": "https://<your-mcp-server>/mcp", "enabled": true }

# 2) the toolset — one URL changes
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams

tools = McpToolset(connection_params=StreamableHTTPConnectionParams(
    # before:  url="https://<your-mcp-server>/mcp"
    url="https://<your-veridect-host>/api/mcp/gateway/toolbox-orders-prod",
    headers={
        "Authorization":            "Bearer " + os.environ["VERIDECT_API_KEY"],   # your Veridect tenant
        "X-Upstream-Authorization": "Bearer " + upstream_token,                 # forwarded to the server as Authorization
    }))
agent = LlmAgent(name="order_support_agent", model="gemini-2.5-pro", tools=[tools])

# 3) what the agent sees on a greenlight: the server's own result, plus
#    result._meta["veridect/verdict"] and result._meta["veridect/bundleId"]
#    on escalate / block: a JSON-RPC error (-32003 / -32004) carrying the
#    verdict and the record id — and the server never receives the call.
Run it live

Four ADK-shaped actions, through the live system, now.

Each card sends the exact request the callback, the Apigee policy, or the toolset would send, to the live Veridect system on a shared sandbox tenant. The verdicts are real multi-model decisions made while you wait; the records are written to the ledger and signed; the Verify button re-derives the verdict from the recorded inputs and checks the signature against the published key. Expected outcomes are stated in advance — the engine decides.

Ready. Each decision takes a few seconds while the model roster deliberates.
LIVE 01 · PATH 01 · ADK CALLBACK

Ship a replacement for an item that arrived damaged

An order-support agent proposes create_replacement_shipment for an order whose item arrived damaged — same item, same address on file, standard shipping, the customer’s photo already on the ticket. Its configured authority: “may read orders and may approve replacement shipments for items reported damaged.”

Expected: greenlight — inside authority, no policy class fires, the roster agrees. The callback returns None, the tool runs, and the record id sits in session state.

Waiting. Request shape: the callback’s body, verbatim.
LIVE 02 · PATH 02 · APIGEE POLICY

A read-only reporting agent tries to delete rows from a dataset

A weekly-report agent proposes delete_rows on the analytics.events_daily table after judging a partition duplicated. Its configured authority: “read-only: may query BigQuery datasets to draft weekly reports.”

Expected: block — a read-only agent proposing to delete rows is a categorical no-authority action; the deterministic scope check decides, the models are consulted for the record, and the proxy raises the fault before the call reaches the target.

Waiting. Request shape: the Apigee callout’s body, verbatim.
LIVE 03 · PATH 01 · ADK CALLBACK

Release a vendor payment above the policy limit

An accounts-payable agent, inside its authority (“may read invoices and may release payments to approved vendors”), calls release_vendor_payment for an approved invoice at an amount above this tenant’s policy limit of $10,000.

Expected: escalate — the deterministic dollar_threshold policy class fires and routes the action to the queue the policy names. Authorized but consequential actions escalate to a person; they are never silently blocked and never silently allowed.

Waiting. Request shape: the callback’s body, verbatim.
LIVE 04 · PATH 03 · MCP

The same tools/call, two tenants, two outcomes

A JSON-RPC tools/call for lookup_policy_limit goes through the live Veridect MCP gateway to a sample tool server that counts what it actually receives — the call an ADK toolset would make. First on the shared sandbox tenant; then on a tenant that requires a signed identity envelope, sent without one.

Expected: first call forwarded, the tool’s own hit counter goes up by one and the result carries _meta["veridect/bundleId"]; second call refused inside the protocol (-32004 identity_not_presented), counter unchanged, refusal on the ledger.

Waiting. Request shape: JSON-RPC 2.0, verbatim.

What on this page is live, and what is illustrative

Live: every verdict, confidence, dissent register, policy class, escalation route, ledger write, hash chain, Ed25519 signature, MCP forwarding decision and verification result above comes from the production Veridect system on a shared sandbox tenant — the same endpoints an integrator calls. The consensus roster is four frontier providers from independent vendors with a decisive-verdict early stop, so a decision on this surface typically records three; the models are named in each record’s dissent register. The payment threshold and the protected-data classes are this sandbox tenant’s policy; in your tenant every threshold is yours.

Illustrative: the agent side. No ADK agent, Agent Engine deployment, Apigee proxy or BigQuery statement executes from this page; each card sends the exact request the callback, the policy or the toolset would send, so what you watch is the decision those integrations would receive. The MCP calls in Live 04 leave this browser as a standard MCP client; an ADK toolset’s MCP connection was not exercised here. The code above is written against the documented ADK before_tool_callback contract, McpToolset connection parameters, and standard Apigee policies; the proxy is shown schematically, the header names are yours to choose, and the server URL is a placeholder for your own. The integration is demonstrated wiring, not a Google Cloud-certified, Marketplace-listed or endorsed solution.

Verification proves that the enforcement decision re-derives from the recorded inputs and that the record is unmodified and signed by the published key. It does not re-run the models: the consensus summary is attested through the recorded dissent register and verifier-text hash, and disclosed as such in the proof itself.

Google Cloud, Gemini, Gemini Enterprise, Vertex AI, Agent Development Kit, Apigee and BigQuery are trademarks of Google LLC. Veridect is an independent company and is not affiliated with or endorsed by Google.

Five questions, answered for a Google Cloud team

The short version.

How does this help?

It lets agents on the Gemini Enterprise Agent Platform into the tool calls that carry consequences — refunds, payments, dataset changes, record rewrites — because an independent judgment stands in front of each action and a signed record stands behind it. The model that proposes the action is never the one that approves it.

How do I integrate it?

One of the three paths above: a callback on the agent, a policy on the Apigee proxy, or one MCP URL in the toolset. Your agents, tools, deployments and models stay as they are. The decision records export as newline-delimited JSON into BigQuery or Cloud Logging. It runs where you say, on your keys.

How long does it take?

The system is live today. A private sandbox on your own policy thresholds in a day once you say go; production typically about two weeks, with the pace set mostly on your side — security review, keys, access. Ours is ready on day one.

How does this make money?

Three levers, none of them invented here: revenue held back because agents could not be trusted with the consequential step; cost stopped on human review of actions a signed record now settles; losses not taken on the actions that should never have executed. Your own number comes out of the sandbox.

Why you and not a big well-known company?

Because the judgment has to be independent of the model and of the platform to be worth anything to an auditor. The platform’s own guardrails and the model’s own safety settings are the platform’s view of its agents; a platform grading its own agents is self-governance. Veridect is a separate control plane with its own ledger and keys, validated by an external red team on scope-violation semantics, and verifiable offline. Try to forge a record on the live tour; the engine refuses it.

Test-drive it yourself.

Run the four actions above, verify the records, then take the full live tour — identity envelopes, delegation chains, cross-agent exposure, the fleet layer, and the forgery the engine refuses. Seven minutes, open access.

Prefer to see it on your own scenarios? Paste one on the pre-action console — or write to lrussell@veridect.ai and a scoped production sandbox on your own thresholds and your own tenant follows in a day.

The same control plane, built the same way for Snowflake, Microsoft, AWS, ServiceNow, CrowdStrike, Rubrik, Salesforce, Databricks and Okta — one engine behind all ten pages, each run live. All ten platforms →