A multi-agent system for intelligent insurance cross-selling built with Google's Agent Development Kit (ADK), Model Context Protocol (MCP) servers, and agent-to-agent communication. This system orchestrates insurance cross-selling opportunities by analyzing customer data, identifying suitable products, and coordinating customer communications through specialized AI agents.
This showcase demonstrates the capabilities of the Agentic Layer platform for building complex multi-agent AI systems. Further information about the Agentic Layer can be found in our documentation.
- Intro
- Prerequisites
- Getting Started
- Development
- End-to-End (E2E) Testing
- PII Guardrail Demo
- Testing Tools and Their Configuration
- Sample Data
- Project Architecture
In this showcase, a host agent uses tools and calls other agents to facilitate user requests like so:
Conversation 1:
Nutzer: Bitte bereite mir ein Kundengespräch mit der Kundin Anna Müller vor.
Agent: Gern helfe ich dir, das Gespräch vorzubereiten. Hier sind Optionen für verschiedene Verkaufsstrategien: …
Nutzer: Bitte verschicke eine E-Mail an die Kundin mit einer Agenda.
Agent: Erledigt.
Conversation 2:
Nutzer: Bitte bereite mir ein Kundengespräch mit dem Kunden Thomas Schmidt vor. Sende außerdem eine Erinnerungs-Mail an den Kunden, dass das Gespräch stattfindet.
Agent: Hier ist die Vorbereitung für dein Gespräch. Die Erinnerungsmail habe ich verschickt: …
The following tools and dependencies are required to run this project:
- mise: Dev tool manager — installs Python, uv, pre-commit, tilt
- Docker: For containerization and local Kubernetes
- Gemini API Key
# Install all development tools via mise (Python, uv, pre-commit, tilt, jq, helm, kustomize)
mise install# Install Python dependencies
uv sync --directory mcp-servers# Authenticate with Google Cloud for AI model access
gcloud auth application-default loginCreate a .env file in the root directory with the following content:
# Google Cloud Configuration
GOOGLE_GENAI_USE_VERTEXAI=FALSE
GOOGLE_CLOUD_PROJECT=qaware-paal
GOOGLE_CLOUD_LOCATION=europe-west3
GOOGLE_API_KEY=your-google-api-key
# LiteLLM Api Key. Defaults to the master key (optional)
LITELLM_PROXY_API_KEY=sk-your-api-keyLaunch all services using Tilt:
# Start core agents and MCP servers
tilt upOptional components can be enabled using profiles. Specify one or more profiles with --profile:
# Start with LibreChat UI
tilt up -- --profile librechat
# Start with Testbench for RAGAS evaluations
tilt up -- --profile testbench
# Combine multiple profiles
tilt up -- --profile librechat --profile testbench| Profile | Description |
|---|---|
librechat |
Deploys a LibreChat instance as a chat UI for interacting with the insurance host agent. Available at http://localhost:11003. |
testbench |
Deploys the Testbench with TestKube for running RAGAS evaluation TestWorkflows against the agents. |
Expected Results:
- Grafana at http://localhost:11000
- AI Gateway at http://localhost:11001
- Agent Gateway at http://localhost:11002
- Insurance Host Agent at http://localhost:11010
- Communications Agent at http://localhost:11011
- Cross-Selling Agent at http://localhost:11012
- Frontend at http://localhost:11013
- Customer CRM MCP Server at http://localhost:11020
- Insurance Products MCP Server at http://localhost:11021
With profiles enabled:
- LibreChat (chat interface) at http://localhost:11003 (
librechatprofile)
This project provides a Helm chart for deploying the showcase to Kubernetes clusters.
The Helm chart is published to GitHub Container Registry for each release tag. You need to install the Agentic Layer components first, see https://docs.agentic-layer.ai.
# Install the latest release
helm install showcase-cross-selling \
oci://ghcr.io/agentic-layer/charts/showcase-cross-selling \
--version 0.6.0 \
--namespace showcase-cross-selling \
--create-namespaceFor detailed contributing guidelines, refer to the global contributing guide.
Mandatory first step for contributors:
# Activate pre-commit hooks
pre-commit installCode Style:
- Linting: Ruff with 120 character line limit
- Type Checking: mypy for static type analysis
- Security: Bandit for security vulnerability detection
- Import Organization: import-linter for dependency management
Development Commands:
# Run all quality checks
uv run --directory mcp-servers poe check
# Individual checks
uv run --directory mcp-servers poe mypy # Type checking
uv run --directory mcp-servers poe ruff # Linting and formatting
uv run --directory mcp-servers poe bandit # Security analysis
uv run --directory mcp-servers poe lint-imports # Import dependency validation
uv run --directory mcp-servers poe test # Execute test suite
# Auto-formatting
uv run --directory mcp-servers poe format # Code formatting
uv run --directory mcp-servers poe lint # Auto-fix linting issuesExecute the end-to-end test suite to validate the complete agent workflow:
# Run the cross-selling conversation test
./test/e2e/a2a-message.shPrerequisites for E2E Tests:
- All services must be running (
tilt up)
Test Coverage:
- Cross-selling strategy generation for customer
Anna Müller - Agent-to-agent communication validation
- OpenAI-compatible API endpoint functionality
- Response content validation for German language interactions
The project includes TestKube TestWorkflows for automated RAGAS evaluation of agents. To run them manually:
# Run the cross-selling agent evaluation
testkube run tw cross-selling-ragas-evaluation
# Run the insurance host agent evaluation
testkube run tw insurance-host-ragas-evaluationResults can be viewed in the Workflow Evaluations Dashboard in Grafana (http://localhost:11000).
Prerequisites:
- All agent services must be running (
tilt up) - TestKube CLI must be installed
The showcase enforces a PII guardrail at the AI Gateway using
Presidio. Customer emails and
phone numbers are masked before they reach the LLM, while the broker's
workflow continues to work end-to-end because the agents reference
customers by customer_id, not by PII.
The guardrail is configured in deploy/local/guardrail-presidio.yaml.
Start the stack with a chat UI — either the showcase frontend (default) or LibreChat:
# Option A: showcase frontend at http://localhost:11013
tilt up
# Option B: LibreChat at http://localhost:11003
tilt up -- --profile librechatThen open the chat UI and walk through the two scenarios below. They show different sides of the guardrail.
Send these messages to the host agent in order:
- Bitte bereite mir ein Kundengespräch mit der Kundin Anna Müller vor.
- Bitte verschicke eine E-Mail an die Kundin mit einer Agenda.
Expected: a German cross-selling strategy for Anna Müller, followed
by a confirmation that the email was sent. The strategy contains no
email address and no phone number — yet the email send still
succeeds, because the send_email tool addresses the recipient by
customer_id.
In a fresh conversation, ask the host agent directly for a customer's contact data:
Wie lautet die Email-Adresse von Anna Müller?
Expected: the agent refuses in German, explains that contact data is private, and offers to send an email on the broker's behalf — for example: "Die E-Mail-Adresse von Anna Müller unterliegt dem Datenschutz und kann daher nicht an Sie weitergegeben werden. Gerne kann ich jedoch eine E-Mail in Ihrem Namen verfassen…".
This behaviour is enforced by the # PII Protection rules in the
insurance-host-agent and cross-selling-agent instructions
(chart/templates/*.yaml). Without them, the LLM would only see a
<EMAIL_ADDRESS> placeholder where the real email used to be and
would tend to fabricate a plausible-looking address to fill the
gap. The prompt rules teach the agent to recognise the masked state
and decline instead.
Inspect the Presidio pod logs for masked tokens in the anonymizer payload:
kubectl -n ai-gateway logs deploy/presidio | grep -E '<EMAIL_ADDRESS>|<PHONE_NUMBER>'Or open Grafana at http://localhost:11000 and find the Presidio analyze/anonymize span on the request trace.
The mock send_email(customer_id, subject, body) does not need an email
address — the system maps customer_id to the recipient downstream.
The cross-selling LLM call only needs the customer's profile signals
(age, occupation, family situation, existing policies) to recommend
products. PII is therefore unnecessary in the LLM context, and the
guardrail enforces that.
Primary Tool: Bash/cURL Integration Tests
- Location:
test/e2e/a2a-message.sh - Configuration: Tests use OpenAI-compatible API endpoints
- Validation: Response content matching using
grepwith German keywords
Example Test Configuration:
# API endpoint configuration
API_ENDPOINT="http://localhost:11002/api/v1/chat/completions"
MODEL_NAME="insurance_host_agent"
TIMEOUT="90" # seconds# Content validation patterns
EXPECTED_PATTERNS="cust001\|cross.sell\|strategie\|kunde"The system includes mock customer data accessible through the Customer CRM MCP server:
Sample Customer Record (Anna Müller):
{
"customer_id": "cust001",
"name": "Anna Müller",
"current_policies": [
"auto_insurance",
"home_insurance"
],
"demographics": {
"age": 35,
"location": "Munich",
"income_level": "middle"
}
}Sample API Request:
# Test cross-selling recommendation
curl -X POST http://localhost:11002/insurance-host-agent \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [
{
"kind": "text",
"text": "Welche Cross-Selling-Möglichkeiten gibt es für unsere Kundin Anna Müller?"
}
],
"messageId": "9229e770-767c-417b-a0b0-f0741243c589",
"contextId": "abcd1234-5678-90ab-cdef-1234567890ab"
},
"metadata": {"conversationId": "9229e770-767c-417b-a0b0-f0741243c589"}
}
}'Database Seeding: Customer and product data is automatically initialized when MCP servers start. No manual seeding required.
frontend/ # React/TypeScript frontend application
├── Dockerfile # Multi-stage build (Node.js → Nginx)
├── package.json # Frontend dependencies
├── vite.config.ts # Vite build configuration
├── nginx.conf.template # Nginx reverse proxy config
└── src/ # React source code
mcp-servers/ # Python MCP servers
├── Dockerfile # Single image, server selected via CMD
├── pyproject.toml # Unified Python project
└── src/
├── shared/ # Shared utilities (otel, middleware, response helpers)
├── customer_crm/ # Customer relationship management data
└── insurance_products/ # Insurance product catalog server