MCP Integration
Use Veto with Model Context Protocol (MCP) tool definitions.
Veto supports Model Context Protocol (MCP) tool definitions through provider adapters and a guarded callTool forwarder.
MCP tools are schema-only. They do not contain an execute function, so veto.wrap() is for executable in-process tools and veto.wrapMCPTools() is for MCP forwarding. If you want to protect an MCP server you don't own or can't modify, skip to the MCP Gateway guide instead.
Quick start
Pass MCP tool definitions plus your actual MCP callTool implementation:
import { Veto } from 'veto-sdk';
const veto = await Veto.init();
const { tools, callTool } = veto.wrapMCPTools(mcpToolDefinitions, {
callTool: (input) => mcpClient.callTool(input),
});
// Give `tools` to the model. Use guarded `callTool` when it requests a tool.
await callTool({
name: 'read_file',
arguments: { path: '/repo/package.json' },
});How MCP tools differ
MCP tools use inputSchema instead of parameters:
// MCP tool format
const mcpTool = {
name: "read_file",
description: "Read a file from disk",
inputSchema: {
type: "object",
properties: {
path: { type: "string" },
},
required: ["path"],
},
};
// OpenAI tool format (what Veto normalizes to internally)
const openAITool = {
type: "function",
function: {
name: "read_file",
description: "Read a file from disk",
parameters: {
type: "object",
properties: {
path: { type: "string" },
},
required: ["path"],
},
},
};When you register MCP tools for Charter, the SDK converts inputSchema to Veto tool parameters. Policies and rules reference tool arguments the same way regardless of the source format.
Manual adapter
For advanced use cases, you can use the adapter functions directly:
import { fromMCP, isMCPTool } from 'veto-sdk/providers';
// Check if a tool is MCP format
if (isMCPTool(tool)) {
const normalized = fromMCP(tool);
// normalized has OpenAI-style `parameters` instead of `inputSchema`
}Example: MCP server with Veto policies
import { Veto } from 'veto-sdk';
// Your MCP server tools
const mcpTools = [
{
name: "execute_command",
description: "Run a shell command",
inputSchema: {
type: "object",
properties: {
command: { type: "string" },
cwd: { type: "string" },
},
required: ["command"],
},
},
{
name: "write_file",
description: "Write content to a file",
inputSchema: {
type: "object",
properties: {
path: { type: "string" },
content: { type: "string" },
},
required: ["path", "content"],
},
},
];
const veto = await Veto.init();
const safeMcp = veto.wrapMCPTools(mcpTools, {
callTool: (input) => mcpClient.callTool(input),
});
await safeMcp.callTool({
name: "execute_command",
arguments: { command: "ls", cwd: "/repo" },
});With a YAML rule like:
rules:
- id: restrict-commands
name: Block dangerous shell commands
action: block
tools:
- execute_command
conditions:
- field: arguments.command
operator: matches
value: "^(rm -rf|sudo|chmod 777)"Exports
| Import | What |
|---|---|
fromMCP | Convert a single MCP tool to Veto's internal format |
isMCPTool | Type guard, returns true if the tool has inputSchema |
Veto.wrapMCPTools() | Guard a schema-only MCP callTool forwarder before the upstream server runs |
Provider adapters are available from veto-sdk/providers; wrapMCPTools() is a Veto client method.
Register MCP tools for Charter
If you want Charter to draft policies against an MCP server's tool inventory, register the MCP tools/list output with the cloud SDK:
import { Veto } from "veto-sdk";
const veto = await Veto.init({
baseUrl: "https://api.veto.so",
apiKey: process.env.VETO_API_KEY!,
});
await veto.registerTools([
{
name: "execute_command",
description: "Run a shell command",
parameters: [
{ name: "command", type: "string", required: true, description: "Command to run" },
{ name: "cwd", type: "string", required: false, description: "Working directory" },
],
},
]);
const res = await fetch("https://api.veto.so/v1/charter/turn", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Veto-API-Key": process.env.VETO_API_KEY!,
},
body: JSON.stringify({
message: "Shell commands that change permissions require an engineering lead approval.",
mode: "compile",
surface: "mcp",
}),
});
const draft = await res.json();registerTools() accepts a parameters array where each entry maps to a JSON Schema property. Include required, description, type, and any constraint hints.
Not your MCP server?
If you're connecting to a third-party MCP server or want to enforce policies without modifying the server code, use the MCP Gateway instead.
The gateway runs as a proxy: your MCP client calls POST /v1/mcp/:slug (managed) or veto mcp serve (self-hosted), Veto validates every tools/call against your policies, and the upstream receives the request only if it passes. No SDK, no code changes on the server side.
Polymarket agents: See the Polymarket With Veto MCP guide for a ready-made MCP sidecar that wraps the Polymarket CLI with Veto policy guardrails. It covers tool coverage, policy profiles, simulation vs live trading, and economic authorization.

