VoixCall

VoixCall for developers

MCP server

One remote MCP server, OAuth only, acting on the connected user's personal account.

Server URLhttps://api.voixcall.com/mcp
TransportStreamable HTTP, stateless, JSON responses (no SSE stream to hold open). Mcp-Session-Id and Mcp-Protocol-Version request headers are accepted.
AuthenticationOAuth 2.1 access token as a bearer token, obtained through the standard discovery flow below. API keys are not accepted here (they work on /v1 only); test-mode credentials are rejected.
Protected-resource metadata/.well-known/oauth-protected-resource/mcp (RFC 9728)
Authorization-server metadata/.well-known/oauth-authorization-server (RFC 8414)
Client registrationClient ID Metadata Documents (an https client_id that serves its own metadata; what Claude uses) or Dynamic Client Registration at /oauth/register. PKCE S256 is required; there are no client secrets.
Server namevoixcall, title “VoixCall”, version 0.1.0
Rate limitReads budget: 60 requests/min per connection, 120/min per user. See rate limits.

How authentication works

An unauthenticated request to /mcp gets a 401 whose WWW-Authenticate header points at the protected-resource metadata. From there a client finds the authorization server, registers, runs the authorization-code flow with PKCE and comes back with a bearer token bound to the https://api.voixcall.com/mcp resource. Clients that implement the MCP authorization specification do all of this without configuration.

Discovery probe
curl -si https://api.voixcall.com/mcp
# HTTP/1.1 401 Unauthorized
# WWW-Authenticate: Bearer error="invalid_token", resource_metadata="https://api.voixcall.com/.well-known/oauth-protected-resource/mcp"
# Request-Id: req_…
Protected-resource metadata
curl -s https://api.voixcall.com/.well-known/oauth-protected-resource/mcp
{
  "resource": "https://api.voixcall.com/mcp",
  "authorization_servers": ["https://api.voixcall.com"],
  "scopes_supported": ["rates:read", "credits:read", "calls:read", "calls:place", "contacts:read",
                       "numbers:read", "messages:read", "messages:history", "transcripts:read", "webhooks:manage"],
  "bearer_methods_supported": ["header"],
  "resource_name": "VoixCall MCP",
  "resource_documentation": "https://voixcall.com/developers/mcp"
}

On the consent page at app.voixcall.com/oauth/consent the user sees the client's name, how it registered (“registered by URL”, “self-registered” or “verified partner”), the host it redirects to, and each requested scope as a sentence. Self-registered clients asking for calls:place, messages:read, messages:history or transcripts:read need a second confirmation checkbox. After Allow, the user gets an email “New app connected”.

Tools

Every tool is prefixed voixcall_, sets title, and returns structuredContent matching its outputSchema plus a one-line spoken summary an assistant can read aloud. Business failures are returned as isError: true results with actionable text; protocol errors are reserved for unknown tools and malformed arguments. The server's instructions tell the assistant: “Tools act only on the connected personal account. Say what a tool returned; do not invent numbers, prices or call details.”

Live production

