Skip to main content
Glama
freesolo-co

Clado MCP Server

by freesolo-co

retrieve_contacts

Retrieve email addresses and phone numbers from LinkedIn profiles. Supports reverse lookup using email or phone numbers to find corresponding profiles.

Instructions

Retrieves email addresses and phone numbers for LinkedIn profiles. Supports reverse lookup via email or phone. Email enrichment costs 4 credits if found, phone enrichment costs 10 credits if found.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
linkedin_urlNoLinkedIn profile URL to get contact information for (e.g., 'https://www.linkedin.com/in/username')
emailNoEmail address to find profile and get contact information (e.g., 'john.doe@example.com')
phoneNoPhone number to find profile and get contact information (e.g., '+1234567890')
email_enrichmentNoIf true, returns emails (costs 4 credits if email found). Can be combined with phone_enrichment
phone_enrichmentNoIf true, returns phone numbers (costs 10 credits if phone found). Can be combined with email_enrichment

Implementation Reference

  • The main handler function `retrieveContactsTool` that implements the tool logic: validates parameters, constructs API request to Clado's enrich/contacts endpoint, handles response, calculates costs, and formats output.
    export const retrieveContactsTool = async ({
      linkedin_url,
      email,
      phone,
      email_enrichment = false,
      phone_enrichment = false,
    }: RetrieveContactsParams) => {
      const identifiers = [linkedin_url, email, phone].filter(Boolean);
      if (identifiers.length === 0) {
        throw new Error("Must provide exactly one of: LinkedIn URL, email, or phone number");
      }
      if (identifiers.length > 1) {
        throw new Error("Must provide exactly one of: LinkedIn URL, email, or phone number");
      }
    
      if (!email_enrichment && !phone_enrichment) {
        throw new Error("At least one enrichment type (email_enrichment or phone_enrichment) must be set to true");
      }
    
      const apiUrl = new URL("https://search.clado.ai/api/enrich/contacts");
    
      if (linkedin_url) {
        apiUrl.searchParams.append("linkedin_url", linkedin_url);
      } else if (email) {
        apiUrl.searchParams.append("email", email);
      } else if (phone) {
        apiUrl.searchParams.append("phone", phone);
      }
    
      apiUrl.searchParams.append("email_enrichment", String(email_enrichment));
      apiUrl.searchParams.append("phone_enrichment", String(phone_enrichment));
    
      const response = await makeCladoRequest(apiUrl.toString(), {});
      const responseData = await response.json();
    
      if (responseData.error) {
        throw new Error(
          `Failed to retrieve contact information: ${JSON.stringify(responseData.error)}`
        );
      }
    
      let costMessage = "";
      if (responseData.data && responseData.data[0]) {
        const contactData = responseData.data[0];
        const hasEmails = contactData.contacts?.some((c: any) => c.type === "email");
        const hasPhones = contactData.contacts?.some((c: any) => c.type === "phone");
        
        const costs = [];
        if (email_enrichment && hasEmails) costs.push("4 credits for email");
        if (phone_enrichment && hasPhones) costs.push("10 credits for phone");
        
        if (costs.length > 0) {
          costMessage = ` (Cost: ${costs.join(" + ")})`;
        }
      }
    
      return {
        content: [
          {
            type: "text" as const,
            text: `Contact information retrieved successfully${costMessage}: ${JSON.stringify(responseData, null, 2)}`
          }
        ]
      };
    };
  • Zod schema definition for input parameters of the retrieve_contacts tool.
    export const retrieveContactsSchema = {
      linkedin_url: z.string().optional().describe("LinkedIn profile URL to get contact information for (e.g., 'https://www.linkedin.com/in/username')"),
      email: z.string().optional().describe("Email address to find profile and get contact information (e.g., 'john.doe@example.com')"),
      phone: z.string().optional().describe("Phone number to find profile and get contact information (e.g., '+1234567890')"),
      email_enrichment: z.boolean().default(false).describe("If true, returns emails (costs 4 credits if email found). Can be combined with phone_enrichment"),
      phone_enrichment: z.boolean().default(false).describe("If true, returns phone numbers (costs 10 credits if phone found). Can be combined with email_enrichment"),
    };
  • src/index.ts:38-43 (registration)
    Registration of the retrieve_contacts tool in the main MCP server setup in index.ts.
    server.tool(
      retrieveContactsName,
      retrieveContactsDescription,
      retrieveContactsSchema,
      retrieveContactsTool
    );
  • Registration of the retrieve_contacts tool in the server setup module.
    server.tool(
      retrieveContactsName,
      retrieveContactsDescription,
      retrieveContactsSchema,
      retrieveContactsTool
    );
  • TypeScript type definition matching the schema for RetrieveContactsParams.
    type RetrieveContactsParams = {
      linkedin_url?: string;
      email?: string;
      phone?: string;
      email_enrichment?: boolean;
      phone_enrichment?: boolean;
    };
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively adds valuable context beyond what the input schema provides: it discloses credit costs (4 credits for email enrichment if found, 10 credits for phone enrichment if found), which is crucial for understanding resource usage and potential expenses. This information isn't captured in the schema, making the description transparent about behavioral traits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded, consisting of two concise sentences that efficiently convey the tool's purpose, capabilities, and cost implications. Every sentence earns its place by providing essential information without redundancy or unnecessary details, making it easy for an AI agent to parse and understand quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of a tool with 5 parameters, no annotations, and no output schema, the description does a good job of providing context. It explains the tool's purpose, reverse lookup support, and credit costs, which are critical for usage. However, it doesn't describe the return format or what happens when no data is found, leaving some gaps in completeness for a tool without an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 100%, meaning all parameters are well-documented in the schema itself. The description adds some semantic context by mentioning credit costs associated with 'email_enrichment' and 'phone_enrichment', but it doesn't provide additional meaning beyond what the schema already covers for parameters like 'linkedin_url', 'email', or 'phone'. Given the high schema coverage, a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: retrieving email addresses and phone numbers for LinkedIn profiles, with support for reverse lookup via email or phone. It specifies the resource (LinkedIn profiles) and the action (retrieving contact information). However, it doesn't explicitly differentiate this tool from sibling tools like 'enrich_linkedin' or 'search_for_users', which might have overlapping functionality.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by mentioning reverse lookup capabilities and credit costs, but it doesn't provide explicit guidance on when to use this tool versus alternatives like 'enrich_linkedin' or 'search_for_users'. It mentions cost implications, which helps inform usage decisions, but lacks direct comparisons or exclusions for sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/freesolo-co/search-mcp'

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