Static source inference · medium confidence · evidence: structured output
No deprecated protocol patterns detected
Summary
The Vapi MCP server has 13 tools with schemas derived from Zod that are explicitly registered via server.registerTool() and server.tool() calls. Tool names follow verb_noun conventions (list_*, create_*, get_*, update_*), which is correct. However, descriptions are uniformly very short (10-40 chars), well below the 50-200 char baseline for LLM optimization. Parameter descriptions exist but are often single-line and lack actionable constraints (e.g., 'Name of the assistant' without guidance on length, format, or reserved characters). Schemas are present but exported from Zod without visibility into the full shape, the source excerpt is truncated at 'export const GoogleModels = {' in src/schemas/index.ts. Output schemas are not documented in tool descriptions. Error handling guidance is absent from descriptions. Most tools are simple CRUD wrappers (list, get, create, update) with minimal composition logic visible. The server uses STDIO transport, which is a hard constraint on protocol readiness but does not directly penalize definition quality.
Tool descriptions uniformly short (10-40 chars, 7x below 50-200 char baseline). Examples: 'Lists all Vapi assistants', 'Gets a Vapi assistant by ID'. LLMs cannot differentiate tools or understand when to invoke them without richer context. No guidance on prerequisites, return types, or idempotency.
Parameter descriptions lack actionable constraints. E.g., 'Name of the assistant' (create_assistant.name) has no length, format, or reserved-character guidance. 'Instructions for the assistant' (create_assistant.instructions) lacks guidance on max tokens, embedding language, or supported syntax. LLMs will guess, causing validation failures.
Expand all tool descriptions to 50-200 characters, following the baseline for LLM optimization. Example: 'list_assistants: Lists all Vapi voice assistants. Returns assistant ID, name, LLM config, voice settings, and tool references. Use this to discover available assistants before creating calls.'
Add constraint descriptions to every parameter. For 'name' fields, specify max length and forbidden characters. For 'instructions', specify max tokens and supported formats (plain text, markdown). For 'model', reference the enum values explicitly: 'Must be one of: gpt-4o, gpt-4o-mini (OpenAI), claude-3-7-sonnet-20250219, claude-3-5-haiku-20241022 (Anthropic), ...'
Document output schemas in tool descriptions. Example: 'Returns an object with fields: id (UUID), name (string), llm (object with provider and model), voice (object with provider and voiceId), toolIds (array of strings), createdAt (ISO 8601 datetime). Pass the returned id to get_assistant, update_assistant, or create_call.'
Add error handling to descriptions. Example: 'Creates a new Vapi assistant. Returns error if name is empty or exceeds 255 chars, if LLM provider is unsupported, or if any toolId does not exist. If name is duplicate, request a unique name; if toolId fails, call list_tools first to validate IDs.'
Add pagination parameters to list tools. Modify list_assistants, list_calls, list_phone_numbers, list_tools to accept 'limit' (1-100, default 20) and 'offset' or 'cursor' params. Document that responses include a 'total' count and 'nextCursor' if more results exist.
No documented output schemas. Tool descriptions say what they do ('Lists all Vapi assistants') but not what fields the response contains or how to chain results to downstream tools. LLMs cannot know which fields to extract for follow-up calls.
No error handling guidance. Descriptions do not explain what errors may occur, whether they are retryable, or how the LLM should recover. E.g., 'Creates a new Vapi assistant' does not mention what happens if the name is a duplicate, if LLM config is invalid, or if tool IDs do not exist.
List tools (list_assistants, list_calls, list_phone_numbers, list_tools) have no pagination parameters visible in schemas. Response descriptions do not mention limits, offsets, total counts, or next_cursor. Without pagination, large result sets may exhaust context or fail.
Complex nested parameter schemas (e.g., create_tool.transferCall.destinations[].properties) lack per-property descriptions. LLMs must infer meaning from property names alone, 'callerId' is ambiguous (Caller ID format? E.164? Alphanumeric?).
create_call parameter 'scheduledAt' accepts ISO datetime but description lacks guidance on timezone handling, past/future constraints, or minimum lead time. LLMs may pass invalid or ambiguous timestamps.
No idempotency hints. Tools like create_assistant, create_call, create_tool do not indicate whether calling them twice with identical params produces one or two resources. Agents need this to safely retry on failures.
create_assistantcreate_callcreate_tool
Add descriptions to nested parameter properties in create_tool and update_tool. For transferCall.destinations[].callerId, specify: 'Caller ID for the transfer in E.164 format (e.g., +16054440129) or alphanumeric (max 15 chars). Must be verified with your carrier.'
Add timezone guidance to create_call.scheduledAt: 'ISO 8601 datetime (e.g., 2025-03-25T22:39:27.771Z). Must be in the future (minimum 5 minutes from now). Interpreted as UTC.'
Add idempotency documentation to write tools. Example for create_assistant: 'This operation is idempotent: calling it twice with the same name and config will succeed without creating a duplicate. Pass a unique name to create multiple assistants.'
Create documentation guide or README with examples showing how to chain tools. E.g., 'Create an assistant, then immediately pass its returned assistantId to create_call to make an outbound call with that assistant.'
Add tool annotations (readOnlyHint, destructiveHint, idempotentHint) to tool registrations for protocol compliance. Mark list_*, get_* as readOnly; mark create_*, delete_* as destructive; clarify idempotency where applicable.