A Model Context Protocol (MCP) server implementation for the VoIPBin API. This server enables AI models to interact with VoIP services through a standardized interface.
Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
VoIPBin MCP Server exhibits significant quality gaps across naming, descriptions, parameter validation, and schema documentation. While all 20 tools are explicitly registered in src/main.py with basic names and descriptions, critical deficiencies prevent this from reaching production readiness. Tool names follow verb_noun convention (positive), but descriptions are uniformly generic (10 - 30 words, averaging ~20 chars for tools like 'Retrieve a list of calls with optional filtering'). Parameter schemas are severely underspecified: 'params' and 'body' parameters are typed as bare 'object' with only trivial descriptions ('Optional filtering parameters', 'Call creation parameters'), no enum constraints, no nested field documentation, no format specifications. Output schemas are entirely undocumented; callers cannot plan downstream calls or extract specific fields. Error handling is absent, tools return raw HTTP responses as JSON strings with no recovery guidance. No rate limiting, no idempotence declarations, no pagination support despite list tools potentially returning thousands of items. Security is weak: API_KEY is injected via environment variable (correct), but parameters are logged in plaintext (logging.debug f-strings), secrets could leak into traces. Tools lack per-tool scope/permission documentation. Composition is poor: list tools (get_calls, get_campaigns, etc.) expose identical filtering patterns but provide no pagination strategy, forcing agents to request all records and hope results fit context. Critical pattern violations: no tool annotation hints (readOnlyHint/destructiveHint/idempotentHint), no Multi Round-Trip Request support, no structured response shaping.
Parameters use bare 'object' type with no nested field documentation. 'params' and 'body' fields lack enum constraints, format specifications, required/optional field definitions, and value ranges. LLMs cannot determine valid input structures.
Output schemas are completely undocumented. Tools return raw JSON strings from VoIPBin API without describing field structure, data types, or how to chain calls. Agents cannot plan subsequent actions or extract required IDs.
Add detailed tool descriptions (150 - 250 chars) explaining WHAT each tool does, WHEN to call it instead of similar tools, and what it returns. Example: 'Retrieve all active calls with optional filtering by status, agent, or campaign. Supports pagination via limit and offset. Returns call_id, caller, callee, status, duration, start_time. Call this first to find a specific call, then use get_call for full details.'
Replace 'params' and 'body' parameters with explicit, typed, documented fields. For get_calls: add 'status' (enum: active|completed|missed|on_hold), 'agent_id' (string), 'limit' (integer 1 - 100, default 20), 'offset' (integer, default 0). For create_call: add 'from_number' (E.164 format), 'to_number' (E.164 format), 'campaign_id' (string), with clear descriptions and validation rules.
Add pagination to all list tools (limit, offset, total_count) with max limit enforced (e.g. 100). Update descriptions to state: 'Limit results to 20 - 100 records per page. Pass offset to fetch the next page. Returns total_count to enable agent planning.'
Implement error handling with recovery guidance. Catch HTTP exceptions and return structured errors: '{ error: "invalid_agent_id", message: "Agent U2405 not found. Try get_agents() to find valid agent IDs.", retryable: false }'. Distinguish 4xx (user-fixable) from 5xx (retryable) from timeout (retryable with backoff).
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
List tools (get_calls, get_agents, get_campaigns, etc.) accept 'params' for filtering but provide no pagination support (limit, offset, page_size, next_cursor). Without pagination, agents requesting large datasets will exhaust context or timeout.
Tool descriptions are generic and under 50 characters. Examples: 'Retrieve a list of calls with optional filtering', 'Get details of a specific call'. Descriptions lack context on WHEN to use each tool, what prerequisites exist, or what fields are returned. Cannot differentiate similar tools.
No error handling or recovery guidance. Tools return raw HTTP response text; on failure, LLMs receive unstructured error messages without actionable next steps. Missing pattern: error classification (retryable vs user-fixable vs fatal) and recovery suggestions.
API key and credentials logged in plaintext via logging.debug(). Parameters and request bodies are dumped to logs without sanitization: 'logger.debug(f"Parameters: {params}")'. Credentials will leak into execution traces and audit logs.
No rate limiting or timeouts. Agents can invoke create_call or send_chat_message in loops without bounds. An agent retry loop could generate thousands of requests per minute, overwhelming the VoIPBin API and incurring charges.
Parameter descriptions are trivial: 'Optional filtering parameters', 'Call creation parameters'. No format specifications, constraints, ranges, or examples. LLMs must guess what filtering keys and body fields are valid.
No confirmation or dry-run patterns for destructive operations. 'end_call' immediately terminates an active call; 'create_call' immediately initiates communication. Agents making mistakes cannot be easily recovered from.
Add tool annotations: mark read-only tools with readOnlyHint=true (all get_* and list tools). Mark write operations with destructiveHint=true (end_call, create_call destructive because it initiates communication; delete_* if added). Mark idempotent operations (if any) with idempotentHint=true.
Remove plaintext logging of parameters, request bodies, and API keys. Replace 'logger.debug(f"Parameters: {params}")' with 'logger.debug(f"Calling {method} {endpoint}")'. Use structured logging with redacted fields for sensitive data.
Add rate limiting per agent/user (e.g. 10 calls/minute for write operations) with clear backoff responses: '{ error: "rate_limited", retry_after_seconds: 60 }'. Document in tool descriptions.
Add optional confirmation steps for destructive operations. Example: end_call could accept a 'confirm_token' parameter generated by a separate 'prepare_end_call(call_id)' tool that returns a token and summary ('Confirm ending call with John Doe, 45 seconds duration'). This requires explicit second call, preventing accidental terminations.
Expand parameter descriptions to match production baseline (~72 chars avg). Example: 'Status of the call (active, completed, missed, on_hold). Use this to filter list results by state.'
Add chaining metadata to responses. If create_call returns call_id, get_call should document that you can pass that call_id directly. If get_chats returns chat_id, send_chat_message should explicitly accept chat_id as a parameter.
Document required/optional nested fields in 'body' parameters by example. For create_call body, document: '{ "from_number": "required, E.164", "to_number": "required, E.164", "campaign_id": "optional" }'.
Add schema constraints to parameter types. For 'status' enums, define exactly which values are valid. For numeric limits, add min/max. For string formats, add regex patterns or length limits in descriptions.
Implement graceful degradation: if an enrichment fails (e.g. agent lookup inside get_call), return the core call data with a warning field ('warning: agent details unavailable') rather than a hard error.
Create a discovery tool 'describe_filtering_options(resource_type)' that lists valid filter keys and enums for each resource (calls, agents, campaigns). This enables agents to self-discover constraints instead of guessing.