UNPKG

@rockship/apollo-io-mcp

Version:

A powerful Model Context Protocol (MCP) server implementation for seamless Apollo.io API integration, enabling AI assistants to interact with Apollo.io data

243 lines 8.81 kB
import axios from "axios"; import dotenv from "dotenv"; import { contactSearchMappingResponse, organizationSearchMappingResponse, peopleSearchMappingResponse, } from "../../utils/mapping-response.js"; import { stripUrl } from "../../utils/url-helpers.js"; // Load environment variables dotenv.config(); export class ApolloClient { apiKey; baseUrl; headers; axiosInstance; constructor(apiKey) { this.apiKey = apiKey || process.env.APOLLO_IO_API_KEY || ""; if (!this.apiKey) { throw new Error("APOLLO_IO_API_KEY environment variable is required"); } this.baseUrl = "https://api.apollo.io/api/v1"; this.headers = { "Content-Type": "application/json", "Cache-Control": "no-cache", "x-api-key": this.apiKey, }; this.axiosInstance = this.getAxiosInstance({ baseUrl: this.baseUrl }); } getAxiosInstance({ baseUrl }) { return axios.create({ baseURL: baseUrl, headers: this.headers, }); } async request({ baseUrl = "", url = "", method = "post", data, query, }) { let response = null; try { // console.log("url", url); // console.log("query", query); const config = {}; if (query) { config.params = query; } if (method === "get" || method === "delete") { // For GET and DELETE, data (request body) should be passed in the config object response = baseUrl ? await this.getAxiosInstance({ baseUrl })[method](url, config) : await this.axiosInstance[method](url, config); } else { // For POST, PUT, PATCH, data is the second argument, and config is the third response = baseUrl ? await this.getAxiosInstance({ baseUrl })[method](url, data, config) : await this.axiosInstance[method](url, data, config); } if (response.status === 200) { return response.data; } else { // console.log(`Error: ${response.status} - ${response.statusText}`); return null; } } catch (error) { // console.log( // `Error: ${error.response ? error.response.status : "N/A"} - ${ // error.response // ? error.response.statusText || error.message // : error.message // }` // ); return null; } } /** * Use the Contact Search endpoint to find contacts. * https://docs.apollo.io/reference/contact-search */ async contactSearch(query) { const response = await this.request({ url: "/contacts/search", method: "post", query, }); return contactSearchMappingResponse(response); } /** * Use the People Enrichment endpoint to enrich data for 1 person. * https://docs.apollo.io/reference/people-enrichment */ async peopleEnrichment(query) { const response = await this.request({ url: "/people/match", method: "post", query, }); return response; } /** * Use the Organization Enrichment endpoint to enrich data for 1 company. * https://docs.apollo.io/reference/organization-enrichment */ async organizationEnrichment(query) { const response = await this.request({ url: "/organizations/enrich", method: "post", query, }); return response; } /** * Use the People Search endpoint to find people. * https://docs.apollo.io/reference/people-search */ async peopleSearch(query) { const response = await this.request({ url: "/mixed_people/search", method: "post", query, }); return peopleSearchMappingResponse(response); } /** * Use the Organization Search endpoint to find organizations. * https://docs.apollo.io/reference/organization-search */ async organizationSearch(query) { const response = await this.request({ url: "/mixed_companies/search", method: "post", query, }); return organizationSearchMappingResponse(response); } /** * Use the Organization Job Postings endpoint to find job postings for a specific organization. * https://docs.apollo.io/reference/organization-jobs-postings */ async organizationJobPostings(organizationId) { const response = await this.request({ url: `/organizations/${organizationId}/job_postings`, method: "get", }); return response; } /** * Get email address for a person using their Apollo ID */ async getPersonEmail(apolloId) { if (!apolloId) { throw new Error("Apollo ID is required"); } const payload = { entity_ids: [apolloId], analytics_context: "Searcher: Individual Add Button", skip_fetching_people: true, cta_name: "Access email", cacheKey: Date.now(), }; const response = await this.request({ baseUrl: "https://app.apollo.io/api/v1", url: "/mixed_people/add_to_my_prospects", method: "post", data: payload, }); const emails = ((response && response.contacts) || []).map((contact) => contact.email); return emails; } /** * Find employees of a company using company name or website/LinkedIn URL */ async employeesOfCompany(query) { const { company, website_url, linkedin_url } = query; if (!company) { throw new Error("Company name is required"); } const strippedWebsiteUrl = stripUrl(website_url); const strippedLinkedinUrl = stripUrl(linkedin_url); // First search for the company const companySearchPayload = { q_organization_name: company, page: 1, per_page: 100, }; const mixedCompaniesResponse = await this.request({ url: "/mixed_companies/search", method: "post", query: companySearchPayload, }); if (!mixedCompaniesResponse) { throw new Error("No data received from Apollo API"); } let organizations = mixedCompaniesResponse.organizations; if (organizations.length === 0) { throw new Error("No organizations found"); } // Filter companies by website or LinkedIn URL if provided const companyObjs = organizations.filter((item) => { const companyLinkedin = stripUrl(item.linkedin_url); const companyWebsite = stripUrl(item.website_url); if (strippedLinkedinUrl && companyLinkedin && companyLinkedin === strippedLinkedinUrl) { return true; } else if (strippedWebsiteUrl && companyWebsite && companyWebsite === strippedWebsiteUrl) { return true; } return false; }); // If we have filtered results, use the first one, otherwise use the first from the original search const companyObj = companyObjs.length > 0 ? companyObjs[0] : organizations[0]; const companyId = companyObj.id; if (!companyId) { throw new Error("Could not determine company ID"); } // Now search for employees const peopleSearchPayload = { organization_ids: [companyId], page: 1, per_page: 100, }; // Add optional filters if provided in the tool config if (query.person_seniorities) { peopleSearchPayload.person_titles = (query.person_seniorities || "") .split(",") .map((item) => item.trim()); } if (query.contact_email_status) { peopleSearchPayload.contact_email_status_v2 = (query.contact_email_status || "") .split(",") .map((item) => item.trim()); } const peopleResponse = await this.request({ url: "/mixed_people/search", method: "post", query: peopleSearchPayload, }); if (!peopleResponse) { throw new Error("No data received from Apollo API"); } return peopleSearchMappingResponse(peopleResponse); } } //# sourceMappingURL=apollo-client.js.map