Agent frameworks
@tuppence/agent-tools gives an agent framework the same tools as the
MCP server, in that framework’s shape. It fetches them with your key, so the agent
sees only what the key allows.
1. Install and give it a key
Section titled “1. Install and give it a key”npm install @tuppence/agent-toolsexport TUPPENCE_SECRET_KEY=rk_test_…Use a restricted key with only the scopes the agent needs: for example, payment_links:read
and payment_links:write for an agent that sells with links. TUPPENCE_API_KEY also works, or pass
apiKey.
2. Hand the tools to your agent
Section titled “2. Hand the tools to your agent”import { Agent, run } from "@openai/agents";import { tuppenceTools } from "@tuppence/agent-tools/openai-agents";
const { tools, close } = await tuppenceTools();const agent = new Agent({ name: "Billing assistant", instructions: "Amounts are integers in the currency's minor unit (pence, cents). When you create a payment link, reply with its URL.", tools,});const result = await run(agent, "Make a £15 payment link for a deep research report.");console.log(result.finalOutput);await close();import { Agent, run } from "@openai/agents";import { tuppenceTools } from "@tuppence/agent-tools/openai-agents";
const { tools, close } = await tuppenceTools();const agent = new Agent({ name: "Billing assistant", instructions: "Amounts are integers in the currency's minor unit (pence, cents). When you create a payment link, reply with its URL.", tools,});const result = await run(agent, "Make a $15 payment link for a deep research report.");console.log(result.finalOutput);await close();import { Agent, run } from "@openai/agents";import { tuppenceTools } from "@tuppence/agent-tools/openai-agents";
const { tools, close } = await tuppenceTools();const agent = new Agent({ name: "Billing assistant", instructions: "Amounts are integers in the currency's minor unit (pence, cents). When you create a payment link, reply with its URL.", tools,});const result = await run(agent, "Make a €15 payment link for a deep research report.");console.log(result.finalOutput);await close();import { createAgent } from "langchain";import { tuppenceTools } from "@tuppence/agent-tools/langchain";
const { tools, close } = await tuppenceTools();const agent = createAgent({ model: "openai:gpt-5", tools });const result = await agent.invoke({ messages: [{ role: "user", content: "Make a £15 payment link for a deep research report." }],});await close();import { createAgent } from "langchain";import { tuppenceTools } from "@tuppence/agent-tools/langchain";
const { tools, close } = await tuppenceTools();const agent = createAgent({ model: "openai:gpt-5", tools });const result = await agent.invoke({ messages: [{ role: "user", content: "Make a $15 payment link for a deep research report." }],});await close();import { createAgent } from "langchain";import { tuppenceTools } from "@tuppence/agent-tools/langchain";
const { tools, close } = await tuppenceTools();const agent = createAgent({ model: "openai:gpt-5", tools });const result = await agent.invoke({ messages: [{ role: "user", content: "Make a €15 payment link for a deep research report." }],});await close();The Claude Agent SDK connects to MCP servers itself, so the package supplies the connection:
import { query } from "@anthropic-ai/claude-agent-sdk";import { TUPPENCE_TOOLS, tuppenceMcpServer } from "@tuppence/agent-tools/claude-agent-sdk";
for await (const message of query({ prompt: "Make a £15 payment link for a deep research report.", options: { mcpServers: { tuppence: tuppenceMcpServer() }, allowedTools: [TUPPENCE_TOOLS], // or one by one: mcp__tuppence__create_payment_link },})) { console.log(message);}import { query } from "@anthropic-ai/claude-agent-sdk";import { TUPPENCE_TOOLS, tuppenceMcpServer } from "@tuppence/agent-tools/claude-agent-sdk";
for await (const message of query({ prompt: "Make a $15 payment link for a deep research report.", options: { mcpServers: { tuppence: tuppenceMcpServer() }, allowedTools: [TUPPENCE_TOOLS], // or one by one: mcp__tuppence__create_payment_link },})) { console.log(message);}import { query } from "@anthropic-ai/claude-agent-sdk";import { TUPPENCE_TOOLS, tuppenceMcpServer } from "@tuppence/agent-tools/claude-agent-sdk";
for await (const message of query({ prompt: "Make a €15 payment link for a deep research report.", options: { mcpServers: { tuppence: tuppenceMcpServer() }, allowedTools: [TUPPENCE_TOOLS], // or one by one: mcp__tuppence__create_payment_link },})) { console.log(message);}Each example runs in CI against the real API, with a scripted model in place of the LLM. The agent creates a real link and gets its URL back.
When the API says no
Section titled “When the API says no”| A refused call | The tool returns the API’s error (code, message, param) instead of crashing, so the agent can read it and correct the call. |
| Retries | Money-moving tools require an idempotency_key. A retry sends the same one, so the money moves once. |
For one of your connected accounts
Section titled “For one of your connected accounts”A platform’s agent can work for one of its connected accounts. Pass account
when connecting and every tool acts as that account (its payments, links and bookings) using your
key. The platform’s own Connect tools are then hidden.
| Framework | |
|---|---|
| OpenAI Agents SDK, LangChain | tuppenceTools({ account: "acct_…" }) |
| Claude Agent SDK | tuppenceMcpServer({ account: "acct_…" }) |
@tuppence/mcp | TUPPENCE_ACCOUNT=acct_… |
Without it, a single tool call can act as an account through its own account argument
(MCP server).
- MCP server: every tool, and how to connect Claude Desktop or Cursor.
- Agent identity: sign each request as the agent.