#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, Tool } from '@modelcontextprotocol/sdk/types.js'; import { HubSpotClient } from './hubspot-client.js'; import { MCPTokenManager, TokenData } from './token-manager.js'; import { AuthClient } from './auth-client.js'; import dotenv from 'dotenv'; import { parseArgs } from 'node:util'; // Load environment variables dotenv.config(); // Parse command line arguments const { values } = parseArgs({ options: { 'access-token': { type: 'string' }, 'api-key': { type: 'string' } } }); // Initialize authentication - support both custom API keys and direct tokens const customApiKey = values['api-key'] || process.env.MORPHED_MCP_API_KEY; const directToken = values['access-token'] || process.env.HUBSPOT_ACCESS_TOKEN || process.env.HUBSPOT_DEVELOPER_API_KEY || process.env.HUBSPOT_PERSONAL_ACCESS_KEY; let accessToken: string | null = null; if (customApiKey) { console.log('Using custom MCP API key authentication'); // We'll fetch the OAuth token using the API key } else if (directToken) { console.log('Using direct OAuth token authentication'); accessToken = directToken; } else { console.warn('Warning: No authentication method found. Supported options:'); console.warn('- MORPHED_MCP_API_KEY (custom API key)'); console.warn('- HUBSPOT_ACCESS_TOKEN (direct OAuth token)'); console.warn('- HUBSPOT_DEVELOPER_API_KEY (direct token)'); console.warn('- HUBSPOT_PERSONAL_ACCESS_KEY (direct token)'); throw new Error('Authentication is required'); } class HubSpotServer { // Core server properties private server: Server; private hubspot: HubSpotClient | null = null; private authClient: AuthClient | null = null; constructor() { this.server = new Server( { name: 'hubspot-manager', version: '0.1.0', }, { capabilities: { resources: {}, tools: {}, }, } ); this.setupToolHandlers(); this.setupErrorHandling(); } async initialize(): Promise { let finalAccessToken: string; if (customApiKey) { // Use custom API key authentication this.authClient = new AuthClient(customApiKey); finalAccessToken = await this.authClient.getOAuthToken(); console.log('Successfully authenticated with custom MCP API key'); } else if (directToken) { // Use direct OAuth token finalAccessToken = directToken; console.log('Using direct OAuth token authentication'); } else { throw new Error('No authentication method available'); } this.hubspot = new HubSpotClient(finalAccessToken); } private setupErrorHandling(): void { this.server.onerror = (error) => { console.error('[MCP Error]', error); }; process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); process.on('uncaughtException', (error) => { console.error('Uncaught exception:', error); }); process.on('unhandledRejection', (reason, promise) => { console.error('Unhandled rejection at:', promise, 'reason:', reason); }); } private setupToolHandlers(): void { this.server.setRequestHandler(ListToolsRequestSchema, async () => { // Define available tools const tools: Tool[] = [ { name: 'hubspot_create_contact', description: 'Create a new contact in HubSpot', inputSchema: { type: 'object', properties: { firstname: { type: 'string', description: "Contact's first name" }, lastname: { type: 'string', description: "Contact's last name" }, email: { type: 'string', description: "Contact's email address" }, properties: { type: 'object', description: 'Additional contact properties', additionalProperties: true } }, required: ['firstname', 'lastname'] } }, { name: 'hubspot_create_company', description: 'Create a new company in HubSpot', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Company name' }, properties: { type: 'object', description: 'Additional company properties', additionalProperties: true } }, required: ['name'] } }, { name: 'hubspot_create_note', description: 'Create a new note in HubSpot with optional associations', inputSchema: { type: 'object', properties: { body: { type: 'string', description: 'Note content/body text' }, associations: { type: 'array', description: 'Optional associations to link the note to contacts, companies, deals, or tickets', items: { type: 'object', properties: { toObjectType: { type: 'string', description: 'Target object type (contacts, companies, deals, tickets)', enum: ['contacts', 'companies', 'deals', 'tickets'] }, toObjectId: { type: 'string', description: 'ID of the target object to associate with' }, category: { type: 'string', description: 'Association category', default: 'USER_DEFINED' }, typeId: { type: 'number', description: 'Association type ID', default: 1 } }, required: ['toObjectType', 'toObjectId'] } } }, required: ['body'] } }, { name: 'hubspot_get_company_activity', description: 'Get activity history for a specific company', inputSchema: { type: 'object', properties: { companyId: { type: 'string', description: 'HubSpot company ID' } }, required: ['companyId'] } }, { name: 'hubspot_search_tasks', description: 'Search for tasks using CRM v3 API with time filtering', inputSchema: { type: 'object', properties: { minutes: { type: 'number', description: 'Number of minutes to look back (default: 30)', default: 30 }, limit: { type: 'number', description: 'Maximum number of tasks to return (default: 50)', default: 50 } } } }, { name: 'hubspot_search_notes', description: 'Search for notes using CRM v3 API with time filtering', inputSchema: { type: 'object', properties: { minutes: { type: 'number', description: 'Number of minutes to look back (default: 30)', default: 30 }, limit: { type: 'number', description: 'Maximum number of notes to return (default: 50)', default: 50 } } } }, { name: 'hubspot_get_recent_engagements', description: 'Get recent engagement activities across all contacts and companies', inputSchema: { type: 'object', properties: { minutes: { type: 'number', description: 'Number of minutes to look back (default: 30)', default: 30 }, limit: { type: 'number', description: 'Maximum number of engagements to return (default: 50)', default: 50 } } } }, { name: 'hubspot_get_active_companies', description: 'Get most recently active companies from HubSpot', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of companies to return (default: 10)', default: 10 }, updatedAfter: { type: 'string', description: 'Optional ISO timestamp to fetch companies updated after this time' } } } }, { name: 'hubspot_get_active_contacts', description: 'Get most recently active contacts from HubSpot', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of contacts to return (default: 10)', default: 10 }, updatedAfter: { type: 'string', description: 'Optional ISO timestamp to fetch contacts updated after this time' } } } }, { name: 'hubspot_get_deals', description: 'Get deals from HubSpot', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of deals to return (default: 100)', default: 100 }, updatedAfter: { type: 'string', description: 'Optional ISO timestamp to fetch deals updated after this time' } } } }, { name: 'hubspot_get_current_user', description: 'Get current user information from HubSpot', inputSchema: { type: 'object', properties: {} } }, { name: 'hubspot_get_tickets', description: 'Get tickets from HubSpot', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of tickets to return (default: 100)', default: 100 } } } }, { name: 'hubspot_get_orders', description: 'Get orders from HubSpot', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of orders to return (default: 100)', default: 100 } } } }, { name: 'hubspot_get_engagement_associations', description: 'Get associations for a specific engagement (note, task, email, etc.) to see which companies, contacts, deals it was created under', inputSchema: { type: 'object', properties: { engagement_id: { type: 'string', description: 'HubSpot engagement ID to get associations for' } }, required: ['engagement_id'] } }, { name: 'hubspot_update_contact', description: 'Update an existing contact in HubSpot (ignores if contact does not exist)', inputSchema: { type: 'object', properties: { contact_id: { type: 'string', description: 'HubSpot contact ID to update' }, properties: { type: 'object', description: 'Contact properties to update', additionalProperties: true } }, required: ['contact_id', 'properties'] } }, { name: 'hubspot_update_company', description: 'Update an existing company in HubSpot (ignores if company does not exist)', inputSchema: { type: 'object', properties: { company_id: { type: 'string', description: 'HubSpot company ID to update' }, properties: { type: 'object', description: 'Company properties to update', additionalProperties: true } }, required: ['company_id', 'properties'] } }, { name: 'hubspot_get_contact_by_id', description: 'Get a specific contact by ID', inputSchema: { type: 'object', properties: { contact_id: { type: 'string', description: 'HubSpot contact ID' } }, required: ['contact_id'] } }, { name: 'hubspot_get_company_by_id', description: 'Get a specific company by ID', inputSchema: { type: 'object', properties: { company_id: { type: 'string', description: 'HubSpot company ID' } }, required: ['company_id'] } }, { name: 'hubspot_get_deal_by_id', description: 'Get a specific deal by ID', inputSchema: { type: 'object', properties: { deal_id: { type: 'string', description: 'HubSpot deal ID' } }, required: ['deal_id'] } }, { name: 'hubspot_get_ticket_by_id', description: 'Get a specific ticket by ID', inputSchema: { type: 'object', properties: { ticket_id: { type: 'string', description: 'HubSpot ticket ID' } }, required: ['ticket_id'] } }, { name: 'hubspot_get_engagement_by_id', description: 'Get a specific engagement by ID', inputSchema: { type: 'object', properties: { engagement_id: { type: 'string', description: 'HubSpot engagement ID' } }, required: ['engagement_id'] } }, { name: "hubspot_refresh_token", description: "Refresh HubSpot OAuth access token using refresh token", inputSchema: { type: "object", properties: { portal_id: { type: "string", description: "HubSpot portal ID" }, refresh_token: { type: "string", description: "Current refresh token" }, current_access_token: { type: "string", description: "Current access token for validation" } }, required: ["portal_id", "refresh_token", "current_access_token"] } }, { name: "hubspot_validate_token", description: "Validate HubSpot access token and get expiration info", inputSchema: { type: "object", properties: { access_token: { type: "string", description: "Access token to validate" } }, required: ["access_token"] } }, { name: "hubspot_token_health", description: "Check token health status and refresh requirements", inputSchema: { type: "object", properties: { portal_id: { type: "string", description: "HubSpot portal ID" }, access_token: { type: "string", description: "Current access token" }, expires_at: { type: "string", description: "Token expiration timestamp (ISO string or timestamp)" } }, required: ["portal_id", "access_token", "expires_at"] } }, // Marketing Hub Tools { name: "hubspot_get_forms", description: "Get marketing forms and their fields", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of forms to retrieve", default: 100 } } } }, { name: "hubspot_get_form_submissions", description: "Get form submissions for a specific form", inputSchema: { type: "object", properties: { form_id: { type: "string", description: "Form ID", required: true }, limit: { type: "number", description: "Number of submissions to retrieve", default: 100 } }, required: ["form_id"] } }, { name: "hubspot_get_marketing_emails", description: "Get marketing emails and their performance", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of emails to retrieve", default: 100 } } } }, { name: "hubspot_get_email_events", description: "Get email event metrics (opens, clicks, bounces)", inputSchema: { type: "object", properties: { email_id: { type: "string", description: "Email ID" }, event_type: { type: "string", description: "Event type (OPEN, CLICK, DELIVERED, etc.)" }, limit: { type: "number", description: "Number of events to retrieve", default: 1000 } } } }, { name: "hubspot_get_campaigns", description: "Get marketing campaigns and their performance", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of campaigns to retrieve", default: 100 } } } }, { name: "hubspot_get_analytics", description: "Get website analytics data", inputSchema: { type: "object", properties: { start_date: { type: "string", description: "Start date (YYYY-MM-DD)" }, end_date: { type: "string", description: "End date (YYYY-MM-DD)" }, metrics: { type: "array", description: "Metrics to retrieve", items: { type: "string" } } } } }, { name: "hubspot_get_blog_posts", description: "Get blog posts and their performance", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of blog posts to retrieve", default: 100 } } } }, { name: "hubspot_get_landing_pages", description: "Get landing pages and their performance", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of pages to retrieve", default: 100 } } } }, // Sales Hub Tools { name: "hubspot_get_pipelines", description: "Get deal pipelines and their stages", inputSchema: { type: "object", properties: { object_type: { type: "string", description: "Object type (deals, tickets)", default: "deals" } } } }, { name: "hubspot_get_properties", description: "Get property definitions for objects", inputSchema: { type: "object", properties: { object_type: { type: "string", description: "Object type (contacts, companies, deals, tickets)", required: true } }, required: ["object_type"] } }, { name: "hubspot_get_quotes", description: "Get quotes linked to deals", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of quotes to retrieve", default: 100 } } } }, { name: "hubspot_get_users", description: "Get users, owners, and teams", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of users to retrieve", default: 100 } } } }, // Service Hub Tools { name: "hubspot_get_conversations", description: "Get conversations (live chat and email)", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of conversations to retrieve", default: 100 } } } }, { name: "hubspot_get_knowledge_base", description: "Get knowledge base articles", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of articles to retrieve", default: 100 } } } }, // Operations Hub Tools { name: "hubspot_get_custom_objects", description: "Get custom objects and their records", inputSchema: { type: "object", properties: { object_type: { type: "string", description: "Custom object type", required: true }, limit: { type: "number", description: "Number of records to retrieve", default: 100 } }, required: ["object_type"] } }, { name: "hubspot_get_associations", description: "Get associations between objects", inputSchema: { type: "object", properties: { from_object_type: { type: "string", description: "Source object type", required: true }, to_object_type: { type: "string", description: "Target object type", required: true }, object_id: { type: "string", description: "Object ID to get associations for", required: true } }, required: ["from_object_type", "to_object_type", "object_id"] } }, // CMS Hub Tools { name: "hubspot_get_site_pages", description: "Get website pages and their metadata", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of pages to retrieve", default: 100 } } } }, { name: "hubspot_get_files", description: "Get media files (images, documents, etc.)", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of files to retrieve", default: 100 } } } }, { name: "hubspot_get_hubdb_tables", description: "Get HubDB tables and their data", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of tables to retrieve", default: 100 } } } }, // Commerce Hub Tools { name: "hubspot_get_products", description: "Get product catalog with SKU, pricing, descriptions", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of products to retrieve", default: 100 } } } }, { name: "hubspot_get_line_items", description: "Get line items tied to deals/orders", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of line items to retrieve", default: 100 } } } }, // Enterprise Tools { name: "hubspot_search_objects", description: "Search across all CRM objects", inputSchema: { type: "object", properties: { object_type: { type: "string", description: "Object type to search", required: true }, query: { type: "string", description: "Search query", required: true }, limit: { type: "number", description: "Number of results to retrieve", default: 100 } }, required: ["object_type", "query"] } }, { name: "hubspot_get_lists", description: "Get contact lists from HubSpot", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of lists to retrieve", default: 50 } } } }, { name: "hubspot_get_workflows", description: "Get automation workflows from HubSpot", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of workflows to retrieve", default: 50 } } } }, { name: "hubspot_get_domains", description: "Get website domains from HubSpot", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of domains to retrieve", default: 10 } } } } ]; return { tools }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { try { if (!this.hubspot) { throw new Error('HubSpot client not initialized. Server must be initialized first.'); } const args = request.params.arguments ?? {}; switch (request.params.name) { case 'hubspot_create_contact': { const result = await this.hubspot.createContact( args.firstname as string, args.lastname as string, args.email as string | undefined, args.properties as Record | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_create_company': { const result = await this.hubspot.createCompany( args.name as string, args.properties as Record | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_create_note': { const result = await this.hubspot.createNote( args.body as string, args.associations as any[] | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_active_companies': { const result = await this.hubspot.getRecentCompanies( args.limit as number | undefined, args.updatedAfter as string | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_active_contacts': { const result = await this.hubspot.getRecentContacts( args.limit as number | undefined, args.updatedAfter as string | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_deals': { const result = await this.hubspot.getRecentDeals( args.limit as number | undefined, args.updatedAfter as string | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_current_user': { const result = await this.hubspot.getCurrentUser(); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_tickets': { const result = await this.hubspot.getRecentTickets(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_orders': { const result = await this.hubspot.getRecentOrders(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_update_contact': { const result = await this.hubspot.updateContact( args.contact_id as string, args.properties as Record ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_update_company': { const result = await this.hubspot.updateCompany( args.company_id as string, args.properties as Record ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_contact_by_id': { const result = await this.hubspot.getContactById(args.contact_id as string); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_company_by_id': { const result = await this.hubspot.getCompanyById(args.company_id as string); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_deal_by_id': { const result = await this.hubspot.getDealById(args.deal_id as string); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_ticket_by_id': { const result = await this.hubspot.getTicketById(args.ticket_id as string); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_refresh_token': { const tokenManager = new MCPTokenManager(args.current_access_token as string); const tokenData: TokenData = { portalId: args.portal_id as string, accessToken: args.current_access_token as string, refreshToken: args.refresh_token as string, expiresAt: Date.now() + (30 * 60 * 1000) // Assume 30 minutes if not provided }; const result = await tokenManager.refreshToken(tokenData); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_validate_token': { const tokenManager = new MCPTokenManager(args.access_token as string); const result = await tokenManager.validateToken(args.access_token as string); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_token_health': { const tokenManager = new MCPTokenManager(args.access_token as string); const tokenData: TokenData = { portalId: args.portal_id as string, accessToken: args.access_token as string, refreshToken: '', // Not needed for health check expiresAt: typeof args.expires_at === 'string' ? (args.expires_at.includes('T') ? new Date(args.expires_at).getTime() : parseInt(args.expires_at)) : args.expires_at as number }; const result = tokenManager.getTokenHealth(tokenData); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } // Marketing Hub Tools case 'hubspot_get_forms': { const result = await this.hubspot.getForms(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_form_submissions': { const result = await this.hubspot.getFormSubmissions( args.form_id as string, args.limit as number | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_marketing_emails': { const result = await this.hubspot.getMarketingEmails(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_email_events': { const result = await this.hubspot.getEmailEvents( args.limit as number | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_campaigns': { const result = await this.hubspot.getCampaigns(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_analytics': { const result = await this.hubspot.getAnalytics( args.start_date as string, args.end_date as string ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_blog_posts': { const result = await this.hubspot.getBlogPosts(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_landing_pages': { const result = await this.hubspot.getLandingPages(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } // Sales Hub Tools case 'hubspot_get_pipelines': { const result = await this.hubspot.getPipelines(args.object_type as string | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_properties': { const result = await this.hubspot.getProperties(args.object_type as string); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_quotes': { const result = await this.hubspot.getQuotes(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_users': { const result = await this.hubspot.getUsers(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } // Service Hub Tools case 'hubspot_get_conversations': { const result = await this.hubspot.getConversations(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_knowledge_base': { const result = await this.hubspot.getKnowledgeBase(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } // Operations Hub Tools case 'hubspot_get_custom_objects': { const result = await this.hubspot.getCustomObjects( args.object_type as string, args.limit as number | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_associations': { const result = await this.hubspot.getAssociations( args.from_object_type as string, args.to_object_type as string, args.object_id as string ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } // CMS Hub Tools case 'hubspot_get_site_pages': { const result = await this.hubspot.getSitePages(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_files': { const result = await this.hubspot.getFiles(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_hubdb_tables': { const result = await this.hubspot.getHubDbTables(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } // Commerce Hub Tools case 'hubspot_get_products': { const result = await this.hubspot.getProducts(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_line_items': { const result = await this.hubspot.getLineItems(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } // Enterprise Tools case 'hubspot_search_objects': { const result = await this.hubspot.searchObjects( args.object_type as string, args.query as string, args.limit as number | undefined ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_lists': { const result = await this.hubspot.getLists(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_workflows': { const result = await this.hubspot.getWorkflows(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } case 'hubspot_get_domains': { const result = await this.hubspot.getDomains(args.limit as number | undefined); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } default: throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}` ); } } catch (error: any) { console.error(`Error executing tool ${request.params.name}:`, error); return { content: [{ type: 'text', text: `HubSpot API error: ${error.message}` }], isError: true, }; } }); } async run(): Promise { await this.initialize(); const transport = new StdioServerTransport(); await this.server.connect(transport); console.log('HubSpot MCP server started'); } } export async function serve(): Promise { const client = new HubSpotServer(); await client.run(); } const server = new HubSpotServer(); server.run().catch(console.error);