Skip to main content
Glama
RayanZaki

MCP Google Contacts Server

by RayanZaki

search_contacts

Find contacts in Google Contacts by searching names, emails, or phone numbers with a query and optional result limit.

Instructions

Search contacts by name, email, or phone number.

    Args:
        query: Search term to find in contacts
        max_results: Maximum number of results to return (default: 10)
    

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
max_resultsNo

Implementation Reference

  • The main handler function for the 'search_contacts' MCP tool. Decorated with @mcp.tool(), it initializes the Google Contacts service, lists contacts, performs case-insensitive substring search across displayName, givenName, familyName, email, and phone fields, limits results, and formats output using format_contacts_list.
    @mcp.tool()
    async def search_contacts(query: str, max_results: int = 10) -> str:
        """Search contacts by name, email, or phone number.
        
        Args:
            query: Search term to find in contacts
            max_results: Maximum number of results to return (default: 10)
        """
        service = init_service()
        if not service:
            return "Error: Google Contacts service is not available. Please check your credentials."
        
        try:
            # Get all contacts and filter locally with more flexible search
            all_contacts = service.list_contacts(max_results=max(100, max_results*2))
            
            query = query.lower()
            matches = []
            
            for contact in all_contacts:
                if (query in contact.get('displayName', '').lower() or
                    query in contact.get('givenName', '').lower() or
                    query in contact.get('familyName', '').lower() or
                    query in str(contact.get('email', '')).lower() or
                    query in str(contact.get('phone', '')).lower()):
                    matches.append(contact)
                    
                if len(matches) >= max_results:
                    break
                    
            if not matches:
                return f"No contacts found matching '{query}'."
                
            return f"Search results for '{query}':\n\n{format_contacts_list(matches)}"
        except Exception as e:
            return f"Error: Failed to search contacts - {str(e)}"
  • In the main server entrypoint, creates the FastMCP server instance and calls register_tools(mcp), which defines and registers the search_contacts tool (along with others) using the @mcp.tool() decorator.
    mcp = FastMCP("google-contacts")
    
    # Register all tools
    register_tools(mcp)
  • Global helper function init_service() used by search_contacts (and all tools) to lazily initialize the GoogleContactsService instance from env vars or credential files.
    def init_service() -> Optional[GoogleContactsService]:
        """Initialize and return a Google Contacts service instance.
        
        Returns:
            GoogleContactsService instance or None if initialization fails
        """
        global contacts_service
        
        if contacts_service:
            return contacts_service
        
        try:
            # First try environment variables
            try:
                contacts_service = GoogleContactsService.from_env()
                print("Successfully loaded credentials from environment variables.")
                return contacts_service
            except GoogleContactsError:
                pass
                
            # Then try default file locations
            for path in config.credentials_paths:
                if path.exists():
                    try:
                        print(f"Found credentials file at {path}")
                        contacts_service = GoogleContactsService.from_file(path)
                        print("Successfully loaded credentials from file.")
                        return contacts_service
                    except GoogleContactsError as e:
                        print(f"Error with credentials at {path}: {e}")
                        continue
                    
            print("No valid credentials found. Please provide credentials to use Google Contacts.")
            return None
            
        except Exception as e:
            print(f"Error initializing Google Contacts service: {str(e)}")
            traceback.print_exc()
            return None
  • The GoogleContactsService.list_contacts() method called by search_contacts to fetch a batch of contacts for local filtering.
    def list_contacts(self, name_filter: Optional[str] = None, 
                     max_results: int = None) -> List[Dict[str, Any]]:
        """List contacts, optionally filtering by name.
        
        Args:
            name_filter: Optional filter to find contacts by name
            max_results: Maximum number of results to return
            
        Returns:
            List of contact dictionaries
            
        Raises:
            GoogleContactsError: If API request fails
        """
        max_results = max_results or config.default_max_results
        
        try:
            # Get list of connections (contacts)
            results = self.service.people().connections().list(
                resourceName='people/me',
                pageSize=max_results,
                personFields='names,emailAddresses,phoneNumbers',
                sortOrder='FIRST_NAME_ASCENDING'
            ).execute()
            
            connections = results.get('connections', [])
            
            if not connections:
                return []
            
            contacts = []
            for person in connections:
                names = person.get('names', [])
                if not names:
                    continue
                
                name = names[0]
                given_name = name.get('givenName', '')
                family_name = name.get('familyName', '')
                display_name = name.get('displayName', '')
                
                # Apply name filter if provided
                if name_filter and name_filter.lower() not in display_name.lower():
                    continue
                
                # Get email addresses
                emails = person.get('emailAddresses', [])
                email = emails[0].get('value') if emails else None
                
                # Get phone numbers
                phones = person.get('phoneNumbers', [])
                phone = phones[0].get('value') if phones else None
                
                contacts.append({
                    'resourceName': person.get('resourceName'),
                    'givenName': given_name,
                    'familyName': family_name,
                    'displayName': display_name,
                    'email': email,
                    'phone': phone
                })
            
            return contacts
        
        except HttpError as error:
            raise GoogleContactsError(f"Error listing contacts: {error}")

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/RayanZaki/mcp-google-contacts-server'

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