Skip to content
Warrantv0.1

Framework recipes

Claude Code, Cursor, LangGraph and the Vercel AI SDK.

Two of these are MCP configuration and two are code — the split is whether the framework speaks MCP natively.

export WARRANT_API_KEY=wr_test_8f0c1b4e2b1a4d599d0e3a2f7c1b9e44

Every sample below runs against sandbox with a wr_test_ key.

Claude Code

claude mcp add --scope project warrant -- npx -y @gowarrant/mcp@latest

--scope project writes .mcp.json in the repo, so the whole team gets the same tools. Drop it for a user-level install.

The agent then has the five tools from the MCP page. Ask it to "open a warrant for the invoice API and verify it" and it will call warrant_open then warrant_verify. It cannot settle — that is not a tool it has.

Cursor

npx gowarrant init --client cursor

Writes .cursor/mcp.json. Restart Cursor and the tools appear.

LangGraph

LangGraph has no MCP client of its own, so wire the SDK as tools.

# The Warrant SDK is TypeScript; call the API directly from Python.
import os, uuid, requests

BASE = "https://api.gowarrant.xyz"
HEADERS = {"Authorization": f"Bearer {os.environ['WARRANT_API_KEY']}"}

def open_warrant(payee: str, amount: str, source_url: str) -> dict:
    """amount is the smallest unit as a string: "8400000" is 8.40 USDC."""
    r = requests.post(
        f"{BASE}/v1/warrants",
        headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
        json={
            "amount": amount,
            "payee": payee,
            "deadline": "2026-08-16T12:00:00.000Z",
            "spec": {"clauses": [{"kind": "http.status", "equals": 200}]},
        },
        timeout=20,
    )
    r.raise_for_status()
    return r.json()

Bind that as a tool on your graph node. The important part is that amount is a string of the smallest unit — Python would happily send 8.4 as a float, and the API rejects it.

Keep settlement out of the graph. A node that can release funds is a node that can be prompt-injected into releasing funds.

Vercel AI SDK

import { tool } from "ai";
import { z } from "zod";
import { Warrant, usdc } from "@gowarrant/sdk";

const warrant = new Warrant();

export const openWarrant = tool({
  description: "Hold funds against a deliverable that can be checked.",
  parameters: z.object({
    payee: z.string(),
    // A decimal string, never a number: the model will write 8.4 given a chance.
    amount: z.string().regex(/^\d+(\.\d+)?$/),
    sourceUrl: z.string().url(),
  }),
  execute: async ({ payee, amount, sourceUrl }) => {
    const w = await warrant.open({
      amount: usdc(amount),
      payee,
      spec: { clauses: [{ kind: "http.status", equals: 200 }] },
      deadline: new Date(Date.now() + 3_600_000),
    });
    return { id: w.id, state: w.state, sourceUrl };
  },
});

export const verifyWarrant = tool({
  description: "Check the deliverable and let the policy decide.",
  parameters: z.object({ id: z.string(), sourceUrl: z.string().url() }),
  execute: async ({ id, sourceUrl }) => {
    const after = await warrant.verify(id, { source_url: sourceUrl });
    return { state: after.state };
  },
});

usdc() takes the decimal string and produces the Amount the SDK requires, so the conversion happens once, in typed code, rather than in a prompt.

The rule across all four

Give an agent open and verify. Do not give it release, partialRelease or refund.

Those three endpoints refuse an API key regardless, so exposing them as tools produces a 403 rather than a payment — but the reason to leave them out is simpler than that. The value of this product is that a person looked at the evidence when the check did not cleanly pass. A tool that skips them is a tool that removes the reason to use Warrant at all.

Amounts

Whatever the framework, what reaches the wire is an integer string of the smallest unit, validated against ^[0-9]+$.

"8400000"    8.40 USDC
8400000      rejected — a JSON number
"8.40"       rejected — not the smallest unit

The SDK's usdc() and the MCP tool schema both accept the decimal form and do the conversion. Calling the API directly, as the LangGraph sample does, means doing it yourself.