Skip to content

Google Vertex AI (Agent Builder + ADK) + A2A governance with MeshGuard ​

MeshGuard adds agent identity, policy enforcement, and auditing on top of Google Vertex AI agents—especially when you operate a multi-agent mesh where agents delegate work to other agents (A2A / Agent-to-Agent).

This guide shows:

  • How to govern Vertex AI agents built with Google’s Agent Development Kit (ADK)
  • How to enforce policy on A2A (Agent2Agent) communication
  • How to attach MeshGuard checks to tools, delegation, and cross-agent messages

Terminology

  • Vertex AI Agent Builder: Google’s managed agent orchestration/product surface.
  • ADK (Agent Development Kit): The Python SDK you use to implement agents and tools.
  • A2A (Agent2Agent): A pattern/protocol where one agent delegates tasks or sends messages to another agent.
  • MeshGuard: Your governance layer. In this integration, MeshGuard acts as the Policy Enforcement Point (PEP).

Why MeshGuard for Vertex AI multi-agent systems? ​

Vertex AI provides strong safety controls (e.g., content safety filters, grounding tools, prompt/response moderation), but enterprise agent systems also need:

  • Agent identity & authentication: Which agent is acting? Which org/team owns it?
  • Delegation controls: Which agents may delegate to which other agents, and for what tasks?
  • Tool/permission enforcement: Can this agent call this tool right now, given the context?
  • Unified audit across vendors and runtimes (Vertex AI, internal services, other LLM stacks)

MeshGuard provides these as a consistent layer, independent of the underlying model provider.


Architecture ​

A common governance placement looks like:

  1. Agent runtime (ADK / Agent Builder)
  2. MeshGuard check before sensitive actions:
    • tool invocation (e.g., CRM read)
    • A2A send (delegate)
    • A2A receive (accept delegation)
  3. Execute only if permitted
  4. Log / audit decision context + outcome

MeshGuard is the policy enforcement point for:

  • tool:* permissions
  • data:* permissions
  • a2a:* permissions (cross-agent communication)

Prerequisites ​

  • Python 3.10+
  • A Google Cloud project with Vertex AI enabled
  • Auth configured (one of):
    • gcloud auth application-default login (dev)
    • Workload Identity / Service Account JSON (prod)
  • MeshGuard agent token (per agent identity)

Install dependencies:

bash
pip install google-cloud-aiplatform meshguard

Initialize Vertex AI:

python
import vertexai

vertexai.init(
    project="YOUR_GCP_PROJECT_ID",
    location="us-central1",
)

MeshGuard client setup (per agent) ​

Each running agent should authenticate to MeshGuard with its own agent token. This ensures audits and policy are tied to an agent identity.

python
from meshguard import MeshGuardClient

meshguard = MeshGuardClient(
    gateway_url="https://dashboard.meshguard.app",
    agent_token="YOUR_AGENT_TOKEN",
)

Pattern 1: Govern tool calls inside an ADK agent ​

Wrap every sensitive tool call with a MeshGuard check.

Example: a governed CRM read tool ​

python
from typing import Any, Dict
from meshguard import MeshGuardClient

class CRMTool:
    def __init__(self, meshguard: MeshGuardClient):
        self.meshguard = meshguard

    def read_contact(self, contact_id: str, *, actor: str) -> Dict[str, Any]:
        # PEP: enforce policy *before* accessing data
        decision = self.meshguard.check(
            "read:contacts",
            context={
                "actor": actor,
                "resource": {"type": "contact", "id": contact_id},
                "tool": "crm.read_contact",
            },
        )
        if not decision.get("allow", False):
            raise PermissionError(f"MeshGuard denied read:contacts: {decision}")

        # Your real CRM call here
        return {"id": contact_id, "name": "Ada Lovelace", "email": "ada@example.com"}

Calling the tool from a Vertex AI Gemini model flow ​

The google-cloud-aiplatform package provides the vertexai Python module.

python
import vertexai
from vertexai.generative_models import GenerativeModel

from meshguard import MeshGuardClient

vertexai.init(project="YOUR_GCP_PROJECT_ID", location="us-central1")
model = GenerativeModel("gemini-1.5-pro")

meshguard = MeshGuardClient(
    gateway_url="https://dashboard.meshguard.app",
    agent_token="YOUR_AGENT_TOKEN",
)

crm = CRMTool(meshguard)

prompt = "Fetch contact 123 and summarize the email domain."  # example
response = model.generate_content(prompt)

