Claude runtime authorization

Wrap Claude tool_use blocks with Veto. Each governed tool_use block is evaluated before dispatch: allow, review, or deny, with an exportable decision record per governed decision.

The problem with Claude tool use

Claude supports tool-use agent workflows. The Anthropic SDK gives it tools, the Agent SDK gives it autonomy, and MCP gives it access to external systems. But none of these provide runtime authorization at the tool boundary. Claude decides what to do and your code executes it unconditionally.

The risk is the tool boundary. Claude can reason well and still call a tool with high-impact arguments when context is poisoned, stale, or incomplete. Sandboxing limits part of the blast radius. Enforcement decides whether the proposed action should run at all.

No pre-execution check

The Anthropic SDK's tool_use flow returns tool calls for you to execute. There is no built-in step between "Claude wants to call this" and "your code runs it."

MCP has no auth layer

MCP's authentication is optional. Enterprise deployments using Claude Desktop or Claude Code expose MCP tools with no centralized access control or decision records.

Prompt injection persists

OWASP LLM01:2025 ranks prompt injection as the top LLM vulnerability. Constitutional AI reduces risk but cannot eliminate it. Enforcement is the defense-in-depth layer.

Before and after Veto

The left tab shows a standard Claude tool_use loop. Claude calls tools, your code executes them blindly. The right tab adds Veto. Same agent, same tools, but governed call goes through policy evaluation first.

ts
import Anthropic from '@anthropic-ai/sdk'

const client = new Anthropic()

const tools = [
  {
    name: 'send_email',
    description: 'Send an email',
    input_schema: {
      type: 'object',
      properties: {
        to: { type: 'string' },
        subject: { type: 'string' },
        body: { type: 'string' },
      },
      required: ['to', 'subject', 'body'],
    },
  },
  {
    name: 'delete_records',
    description: 'Delete database records',
    input_schema: {
      type: 'object',
      properties: {
        table: { type: 'string' },
        where: { type: 'string' },
      },
      required: ['table', 'where'],
    },
  },
]

const response = await client.messages.create({
  model: process.env.ANTHROPIC_MODEL!,
  max_tokens: 1024,
  tools,
  messages: [{ role: 'user', content: userMessage }],
})

// Claude decides to call delete_records.
// Your code executes it. No questions asked.
for (const block of response.content) {
  if (block.type === 'tool_use') {
    const result = await executeTool(block.name, block.input)
    // No policy decision happens here.
  }
}

Policy configuration

Define what Claude can and cannot do in declarative YAML. Version control it alongside your code. No prompt engineering. No reliance on model cooperation.

veto/policies.yaml
rules:
  - name: block_destructive_writes
    description: Prevent DELETE/DROP on production tables
    tool: delete_records
    when: context.environment == "production"
    action: deny
    message: "Destructive writes blocked in production"

  - name: approve_large_transfers
    description: Human approval for transfers over $1,000
    tool: transfer_funds
    when: args.amount > 1000
    action: require_approval
    approvers: [finance-team]
    message: "Large transfer requires finance team approval"

  - name: block_external_email
    description: Block emails to non-company domains
    tool: send_email
    when: "!args.to.endsWith('@approved.example')"
    action: deny
    message: "External emails require manual sending"

  - name: read_only_queries
    description: Only allow SELECT queries
    tool: query_database
    when: "!args.query.toUpperCase().startsWith('SELECT')"
    action: deny
    message: "Only read-only queries are permitted"

First governed call

1

Install the SDK

npm install veto-sdk @anthropic-ai/sdk
2

Define policies

Create veto/policies.yaml with rules for each tool. Match on tool name, constrain arguments, set actions: allow, deny, or require_approval.

3

Validate before executing

Call veto.guard() in your tool_use handler. Check the decision. Execute only if allowed. The model, your prompts, and your model and prompt wiring stay outside the policy surface.

What Veto covers for Claude agents

Tool scoping

Allowlist which tools Claude can call per environment, user role, or time of day. Deny everything else by default. Principle of least privilege for agents.

Argument constraints

Block specific argument values: email domains, SQL statements containing DELETE, payment amounts above a threshold. Enforce at the data level, not the prompt level.

Human review

Route review-required tool calls to approval queues. Approvers get configured approval channel or email notifications with the decision context. The agent pauses until a human responds.

Decision record

Governed tool calls can log tool name, arguments, decision, reason, timestamp, and user context. Queryable via API. Exportable for SOC 2 and compliance.

Frequently asked questions

How does Claude interact with Veto policy enforcement?
Veto evaluates governed tool calls in your code, outside the model's context window. Claude can still propose a destructive call; it does not control the policy decision on the governed path.
Does Veto work with Claude's MCP support?
Yes. Veto provides a managed MCP gateway that intercepts tool calls from any MCP client, including Claude Desktop, Claude Code, and Cursor. Point your MCP client at Veto's gateway URL. Governed tool calls flow through the policy engine before reaching the upstream server.
Does this add latency to Claude responses?
Policy evaluation stays in-process before dispatch. Claude inference remains the slower path. Human approval workflows pause the agent until a reviewer responds, but standard allow/block decisions stay on the local decision path.
Does it work with streaming?
Yes. Veto validates at the tool_use boundary, not on streamed text. When Claude's streaming response includes a tool_use block, Veto evaluates the complete tool call before your code executes it. Text streaming is unaffected.

Related integrations

Make Claude tool calls enforceable.