MCP server
What it is
Section titled “What it is”Vauchflow ships an in-process Model Context Protocol (MCP) server at POST /v1/mcp. There is no separate npm package or sidecar process — the MCP server runs inside the Vauchflow API JAR and shares the same tenant isolation, rate limiting, and audit logging as the REST API.
Transport: HTTP JSON-RPC 2.0. Each call is an independent POST request — the endpoint is stateless.
AI agents that support MCP (Claude Desktop, Cursor, Windsurf, and custom MCP clients) can call Vauchflow tools directly using natural language without going through the REST API surface.
X-API-Key: vf_ak_your-agent-key-hereUse a vf_ak_* agent key with only the scopes your agent needs. Read tools require *_READ or VOUCHER_VALIDATE scopes. Write tools require *_WRITE or VOUCHER_REDEEM scopes — these must be explicitly granted at key creation time.
Secret keys (vf_sk_*) also work and bypass scope checks and the approval gate entirely — use them only in trusted server-side contexts.
Publishable keys (vf_pk_*) are rejected at the MCP endpoint.
Setup — Claude Desktop
Section titled “Setup — Claude Desktop”1. Create an agent key
Section titled “1. Create an agent key”curl -X POST https://api.vauchflow.com/v1/api-keys/agent \ -H "X-API-Key: vf_sk_your-secret-key" \ -H "Content-Type: application/json" \ -d '{ "name": "Claude Desktop Agent", "scopes": ["CAMPAIGN_READ", "VOUCHER_READ", "VOUCHER_VALIDATE"], "ttlDays": 30 }'Copy the rawKey from the response — it is shown once only.
2. Add to Claude Desktop config
Section titled “2. Add to Claude Desktop config”Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent path on your OS:
{ "mcpServers": { "vauchflow": { "url": "https://api.vauchflow.com/v1/mcp", "headers": { "X-API-Key": "vf_ak_your-agent-key-here" } } }}Restart Claude Desktop. Prompt: “List my Vauchflow campaigns” or “Is voucher SUMMER20 valid?”
Available tools
Section titled “Available tools”Read tools
Section titled “Read tools”| Tool | Required scope | Description |
|---|---|---|
list_campaigns | CAMPAIGN_READ | List tenant campaigns with optional status filter |
get_campaign | CAMPAIGN_READ | Full campaign record including rules and live stats |
get_voucher | VOUCHER_READ | Voucher record by code |
validate_voucher | VOUCHER_VALIDATE | Validate a code without redeeming — checks status, expiry, limits, rules |
get_redemption | VOUCHER_READ | Redemption record by UUID (last 2 months only — partition window) |
analytics_overview | ANALYTICS_READ | Tenant-level analytics summary |
campaign_performance | ANALYTICS_READ | Per-campaign metrics and time series |
Write tools
Section titled “Write tools”Write tools ship in v1. High-risk writes (campaign creation, bulk voucher creation, webhook configuration) route to the operator approval queue by default and return a pending_approval result — not an error.
| Tool | Required scope | Default disposition | Description |
|---|---|---|---|
create_customer | CUSTOMER_WRITE | auto-execute | Create a customer reference. Idempotent on external_ref. |
update_customer | CUSTOMER_WRITE | auto-execute | Update an existing customer’s tags or metadata. |
redeem_voucher | VOUCHER_REDEEM | auto-execute | Atomically redeem a voucher. Idempotent on (code, customer_id, idempotency_key). |
create_voucher (count = 1) | VOUCHER_WRITE | auto-execute | Create a single voucher. |
create_voucher (count > 100) | VOUCHER_WRITE | pending-approval | Bulk voucher creation above the tenant policy threshold routes to the approval queue. The default threshold is 100. Tenants can override via the create_voucher key in tenants.agent_approval_policy (see below). |
create_campaign | CAMPAIGN_WRITE | pending-approval | Create a campaign. Routes to approval queue by default. |
update_campaign | CAMPAIGN_WRITE | pending-approval | Update an existing campaign (PATCH semantics). Routes to approval queue by default. |
create_webhook | WEBHOOK_WRITE | pending-approval | Register a webhook endpoint. Routes to approval queue by default. |
delete_webhook | WEBHOOK_WRITE | pending-approval | Deactivate a webhook endpoint (soft-delete via status=INACTIVE; not a hard delete). Routes to approval queue by default. |
Per-tenant policy overrides
Section titled “Per-tenant policy overrides”Each action’s default disposition can be overridden per tenant via the agent_approval_policy JSONB column on the tenants table. The override value for an action is either a plain string shorthand or a nested threshold object:
{ "create_campaign": "auto", "create_voucher": { "mode": "pending_approval", "threshold_count": 50 }}"auto"— always auto-execute this action for the tenant (bypasses the approval gate)."pending_approval"— always queue for approval, regardless of count.{ "mode": "pending_approval", "threshold_count": <N> }— auto-execute whencount <= N, route to the approval queue whencount > N. This is the threshold form used forcreate_voucher.
To lower the bulk-voucher threshold from 100 to 50 for a tenant, store:
{ "create_voucher": { "mode": "pending_approval", "threshold_count": 50 } }See Approval queue for operator SQL and the full override reference.
Pending approval flow
Section titled “Pending approval flow”The pending-approval payload (like all MCP tool results) is delivered through the standard MCP content[].text envelope per MCP 2024-11-05 spec. Parsers should JSON.parse(response.result.content[0].text) to access the inner shape. The full wire response looks like:
{ "jsonrpc": "2.0", "id": "<req-id>", "result": { "content": [{ "type": "text", "text": "{\"status\":\"pending_approval\",\"approval_id\":\"...\",\"action_type\":\"create_campaign\",\"expires_at\":\"...\",\"poll_url\":\"...\",\"message\":\"...\"}" }], "isError": false }}The parsed inner shape when a write call routes to the approval queue (not an error) is:
{ "status": "pending_approval", "approval_id": "<uuid>", "action_type": "create_voucher", "expires_at": "2026-05-04T11:30:00Z", "poll_url": "/v1/agent-approvals/<uuid>", "message": "This action requires operator approval before execution."}The agent should poll GET /v1/agent-approvals/<uuid> (using its own vf_ak_* key) until the status reaches a terminal state (executed, rejected, or expired). For push notifications, subscribe to agent.action.* webhook events instead of polling.
See Approval queue for the full lifecycle, operator review UI, and the per-tenant policy override mechanism.
Dry run
Section titled “Dry run”All write tools except delete_webhook accept dry_run: true in the arguments. A dry-run call returns the planned outcome without persisting anything to the database. The response includes a top-level dry_run: true flag:
{ "jsonrpc": "2.0", "id": 5, "result": { "dry_run": true, "id": "00000000-0000-0000-0000-000000000000", "code": "SUMMER20", "status": "ACTIVE", "discountType": "PERCENTAGE", "discountValue": 20.00 }}Dry-run calls are safe to call at any time — they never write rows, never trigger the approval gate, and never fire outbox events.
Error envelope
Section titled “Error envelope”Errors follow the D5 unified envelope:
{ "error": { "code": "scope_required", "message": "This endpoint requires the 'CAMPAIGN_READ' scope", "meta": {} }}JSON-RPC error codes:
| Code | Meaning |
|---|---|
-32004 | scope_required — agent key is missing the required scope |
-32601 | Method not found — incorrect tool name; call tools/list to enumerate |
-32603 | Internal error / resource not found for this tenant |
Tool examples
Section titled “Tool examples”list_campaigns
Section titled “list_campaigns”Request:
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "list_campaigns", "arguments": { "status": "ACTIVE", "limit": 20 } }}Response:
{ "jsonrpc": "2.0", "id": 1, "result": { "campaigns": [ { "id": "550e8400-...", "name": "Summer Sale", "status": "ACTIVE" } ], "total": 1, "returned": 1 }}validate_voucher
Section titled “validate_voucher”Request:
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "validate_voucher", "arguments": { "code": "SUMMER20", "customer_id": "cust_abc123", "order_value": 75.00 } }}Response:
{ "jsonrpc": "2.0", "id": 2, "result": { "valid": true, "code": "SUMMER20", "discountType": "PERCENTAGE", "discountValue": 20.00, "discountAmount": 15.00, "remainingRedemptions": 94 }}create_voucher (pending-approval path)
Section titled “create_voucher (pending-approval path)”Request:
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "create_voucher", "arguments": { "discount_type": "PERCENTAGE", "discount_value": 20, "count": 150, "prefix": "SUMMER" } }}Response (approval queue — not an error):
{ "jsonrpc": "2.0", "id": 3, "result": { "status": "pending_approval", "approval_id": "d4e5f6a7-b8c9-4d01-a234-56789abcdef0", "action_type": "create_voucher", "expires_at": "2026-05-04T11:30:00Z", "poll_url": "/v1/agent-approvals/d4e5f6a7-b8c9-4d01-a234-56789abcdef0", "message": "This action requires operator approval before execution." }}See also: AI agents overview · Approval queue