Calls
FreeNot checkedPlace real, disclosed phone calls to businesses straight from your coding agent — the Speko "AI calls for devs" MCP. Single self-contained package: `npx @spekoa
About
Place real, disclosed phone calls to businesses straight from your coding agent — the Speko "AI calls for devs" MCP. Single self-contained package: npx @spekoai/mcp-calls init to set up.
README
Find a business and place a real, disclosed phone call to it — straight from your coding agent.
"call Sakura Sushi and ask if they have a table for 4 at 8pm" →
"Hi, I'm John's AI assistant…"→OUTCOME: table for 4 at 8pm, booked under John— back in your terminal.
This repo is a demo. It shows how a developer can wire a Claude Code MCP to Speko's calling platform: get an API key from platform.speko.dev, bring your own business-lookup (Google Places), and let Speko place the call.
What it showcases
- Get a key, make a call.
SPEKO_API_KEYfrom platform.speko.dev → real outbound calls via the official @spekoai/sdk. - Bring-your-own lookup. The Google business lookup lives in this demo's own server, not baked into
api.speko.dev. Speko's API stays focused on calling; discovery is the app's concern. - Safety as the product. A non-removable AI disclosure, business-line checks where required, no-sell/harassment/impersonation screens, rate caps, local DNC, after-hours confirmation, and signed dial tokens — all enforced server-side, where they can't be patched around.
- Two clean tiers. A thin, secret-free MCP (mcp-framework) over a backing API that holds the keys.
Architecture
┌─────────────┐ MCP (stdio) ┌──────────────────────┐ HTTP (+SPEKO_API_KEY) ┌──────────────────┐
│ Claude Code │ ───────────────▶ │ mcp/ (no secrets) │ ────────────────────────▶ │ api.speko.dev │
│ (you) │ lookup/make/ │ mcp-framework tools │ via @spekoai/sdk │ dial · poll · │
└─────────────┘ readiness └──────────┬───────────┘ │ transcript │
│ HTTP └──────────────────┘
▼
┌──────────────────────────────────────────┐
│ server/ (the backing API — holds keys) │
│ • Google Places business lookup │
│ • Twilio carrier line-type check │
│ • signed HMAC dial tokens │
│ • disclosure + abuse guardrails │
└──────────────────────────────────────────┘
mcp/— the MCP server Claude Code talks to. Built on mcp-framework. Holds no secrets; every tool just callsserver/over HTTP.server/— a small Express API. HoldsSPEKO_API_KEY, the Google Places / Twilio keys, and the dial-token secret. Runs the lookup, enforces every safety rail, and dials through@spekoai/sdk.
Why split it? Two reasons: secrets and rails must live somewhere trusted (you can't ship keys in an npx package), and per the demo's design the Google lookup stays out of api.speko.dev — it belongs to the app.
Quickstart
# one command: sign in with your browser, then it writes the MCP into every coding
# agent it detects (Claude Code/Desktop, Cursor, Windsurf, VS Code, Gemini, Codex, Cline)
# and installs the calling guide in each.
npx @spekoai/mcp-calls@latest init
init signs you in via your browser, then writes your key into every coding agent it finds.
Already have a key, or on a headless box? --token sk_... or --paste skips the browser, and
npx @spekoai/mcp-calls login re-authenticates later. The package runs single-process —
your key calls api.speko.dev directly (no separate server to boot).
Then, in your agent:
> "call Sakura Sushi and ask if they have a table for 4 at 8pm — my name is John"
Manual / CI setup (skip the wizard)
# Claude Code
claude mcp add speko-calls --scope user --env SPEKO_API_KEY=sk_... -- npx -y @spekoai/mcp-calls
// Claude Desktop — claude_desktop_config.json
{ "mcpServers": { "speko-calls": {
"command": "npx", "args": ["-y", "@spekoai/mcp-calls"],
"env": { "SPEKO_API_KEY": "sk_..." }
} } }
To route through a hosted/remote backing server instead of running in-process, set
SPEKO_MCP_SERVER_URL (then SPEKO_API_KEY lives on that server, not in your client).
lookup_business mints a dial token → make_call places the disclosed call and streams progress
while it rings → the OUTCOME: line lands back in your terminal.
Telephony note: real calls require the Speko deployment's outbound SIP trunk / caller-ID to be configured. If
make_callreturnsnot_connected(the AI agent starts but the phone never rings), runcheck_call_readiness— the demo reports this honestly rather than faking a result.
Tools
| Tool | What it does |
|---|---|
lookup_business(name, location?, phone_number?) |
Resolve a business → dialable candidates + a signed dial_token per callable one (the only path that can authorize make_call). Pass phone_number (E.164 — e.g. found via the agent's web search) to skip the directory lookup; still carrier-verified as a business line. |
make_call(dial_token, objective, caller_name, context?) |
Place the disclosed, objective-scoped call. Waits for completion, streams progress, returns the OUTCOME line + transcript. Reports connected/answered honestly — a call the platform never actually puts on the wire (no telephony leg) comes back as not_connected, never a fake success. |
call_number(phone_number, objective, caller_name) |
Disclosed PERSONAL call to a specific number (e.g. a friend) — mobiles allowed. On by default (set SPEKO_ALLOW_DIRECT_DIAL=0 to restrict to business lines). |
get_call(call_id) |
Read-only: re-check an existing call's status, OUTCOME, and transcript. Never dials. |
check_call_readiness() |
Read-only preflight — auth, credit balance, outbound caller-ID. Never dials. |
call_me (ring the account owner's own verified phone) ships in v2, once the platform exposes a
verified personal phone — it is intentionally not registered in v1 (no inert tools in the agent's
context); check_call_readiness reports its availability.
Safety rails (enforced in server/)
Built around consent and server-side enforcement: a hard-coded, non-overridable AI disclosure,
business-line verification on lookup_business, no-sell/no-spam + harassment + impersonation
screens, per-number rate caps, a local do-not-call list (speko dnc), an after-hours
confirmation gate (08:00–21:00 destination-local; late or unknown-timezone calls need explicit
human confirmation), signed account-bound dial tokens (HMAC-SHA256, 15-min TTL), and
nonce-delimited prompt blocks against injection. These run server-side because an open npm package
can be patched around.
Layout
mcp-dev-calls/
├── mcp/ # the MCP server (mcp-framework, no secrets)
│ ├── src/
│ │ ├── index.ts # MCPServer bootstrap (stdio)
│ │ ├── tools/ # LookupBusiness · MakeCall · CheckCallReadiness · CallMe
│ │ └── http/ # client to the backing server
│ └── server.json # MCP registry metadata
├── server/ # the backing API (Express; holds keys + rails)
│ ├── src/
│ │ ├── index.ts # HTTP bootstrap
│ │ ├── routes.ts # POST /lookup · POST /call · GET /readiness · GET /call/:id
│ │ ├── lookup/ # Google Places + Twilio + demo fallback
│ │ ├── safety/ # dial tokens · objective screen · disclosure prompt
│ │ ├── speko/ # @spekoai/sdk wrapper (+ raw session read)
│ │ └── calls/ # make_call · readiness · get_call · connection assessment
│ └── test/ # unit tests for the safety-critical logic
├── scripts/ # place-call.mjs (one-shot demo runner) · inspect-call.mjs (diagnostics)
├── .env.example # both tiers
└── package.json # npm workspaces root
Develop
npm run typecheck # tsc --noEmit, both tiers
npm test # vitest (server safety rails)
npm run build # tsc → dist/, both tiers
npm run dev:server # backing API with watch
npm run dev:mcp # MCP over stdio with watch
MIT © SpekoAI
Install Calls in Claude Desktop, Claude Code & Cursor
unyly install callsInstalls into Claude Desktop, Claude Code, Cursor & VS Code — handles npx, uvx and build-from-source repos for you.
First time? Get the CLI: curl -fsSL https://unyly.org/install | sh
Or configure manually
Run in your terminal:
claude mcp add calls -- npx -y @spekoai/mcp-callsFAQ
Is Calls MCP free?
Yes, Calls MCP is free — one-click install via Unyly at no cost.
Does Calls need an API key?
No, Calls runs without API keys or environment variables.
Is Calls hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Calls in Claude Desktop, Claude Code or Cursor?
Open Calls on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare Calls with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
