Verdict API
Let your own API or MCP server call ShieldAgent for a security verdict before executing any tool call — without changing your traffic flow.
Overview
The Verdict API is for customers who own and operate their own API or MCP server. Instead of routing agent traffic through the ShieldAgent proxy, your server calls client.scan() with the incoming request payload. ShieldAgent runs the full multi-stage security pipeline and returns a verdict — allow, block, or human_review. Your code enforces it.
The agent's traffic flow is completely unchanged. The agent talks to your server normally. Your server makes a separate HTTP call to ShieldAgent and decides whether to execute the tool.
When to Use the Verdict API
| Situation | Recommended approach |
|---|---|
| You operate your own REST API that agents call | Verdict API — add client.scan() before your handler executes |
| You operate your own MCP server with tool handlers | Verdict API — add client.scan() in each tool handler |
| You want security scanning without changing agent routing | Verdict API — the agent's endpoint URL stays the same |
| You don't own the server (agents call a third-party) | Inline proxy — route agents through ShieldAgent instead |
| You want infrastructure-enforced blocking (can't trust code) | Inline proxy (Position 1) — ShieldAgent blocks before forwarding |
Quick Start
TypeScript — MCP server
import { ShieldAgentClient } from '@shieldagent/sdk';
const shield = new ShieldAgentClient({
baseUrl: 'https://proxy.shieldagent.io',
apiKey: '{your-api-key}',
});
// Inside your MCP tool handler:
async function handleToolCall(toolName: string, params: unknown) {
const verdict = await shield.scan({
tenantId: '{your-tenant-id}',
toolName,
params,
// agentId is optional — see "Agent Identity" section below
context: { transport: 'mcp' },
});
if (verdict.action === 'block') {
throw new Error(`Blocked: ${verdict.reason}`);
}
if (verdict.action === 'human_review') {
return { status: 'pending_review', reviewId: verdict.reviewId };
}
// verdict.action === 'allow'
return executeToolLocally(toolName, params);
}Python — REST API handler
from shieldagent import ShieldAgentClient
shield = ShieldAgentClient(
base_url="https://proxy.shieldagent.io",
api_key="{your-api-key}",
)
# Inside your API handler:
async def handle_request(agent_id: str, method: str, path: str, body: dict):
verdict = await shield.scan(
tenant_id="{your-tenant-id}",
agent_id=agent_id, # optional — omit if not known
tool_name=f"api:{method}:{path}",
params={"method": method, "path": path, "body": body},
context={"transport": "rest"},
)
if verdict.action == "block":
raise HTTPException(status_code=403, detail=verdict.reason)
if verdict.action == "human_review":
return {"status": "pending_review", "review_id": verdict.review_id}
return execute_handler(method, path, body)Scan Request
The SDK calls client.scan() on the ShieldAgent API. Authenticate with a tenant API key (Bearer token).
{
"agentId": "agent-uuid", // OPTIONAL — omit if server cannot identify the agent
"clientHint": "Claude Desktop", // OPTIONAL — from MCP clientInfo.name, for best-effort matching
"toolName": "read_file",
"params": { "path": "/etc/passwd" },
"include_findings": false, // opt-in; requires verdictDetailedFindings tenant permission
"context": {
"transport": "mcp", // "mcp" | "rest" | "custom"
"sourceIp": "10.0.1.5", // optional — used for rate limiting
"sessionId": "sess-123" // optional — enables excessive agency detection
}
}Scan Response
Default (all tenants)
{
"action": "block", // "allow" | "block" | "human_review"
"reason": "Security threat detected", // generic — no detection detail
"riskScore": 87,
"auditEventId": "evt-uuid", // audit event was written
"reviewId": null // set when action is "human_review"
}Detailed findings ((requires include_findings: true + tenant permission))
{
"action": "block",
"reason": "Prompt injection detected in tool arguments",
"findings": [
{
"type": "injection",
"severity": "critical",
"detail": "Path traversal pattern detected"
}
],
"riskScore": 87,
"auditEventId": "evt-uuid",
"reviewId": null
}Detailed findings are disabled by default. Without tiering, an attacker with Verdict API access could iteratively probe which scanner caught their payload and craft evasion attempts. Enable only for trusted internal tooling via the tenant settings in the ShieldAgent dashboard.
Security Checks
The Verdict API applies the same comprehensive security checks as the inline proxy. Your request is evaluated against all configured protections before returning a verdict.
- Authentication and tenant validation
- Rate limiting (per-tenant and per-agent)
- Tool access control (approved tools allowlist)
- Policy evaluation against your configured rules
- Security scanning (prompt injection, DLP, tool drift, cross-origin, excessive agency)
- Risk score evaluation
- Audit trail logging
Agent Identity
agentId is optional. The MCP protocol does not expose agent identity — clientInfo from the MCP initialize handshake identifies the client software (e.g., "Claude Desktop"), not the individual agent. Your API or MCP server may not know which specific agent is calling.
| Scenario | What to send | Pipeline behavior |
|---|---|---|
| Your HTTP API authenticates agents and maps them to ShieldAgent agent IDs | agentId: "agent-uuid" | Full per-agent pipeline: per-agent policies, risk score, rate limits, tool allowlist |
| Your MCP server knows the client software (from MCP clientInfo.name) but not the agent | clientHint: "Claude Desktop" | ShieldAgent matches against registered agent names. If exactly one matches, uses it. Otherwise falls back to tenant-level. |
| Your server cannot identify the calling agent | (omit agentId and clientHint) | Tenant-level pipeline: tenant-wide policies, no per-agent risk or baseline |
Enforcement Observability
Because your code enforces the verdict (not ShieldAgent infrastructure), the audit trail cannot automatically confirm whether a block verdict was honored. Use client.confirmExecution() to close the loop.
// After executing or rejecting a tool call, confirm the outcome:
await shield.confirmExecution(verdict.auditEventId, {
executed: false, // true = tool ran; false = tool was blocked by your code
});Compliance note
Tenants that do not call confirmExecution() appear as enforcement unknown in ShieldAgent compliance reports. For EU AI Act Art. 9 compliance, organizations using the Verdict API must document their enforcement mechanism and demonstrate enforcement rates via audit evidence. The ShieldAgent Annex IV auto-generated report includes your deployment position and confirmExecution() rates for regulators.
Shared Responsibility Model
The Verdict API shifts enforcement from ShieldAgent infrastructure to your code. This is standard in the security industry — analogous to AWS WAF Count mode or CrowdStrike Detect mode. ShieldAgent's compliance certifications apply to its detection and pipeline capabilities; whether your deployment achieves full enforcement depends on your integration.
| Responsibility | Inline proxy | Verdict API |
|---|---|---|
| Threat detection | ShieldAgent | ShieldAgent |
| Policy evaluation | ShieldAgent | ShieldAgent |
| Risk scoring | ShieldAgent | ShieldAgent |
| Audit trail | ShieldAgent | ShieldAgent |
| Enforcement (blocking) | ShieldAgent — infrastructure-guaranteed | Your code — verified via confirmExecution() |
API Reference
scan()—Submit a request payload for security scanning. Returns a verdict.confirmExecution()—Confirm whether a scan verdict was enforced (closes audit loop).Authenticate with a tenant-scoped API key (Bearer token). See the SDK documentation for full integration guides.
Related
- Architecture Overview →All deployment positions and integration patterns
- TypeScript SDK →SDK reference including scan() and confirmExecution()
- Python SDK →Python SDK reference
- Risk Scoring Model →How riskScore in the verdict response is calculated
- Compliance Frameworks →EU AI Act Art. 9 and Annex IV implications for Verdict API deployments