#!/usr/bin/env node /** * Apollo.io MCP Server * Provides tools for interacting with the Apollo.io sales engagement platform */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js'; import { ApolloClient } from './client/apollo-client.js'; // Import all tool definitions import { listContactsTool, getContactTool, searchContactsTool, createContactTool, updateContactTool, deleteContactTool, } from './tools/contacts.js'; import { listAccountsTool, getAccountTool, searchAccountsTool, createAccountTool, updateAccountTool, } from './tools/accounts.js'; import { listSequencesTool, getSequenceTool, createSequenceTool, addContactsToSequenceTool, removeContactsFromSequenceTool, } from './tools/sequences.js'; import { sendEmailTool, listEmailAccountsTool, listEmailThreadsTool, getEmailThreadTool, } from './tools/emails.js'; import { listTasksTool, createTaskTool, updateTaskTool, } from './tools/tasks.js'; import { listOpportunitiesTool, createOpportunityTool, updateOpportunityTool, } from './tools/opportunities.js'; // Collect all tools const ALL_TOOLS = [ // Contacts (6 tools) listContactsTool, getContactTool, searchContactsTool, createContactTool, updateContactTool, deleteContactTool, // Accounts (5 tools) listAccountsTool, getAccountTool, searchAccountsTool, createAccountTool, updateAccountTool, // Sequences (5 tools) listSequencesTool, getSequenceTool, createSequenceTool, addContactsToSequenceTool, removeContactsFromSequenceTool, // Emails (4 tools) sendEmailTool, listEmailAccountsTool, listEmailThreadsTool, getEmailThreadTool, // Tasks (3 tools) listTasksTool, createTaskTool, updateTaskTool, // Opportunities (3 tools) listOpportunitiesTool, createOpportunityTool, updateOpportunityTool, ]; // Initialize Apollo client const apiKey = process.env.APOLLO_API_KEY; if (!apiKey) { throw new Error('APOLLO_API_KEY environment variable is required'); } const apolloClient = new ApolloClient({ apiKey }); // Create MCP server const server = new Server( { name: 'apollo-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Register tool list handler server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: ALL_TOOLS, }; }); // Register tool call handler server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { // Contact tools case 'list_contacts': return await handleListContacts(args); case 'get_contact': return await handleGetContact(args); case 'search_contacts': return await handleSearchContacts(args); case 'create_contact': return await handleCreateContact(args); case 'update_contact': return await handleUpdateContact(args); case 'delete_contact': return await handleDeleteContact(args); // Account tools case 'list_accounts': return await handleListAccounts(args); case 'get_account': return await handleGetAccount(args); case 'search_accounts': return await handleSearchAccounts(args); case 'create_account': return await handleCreateAccount(args); case 'update_account': return await handleUpdateAccount(args); // Sequence tools case 'list_sequences': return await handleListSequences(args); case 'get_sequence': return await handleGetSequence(args); case 'create_sequence': return await handleCreateSequence(args); case 'add_contacts_to_sequence': return await handleAddContactsToSequence(args); case 'remove_contacts_from_sequence': return await handleRemoveContactsFromSequence(args); // Email tools case 'send_email': return await handleSendEmail(args); case 'list_email_accounts': return await handleListEmailAccounts(args); case 'list_email_threads': return await handleListEmailThreads(args); case 'get_email_thread': return await handleGetEmailThread(args); // Task tools case 'list_tasks': return await handleListTasks(args); case 'create_task': return await handleCreateTask(args); case 'update_task': return await handleUpdateTask(args); // Opportunity tools case 'list_opportunities': return await handleListOpportunities(args); case 'create_opportunity': return await handleCreateOpportunity(args); case 'update_opportunity': return await handleUpdateOpportunity(args); default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } } catch (error) { if (error instanceof McpError) throw error; throw new McpError( ErrorCode.InternalError, `Tool execution failed: ${error instanceof Error ? error.message : String(error)}` ); } }); // Tool implementation functions async function handleListContacts(args: any) { const result = await apolloClient.getPaginated('/contacts', args, args.page, args.per_page); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleGetContact(args: any) { const result = await apolloClient.get(`/contacts/${args.id}`); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleSearchContacts(args: any) { const result = await apolloClient.searchContacts(args, args.page, args.per_page); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleCreateContact(args: any) { const result = await apolloClient.post('/contacts', args); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleUpdateContact(args: any) { const { id, ...updateData } = args; const result = await apolloClient.patch(`/contacts/${id}`, updateData); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleDeleteContact(args: any) { const result = await apolloClient.delete(`/contacts/${args.id}`); return { content: [ { type: 'text', text: JSON.stringify({ success: true, id: args.id }, null, 2), }, ], }; } async function handleListAccounts(args: any) { const result = await apolloClient.getPaginated('/accounts', args, args.page, args.per_page); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleGetAccount(args: any) { const result = await apolloClient.get(`/accounts/${args.id}`); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleSearchAccounts(args: any) { const result = await apolloClient.searchAccounts(args, args.page, args.per_page); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleCreateAccount(args: any) { const result = await apolloClient.post('/accounts', args); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleUpdateAccount(args: any) { const { id, ...updateData } = args; const result = await apolloClient.patch(`/accounts/${id}`, updateData); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleListSequences(args: any) { const result = await apolloClient.getPaginated('/emailer_campaigns', args, args.page, args.per_page); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleGetSequence(args: any) { const result = await apolloClient.get(`/emailer_campaigns/${args.id}`); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleCreateSequence(args: any) { const result = await apolloClient.post('/emailer_campaigns', args); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleAddContactsToSequence(args: any) { const result = await apolloClient.post('/emailer_campaigns/add_contact_ids', args); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleRemoveContactsFromSequence(args: any) { const result = await apolloClient.post('/emailer_campaigns/remove_contact_ids', args); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleSendEmail(args: any) { const result = await apolloClient.post('/emailer_messages', args); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleListEmailAccounts(args: any) { const result = await apolloClient.get('/email_accounts'); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleListEmailThreads(args: any) { const result = await apolloClient.getPaginated('/emailer_threads', args, args.page, args.per_page); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleGetEmailThread(args: any) { const result = await apolloClient.get(`/emailer_threads/${args.id}`); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleListTasks(args: any) { const result = await apolloClient.getPaginated('/tasks', args, args.page, args.per_page); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleCreateTask(args: any) { const result = await apolloClient.post('/tasks', args); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleUpdateTask(args: any) { const { id, ...updateData } = args; const result = await apolloClient.patch(`/tasks/${id}`, updateData); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleListOpportunities(args: any) { const result = await apolloClient.getPaginated('/opportunities', args, args.page, args.per_page); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleCreateOpportunity(args: any) { const result = await apolloClient.post('/opportunities', args); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } async function handleUpdateOpportunity(args: any) { const { id, ...updateData } = args; const result = await apolloClient.patch(`/opportunities/${id}`, updateData); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } // Start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('Apollo MCP Server running on stdio'); } main().catch((error) => { console.error('Fatal error in main():', error); process.exit(1); });