Claude Agent SDK
Give a Claude Agent a phone tool via the OpenPhn API.
There's no dedicated OpenPhn SDK today — Claude Agents integrate with
OpenPhn by calling the REST API directly as a tool. This works well
because the OpenPhn POST /v1/calls shape is already agent-friendly
(objective in, outcome schema defined up-front, outcome JSON back out).
Option A — OpenPhn as an MCP server (recommended)
If your Claude Agent supports MCP, this is the shortest path. See the
MCP → Claude Desktop quickstart — the same
mcpServers block works anywhere the Anthropic Desktop Extensions
runtime reads config from.
Option B — hand-rolled REST tool
When you need fine-grained control (logging, retry policy, custom
consent checks) you can register a tool on the agent that wraps
POST /v1/calls:
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic();
const tools = [
{
name: "openphn_make_call",
description: "Place a phone call via OpenPhn. Returns a call_id; poll openphn_get_call for outcome.",
input_schema: {
type: "object",
required: ["to", "objective", "outcome_schema", "consent_type"],
properties: {
to: { type: "string", description: "E.164 phone number" },
objective: { type: "string", description: "Plain-English goal for the call" },
outcome_schema: { type: "object", description: "Typed fields you want back" },
consent_type: { type: "string", enum: ["prior_express", "existing_business_relationship", "emergency"] },
},
},
},
{
name: "openphn_get_call",
description: "Fetch the current state and outcome of an OpenPhn call by id.",
input_schema: {
type: "object",
required: ["call_id"],
properties: { call_id: { type: "string" } },
},
},
];
// In your tool-use loop, when the model invokes openphn_make_call:
async function handleOpenPhn(toolName: string, input: any) {
const base = "https://api.openphn.com";
const headers = {
"Authorization": `Bearer ${process.env.OPENPHN_KEY!}`,
"Content-Type": "application/json",
};
if (toolName === "openphn_make_call") {
const res = await fetch(`${base}/v1/calls`, {
method: "POST",
headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify(input),
});
return res.json();
}
if (toolName === "openphn_get_call") {
const res = await fetch(`${base}/v1/calls/${input.call_id}`, { headers });
return res.json();
}
throw new Error(`Unknown tool: ${toolName}`);
}Why MCP is usually better
- One config change, four tools, no hand-rolled schemas.
- Scope + rate-limit handling is on OpenPhn's side.
- You don't have to keep your tool schemas in sync when OpenPhn adds new capabilities.
Use Option B when your Claude Agent deployment doesn't support MCP yet or you need a custom retry/audit layer in front of OpenPhn.