Skip to main content
Sign in →

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.

Traffic flow
Agent ──► Your Server (API / MCP)
│ SDK: client.scan(payload)
ShieldAgent API (runs security pipeline)
│ verdict: allow / block / human_review
Your Server (executes if allowed, rejects if blocked)

When to Use the Verdict API

SituationRecommended approach
You operate your own REST API that agents callVerdict API — add client.scan() before your handler executes
You operate your own MCP server with tool handlersVerdict API — add client.scan() in each tool handler
You want security scanning without changing agent routingVerdict 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

typescript
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

python
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).

json
{
  "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)

json
{
  "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)

json
{
  "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.

StageVerdict API behavior
AuthAPI key → tenant resolution. AuthContext built from request body (agentId).
Risk HintLooks up cached risk score for the agent (if agentId provided).
Rate LimitPer-tenant + per-agent rate limiting via Redis.
Tool AccessChecks approved_tools allowlist for the agent.
PolicyEvaluates compiled policy rules against toolName + params.
SecurityPrompt injection (regex + ML), DLP scan, tool drift, cross-origin, excessive agency.
Risk EnforcementTier-based blocking if agent risk score exceeds threshold.
AuditWrites audit event with source: 'verdict_api' (distinguishes from proxy events).
ForwardSKIPPED — 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.

ScenarioWhat to sendPipeline behavior
Your HTTP API authenticates agents and maps them to ShieldAgent agent IDsagentId: "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 agentclientHint: "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.

typescript
// 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.

ResponsibilityInline proxyVerdict API
Threat detectionShieldAgentShieldAgent
Policy evaluationShieldAgentShieldAgent
Risk scoringShieldAgentShieldAgent
Audit trailShieldAgentShieldAgent
Enforcement (blocking)ShieldAgent — infrastructure-guaranteedYour 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

POST/tenants/:tenantId/scanSubmit a request payload for security scanning. Returns a verdict.
POST/tenants/:tenantId/verdict-confirmationsConfirm whether a scan verdict was enforced (closes audit loop).

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