Skip to content

MCP server

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-here

Use 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.

Terminal window
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.

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?”

ToolRequired scopeDescription
list_campaignsCAMPAIGN_READList tenant campaigns with optional status filter
get_campaignCAMPAIGN_READFull campaign record including rules and live stats
get_voucherVOUCHER_READVoucher record by code
validate_voucherVOUCHER_VALIDATEValidate a code without redeeming — checks status, expiry, limits, rules
get_redemptionVOUCHER_READRedemption record by UUID (last 2 months only — partition window)
analytics_overviewANALYTICS_READTenant-level analytics summary
campaign_performanceANALYTICS_READPer-campaign metrics and time series

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.

ToolRequired scopeDefault dispositionDescription
create_customerCUSTOMER_WRITEauto-executeCreate a customer reference. Idempotent on external_ref.
update_customerCUSTOMER_WRITEauto-executeUpdate an existing customer’s tags or metadata.
redeem_voucherVOUCHER_REDEEMauto-executeAtomically redeem a voucher. Idempotent on (code, customer_id, idempotency_key).
create_voucher (count = 1)VOUCHER_WRITEauto-executeCreate a single voucher.
create_voucher (count > 100)VOUCHER_WRITEpending-approvalBulk 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_campaignCAMPAIGN_WRITEpending-approvalCreate a campaign. Routes to approval queue by default.
update_campaignCAMPAIGN_WRITEpending-approvalUpdate an existing campaign (PATCH semantics). Routes to approval queue by default.
create_webhookWEBHOOK_WRITEpending-approvalRegister a webhook endpoint. Routes to approval queue by default.
delete_webhookWEBHOOK_WRITEpending-approvalDeactivate a webhook endpoint (soft-delete via status=INACTIVE; not a hard delete). Routes to approval queue by default.

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 when count <= N, route to the approval queue when count > N. This is the threshold form used for create_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.

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.

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.

Errors follow the D5 unified envelope:

{
"error": {
"code": "scope_required",
"message": "This endpoint requires the 'CAMPAIGN_READ' scope",
"meta": {}
}
}

JSON-RPC error codes:

CodeMeaning
-32004scope_required — agent key is missing the required scope
-32601Method not found — incorrect tool name; call tools/list to enumerate
-32603Internal error / resource not found for this tenant

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
}
}

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
}
}

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