Content
# ai-defense-google-adk
Cisco AI Defense plugin for [Google ADK](https://google.github.io/adk-docs/) — native callback-based LLM and MCP tool inspection.
This package integrates [Cisco AI Defense](https://www.cisco.com/site/us/en/products/security/ai-defense/index.html) runtime inspection directly into the ADK Runner lifecycle using a `BasePlugin` and per-agent callbacks. It supports both LLM prompt/response inspection and MCP tool call inspection, with monitor and enforce modes, plus optional violation callbacks and structured enforcement metadata.
## Use Cases
- **Runtime protection for Gemini calls**: Inspect user prompts before model calls and model outputs after generation, then allow or block based on policy (Monitor or Enforce).
- **Tool and MCP call inspection**: Inspect tool call requests before execution and tool responses after execution, and block unsafe tool behavior in Enforce mode with clear metadata.
- **Auditable decision trace and alerts**: Capture decision context (action, severity, classifications, request\_id/event\_id) and optionally trigger an `on_violation` callback for monitoring and incident response.
## Prerequisites
- [Cisco AI Defense](https://www.cisco.com/site/us/en/products/security/ai-defense/index.html) account and API key
- Python >= 3.10
- [Google ADK](https://google.github.io/adk-docs/) >= 1.0.0
## Installation
```bash
pip install cisco-aidefense-google-adk
```
## Quick Start (one-liner)
The fastest way to add AI Defense to any ADK agent:
```python
from aidefense_google_adk import defend
# Defend an agent (attaches all 4 callbacks automatically)
agent = defend(agent, mode="enforce")
# Or get a plugin for the App
plugin = defend(mode="enforce")
app = App(name="my_app", root_agent=agent, plugins=[plugin])
```
Set the `AI_DEFENSE_API_KEY` environment variable (and `AI_DEFENSE_MCP_API_KEY` for tool inspection) and you're done.
### Environment Variables
| Variable | Used by | Description |
|----------|---------|-------------|
| `AI_DEFENSE_API_KEY` | Raw client (LLM) | API key for prompt/response inspection |
| `AI_DEFENSE_MCP_API_KEY` | Raw client (MCP) | API key for tool call inspection |
| `AI_DEFENSE_RUNTIME_URL` | Raw client | Custom runtime endpoint URL |
| `AI_DEFENSE_MODE` | Raw client | Default mode (`monitor` / `enforce` / `off`) |
| `AI_DEFENSE_API_MODE_LLM_API_KEY` | Inspector (LLM) | API key for LLM inspection via agentsec |
| `AI_DEFENSE_API_MODE_MCP_API_KEY` | Inspector (MCP) | API key for MCP inspection via agentsec |
| `AI_DEFENSE_API_MODE_LLM_ENDPOINT` | Inspector (LLM) | Endpoint for LLM inspection |
| `AI_DEFENSE_API_MODE_MCP_ENDPOINT` | Inspector (MCP) | Endpoint for MCP inspection |
To see inspection logs without configuring Python logging:
```python
from aidefense_google_adk import configure_logging
configure_logging()
```
### Plugin (Tier 2) — Global, applies to all agents
```python
import os
from google.adk.agents import LlmAgent
from google.adk.apps import App
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from aidefense_google_adk import CiscoAIDefensePlugin
agent = LlmAgent(model="gemini-2.5-flash", name="assistant", instruction="...")
# API key auto-resolves from AI_DEFENSE_API_KEY env var
app = App(
name="my_app",
root_agent=agent,
plugins=[
CiscoAIDefensePlugin(mode="enforce"),
],
)
runner = Runner(app=app, session_service=InMemorySessionService())
```
### Agent Callbacks (Tier 1) — Per-agent
```python
from aidefense_google_adk import make_aidefense_callbacks
# API key auto-resolves from AI_DEFENSE_API_KEY env var
cbs = make_aidefense_callbacks(mode="enforce")
agent = LlmAgent(model="gemini-2.5-flash", name="assistant", instruction="...")
cbs.apply_to(agent) # wires all 4 callbacks in one call
```
## Modes
| Mode | Behavior |
|------|----------|
| `monitor` | Inspect all traffic, log violations, never block (default) |
| `enforce` | Inspect all traffic, block requests/responses that violate policy |
| `off` | Skip inspection entirely |
Modes can be set globally or per-channel:
```python
CiscoAIDefensePlugin(
mode="monitor", # default for both
llm_mode="enforce", # override for LLM only
mcp_mode="off", # override for tools only
)
```
## Callbacks Covered
| ADK Callback | Raw Client | Inspector | What it inspects |
|---|---|---|---|
| `before_model_callback` | `ChatInspectionClient.inspect_prompt()` | `LLMInspector.ainspect_conversation()` | User prompt before LLM call |
| `after_model_callback` | `ChatInspectionClient.inspect_response()` | `LLMInspector.ainspect_conversation()` | LLM response after generation |
| `before_tool_callback` | `MCPInspectionClient.inspect()` | `MCPInspector.ainspect_request()` | Tool call request before execution |
| `after_tool_callback` | `MCPInspectionClient.inspect()` | `MCPInspector.ainspect_response()` | Tool call result after execution |
## Violation Callback
Receive notification of every violation regardless of mode:
```python
def handle_violation(result):
print(f"Violation: {result.action} / {result.severity}")
CiscoAIDefensePlugin(
mode="monitor",
on_violation=handle_violation,
)
```
## Enforced Tool Block Payloads
In `enforce` mode, blocked tool callbacks keep the legacy `error` field and
also return structured metadata when Cisco AI Defense provides it:
```python
{
"error": "Tool response from 'query_database' blocked by Cisco AI Defense policy.",
"blocked": True,
"action": "Block",
"stage": "tool_response",
"severity": "HIGH",
"classifications": ["PRIVACY_VIOLATION"],
"rules": [{"rule_name": "PII", "classification": "PRIVACY_VIOLATION"}],
"event_id": "...",
"request_id": "...",
}
```
This makes it easier to audit or render enforced tool decisions without
reconstructing the decision from logs.
## Inspector-based Integration (agentsec)
In addition to the raw-client modules above, this package provides
**Inspector-based** variants that use `LLMInspector` / `MCPInspector` from
the agentsec SDK layer. These add:
- Automatic retry with exponential backoff
- Fail-open / fail-closed semantics
- Structured `Decision` objects with severity, classifications, rules, and event IDs
- Auto-resolution of API keys and endpoints from environment variables
### AgentsecPlugin (Tier 2) — Global, applies to all agents
```python
from aidefense_google_adk import AgentsecPlugin
# API key auto-resolves from AI_DEFENSE_API_MODE_LLM_API_KEY env var
app = App(
name="my_app",
root_agent=agent,
plugins=[
AgentsecPlugin(
mode="enforce",
fail_open=True,
retry_total=3,
retry_backoff=0.5,
),
],
)
runner = Runner(app=app, session_service=InMemorySessionService())
```
### Agentsec Callbacks (Tier 1) — Per-agent
```python
from aidefense_google_adk import make_agentsec_callbacks
# API key auto-resolves from AI_DEFENSE_API_MODE_LLM_API_KEY env var
cbs = make_agentsec_callbacks(
mode="enforce",
fail_open=True,
)
agent = LlmAgent(
model="gemini-2.5-flash",
name="assistant",
instruction="...",
before_model_callback=cbs.before_model,
after_model_callback=cbs.after_model,
before_tool_callback=cbs.before_tool,
after_tool_callback=cbs.after_tool,
)
```
### Violation Callback with Decision Objects
The Inspector-based modules pass `Decision` objects (not raw `InspectResponse`)
to the `on_violation` callback:
```python
def handle_violation(decision):
print(f"Action: {decision.action}")
print(f"Severity: {decision.severity}")
print(f"Classifications: {decision.classifications}")
print(f"Rules: {decision.rules}")
print(f"Event ID: {decision.event_id}")
AgentsecPlugin(
mode="monitor",
on_violation=handle_violation,
)
```
### Which Approach Should I Use?
| Feature | Raw Client (`CiscoAIDefensePlugin`) | Inspector (`AgentsecPlugin`) |
|---------|-------------------------------------|------------------------------|
| Retry with backoff | Via `Config(retry_config={...})` (HTTP-level) | Built-in application-level (`retry_total`, `retry_backoff`) |
| Fail-open / fail-closed | Configurable via `fail_open` param | Configurable via `fail_open` param |
| Violation data | `InspectResponse` (`.is_safe`, `.action`, `.severity`, `.classifications`, `.rules`, `.event_id`) | `Decision` (`.allows()`, `.severity`, `.classifications`, `.rules`, `.event_id`) |
| API key resolution | `AI_DEFENSE_API_KEY` (LLM) + `AI_DEFENSE_MCP_API_KEY` (MCP) | `AI_DEFENSE_API_MODE_LLM_API_KEY` + `AI_DEFENSE_API_MODE_MCP_API_KEY` |
| Custom endpoint | Via `Config` object (full HTTP/TLS/pool control) | Via `endpoint` string param |
| Best for | Full control over HTTP config (TLS, pool, headers) | Simpler API with application-level retry |
## Additional agentsec Approaches
### Monkey-patching with `agentsec.protect()`
Two lines of code before importing ADK — all LLM and MCP calls are
transparently inspected:
```python
from aidefense.runtime import agentsec
agentsec.protect(
api_mode={
"llm": {"mode": "monitor"},
"mcp": {"mode": "monitor"},
},
)
# Now import and use ADK as usual — calls are already patched
from google.adk.agents import LlmAgent
```
See [`examples/agentsec_protect.py`](examples/agentsec_protect.py) for a
complete runnable example.
### Manual Inspector Wiring
Wire the agentsec inspectors into ADK's per-agent callback hooks directly
for maximum customization:
```python
from aidefense.runtime.agentsec.inspectors import LLMInspector, MCPInspector
llm_inspector = LLMInspector()
mcp_inspector = MCPInspector()
async def before_model_callback(*, callback_context, llm_request):
decision = await llm_inspector.ainspect_conversation(messages, metadata)
if not decision.allows():
return blocked_response(decision.reasons)
return None
agent = LlmAgent(
model="gemini-2.5-flash",
name="assistant",
instruction="...",
before_model_callback=before_model_callback,
# ... other callbacks
)
```
See [`examples/agentsec_callbacks.py`](examples/agentsec_callbacks.py) for a
complete runnable example.
### Running the agentsec Examples
```bash
pip install cisco-aidefense-google-adk[examples]
cd examples
cp .env.example .env # fill in your API keys
python agentsec_plugin.py # AgentsecPlugin (Tier 2)
python agentsec_plugin.py --callbacks # make_agentsec_callbacks (Tier 1)
python agentsec_protect.py # monkey-patching approach
python agentsec_callbacks.py # manual Inspector wiring
```
## Resources
- [GitHub Repository](https://github.com/cisco-ai-defense/ai-defense-google-adk)
- [Cisco AI Defense](https://www.cisco.com/site/us/en/products/security/ai-defense/index.html)
- [Google ADK Documentation](https://google.github.io/adk-docs/)
- [cisco-aidefense-sdk on PyPI](https://pypi.org/project/cisco-aidefense-sdk/)
## Development
```bash
pip install -e ".[dev]"
pytest
```
## License
Distributed under the `Apache 2.0` License. See [LICENSE](https://github.com/cisco-ai-defense/ai-defense-google-adk/tree/main/LICENSE) for more information.
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.