Skip to main content

What is MCP?

Model Context Protocol (MCP) is a standard for AI agents to call tools on external servers. Each tool invocation is a structured request that your server handles. Veto integrates at the MCP layer — authorization is evaluated before any tool handler executes. If a call is denied, your handler code never runs.

Installation

npm install @useveto/node

Integration options

VetoMcpOptions

Both createVetoGuard and vetoMiddleware accept a VetoMcpOptions object as their second argument.
OptionTypeRequiredDescription
agentIdstringYesThe agent ID to authorize against. Must match a registered agent in your Veto account.
onError"deny" | "allow"NoWhat to do when the Veto API is unreachable. Default: "deny" (fail-closed).
onDenied(toolName, reason) => voidNoOptional callback invoked whenever authorization is denied. Use for logging or metrics.
const protect = createVetoGuard(veto, {
  agentId: "support-bot",
  onError: "deny",           // fail-closed (default)
  onDenied: (toolName, reason) => {
    metrics.increment("veto.denied", { tool: toolName });
    logger.warn(`Tool denied: ${toolName}${reason}`);
  },
});

Fail-closed behavior

If the Veto API is unreachable (network error, timeout, 5xx), tool calls are blocked by default. This ensures your agent cannot take unauthorized actions simply because authorization is temporarily unavailable.
Fail-closed is the right default for production. A momentary network partition should not become a security gap.
Setting onError: "allow" (fail-open) lets tool calls proceed when Veto is unreachable. This is not recommended for production — use it only in development or for non-sensitive tools where availability outweighs authorization risk.

How it works

MCP Client → MCP Server → createVetoGuard → Veto API
                               ↓                  ↓
                         (allowed) run handler  (denied) isError: true
Step by step:
  1. An MCP client sends a tools/call request.
  2. createVetoGuard (or vetoMiddleware) intercepts the call before your handler runs.
  3. It sends an authorization check to the Veto API with the agent ID, tool name, and parameters.
  4. Allowed — your tool handler executes and returns its result.
  5. Denied — Veto returns { isError: true } without executing your handler. (vetoMiddleware throws instead.)
  6. Veto API unreachable — tool call is blocked (fail-closed by default).
Every decision is recorded in the Veto audit log regardless of outcome.