ToolScopeDescription and annotationsInput → output
voixcall_whoami
title: Who am I
any “Use this to confirm which VoixCall account is connected. Do not use for anything else.”
readOnlyHint: true, idempotentHint: true, destructiveHint: false, openWorldHint: false
no input → email, display_name, spoken (one sentence: “You're connected to VoixCall as Name (email).”)

Planned not live

These follow the read endpoints in phase 2 and later phases. Names, scopes and annotations are from the specification and may still change before they ship; the changelog announces each one. There will be no top-up tool, no number purchase and no message sending.

ToolScopeAnnotationsInput → output
voixcall_get_rate planned rates:read read-only destination (E.164 or country name) → rate, billing increment; estimate: true for a country name with a request for the full number
voixcall_get_balance planned credits:read read-only none → amount, currency, low_balance, billing_url (informational; there is no purchase tool)
voixcall_search_contacts planned contacts:read read-only query, limit ≤ 5 → matches
voixcall_list_calls planned calls:read read-only limit ≤ 10, direction → calls; contact names need contacts:read
voixcall_get_call planned calls:read read-only call_id → call with live status and cost so far
voixcall_get_call_summary planned transcripts:read read-only call_id → summary, action items, reference numbers; gated by the “Allow connected apps to read call summaries” switch (off by default); never starts a transcription
voixcall_list_numbers planned numbers:read read-only none → numbers with messages_opt_in
voixcall_read_messages planned messages:read read-only number (must be opted in), window_minutes ≤ 60 → messages; codes must not be forwarded to anyone
voixcall_quote_call planned calls:place read-only to (E.164 or contact id), record → quote with quote_id, rates, the number that will ring, the caller ID shown, expires_at
voixcall_place_call planned calls:place not read-only, not idempotent quote_id → call in ringing_you; a quote can be placed once; your phone rings first and you press 1 to connect
voixcall_end_call planned calls:place idempotent call_id → final call

Placing a call will always be two steps: voixcall_quote_call shows the price and the number that will ring, and voixcall_place_call accepts only that single-use quote. Your own phone rings first and you press 1 to connect, so no assistant can spend your balance without you on the line.

Per-client setup

Claude Code

Terminal
claude mcp add --transport http voixcall https://api.voixcall.com/mcp
claude mcp login voixcall
claude mcp list

claude mcp login voixcall opens the consent page in your browser. Claude Code registers with its own client metadata document, so the consent page shows it as “registered by URL: claude.ai”. It currently requests every advertised scope; you can only allow or deny the set as a whole. Verified against production.

claude.ai (custom connectors)

Settings → Connectors → Add custom connector. Name it VoixCall, set the URL to https://api.voixcall.com/mcp and leave the OAuth client id and secret empty. Click Connect, approve on app.voixcall.com, then enable the connector in a chat. claude.ai connectors use the same standard MCP discovery and OAuth 2.1 flow. Unlike Claude Code, they connect from Anthropic's servers with an https callback, which we have not yet exercised end to end.

ChatGPT

ChatGPT's connector settings take the same server URL and use the same standard MCP discovery and OAuth 2.1 flow. Unlike Claude Code, ChatGPT connects from OpenAI's servers with an https callback, which we have not yet exercised end to end; treat it as untested until the changelog says otherwise.

MCP Inspector (for testing)

Terminal
npx @modelcontextprotocol/inspector
# In the UI: Transport Type "Streamable HTTP", URL https://api.voixcall.com/mcp,
# then Connect. The Inspector registers itself (Dynamic Client Registration),
# opens the consent page, and lists voixcall_whoami under Tools.

Verified with Inspector 2.8.0: registration by Dynamic Client Registration, the sensitive-scope checkbox on consent, and voixcall_whoami returning structured output.

Other clients and your own code

Any client that implements MCP over Streamable HTTP with the authorization specification works. If you write your own, use the quickstart's curl flow with resource=https://api.voixcall.com/mcp to get a token, then POST JSON-RPC to /mcp with Authorization: Bearer vcat_…, Content-Type: application/json and Accept: application/json.

What the user controls

  • Settings → Connected apps in the web app lists every connected client with its name, registration kind, redirect host, scopes, when it was first authorized and when it was last used. Disconnect revokes all of that client's tokens immediately; the next call gets invalid_token with “Reconnect VoixCall in your assistant”.
  • Two sharing switches coming: “Allow connected apps to read call summaries” and, per number, “Allow connected apps to read messages on this number”. Both are off by default and are shown but not yet active; they gate the transcript and message tools when those ship.
  • A password reset revokes every connected app and every API key.
  • Every new connection is emailed to the account owner, and connections, disconnections and token refreshes are written to an audit log kept up to 400 days (automatic deletion job in progress; a view of it on the Connected apps page is coming).

More on what each scope exposes, and for how long, in privacy for connected apps.