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 or sidecar — 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 POST /tenants/:tenantId/scan on the ShieldAgent proxy (port 3100). 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",
"scanner": "regex"
}
],
"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.
Pipeline Stages
The Verdict API runs the same multi-stage pipeline as the proxy. The only difference: the forwarding step is skipped and the verdict is returned to your code instead.
| Stage | Verdict API behavior |
|---|---|
| Auth | API key → tenant resolution. AuthContext built from request body (agentId). |
| Risk Hint | Looks up cached risk score for the agent (if agentId provided). |
| Rate Limit | Per-tenant + per-agent rate limiting via Redis. |
| Tool Access | Checks approved_tools allowlist for the agent. |
| Policy | Evaluates compiled policy rules against toolName + params. |
| Security | Prompt injection (regex + ML), DLP scan, tool drift, cross-origin, excessive agency. |
| Risk Enforcement | Tier-based blocking if agent risk score exceeds threshold. |
| Audit | Writes audit event with source: 'verdict_api' (distinguishes from proxy events). |
| Forward | SKIPPED — verdict returned to caller instead. |
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() |
If your compliance requirements demand infrastructure-enforced blocking and you own your server, consider the sidecar-of-server variant — ShieldAgent runs as a sidecar alongside your server and blocks inline before your handler runs. Contact your account team for details.
API Reference
Both endpoints are on the proxy service (port 3100), not the Management API. Authenticate with a tenant-scoped API key (Bearer token). The proxy process hosts the full pipeline — rate limiter, policy cache, ML classifier, DLP engine, risk scorer.
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