searchContacts
Find specific contacts in Clay by searching job titles, companies, locations, or keywords. Returns detailed contact records to answer questions like "Who works at X?" or "Who specializes in Y?".
Instructions
Search for contacts and return matching people. Use for questions about specific contacts or "who" questions (e.g. "Who did I meet most?" or "who works as an engineer?"). Returns actual contact records for queries needing specific people.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| company_name | No | If the query refers to a company or acronym of companies, list company names as they would on a LinkedIn profile. | |
| exclude_contact_ids | No | Used to exclude previously returned contact IDs when the user asks for more results (e.g. "who else" or "show me more"). You should pass all contact IDs from previous searchContacts responses to ensure new results are shown. | |
| job_title | No | If the query refers to a job title, position, or industry, list relevant job titles as they would be on a LinkedIn profile. Examples: Developer should return positions such as 'Software Engineer', 'Full Stack Developer', 'Data Scientist', etc. Banker should return positions such as 'Financial Analyst', 'Investment Banker', 'Credit Analyst', etc. Healthcare industry should return positions such as 'Registered Nurse', 'Physician', 'Medical Director', etc. Legal industry should return positions such as 'Attorney', 'Legal Counsel', 'Paralegal', etc. | |
| keywords | No | Extract and list specific keywords related to professional expertise, skills, interests, or hobbies that the user is searching for. For example, if someone asks for 'people who know about machine learning or play tennis', the keywords would be ['machine learning', 'tennis']. Do not include job titles or company names here as those have dedicated fields. Focus on capturing domain expertise, technical skills, personal interests, and hobby-related terms that help identify relevant contacts. | |
| limit | No | The number of contacts to return if the user asks for an amount. | |
| location | No | If the query refers to a location (city, state, country, region) where people are located or based, list the locations as they would appear on a LinkedIn profile. For example, if someone asks about "people in New York", return "New York City Metropolitan Area" or if they ask about "contacts in California", return "San Francisco Bay Area", "Greater Los Angeles Area", etc. | |
| query | Yes | The raw search query from the user. Must preserve exact intent and details to enable accurate searching, including: relationship qualifiers, interaction metrics, relationship strength, names, companies, locations, dates (specific dates, date ranges, or relative dates like "last week" are required if mentioned by user), job titles, skills, and logical conditions (OR/AND). | |
| sort_instructions | No | How would you like the results sorted? For example: "most recent contacts" will sort by last interaction date, "closest connections" will sort by interaction count, and "alphabetical" will sort by name. If no sort preference is given, this can be left empty. |
Implementation Reference
- index.js:96-96 (handler)The execute handler for searchContacts tool, which proxies the call to the external Clay API endpoint /search using the shared callTool helper.execute: async (params, { session }) => callTool("/search", params, session),
- index.js:47-95 (schema)Zod schema defining input parameters for the searchContacts tool, including fields like job_title, company_name, location, query, keywords, limit, exclude_contact_ids, and sort_instructions.parameters: z.object({ job_title: z .array(z.string()) .describe( "If the query refers to a job title, position, or industry, list relevant job titles as they would be on a LinkedIn profile. Examples: Developer should return positions such as 'Software Engineer', 'Full Stack Developer', 'Data Scientist', etc. Banker should return positions such as 'Financial Analyst', 'Investment Banker', 'Credit Analyst', etc. Healthcare industry should return positions such as 'Registered Nurse', 'Physician', 'Medical Director', etc. Legal industry should return positions such as 'Attorney', 'Legal Counsel', 'Paralegal', etc." ) .default([]), company_name: z .array(z.string()) .describe( "If the query refers to a company or acronym of companies, list company names as they would on a LinkedIn profile." ) .default([]), location: z .array(z.string()) .describe( 'If the query refers to a location (city, state, country, region) where people are located or based, list the locations as they would appear on a LinkedIn profile. For example, if someone asks about "people in New York", return "New York City Metropolitan Area" or if they ask about "contacts in California", return "San Francisco Bay Area", "Greater Los Angeles Area", etc.' ) .default([]), query: z .string() .describe( 'The raw search query from the user. Must preserve exact intent and details to enable accurate searching, including: relationship qualifiers, interaction metrics, relationship strength, names, companies, locations, dates (specific dates, date ranges, or relative dates like "last week" are required if mentioned by user), job titles, skills, and logical conditions (OR/AND).' ), keywords: z .array(z.string()) .describe( "Extract and list specific keywords related to professional expertise, skills, interests, or hobbies that the user is searching for. For example, if someone asks for 'people who know about machine learning or play tennis', the keywords would be ['machine learning', 'tennis']. Do not include job titles or company names here as those have dedicated fields. Focus on capturing domain expertise, technical skills, personal interests, and hobby-related terms that help identify relevant contacts." ) .default([]), limit: z .number() .describe( "The number of contacts to return if the user asks for an amount." ) .default(10), exclude_contact_ids: z .array(z.number()) .describe( 'Used to exclude previously returned contact IDs when the user asks for more results (e.g. "who else" or "show me more"). You should pass all contact IDs from previous searchContacts responses to ensure new results are shown.' ) .optional(), sort_instructions: z .string() .describe( 'How would you like the results sorted? For example: "most recent contacts" will sort by last interaction date, "closest connections" will sort by interaction count, and "alphabetical" will sort by name. If no sort preference is given, this can be left empty.' ) .optional(), }),
- index.js:43-97 (registration)Registration of the searchContacts tool via server.addTool, specifying name, description, input schema, and execute handler.server.addTool({ name: "searchContacts", description: 'Search for contacts and return matching people. Use for questions about specific contacts or "who" questions (e.g. "Who did I meet most?" or "who works as an engineer?"). Returns actual contact records for queries needing specific people.', parameters: z.object({ job_title: z .array(z.string()) .describe( "If the query refers to a job title, position, or industry, list relevant job titles as they would be on a LinkedIn profile. Examples: Developer should return positions such as 'Software Engineer', 'Full Stack Developer', 'Data Scientist', etc. Banker should return positions such as 'Financial Analyst', 'Investment Banker', 'Credit Analyst', etc. Healthcare industry should return positions such as 'Registered Nurse', 'Physician', 'Medical Director', etc. Legal industry should return positions such as 'Attorney', 'Legal Counsel', 'Paralegal', etc." ) .default([]), company_name: z .array(z.string()) .describe( "If the query refers to a company or acronym of companies, list company names as they would on a LinkedIn profile." ) .default([]), location: z .array(z.string()) .describe( 'If the query refers to a location (city, state, country, region) where people are located or based, list the locations as they would appear on a LinkedIn profile. For example, if someone asks about "people in New York", return "New York City Metropolitan Area" or if they ask about "contacts in California", return "San Francisco Bay Area", "Greater Los Angeles Area", etc.' ) .default([]), query: z .string() .describe( 'The raw search query from the user. Must preserve exact intent and details to enable accurate searching, including: relationship qualifiers, interaction metrics, relationship strength, names, companies, locations, dates (specific dates, date ranges, or relative dates like "last week" are required if mentioned by user), job titles, skills, and logical conditions (OR/AND).' ), keywords: z .array(z.string()) .describe( "Extract and list specific keywords related to professional expertise, skills, interests, or hobbies that the user is searching for. For example, if someone asks for 'people who know about machine learning or play tennis', the keywords would be ['machine learning', 'tennis']. Do not include job titles or company names here as those have dedicated fields. Focus on capturing domain expertise, technical skills, personal interests, and hobby-related terms that help identify relevant contacts." ) .default([]), limit: z .number() .describe( "The number of contacts to return if the user asks for an amount." ) .default(10), exclude_contact_ids: z .array(z.number()) .describe( 'Used to exclude previously returned contact IDs when the user asks for more results (e.g. "who else" or "show me more"). You should pass all contact IDs from previous searchContacts responses to ensure new results are shown.' ) .optional(), sort_instructions: z .string() .describe( 'How would you like the results sorted? For example: "most recent contacts" will sort by last interaction date, "closest connections" will sort by interaction count, and "alphabetical" will sort by name. If no sort preference is given, this can be left empty.' ) .optional(), }), execute: async (params, { session }) => callTool("/search", params, session), });
- index.js:31-41 (helper)Shared helper function callTool used by searchContacts (and other tools) to proxy requests to the external Clay API server with authentication.async function callTool(path, params, session) { console.log('Calling tool', path, session) return fetch(`https://nexum.clay.earth/tools${path}`, { body: JSON.stringify(params), headers: { Authorization: `ApiKey ${session.apiKey}`, "Content-Type": "application/json", }, method: "POST", }).then((res) => res.text()); }