spix_call_create
Initiate automated voice calls using playbooks, specifying destination numbers and sender information to deliver pre-configured messages or interactions.
Instructions
Initiate a voice call
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Destination phone number (E.164) | |
| playbook_id | Yes | Playbook ID | |
| sender | Yes | Sender number (E.164) | |
| contact_id | No | Link to existing contact | |
| webhook_url | No | Override webhook URL |
Implementation Reference
- src/spix_mcp/tools.py:94-204 (handler)The `create_tool_handler` function in `src/spix_mcp/tools.py` handles the execution of all MCP tools by resolving the tool name to a command schema (using `get_schema_by_tool_name`) and dispatching the request to the backend API. There is no specific function named `spix_call_create`; rather, the tool `spix_call_create` is dynamically generated from the `call.create` entry in the `COMMAND_REGISTRY`.
async def create_tool_handler( session: McpSessionContext, tool_name: str, arguments: dict, ) -> list: """Execute an MCP tool call by dispatching to the backend API. This function: 1. Resolves the tool name to a command schema 2. Validates session scope (playbook access, channel access) 3. Builds the API request 4. Dispatches to the backend 5. Returns the response as MCP TextContent Args: session: The MCP session context for scope validation. tool_name: The MCP tool name (e.g., "spix_playbook_create"). arguments: The tool arguments from the MCP client. Returns: List containing a single TextContent with the JSON response. """ # Import here to avoid circular imports and handle missing mcp package try: from mcp.types import TextContent except ImportError: # Fallback for when mcp is not installed class TextContent: # type: ignore[no-redef] def __init__(self, type: str, text: str) -> None: self.type = type self.text = text # Resolve tool name to schema schema = get_schema_by_tool_name(tool_name) if not schema: return [ TextContent( type="text", text=orjson.dumps( {"ok": False, "error": {"code": "unknown_tool", "message": f"Unknown tool: {tool_name}"}} ).decode(), ) ] # Validate tool access (not disabled) try: session.validate_tool_access(schema.path) except Exception as e: from spix_mcp.session import McpScopeError if isinstance(e, McpScopeError): return [TextContent(type="text", text=orjson.dumps({"ok": False, "error": e.to_dict()}).decode())] raise # Validate channel access if applicable channel = infer_channel_from_tool(schema.path) if channel: try: session.validate_channel_access(channel) except Exception as e: from spix_mcp.session import McpScopeError if isinstance(e, McpScopeError): return [TextContent(type="text", text=orjson.dumps({"ok": False, "error": e.to_dict()}).decode())] raise # Handle playbook_id: validate and apply default playbook_id = arguments.get("playbook_id") try: effective_playbook = session.validate_playbook_access(playbook_id) if effective_playbook and not playbook_id: # Apply default playbook arguments["playbook_id"] = effective_playbook except Exception as e: from spix_mcp.session import McpScopeError if isinstance(e, McpScopeError): return [TextContent(type="text", text=orjson.dumps({"ok": False, "error": e.to_dict()}).decode())] raise # Build endpoint URL with path parameters endpoint, remaining_args = build_endpoint_url(schema, arguments) # Dispatch to backend API client = session.client method = schema.http_method.lower() if method == "get": response = await asyncio.to_thread(client.get, endpoint, params=remaining_args if remaining_args else None) elif method == "post": response = await asyncio.to_thread(client.post, endpoint, json=remaining_args if remaining_args else None) elif method == "patch": response = await asyncio.to_thread(client.patch, endpoint, json=remaining_args if remaining_args else None) elif method == "delete": response = await asyncio.to_thread(client.delete, endpoint, params=remaining_args if remaining_args else None) else: response = await asyncio.to_thread(client.get, endpoint) # Build response envelope envelope: dict = {"ok": response.ok, "meta": response.meta} if response.ok: envelope["data"] = response.data if response.pagination: envelope["pagination"] = response.pagination if response.warnings: envelope["warnings"] = response.warnings else: envelope["error"] = response.error return [TextContent(type="text", text=orjson.dumps(envelope).decode())] - src/spix_mcp/registry.py:284-302 (schema)The definition for the command `call.create`, which is automatically exposed as the MCP tool `spix_call_create` based on the mapping logic in `src/spix_mcp/tools.py`.
CommandSchema( path="call.create", cli_usage="spix call create <to> --playbook <id> --sender <number>", http_method="POST", api_endpoint="/calls", mcp_expose="tool", mcp_profile="safe", financial=True, description="Initiate a voice call", positional_args=[ CommandParam("to", "string", required=True, description="Destination phone number (E.164)"), ], params=[ CommandParam("playbook_id", "string", required=True, description="Playbook ID"), CommandParam("sender", "string", required=True, description="Sender number (E.164)"), CommandParam("contact_id", "string", description="Link to existing contact"), CommandParam("webhook_url", "string", description="Override webhook URL"), ], ),