# In a real agent, you would parse tool intents and route to crm.read_contact
contact = crm.read_contact("123", actor="vertex-agent-1")
summary = f"{contact['email'].split('@')[-1]}"
print(summary)

Pattern 2: Govern A2A (Agent2Agent) delegation with MeshGuard ​

When an agent delegates work to another agent, you should govern both sides:

  • Sender: Is agent A allowed to delegate this task to agent B?
  • Receiver: Is agent B allowed to accept tasks of this type from agent A?

This is where MeshGuard becomes a policy enforcement point for A2A.

A2A envelope (minimal) ​

Use a structured envelope so policy can reason about what’s happening:

python
from dataclasses import dataclass
from typing import Any, Dict, Optional

@dataclass
class A2AMessage:
    id: str
    sender: str
    recipient: str
    intent: str                # e.g. "research:vendor"
    payload: Dict[str, Any]
    trace_id: Optional[str] = None

Sender-side enforcement (a2a:send) ​

python
from meshguard import MeshGuardClient

def a2a_send(meshguard: MeshGuardClient, msg: A2AMessage) -> None:
    decision = meshguard.check(
        "a2a:send",
        context={
            "sender": msg.sender,
            "recipient": msg.recipient,
            "intent": msg.intent,
            "trace_id": msg.trace_id,
        },
    )
    if not decision.get("allow", False):
        raise PermissionError(f"MeshGuard denied a2a:send: {decision}")

    # Transport is up to you (HTTP, Pub/Sub, gRPC, etc.)
    # Example placeholder:
    # http_client.post(recipient_url, json=asdict(msg))
    print(f"A2A SEND -> {msg.recipient}: {msg.intent}")

Receiver-side enforcement (a2a:receive) ​

python
from meshguard import MeshGuardClient

def a2a_receive(meshguard: MeshGuardClient, msg: A2AMessage) -> None:
    decision = meshguard.check(
        "a2a:receive",
        context={
            "sender": msg.sender,
            "recipient": msg.recipient,
            "intent": msg.intent,
            "trace_id": msg.trace_id,
        },
    )
    if not decision.get("allow", False):
        raise PermissionError(f"MeshGuard denied a2a:receive: {decision}")

    print(f"A2A RECV <- {msg.sender}: {msg.intent}")

In ADK, “delegation” is often just another tool call (e.g., a tool that sends a task to another agent). The simplest integration strategy is:

  • implement a delegate_to_agent() tool
  • enforce MeshGuard before sending
  • enforce MeshGuard when the recipient receives

Delegation tool example ​

python
import uuid
from meshguard import MeshGuardClient

class DelegationTool:
    def __init__(self, meshguard: MeshGuardClient, *, sender: str):
        self.meshguard = meshguard
        self.sender = sender

    def delegate(self, *, recipient: str, intent: str, payload: dict, trace_id: str | None = None) -> dict:
        msg = {
            "id": str(uuid.uuid4()),
            "sender": self.sender,
            "recipient": recipient,
            "intent": intent,
            "payload": payload,
            "trace_id": trace_id,
        }

        decision = self.meshguard.check(
            "a2a:send",
            context={
                "sender": self.sender,
                "recipient": recipient,
                "intent": intent,
                "trace_id": trace_id,
            },
        )
        if not decision.get("allow", False):
            return {"ok": False, "error": "denied", "decision": decision}

        # Send via your transport
        # transport.send(msg)
        return {"ok": True, "message": msg}

Policy guidance: what to model in MeshGuard ​

Typical actions to define:

  • tool:crm.read_contact
  • data:contacts.read
  • a2a:send
  • a2a:receive
  • a2a:delegate:<intent> (optional, for finer-grained control)

Useful context fields:

  • sender, recipient
  • intent (task class)
  • trace_id (request lineage)
  • resource (data id/type)
  • environment (dev/prod)

Observability & audit ​

MeshGuard decisions should be logged with:

  • agent id / token identity
  • action (a2a:send, read:contacts, etc.)
  • key context fields (resource, recipient, intent)
  • allow/deny outcome and reason

This enables:

  • incident response for delegation misuse
  • demonstrating least-privilege controls
  • cross-vendor audits when your mesh spans Vertex + other systems

End-to-end example ​

See the vertex-ai-multiagent example in the MeshGuard examples repo for a working reference architecture:

  • multiple in-process agents
  • A2A envelopes
  • MeshGuard checks for tool use + delegation
  • minimal test suite

  • Learn: Governing Google Vertex AI Agents with MeshGuard
  • Learn: MeshGuard vs Vertex AI Guardrails

Governance Control Plane for AI Agents