MCP server giving AI agents a phone via Voxplo outbound AI calls.
Four tools with complete Zod schemas, clear descriptions (avg 180 chars), and proper annotations. Naming follows verb_noun convention (place_call, set_appointment, get_call, list_calls). All parameters have type definitions and descriptions. Tool annotations correctly mark read-only vs. destructive operations. Key gaps: output schemas are not documented (handlers return JSON.stringify without field documentation), error messages are generic ('Request failed'), and no guidance on recovery steps or retry logic. Missing pagination documentation for list_calls despite accepting a limit parameter.
Get the status and result of a call by id. status is one of queued | ringing | in_progress (still running, poll again) or completed | no_answer | voicemail | declined | failed (terminal). Returns summary, transcript, and extracted fields.
List recent calls placed by your account (most recent first).
Place an outbound AI phone call toward an objective. Returns a callId immediately; the call is conducted asynchronously. Poll get_call with that callId until status is terminal (completed | no_answer | voicemail | declined | failed).
Place an outbound AI phone call to set up a meeting. The assistant calls the person, agrees a time, and the result (poll get_call) carries outcome (appointment_set | callback_requested | declined | no_answer | failed) and, when set, the appointment (startISO, timezone, durationMinutes, attendee, subject). Returns a callId immediately.
Output schemas not documented. Handlers return JSON.stringify(data) without specifying what fields clients should expect (e.g., get_call returns 'summary, transcript, extracted fields' in description but no schema). LLMs cannot plan downstream tool calls or extract specific fields reliably.
Error handling is generic and non-actionable. errText() returns 'Request failed (status)' without context. LLMs cannot determine if the error is retryable, user-fixable, or fatal, or what to do next. No recovery guidance.
list_calls accepts a limit parameter but does not document pagination behavior, total count, or next_cursor. Description says 'most recent first' but does not explain how to fetch older calls or whether results are capped.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 62 | 2026-07-28+ | v2 |
place_call and set_appointment are non-idempotent (openWorldHint: true, idempotentHint: false) but lack confirmation or dry-run support. Agents retrying on ambiguous failures risk placing duplicate calls. No mitigation pattern offered.
Parameter descriptions include example values (e.g., '+14155550123', 'Asia/Jerusalem', 'weekday mornings next week'). LLMs tend to reuse examples literally rather than adapting to context, causing failures.