Skip to main content
Glama

spix_contact_create

Create a new contact in Spix by providing name, phone, email, and tags to manage contact information.

Instructions

Create a new contact

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesContact name
phoneNoPhone number (E.164)
emailNoEmail address
tagsNoTags for the contact

Implementation Reference

  • The create_tool_handler function is the centralized handler that executes MCP tool calls by resolving the tool name to a CommandSchema, validating session scopes, and dispatching to the backend API.
    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())]
  • The definition of 'contact.create' (mapped to 'spix_contact_create') in the COMMAND_REGISTRY, defining its API endpoint, HTTP method, and input parameters.
    CommandSchema(
        path="contact.create",
        cli_usage="spix contact create --name <n> --phone <p>",
        http_method="POST",
        api_endpoint="/contacts",
        mcp_expose="tool",
        mcp_profile="safe",
        description="Create a new contact",
        params=[
            CommandParam("name", "string", required=True, description="Contact name"),
            CommandParam("phone", "string", description="Phone number (E.164)"),
            CommandParam("email", "string", description="Email address"),
            CommandParam("tags", "array", description="Tags for the contact"),
        ],
    ),
  • The get_mcp_tools function is used to dynamically generate the list of available MCP tools from the COMMAND_REGISTRY, which includes 'contact.create'.
    def get_mcp_tools(profile: str = "safe", disabled: list[str] | None = None) -> list[CommandSchema]:
        """Return tool-exposed commands filtered by profile and disabled list.
    
        Args:
            profile: "safe" or "full". "safe" excludes destructive operations.
            disabled: List of command paths to exclude (e.g., ["billing.plan.set"]).
    
        Returns:
            List of CommandSchema objects to expose as MCP tools.
        """
        disabled_set = set(disabled or [])
        return [
            cmd
            for cmd in COMMAND_REGISTRY
            if cmd.mcp_expose == "tool"
            and (profile == "full" or cmd.mcp_profile == "safe")
            and cmd.path not in disabled_set
        ]

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Spix-HQ/spix-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server