@vineethnkrishnan/hubspot-mcp 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ export interface HubSpotConfig {
2
+ accessToken: string;
3
+ }
4
+ export interface McpToolResponse {
5
+ content: Array<{
6
+ type: string;
7
+ text: string;
8
+ }>;
9
+ isError?: boolean;
10
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import { McpToolResponse } from "./types";
2
+ /**
3
+ * Flattens HubSpot's nested properties object to top-level fields.
4
+ * Input: { id: "123", properties: { firstname: "John", lastname: "Doe" }, ... }
5
+ * Output: { id: "123", firstname: "John", lastname: "Doe" }
6
+ */
7
+ export declare function flattenProperties(record: unknown): unknown;
8
+ /**
9
+ * Removes HubSpot internal metadata keys that waste LLM tokens.
10
+ */
11
+ export declare function stripHubSpotMetadata(obj: unknown, keys?: string[]): unknown;
12
+ /**
13
+ * Simplifies HubSpot association responses from verbose objects to ID arrays.
14
+ * Input: { associations: { companies: { results: [{ id: "456", type: "contact_to_company" }] } } }
15
+ * Output: { associatedCompanyIds: ["456"] } merged into the record
16
+ */
17
+ export declare function simplifyAssociations(record: unknown): unknown;
18
+ /**
19
+ * Composes all HubSpot-specific transformations for LLM optimization.
20
+ */
21
+ export declare function transformHubSpotResponse(data: unknown): unknown;
22
+ /**
23
+ * Transforms HubSpot data and wraps it in the MCP tool response format.
24
+ */
25
+ export declare function formatMcpResponse(data: unknown): McpToolResponse;
26
+ /**
27
+ * Wraps an error in the MCP tool error response format.
28
+ */
29
+ export declare function formatMcpError(error: unknown): McpToolResponse;
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.flattenProperties = flattenProperties;
4
+ exports.stripHubSpotMetadata = stripHubSpotMetadata;
5
+ exports.simplifyAssociations = simplifyAssociations;
6
+ exports.transformHubSpotResponse = transformHubSpotResponse;
7
+ exports.formatMcpResponse = formatMcpResponse;
8
+ exports.formatMcpError = formatMcpError;
9
+ const HUBSPOT_STRIP_KEYS = [
10
+ "archived",
11
+ "archivedAt",
12
+ "propertiesWithHistory",
13
+ "properties_with_history",
14
+ "createdAt",
15
+ "updatedAt",
16
+ ];
17
+ /**
18
+ * Flattens HubSpot's nested properties object to top-level fields.
19
+ * Input: { id: "123", properties: { firstname: "John", lastname: "Doe" }, ... }
20
+ * Output: { id: "123", firstname: "John", lastname: "Doe" }
21
+ */
22
+ function flattenProperties(record) {
23
+ if (record === null || record === undefined)
24
+ return record;
25
+ if (Array.isArray(record))
26
+ return record.map(flattenProperties);
27
+ if (typeof record !== "object")
28
+ return record;
29
+ const obj = record;
30
+ if (!("properties" in obj) || typeof obj.properties !== "object" || obj.properties === null) {
31
+ return record;
32
+ }
33
+ const { properties, ...rest } = obj;
34
+ return { ...rest, ...properties };
35
+ }
36
+ /**
37
+ * Removes HubSpot internal metadata keys that waste LLM tokens.
38
+ */
39
+ function stripHubSpotMetadata(obj, keys = HUBSPOT_STRIP_KEYS) {
40
+ if (obj === null || obj === undefined)
41
+ return obj;
42
+ if (Array.isArray(obj))
43
+ return obj.map((item) => stripHubSpotMetadata(item, keys));
44
+ if (typeof obj !== "object")
45
+ return obj;
46
+ const result = {};
47
+ for (const [key, value] of Object.entries(obj)) {
48
+ if (keys.includes(key))
49
+ continue;
50
+ result[key] = stripHubSpotMetadata(value, keys);
51
+ }
52
+ return result;
53
+ }
54
+ /**
55
+ * Simplifies HubSpot association responses from verbose objects to ID arrays.
56
+ * Input: { associations: { companies: { results: [{ id: "456", type: "contact_to_company" }] } } }
57
+ * Output: { associatedCompanyIds: ["456"] } merged into the record
58
+ */
59
+ function simplifyAssociations(record) {
60
+ if (record === null || record === undefined)
61
+ return record;
62
+ if (Array.isArray(record))
63
+ return record.map(simplifyAssociations);
64
+ if (typeof record !== "object")
65
+ return record;
66
+ const obj = record;
67
+ if (!("associations" in obj) ||
68
+ typeof obj.associations !== "object" ||
69
+ obj.associations === null) {
70
+ return record;
71
+ }
72
+ const { associations, ...rest } = obj;
73
+ const simplified = {};
74
+ for (const [objectType, data] of Object.entries(associations)) {
75
+ if (data && typeof data === "object" && "results" in data) {
76
+ const results = data.results;
77
+ if (Array.isArray(results)) {
78
+ const capitalizedType = objectType.charAt(0).toUpperCase() + objectType.slice(1);
79
+ simplified[`associated${capitalizedType}Ids`] = results.map((r) => String(r.id));
80
+ }
81
+ }
82
+ }
83
+ return { ...rest, ...simplified };
84
+ }
85
+ /**
86
+ * Composes all HubSpot-specific transformations for LLM optimization.
87
+ */
88
+ function transformHubSpotResponse(data) {
89
+ let result = flattenProperties(data);
90
+ result = stripHubSpotMetadata(result);
91
+ result = simplifyAssociations(result);
92
+ return result;
93
+ }
94
+ /**
95
+ * Transforms HubSpot data and wraps it in the MCP tool response format.
96
+ */
97
+ function formatMcpResponse(data) {
98
+ const transformed = transformHubSpotResponse(data);
99
+ return {
100
+ content: [{ type: "text", text: JSON.stringify(transformed, null, 2) }],
101
+ };
102
+ }
103
+ /**
104
+ * Wraps an error in the MCP tool error response format.
105
+ */
106
+ function formatMcpError(error) {
107
+ const message = error instanceof Error ? error.message : String(error);
108
+ return {
109
+ content: [{ type: "text", text: `Error: ${message}` }],
110
+ isError: true,
111
+ };
112
+ }
113
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/common/utils.ts"],"names":[],"mappings":";;AAgBA,8CAYC;AAKD,oDAWC;AAOD,oDA8BC;AAKD,4DAKC;AAKD,8CAKC;AAKD,wCAMC;AA9GD,MAAM,kBAAkB,GAAG;IACzB,UAAU;IACV,YAAY;IACZ,uBAAuB;IACvB,yBAAyB;IACzB,WAAW;IACX,WAAW;CACZ,CAAC;AAEF;;;;GAIG;AACH,SAAgB,iBAAiB,CAAC,MAAe;IAC/C,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAChE,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAE9C,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,IAAI,CAAC,CAAC,YAAY,IAAI,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QAC5F,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC;IACpC,OAAO,EAAE,GAAG,IAAI,EAAE,GAAI,UAAsC,EAAE,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAAC,GAAY,EAAE,OAAiB,kBAAkB;IACpF,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IAClD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACnF,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IAExC,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC,EAAE,CAAC;QAC1E,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QACjC,MAAM,CAAC,GAAG,CAAC,GAAG,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAgB,oBAAoB,CAAC,MAAe;IAClD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACnE,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAE9C,MAAM,GAAG,GAAG,MAAiC,CAAC;IAC9C,IACE,CAAC,CAAC,cAAc,IAAI,GAAG,CAAC;QACxB,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ;QACpC,GAAG,CAAC,YAAY,KAAK,IAAI,EACzB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC;IACtC,MAAM,UAAU,GAA6B,EAAE,CAAC;IAEhD,KAAK,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAuC,CAAC,EAAE,CAAC;QACzF,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,SAAS,IAAK,IAAgC,EAAE,CAAC;YACvF,MAAM,OAAO,GAAI,IAAgC,CAAC,OAAO,CAAC;YAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3B,MAAM,eAAe,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBACjF,UAAU,CAAC,aAAa,eAAe,KAAK,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAA0B,EAAE,EAAE,CACzF,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CACb,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,UAAU,EAAE,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,SAAgB,wBAAwB,CAAC,IAAa;IACpD,IAAI,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACtC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,IAAa;IAC7C,MAAM,WAAW,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IACnD,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KACxE,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,KAAc;IAC3C,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;QACtD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/build/index.js ADDED
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ const zod_1 = require("zod");
8
+ const hubspot_service_1 = require("./services/hubspot.service");
9
+ const contact_tools_1 = require("./tools/contact.tools");
10
+ const deal_tools_1 = require("./tools/deal.tools");
11
+ const company_tools_1 = require("./tools/company.tools");
12
+ // Validate required config
13
+ const HUBSPOT_ACCESS_TOKEN = process.env.HUBSPOT_ACCESS_TOKEN;
14
+ if (!HUBSPOT_ACCESS_TOKEN) {
15
+ console.error("HUBSPOT_ACCESS_TOKEN environment variable is required.");
16
+ process.exit(1);
17
+ }
18
+ const hubspotService = new hubspot_service_1.HubSpotService({
19
+ accessToken: HUBSPOT_ACCESS_TOKEN,
20
+ });
21
+ // Initialize tool classes
22
+ const tools = {
23
+ contacts: new contact_tools_1.ContactTools(hubspotService),
24
+ deals: new deal_tools_1.DealTools(hubspotService),
25
+ companies: new company_tools_1.CompanyTools(hubspotService),
26
+ };
27
+ // Combine all schemas
28
+ const AllToolSchemas = {
29
+ ...contact_tools_1.ContactToolSchemas,
30
+ ...deal_tools_1.DealToolSchemas,
31
+ ...company_tools_1.CompanyToolSchemas,
32
+ };
33
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
34
+ const { version } = require("../package.json");
35
+ const server = new index_js_1.Server({
36
+ name: "hubspot-mcp",
37
+ version,
38
+ }, {
39
+ capabilities: {
40
+ tools: {},
41
+ },
42
+ });
43
+ /**
44
+ * Handler for listing available tools.
45
+ */
46
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
47
+ return {
48
+ tools: Object.entries(AllToolSchemas).map(([name, config]) => ({
49
+ name,
50
+ description: config.description,
51
+ inputSchema: zod_1.z.toJSONSchema(config.schema),
52
+ })),
53
+ };
54
+ });
55
+ const toolRegistry = {};
56
+ for (const name of Object.keys(contact_tools_1.ContactToolSchemas)) {
57
+ toolRegistry[name] = (args) => tools.contacts[name](args);
58
+ }
59
+ for (const name of Object.keys(deal_tools_1.DealToolSchemas)) {
60
+ toolRegistry[name] = (args) => tools.deals[name](args);
61
+ }
62
+ for (const name of Object.keys(company_tools_1.CompanyToolSchemas)) {
63
+ toolRegistry[name] = (args) => tools.companies[name](args);
64
+ }
65
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
66
+ try {
67
+ const { name, arguments: args } = request.params;
68
+ const handler = toolRegistry[name];
69
+ if (!handler) {
70
+ throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Tool not found: ${name}`);
71
+ }
72
+ return await handler(args ?? {});
73
+ }
74
+ catch (error) {
75
+ const message = error instanceof Error ? error.message : String(error);
76
+ return {
77
+ content: [{ type: "text", text: `Error: ${message}` }],
78
+ isError: true,
79
+ };
80
+ }
81
+ });
82
+ /**
83
+ * Start the server using Stdio transport.
84
+ */
85
+ async function main() {
86
+ const transport = new stdio_js_1.StdioServerTransport();
87
+ await server.connect(transport);
88
+ console.error("HubSpot MCP Server running on stdio");
89
+ }
90
+ main().catch((error) => {
91
+ console.error("Server error:", error);
92
+ process.exit(1);
93
+ });
94
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { HubSpotConfig } from "../common/types";
2
+ export declare class HubSpotService {
3
+ private baseUrl;
4
+ private accessToken;
5
+ constructor(config: HubSpotConfig);
6
+ private request;
7
+ private postRequest;
8
+ private handleErrorResponse;
9
+ listContacts(limit?: number, properties?: string[], after?: string): Promise<unknown>;
10
+ getContact(contactId: string, properties?: string[], associations?: string[]): Promise<unknown>;
11
+ searchContacts(query: string, properties?: string[], limit?: number): Promise<unknown>;
12
+ listDeals(limit?: number, properties?: string[], after?: string): Promise<unknown>;
13
+ getDeal(dealId: string, properties?: string[], associations?: string[]): Promise<unknown>;
14
+ listCompanies(limit?: number, properties?: string[], after?: string): Promise<unknown>;
15
+ getCompany(companyId: string, properties?: string[], associations?: string[]): Promise<unknown>;
16
+ }
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HubSpotService = void 0;
4
+ const DEFAULT_CONTACT_PROPERTIES = [
5
+ "firstname",
6
+ "lastname",
7
+ "email",
8
+ "phone",
9
+ "company",
10
+ "lifecyclestage",
11
+ "hs_lead_status",
12
+ ];
13
+ const DEFAULT_DEAL_PROPERTIES = [
14
+ "dealname",
15
+ "amount",
16
+ "dealstage",
17
+ "pipeline",
18
+ "closedate",
19
+ "hs_lastmodifieddate",
20
+ ];
21
+ const DEFAULT_COMPANY_PROPERTIES = [
22
+ "name",
23
+ "domain",
24
+ "industry",
25
+ "city",
26
+ "state",
27
+ "phone",
28
+ "numberofemployees",
29
+ ];
30
+ class HubSpotService {
31
+ baseUrl = "https://api.hubapi.com";
32
+ accessToken;
33
+ constructor(config) {
34
+ this.accessToken = config.accessToken;
35
+ }
36
+ // ===========================================================================
37
+ // HTTP methods
38
+ // ===========================================================================
39
+ async request(path, params) {
40
+ const url = new URL(`${this.baseUrl}${path}`);
41
+ if (params) {
42
+ for (const [key, value] of Object.entries(params)) {
43
+ if (value === undefined || value === null)
44
+ continue;
45
+ if (Array.isArray(value)) {
46
+ for (const item of value) {
47
+ url.searchParams.append(key, item);
48
+ }
49
+ }
50
+ else if (value !== "") {
51
+ url.searchParams.set(key, value);
52
+ }
53
+ }
54
+ }
55
+ const response = await fetch(url.toString(), {
56
+ headers: {
57
+ Authorization: `Bearer ${this.accessToken}`,
58
+ "Content-Type": "application/json",
59
+ },
60
+ });
61
+ if (!response.ok) {
62
+ const errorBody = await response.text().catch(() => "");
63
+ this.handleErrorResponse(response.status, response.statusText, errorBody, response.headers);
64
+ }
65
+ return response.json();
66
+ }
67
+ async postRequest(path, body) {
68
+ const url = `${this.baseUrl}${path}`;
69
+ const response = await fetch(url, {
70
+ method: "POST",
71
+ headers: {
72
+ Authorization: `Bearer ${this.accessToken}`,
73
+ "Content-Type": "application/json",
74
+ },
75
+ body: JSON.stringify(body),
76
+ });
77
+ if (!response.ok) {
78
+ const errorBody = await response.text().catch(() => "");
79
+ this.handleErrorResponse(response.status, response.statusText, errorBody, response.headers);
80
+ }
81
+ return response.json();
82
+ }
83
+ handleErrorResponse(status, statusText, errorBody, headers) {
84
+ switch (status) {
85
+ case 401:
86
+ throw new Error("Authentication failed. Check your HUBSPOT_ACCESS_TOKEN.");
87
+ case 403:
88
+ throw new Error("Access denied. Token may lack required scopes (crm.objects.contacts.read, crm.objects.deals.read).");
89
+ case 404:
90
+ throw new Error("Not found. Check the ID and ensure you have access.");
91
+ case 429: {
92
+ const retryAfter = headers.get("Retry-After") ?? "unknown";
93
+ throw new Error(`Rate limited by HubSpot (100 requests/10 seconds). Retry after ${retryAfter} seconds.`);
94
+ }
95
+ default:
96
+ throw new Error(`HubSpot API error (${status}): ${errorBody || statusText}`);
97
+ }
98
+ }
99
+ // ===========================================================================
100
+ // Contacts
101
+ // ===========================================================================
102
+ async listContacts(limit, properties, after) {
103
+ const resolvedProperties = properties ?? DEFAULT_CONTACT_PROPERTIES;
104
+ const params = {
105
+ limit: String(limit ?? 10),
106
+ properties: resolvedProperties,
107
+ };
108
+ if (after)
109
+ params.after = after;
110
+ return this.request("/crm/v3/objects/contacts", params);
111
+ }
112
+ async getContact(contactId, properties, associations) {
113
+ const resolvedProperties = properties ?? DEFAULT_CONTACT_PROPERTIES;
114
+ const params = {
115
+ properties: resolvedProperties,
116
+ };
117
+ if (associations)
118
+ params.associations = associations;
119
+ return this.request(`/crm/v3/objects/contacts/${contactId}`, params);
120
+ }
121
+ async searchContacts(query, properties, limit) {
122
+ const body = {
123
+ query,
124
+ properties: properties ?? DEFAULT_CONTACT_PROPERTIES,
125
+ limit: limit ?? 10,
126
+ };
127
+ return this.postRequest("/crm/v3/objects/contacts/search", body);
128
+ }
129
+ // ===========================================================================
130
+ // Deals
131
+ // ===========================================================================
132
+ async listDeals(limit, properties, after) {
133
+ const resolvedProperties = properties ?? DEFAULT_DEAL_PROPERTIES;
134
+ const params = {
135
+ limit: String(limit ?? 10),
136
+ properties: resolvedProperties,
137
+ };
138
+ if (after)
139
+ params.after = after;
140
+ return this.request("/crm/v3/objects/deals", params);
141
+ }
142
+ async getDeal(dealId, properties, associations) {
143
+ const resolvedProperties = properties ?? DEFAULT_DEAL_PROPERTIES;
144
+ const params = {
145
+ properties: resolvedProperties,
146
+ };
147
+ if (associations)
148
+ params.associations = associations;
149
+ return this.request(`/crm/v3/objects/deals/${dealId}`, params);
150
+ }
151
+ // ===========================================================================
152
+ // Companies
153
+ // ===========================================================================
154
+ async listCompanies(limit, properties, after) {
155
+ const resolvedProperties = properties ?? DEFAULT_COMPANY_PROPERTIES;
156
+ const params = {
157
+ limit: String(limit ?? 10),
158
+ properties: resolvedProperties,
159
+ };
160
+ if (after)
161
+ params.after = after;
162
+ return this.request("/crm/v3/objects/companies", params);
163
+ }
164
+ async getCompany(companyId, properties, associations) {
165
+ const resolvedProperties = properties ?? DEFAULT_COMPANY_PROPERTIES;
166
+ const params = {
167
+ properties: resolvedProperties,
168
+ };
169
+ if (associations)
170
+ params.associations = associations;
171
+ return this.request(`/crm/v3/objects/companies/${companyId}`, params);
172
+ }
173
+ }
174
+ exports.HubSpotService = HubSpotService;
175
+ //# sourceMappingURL=hubspot.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hubspot.service.js","sourceRoot":"","sources":["../../src/services/hubspot.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import { HubSpotService } from "../services/hubspot.service";
3
+ export declare const CompanyToolSchemas: {
4
+ list_companies: {
5
+ description: string;
6
+ schema: z.ZodObject<{
7
+ limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
8
+ properties: z.ZodOptional<z.ZodArray<z.ZodString>>;
9
+ after: z.ZodOptional<z.ZodString>;
10
+ }, z.core.$strip>;
11
+ };
12
+ get_company: {
13
+ description: string;
14
+ schema: z.ZodObject<{
15
+ company_id: z.ZodString;
16
+ properties: z.ZodOptional<z.ZodArray<z.ZodString>>;
17
+ associations: z.ZodOptional<z.ZodArray<z.ZodString>>;
18
+ }, z.core.$strip>;
19
+ };
20
+ };
21
+ export declare class CompanyTools {
22
+ private hubspotService;
23
+ constructor(hubspotService: HubSpotService);
24
+ list_companies(args: z.infer<typeof CompanyToolSchemas.list_companies.schema>): Promise<import("../common/types").McpToolResponse>;
25
+ get_company(args: z.infer<typeof CompanyToolSchemas.get_company.schema>): Promise<import("../common/types").McpToolResponse>;
26
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CompanyTools = exports.CompanyToolSchemas = void 0;
4
+ const zod_1 = require("zod");
5
+ const utils_1 = require("../common/utils");
6
+ exports.CompanyToolSchemas = {
7
+ list_companies: {
8
+ description: "Lists companies from HubSpot CRM with optional property selection and cursor-based pagination. Returns default properties (name, domain, industry, city, state, phone) unless overridden.",
9
+ schema: zod_1.z.object({
10
+ limit: zod_1.z.number().optional().default(10).describe("Number of companies to return (max 100)."),
11
+ properties: zod_1.z
12
+ .array(zod_1.z.string())
13
+ .optional()
14
+ .describe("Properties to include (e.g., ['name', 'domain', 'industry']). Uses defaults if not specified."),
15
+ after: zod_1.z
16
+ .string()
17
+ .optional()
18
+ .describe("Cursor for pagination. Use the value from paging.next.after in previous response."),
19
+ }),
20
+ },
21
+ get_company: {
22
+ description: "Retrieves full details for a specific HubSpot company including domain, industry, and optional associations (linked contacts, deals).",
23
+ schema: zod_1.z.object({
24
+ company_id: zod_1.z.string().describe("The HubSpot company ID (numeric string, e.g., '11111')."),
25
+ properties: zod_1.z
26
+ .array(zod_1.z.string())
27
+ .optional()
28
+ .describe("Properties to include. Uses defaults if not specified."),
29
+ associations: zod_1.z
30
+ .array(zod_1.z.string())
31
+ .optional()
32
+ .describe("Associated object types to include (e.g., ['contacts', 'deals']). Returns linked object IDs."),
33
+ }),
34
+ },
35
+ };
36
+ class CompanyTools {
37
+ hubspotService;
38
+ constructor(hubspotService) {
39
+ this.hubspotService = hubspotService;
40
+ }
41
+ async list_companies(args) {
42
+ const companies = await this.hubspotService.listCompanies(args.limit, args.properties, args.after);
43
+ return (0, utils_1.formatMcpResponse)(companies);
44
+ }
45
+ async get_company(args) {
46
+ const company = await this.hubspotService.getCompany(args.company_id, args.properties, args.associations);
47
+ return (0, utils_1.formatMcpResponse)(company);
48
+ }
49
+ }
50
+ exports.CompanyTools = CompanyTools;
51
+ //# sourceMappingURL=company.tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"company.tools.js","sourceRoot":"","sources":["../../src/tools/company.tools.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAExB,2CAAoD;AAEvC,QAAA,kBAAkB,GAAG;IAChC,cAAc,EAAE;QACd,WAAW,EACT,2LAA2L;QAC7L,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC;YAC7F,UAAU,EAAE,OAAC;iBACV,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,+FAA+F,CAChG;YACH,KAAK,EAAE,OAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,mFAAmF,CACpF;SACJ,CAAC;KACH;IACD,WAAW,EAAE;QACX,WAAW,EACT,uIAAuI;QACzI,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yDAAyD,CAAC;YAC1F,UAAU,EAAE,OAAC;iBACV,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CAAC,wDAAwD,CAAC;YACrE,YAAY,EAAE,OAAC;iBACZ,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,8FAA8F,CAC/F;SACJ,CAAC;KACH;CACF,CAAC;AAEF,MAAa,YAAY;IACH;IAApB,YAAoB,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAAG,CAAC;IAEtD,KAAK,CAAC,cAAc,CAAC,IAA8D;QACjF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,aAAa,CACvD,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,KAAK,CACX,CAAC;QACF,OAAO,IAAA,yBAAiB,EAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAA2D;QAC3E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAClD,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,YAAY,CAClB,CAAC;QACF,OAAO,IAAA,yBAAiB,EAAC,OAAO,CAAC,CAAC;IACpC,CAAC;CACF;AApBD,oCAoBC"}
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ import { HubSpotService } from "../services/hubspot.service";
3
+ export declare const ContactToolSchemas: {
4
+ list_contacts: {
5
+ description: string;
6
+ schema: z.ZodObject<{
7
+ limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
8
+ properties: z.ZodOptional<z.ZodArray<z.ZodString>>;
9
+ after: z.ZodOptional<z.ZodString>;
10
+ }, z.core.$strip>;
11
+ };
12
+ get_contact: {
13
+ description: string;
14
+ schema: z.ZodObject<{
15
+ contact_id: z.ZodString;
16
+ properties: z.ZodOptional<z.ZodArray<z.ZodString>>;
17
+ associations: z.ZodOptional<z.ZodArray<z.ZodString>>;
18
+ }, z.core.$strip>;
19
+ };
20
+ search_contacts: {
21
+ description: string;
22
+ schema: z.ZodObject<{
23
+ query: z.ZodString;
24
+ properties: z.ZodOptional<z.ZodArray<z.ZodString>>;
25
+ limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
26
+ }, z.core.$strip>;
27
+ };
28
+ };
29
+ export declare class ContactTools {
30
+ private hubspotService;
31
+ constructor(hubspotService: HubSpotService);
32
+ list_contacts(args: z.infer<typeof ContactToolSchemas.list_contacts.schema>): Promise<import("../common/types").McpToolResponse>;
33
+ get_contact(args: z.infer<typeof ContactToolSchemas.get_contact.schema>): Promise<import("../common/types").McpToolResponse>;
34
+ search_contacts(args: z.infer<typeof ContactToolSchemas.search_contacts.schema>): Promise<import("../common/types").McpToolResponse>;
35
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContactTools = exports.ContactToolSchemas = void 0;
4
+ const zod_1 = require("zod");
5
+ const utils_1 = require("../common/utils");
6
+ exports.ContactToolSchemas = {
7
+ list_contacts: {
8
+ description: "Lists contacts from HubSpot CRM with optional property selection and cursor-based pagination. Returns default properties (firstname, lastname, email, phone, company) unless overridden.",
9
+ schema: zod_1.z.object({
10
+ limit: zod_1.z.number().optional().default(10).describe("Number of contacts to return (max 100)."),
11
+ properties: zod_1.z
12
+ .array(zod_1.z.string())
13
+ .optional()
14
+ .describe("Properties to include (e.g., ['firstname', 'lastname', 'email']). Uses defaults if not specified."),
15
+ after: zod_1.z
16
+ .string()
17
+ .optional()
18
+ .describe("Cursor for pagination. Use the value from paging.next.after in previous response."),
19
+ }),
20
+ },
21
+ get_contact: {
22
+ description: "Retrieves full details for a specific HubSpot contact including requested properties and optional associations (linked companies, deals, tickets).",
23
+ schema: zod_1.z.object({
24
+ contact_id: zod_1.z.string().describe("The HubSpot contact ID (numeric string, e.g., '12345')."),
25
+ properties: zod_1.z
26
+ .array(zod_1.z.string())
27
+ .optional()
28
+ .describe("Properties to include. Uses defaults if not specified."),
29
+ associations: zod_1.z
30
+ .array(zod_1.z.string())
31
+ .optional()
32
+ .describe("Associated object types to include (e.g., ['companies', 'deals']). Returns linked object IDs."),
33
+ }),
34
+ },
35
+ search_contacts: {
36
+ description: "Searches HubSpot contacts using free-text search across default searchable properties (name, email, phone, company). Use for finding contacts by name, email, or company.",
37
+ schema: zod_1.z.object({
38
+ query: zod_1.z.string().describe("Search query (e.g., 'John', 'john@example.com', 'Acme Corp')."),
39
+ properties: zod_1.z
40
+ .array(zod_1.z.string())
41
+ .optional()
42
+ .describe("Properties to include in results. Uses defaults if not specified."),
43
+ limit: zod_1.z.number().optional().default(10).describe("Number of results to return (max 100)."),
44
+ }),
45
+ },
46
+ };
47
+ class ContactTools {
48
+ hubspotService;
49
+ constructor(hubspotService) {
50
+ this.hubspotService = hubspotService;
51
+ }
52
+ async list_contacts(args) {
53
+ const contacts = await this.hubspotService.listContacts(args.limit, args.properties, args.after);
54
+ return (0, utils_1.formatMcpResponse)(contacts);
55
+ }
56
+ async get_contact(args) {
57
+ const contact = await this.hubspotService.getContact(args.contact_id, args.properties, args.associations);
58
+ return (0, utils_1.formatMcpResponse)(contact);
59
+ }
60
+ async search_contacts(args) {
61
+ const contacts = await this.hubspotService.searchContacts(args.query, args.properties, args.limit);
62
+ return (0, utils_1.formatMcpResponse)(contacts);
63
+ }
64
+ }
65
+ exports.ContactTools = ContactTools;
66
+ //# sourceMappingURL=contact.tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contact.tools.js","sourceRoot":"","sources":["../../src/tools/contact.tools.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAExB,2CAAoD;AAEvC,QAAA,kBAAkB,GAAG;IAChC,aAAa,EAAE;QACb,WAAW,EACT,0LAA0L;QAC5L,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YAC5F,UAAU,EAAE,OAAC;iBACV,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,mGAAmG,CACpG;YACH,KAAK,EAAE,OAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,mFAAmF,CACpF;SACJ,CAAC;KACH;IACD,WAAW,EAAE;QACX,WAAW,EACT,oJAAoJ;QACtJ,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yDAAyD,CAAC;YAC1F,UAAU,EAAE,OAAC;iBACV,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CAAC,wDAAwD,CAAC;YACrE,YAAY,EAAE,OAAC;iBACZ,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,+FAA+F,CAChG;SACJ,CAAC;KACH;IACD,eAAe,EAAE;QACf,WAAW,EACT,2KAA2K;QAC7K,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;YAC3F,UAAU,EAAE,OAAC;iBACV,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CAAC,mEAAmE,CAAC;YAChF,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;SAC5F,CAAC;KACH;CACF,CAAC;AAEF,MAAa,YAAY;IACH;IAApB,YAAoB,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAAG,CAAC;IAEtD,KAAK,CAAC,aAAa,CAAC,IAA6D;QAC/E,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,YAAY,CACrD,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,KAAK,CACX,CAAC;QACF,OAAO,IAAA,yBAAiB,EAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAA2D;QAC3E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAClD,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,YAAY,CAClB,CAAC;QACF,OAAO,IAAA,yBAAiB,EAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,IAA+D;QACnF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,cAAc,CACvD,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,KAAK,CACX,CAAC;QACF,OAAO,IAAA,yBAAiB,EAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;CACF;AA7BD,oCA6BC"}
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import { HubSpotService } from "../services/hubspot.service";
3
+ export declare const DealToolSchemas: {
4
+ list_deals: {
5
+ description: string;
6
+ schema: z.ZodObject<{
7
+ limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
8
+ properties: z.ZodOptional<z.ZodArray<z.ZodString>>;
9
+ after: z.ZodOptional<z.ZodString>;
10
+ }, z.core.$strip>;
11
+ };
12
+ get_deal: {
13
+ description: string;
14
+ schema: z.ZodObject<{
15
+ deal_id: z.ZodString;
16
+ properties: z.ZodOptional<z.ZodArray<z.ZodString>>;
17
+ associations: z.ZodOptional<z.ZodArray<z.ZodString>>;
18
+ }, z.core.$strip>;
19
+ };
20
+ };
21
+ export declare class DealTools {
22
+ private hubspotService;
23
+ constructor(hubspotService: HubSpotService);
24
+ list_deals(args: z.infer<typeof DealToolSchemas.list_deals.schema>): Promise<import("../common/types").McpToolResponse>;
25
+ get_deal(args: z.infer<typeof DealToolSchemas.get_deal.schema>): Promise<import("../common/types").McpToolResponse>;
26
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DealTools = exports.DealToolSchemas = void 0;
4
+ const zod_1 = require("zod");
5
+ const utils_1 = require("../common/utils");
6
+ exports.DealToolSchemas = {
7
+ list_deals: {
8
+ description: "Lists deals from HubSpot CRM with optional property selection and cursor-based pagination. Returns default properties (dealname, amount, dealstage, pipeline, closedate) unless overridden.",
9
+ schema: zod_1.z.object({
10
+ limit: zod_1.z.number().optional().default(10).describe("Number of deals to return (max 100)."),
11
+ properties: zod_1.z
12
+ .array(zod_1.z.string())
13
+ .optional()
14
+ .describe("Properties to include (e.g., ['dealname', 'amount', 'dealstage']). Uses defaults if not specified."),
15
+ after: zod_1.z
16
+ .string()
17
+ .optional()
18
+ .describe("Cursor for pagination. Use the value from paging.next.after in previous response."),
19
+ }),
20
+ },
21
+ get_deal: {
22
+ description: "Retrieves full details for a specific HubSpot deal including pipeline stage, amount, close date, and optional associations (linked contacts, companies).",
23
+ schema: zod_1.z.object({
24
+ deal_id: zod_1.z.string().describe("The HubSpot deal ID (numeric string, e.g., '67890')."),
25
+ properties: zod_1.z
26
+ .array(zod_1.z.string())
27
+ .optional()
28
+ .describe("Properties to include. Uses defaults if not specified."),
29
+ associations: zod_1.z
30
+ .array(zod_1.z.string())
31
+ .optional()
32
+ .describe("Associated object types to include (e.g., ['contacts', 'companies']). Returns linked object IDs."),
33
+ }),
34
+ },
35
+ };
36
+ class DealTools {
37
+ hubspotService;
38
+ constructor(hubspotService) {
39
+ this.hubspotService = hubspotService;
40
+ }
41
+ async list_deals(args) {
42
+ const deals = await this.hubspotService.listDeals(args.limit, args.properties, args.after);
43
+ return (0, utils_1.formatMcpResponse)(deals);
44
+ }
45
+ async get_deal(args) {
46
+ const deal = await this.hubspotService.getDeal(args.deal_id, args.properties, args.associations);
47
+ return (0, utils_1.formatMcpResponse)(deal);
48
+ }
49
+ }
50
+ exports.DealTools = DealTools;
51
+ //# sourceMappingURL=deal.tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deal.tools.js","sourceRoot":"","sources":["../../src/tools/deal.tools.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAExB,2CAAoD;AAEvC,QAAA,eAAe,GAAG;IAC7B,UAAU,EAAE;QACV,WAAW,EACT,6LAA6L;QAC/L,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,sCAAsC,CAAC;YACzF,UAAU,EAAE,OAAC;iBACV,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,oGAAoG,CACrG;YACH,KAAK,EAAE,OAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,mFAAmF,CACpF;SACJ,CAAC;KACH;IACD,QAAQ,EAAE;QACR,WAAW,EACT,0JAA0J;QAC5J,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;YACf,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;YACpF,UAAU,EAAE,OAAC;iBACV,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CAAC,wDAAwD,CAAC;YACrE,YAAY,EAAE,OAAC;iBACZ,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,kGAAkG,CACnG;SACJ,CAAC;KACH;CACF,CAAC;AAEF,MAAa,SAAS;IACA;IAApB,YAAoB,cAA8B;QAA9B,mBAAc,GAAd,cAAc,CAAgB;IAAG,CAAC;IAEtD,KAAK,CAAC,UAAU,CAAC,IAAuD;QACtE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3F,OAAO,IAAA,yBAAiB,EAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAqD;QAClE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAC5C,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,YAAY,CAClB,CAAC;QACF,OAAO,IAAA,yBAAiB,EAAC,IAAI,CAAC,CAAC;IACjC,CAAC;CACF;AAhBD,8BAgBC"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@vineethnkrishnan/hubspot-mcp",
3
+ "version": "0.1.1",
4
+ "description": "A read-only MCP server for HubSpot CRM API, enabling AI assistants to query contacts, deals, and companies.",
5
+ "main": "build/index.js",
6
+ "bin": {
7
+ "hubspot-mcp": "build/index.js"
8
+ },
9
+ "files": [
10
+ "build/"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "start": "node build/index.js",
15
+ "test": "jest --coverage"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "hubspot",
23
+ "crm",
24
+ "ai",
25
+ "model-context-protocol",
26
+ "contacts",
27
+ "deals",
28
+ "companies"
29
+ ],
30
+ "author": "Vineeth Krishnan",
31
+ "license": "MIT",
32
+ "type": "commonjs",
33
+ "engines": {
34
+ "node": ">=20"
35
+ },
36
+ "dependencies": {
37
+ "@modelcontextprotocol/sdk": "^1.29.0",
38
+ "zod": "^4.3.6"
39
+ },
40
+ "devDependencies": {
41
+ "@types/jest": "^30.0.0",
42
+ "@types/node": "^25.5.0",
43
+ "jest": "^30.3.0",
44
+ "ts-jest": "^29.4.6",
45
+ "typescript": "^5.7.0"
46
+ }
47
+ }