- READMEs added: asana, close, freshdesk, google-console, gusto, square - main.ts + server.ts (lazy loading): activecampaign, clickup, klaviyo, mailchimp, pipedrive, trello, touchbistro, closebot, close, google-console - All 13 compile with 0 TSC errors
392 lines
15 KiB
TypeScript
392 lines
15 KiB
TypeScript
/**
|
|
* Apollo.io Contact Tools
|
|
*/
|
|
|
|
import { z } from 'zod';
|
|
import type { ApolloClient } from '../client/apollo-client.js';
|
|
|
|
const ListContactsInput = z.object({
|
|
page: z.number().min(1).default(1).describe('Page number to retrieve (starts at 1)'),
|
|
per_page: z.number().min(1).max(100).default(25).describe('Number of contacts per page (max 100)'),
|
|
contact_stage_ids: z.array(z.string()).optional().describe('Filter by contact stage IDs'),
|
|
label_ids: z.array(z.string()).optional().describe('Filter by label IDs'),
|
|
owner_id: z.string().optional().describe('Filter by contact owner user ID'),
|
|
});
|
|
|
|
const GetContactInput = z.object({
|
|
id: z.string().describe('The unique ID of the contact to retrieve'),
|
|
});
|
|
|
|
const SearchContactsInput = z.object({
|
|
q_keywords: z.string().optional().describe('Keywords to search in contact name, email, title, or company'),
|
|
person_titles: z.array(z.string()).optional().describe('Filter by job titles (e.g., ["CEO", "CTO", "VP Sales"])'),
|
|
organization_locations: z.array(z.string()).optional().describe('Filter by organization location (city, state, or country)'),
|
|
organization_num_employees_ranges: z.array(z.string()).optional().describe('Filter by employee count ranges (e.g., ["1,10", "11,50", "51,200"])'),
|
|
contact_stage_ids: z.array(z.string()).optional().describe('Filter by contact stage IDs'),
|
|
label_ids: z.array(z.string()).optional().describe('Filter by label IDs'),
|
|
page: z.number().min(1).default(1).describe('Page number (starts at 1)'),
|
|
per_page: z.number().min(1).max(100).default(25).describe('Results per page (max 100)'),
|
|
});
|
|
|
|
const CreateContactInput = z.object({
|
|
first_name: z.string().describe('First name of the contact'),
|
|
last_name: z.string().describe('Last name of the contact'),
|
|
email: z.string().email().optional().describe('Email address'),
|
|
title: z.string().optional().describe('Job title'),
|
|
organization_name: z.string().optional().describe('Company/organization name'),
|
|
phone_numbers: z.array(z.object({ raw_number: z.string() })).optional().describe('Array of phone number objects'),
|
|
linkedin_url: z.string().url().optional().describe('LinkedIn profile URL'),
|
|
city: z.string().optional().describe('City'),
|
|
state: z.string().optional().describe('State or province'),
|
|
country: z.string().optional().describe('Country'),
|
|
label_ids: z.array(z.string()).optional().describe('Array of label IDs to assign'),
|
|
});
|
|
|
|
const UpdateContactInput = z.object({
|
|
id: z.string().describe('The unique ID of the contact to update'),
|
|
first_name: z.string().optional().describe('Updated first name'),
|
|
last_name: z.string().optional().describe('Updated last name'),
|
|
email: z.string().email().optional().describe('Updated email address'),
|
|
title: z.string().optional().describe('Updated job title'),
|
|
organization_name: z.string().optional().describe('Updated company/organization name'),
|
|
contact_stage_id: z.string().optional().describe('Updated contact stage ID'),
|
|
label_ids: z.array(z.string()).optional().describe('Updated array of label IDs (replaces existing)'),
|
|
});
|
|
|
|
const DeleteContactInput = z.object({
|
|
id: z.string().describe('The unique ID of the contact to delete'),
|
|
});
|
|
|
|
const EnrichContactInput = z.object({
|
|
id: z.string().describe('The contact ID to enrich with additional data from Apollo database'),
|
|
});
|
|
|
|
const ListAccountContactsInput = z.object({
|
|
account_id: z.string().describe('The account/organization ID to list contacts for'),
|
|
page: z.number().min(1).default(1).describe('Page number for pagination'),
|
|
per_page: z.number().min(1).max(100).default(25).describe('Number of contacts per page (max 100)'),
|
|
q_keywords: z.string().optional().describe('Keywords to filter contacts'),
|
|
contact_stage_ids: z.array(z.string()).optional().describe('Filter by contact stage IDs'),
|
|
});
|
|
|
|
export default [
|
|
{
|
|
name: 'apollo_list_contacts',
|
|
description: 'Lists contacts from Apollo.io with pagination support. Use when the user wants to browse their contact database, export contacts, or get an overview of contacts. Returns paginated results with cursor-based navigation. Supports filtering by stage, labels, or owner. Each page can contain up to 100 contacts.',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
page: {
|
|
type: 'number',
|
|
description: 'Page number to retrieve (starts at 1)',
|
|
default: 1,
|
|
},
|
|
per_page: {
|
|
type: 'number',
|
|
description: 'Number of contacts per page (max 100)',
|
|
default: 25,
|
|
},
|
|
contact_stage_ids: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Filter by contact stage IDs',
|
|
},
|
|
label_ids: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Filter by label IDs',
|
|
},
|
|
owner_id: {
|
|
type: 'string',
|
|
description: 'Filter by contact owner user ID',
|
|
},
|
|
},
|
|
},
|
|
handler: async (input: unknown, client: ApolloClient) => {
|
|
const validated = ListContactsInput.parse(input);
|
|
const result = await client.get('/contacts', validated);
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'apollo_get_contact',
|
|
description: 'Retrieves a single contact by ID from Apollo.io. Use when the user asks for detailed information about a specific contact, including all custom fields, phone numbers, social profiles, and associated organization. Returns complete contact record with all available fields.',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
id: {
|
|
type: 'string',
|
|
description: 'The unique ID of the contact to retrieve',
|
|
},
|
|
},
|
|
required: ['id'],
|
|
},
|
|
handler: async (input: unknown, client: ApolloClient) => {
|
|
const validated = GetContactInput.parse(input);
|
|
const result = await client.get(`/contacts/${validated.id}`);
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'apollo_search_contacts',
|
|
description: 'Searches for contacts in Apollo.io using advanced filters including keywords, titles, locations, company attributes, and more. Use when the user wants to find contacts matching specific criteria (e.g., "find all CTOs in San Francisco at Series A startups"). Supports complex boolean queries and returns paginated results with up to 100 matches per page. More powerful than list_contacts for targeted prospecting.',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
q_keywords: {
|
|
type: 'string',
|
|
description: 'Keywords to search in contact name, email, title, or company',
|
|
},
|
|
person_titles: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Filter by job titles (e.g., ["CEO", "CTO", "VP Sales"])',
|
|
},
|
|
organization_locations: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Filter by organization location (city, state, or country)',
|
|
},
|
|
organization_num_employees_ranges: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Filter by employee count ranges (e.g., ["1,10", "11,50", "51,200"])',
|
|
},
|
|
contact_stage_ids: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Filter by contact stage IDs',
|
|
},
|
|
label_ids: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Filter by label IDs',
|
|
},
|
|
page: {
|
|
type: 'number',
|
|
description: 'Page number (starts at 1)',
|
|
default: 1,
|
|
},
|
|
per_page: {
|
|
type: 'number',
|
|
description: 'Results per page (max 100)',
|
|
default: 25,
|
|
},
|
|
},
|
|
},
|
|
handler: async (input: unknown, client: ApolloClient) => {
|
|
const validated = SearchContactsInput.parse(input);
|
|
const result = await client.post('/contacts/search', validated);
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'apollo_create_contact',
|
|
description: 'Creates a new contact in Apollo.io. Use when the user wants to add a new person to their database, such as after meeting someone at an event or discovering a new prospect. Accepts contact details including name, email, title, organization, phone numbers, and custom fields. Returns the newly created contact with assigned ID.',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
first_name: {
|
|
type: 'string',
|
|
description: 'First name of the contact',
|
|
},
|
|
last_name: {
|
|
type: 'string',
|
|
description: 'Last name of the contact',
|
|
},
|
|
email: {
|
|
type: 'string',
|
|
description: 'Email address',
|
|
},
|
|
title: {
|
|
type: 'string',
|
|
description: 'Job title',
|
|
},
|
|
organization_name: {
|
|
type: 'string',
|
|
description: 'Company/organization name',
|
|
},
|
|
phone_numbers: {
|
|
type: 'array',
|
|
items: {
|
|
type: 'object',
|
|
properties: {
|
|
raw_number: { type: 'string' },
|
|
},
|
|
},
|
|
description: 'Array of phone number objects',
|
|
},
|
|
linkedin_url: {
|
|
type: 'string',
|
|
description: 'LinkedIn profile URL',
|
|
},
|
|
city: {
|
|
type: 'string',
|
|
description: 'City',
|
|
},
|
|
state: {
|
|
type: 'string',
|
|
description: 'State or province',
|
|
},
|
|
country: {
|
|
type: 'string',
|
|
description: 'Country',
|
|
},
|
|
label_ids: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Array of label IDs to assign',
|
|
},
|
|
},
|
|
required: ['first_name', 'last_name'],
|
|
},
|
|
handler: async (input: unknown, client: ApolloClient) => {
|
|
const validated = CreateContactInput.parse(input);
|
|
const result = await client.post('/contacts', validated);
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'apollo_update_contact',
|
|
description: 'Updates an existing contact in Apollo.io. Use when the user needs to modify contact information such as changing a job title after a promotion, updating contact details, adding labels, or moving a contact to a different stage. Only specified fields will be updated; others remain unchanged. Returns the updated contact record.',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
id: {
|
|
type: 'string',
|
|
description: 'The unique ID of the contact to update',
|
|
},
|
|
first_name: {
|
|
type: 'string',
|
|
description: 'Updated first name',
|
|
},
|
|
last_name: {
|
|
type: 'string',
|
|
description: 'Updated last name',
|
|
},
|
|
email: {
|
|
type: 'string',
|
|
description: 'Updated email address',
|
|
},
|
|
title: {
|
|
type: 'string',
|
|
description: 'Updated job title',
|
|
},
|
|
organization_name: {
|
|
type: 'string',
|
|
description: 'Updated company/organization name',
|
|
},
|
|
contact_stage_id: {
|
|
type: 'string',
|
|
description: 'Updated contact stage ID',
|
|
},
|
|
label_ids: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Updated array of label IDs (replaces existing)',
|
|
},
|
|
},
|
|
required: ['id'],
|
|
},
|
|
handler: async (input: unknown, client: ApolloClient) => {
|
|
const validated = UpdateContactInput.parse(input);
|
|
const { id, ...updateData } = validated;
|
|
const result = await client.put(`/contacts/${id}`, updateData);
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'apollo_delete_contact',
|
|
description: 'Permanently deletes a contact from Apollo.io. Use with caution when the user explicitly wants to remove a contact from the database (e.g., at their request, duplicate cleanup, or GDPR compliance). This action cannot be undone. Returns confirmation of deletion.',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
id: {
|
|
type: 'string',
|
|
description: 'The unique ID of the contact to delete',
|
|
},
|
|
},
|
|
required: ['id'],
|
|
},
|
|
handler: async (input: unknown, client: ApolloClient) => {
|
|
const validated = DeleteContactInput.parse(input);
|
|
const result = await client.delete(`/contacts/${validated.id}`);
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify({ success: true, message: 'Contact deleted successfully' }, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'apollo_enrich_contact',
|
|
description: 'Enriches an existing contact with additional data from Apollo.io database including verified emails, phone numbers, social profiles, and employment history. Use when you have a contact in your database but need more complete information. Returns the enriched contact record with all newly discovered fields.',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
id: {
|
|
type: 'string',
|
|
description: 'The contact ID to enrich with additional data from Apollo database',
|
|
},
|
|
},
|
|
required: ['id'],
|
|
},
|
|
handler: async (input: unknown, client: ApolloClient) => {
|
|
const validated = EnrichContactInput.parse(input);
|
|
const result = await client.post(`/contacts/${validated.id}/enrich`, {});
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
{
|
|
name: 'apollo_list_account_contacts',
|
|
description: 'Lists all contacts associated with a specific account/organization in Apollo.io. Use when the user wants to see all people from a particular company, build an org chart, or identify decision makers within a target account. Returns paginated results with contact details and roles. Supports filtering by keywords and contact stages.',
|
|
inputSchema: {
|
|
type: 'object' as const,
|
|
properties: {
|
|
account_id: {
|
|
type: 'string',
|
|
description: 'The account/organization ID to list contacts for',
|
|
},
|
|
page: {
|
|
type: 'number',
|
|
description: 'Page number for pagination',
|
|
default: 1,
|
|
},
|
|
per_page: {
|
|
type: 'number',
|
|
description: 'Number of contacts per page (max 100)',
|
|
default: 25,
|
|
},
|
|
q_keywords: {
|
|
type: 'string',
|
|
description: 'Keywords to filter contacts',
|
|
},
|
|
contact_stage_ids: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Filter by contact stage IDs',
|
|
},
|
|
},
|
|
required: ['account_id'],
|
|
},
|
|
handler: async (input: unknown, client: ApolloClient) => {
|
|
const validated = ListAccountContactsInput.parse(input);
|
|
const { account_id, ...params } = validated;
|
|
const result = await client.get(`/accounts/${account_id}/contacts`, params);
|
|
return {
|
|
content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
|
|
};
|
|
},
|
|
},
|
|
];
|