@revfleet/hscli 0.7.0 → 0.7.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.
@@ -59,15 +59,7 @@ function textResult(data) {
59
59
  structuredContent: asStructuredContent(safe),
60
60
  };
61
61
  }
62
- async function executeTool(args, fn, toolName) {
63
- // Tag every request made during this tool call with the MCP tool name, so
64
- // trace files produced by `HUBCLI_TELEMETRY_FILE` show up in
65
- // `hubcli trace stats --byToolName`. We use an env var rather than
66
- // threading through the request options because fn() may construct
67
- // arbitrary client.request() chains and we want all of them tagged.
68
- const previousToolName = process.env.HUBCLI_MCP_TOOL_NAME;
69
- if (toolName)
70
- process.env.HUBCLI_MCP_TOOL_NAME = toolName;
62
+ async function executeTool(args, fn) {
71
63
  try {
72
64
  const ctx = mcpContext(args);
73
65
  const client = new HubSpotClient(getToken(ctx.profile), {
@@ -92,14 +84,44 @@ async function executeTool(args, fn, toolName) {
92
84
  }),
93
85
  };
94
86
  }
95
- finally {
96
- if (toolName) {
97
- if (previousToolName === undefined)
87
+ }
88
+ /**
89
+ * Wrap `server.registerTool` so every MCP handler runs with
90
+ * HUBCLI_MCP_TOOL_NAME set to this tool's name. The HTTP layer reads this
91
+ * env var to tag trace/telemetry events, so `hscli trace stats` and
92
+ * `hscli audit by-tool` can break activity down by MCP tool.
93
+ *
94
+ * The SDK's registerTool signature is a heavily-overloaded generic; we
95
+ * stay loosely typed here because every callsite already builds its own
96
+ * config/handler with the right shape.
97
+ */
98
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
+ function registerMcpTool(server, name, config, handler) {
100
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
+ const wrapped = (...handlerArgs) => {
102
+ const previous = process.env.HUBCLI_MCP_TOOL_NAME;
103
+ process.env.HUBCLI_MCP_TOOL_NAME = name;
104
+ const restore = () => {
105
+ if (previous === undefined)
98
106
  delete process.env.HUBCLI_MCP_TOOL_NAME;
99
107
  else
100
- process.env.HUBCLI_MCP_TOOL_NAME = previousToolName;
108
+ process.env.HUBCLI_MCP_TOOL_NAME = previous;
109
+ };
110
+ try {
111
+ const result = handler(...handlerArgs);
112
+ if (result && typeof result.then === "function") {
113
+ return Promise.resolve(result).finally(restore);
114
+ }
115
+ restore();
116
+ return result;
101
117
  }
102
- }
118
+ catch (err) {
119
+ restore();
120
+ throw err;
121
+ }
122
+ };
123
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
+ server.registerTool(name, config, wrapped);
103
125
  }
104
126
  function isEnvTrue(value) {
105
127
  if (!value)
@@ -108,7 +130,7 @@ function isEnvTrue(value) {
108
130
  return normalized === "1" || normalized === "true" || normalized === "yes";
109
131
  }
110
132
  function registerStandardObjectTools(server, objectType) {
111
- server.registerTool(`crm_${objectType}_list`, {
133
+ registerMcpTool(server, `crm_${objectType}_list`, {
112
134
  description: `List ${objectType}`,
113
135
  inputSchema: {
114
136
  ...baseArgsSchema,
@@ -130,7 +152,7 @@ function registerStandardObjectTools(server, objectType) {
130
152
  enrichListResponse(res, portal, objectType);
131
153
  return res;
132
154
  }));
133
- server.registerTool(`crm_${objectType}_get`, {
155
+ registerMcpTool(server, `crm_${objectType}_get`, {
134
156
  description: `Get one ${objectType.slice(0, -1)} by ID`,
135
157
  inputSchema: {
136
158
  ...baseArgsSchema,
@@ -146,7 +168,7 @@ function registerStandardObjectTools(server, objectType) {
146
168
  enrichRecordUrl(res, portal, objectType);
147
169
  return res;
148
170
  }));
149
- server.registerTool(`crm_${objectType}_search`, {
171
+ registerMcpTool(server, `crm_${objectType}_search`, {
150
172
  description: `Search ${objectType}`,
151
173
  inputSchema: {
152
174
  ...baseArgsSchema,
@@ -167,7 +189,7 @@ function registerStandardObjectTools(server, objectType) {
167
189
  enrichListResponse(res, portal, objectType);
168
190
  return res;
169
191
  }));
170
- server.registerTool(`crm_${objectType}_create`, {
192
+ registerMcpTool(server, `crm_${objectType}_create`, {
171
193
  description: `Create ${objectType.slice(0, -1)} (dry-run by default unless force=true)`,
172
194
  inputSchema: {
173
195
  ...baseArgsSchema,
@@ -180,7 +202,7 @@ function registerStandardObjectTools(server, objectType) {
180
202
  enrichRecordUrl(res, portal, objectType);
181
203
  return res;
182
204
  }));
183
- server.registerTool(`crm_${objectType}_update`, {
205
+ registerMcpTool(server, `crm_${objectType}_update`, {
184
206
  description: `Update ${objectType.slice(0, -1)} (dry-run by default unless force=true)`,
185
207
  inputSchema: {
186
208
  ...baseArgsSchema,
@@ -195,26 +217,26 @@ function registerStandardObjectTools(server, objectType) {
195
217
  enrichRecordUrl(res, portal, objectType);
196
218
  return res;
197
219
  }));
198
- server.registerTool(`crm_${objectType}_delete`, {
220
+ registerMcpTool(server, `crm_${objectType}_delete`, {
199
221
  description: `Delete/archive ${objectType.slice(0, -1)} by ID (dry-run by default unless force=true)`,
200
222
  inputSchema: { ...baseArgsSchema, id: z.string().min(1) },
201
223
  }, (args) => executeTool(args, (ctx, client) => {
202
224
  const idSegment = encodePathSegment(args.id, "id");
203
225
  return maybeWrite(ctx, client, "DELETE", `/crm/v3/objects/${objectType}/${idSegment}`);
204
226
  }));
205
- server.registerTool(`crm_${objectType}_merge`, {
227
+ registerMcpTool(server, `crm_${objectType}_merge`, {
206
228
  description: `Merge ${objectType} records (endpoint support varies by object)`,
207
229
  inputSchema: { ...baseArgsSchema, data: z.record(z.string(), z.unknown()) },
208
230
  }, (args) => executeTool(args, (ctx, client) => maybeWrite(ctx, client, "POST", `/crm/v3/objects/${objectType}/merge`, args.data)));
209
- server.registerTool(`crm_${objectType}_batch_read`, {
231
+ registerMcpTool(server, `crm_${objectType}_batch_read`, {
210
232
  description: `Batch read ${objectType}`,
211
233
  inputSchema: { ...baseArgsSchema, data: z.record(z.string(), z.unknown()) },
212
234
  }, (args) => executeTool(args, (_ctx, client) => client.request(`/crm/v3/objects/${objectType}/batch/read`, { method: "POST", body: args.data })));
213
- server.registerTool(`crm_${objectType}_batch_upsert`, {
235
+ registerMcpTool(server, `crm_${objectType}_batch_upsert`, {
214
236
  description: `Batch upsert ${objectType} (dry-run by default unless force=true)`,
215
237
  inputSchema: { ...baseArgsSchema, data: z.record(z.string(), z.unknown()) },
216
238
  }, (args) => executeTool(args, (ctx, client) => maybeWrite(ctx, client, "POST", `/crm/v3/objects/${objectType}/batch/upsert`, args.data)));
217
- server.registerTool(`crm_${objectType}_batch_archive`, {
239
+ registerMcpTool(server, `crm_${objectType}_batch_archive`, {
218
240
  description: `Batch archive ${objectType} (dry-run by default unless force=true)`,
219
241
  inputSchema: { ...baseArgsSchema, data: z.record(z.string(), z.unknown()) },
220
242
  }, (args) => executeTool(args, (ctx, client) => maybeWrite(ctx, client, "POST", `/crm/v3/objects/${objectType}/batch/archive`, args.data)));
@@ -226,7 +248,7 @@ export function registerHubSpotTools(server) {
226
248
  for (const objectType of ENGAGEMENT_OBJECT_TYPES) {
227
249
  registerStandardObjectTools(server, objectType);
228
250
  }
229
- server.registerTool("crm_properties_list", {
251
+ registerMcpTool(server, "crm_properties_list", {
230
252
  description: "List properties for an object type",
231
253
  inputSchema: { ...baseArgsSchema, objectType: z.enum(PROPERTY_OBJECT_TYPES) },
232
254
  }, (args) => executeTool(args, (_ctx, client) => {
@@ -234,7 +256,7 @@ export function registerHubSpotTools(server) {
234
256
  const objectTypeSegment = encodePathSegment(objectTypeValue, "objectType");
235
257
  return client.request(`/crm/v3/properties/${objectTypeSegment}`);
236
258
  }));
237
- server.registerTool("crm_properties_get", {
259
+ registerMcpTool(server, "crm_properties_get", {
238
260
  description: "Get one property definition",
239
261
  inputSchema: { ...baseArgsSchema, objectType: z.enum(PROPERTY_OBJECT_TYPES), propertyName: z.string().min(1) },
240
262
  }, (args) => executeTool(args, (_ctx, client) => {
@@ -243,7 +265,7 @@ export function registerHubSpotTools(server) {
243
265
  const propertyNameSegment = encodePathSegment(args.propertyName, "propertyName");
244
266
  return client.request(`/crm/v3/properties/${objectTypeSegment}/${propertyNameSegment}`);
245
267
  }));
246
- server.registerTool("crm_properties_create", {
268
+ registerMcpTool(server, "crm_properties_create", {
247
269
  description: "Create property (dry-run by default unless force=true)",
248
270
  inputSchema: { ...baseArgsSchema, objectType: z.enum(PROPERTY_OBJECT_TYPES), data: z.record(z.string(), z.unknown()) },
249
271
  }, (args) => executeTool(args, (ctx, client) => {
@@ -251,7 +273,7 @@ export function registerHubSpotTools(server) {
251
273
  const objectTypeSegment = encodePathSegment(objectTypeValue, "objectType");
252
274
  return maybeWrite(ctx, client, "POST", `/crm/v3/properties/${objectTypeSegment}`, args.data);
253
275
  }));
254
- server.registerTool("crm_properties_update", {
276
+ registerMcpTool(server, "crm_properties_update", {
255
277
  description: "Update property (dry-run by default unless force=true)",
256
278
  inputSchema: {
257
279
  ...baseArgsSchema,
@@ -265,7 +287,7 @@ export function registerHubSpotTools(server) {
265
287
  const propertyNameSegment = encodePathSegment(args.propertyName, "propertyName");
266
288
  return maybeWrite(ctx, client, "PATCH", `/crm/v3/properties/${objectTypeSegment}/${propertyNameSegment}`, args.data);
267
289
  }));
268
- server.registerTool("crm_associations_list", {
290
+ registerMcpTool(server, "crm_associations_list", {
269
291
  description: "List associations between CRM objects (supports standard types, engagements, and custom object type IDs like 2-199622513)",
270
292
  inputSchema: {
271
293
  ...baseArgsSchema,
@@ -284,7 +306,7 @@ export function registerHubSpotTools(server) {
284
306
  appendOptional(params, "after", args.after);
285
307
  return client.request(`/crm/v4/objects/${fromObjectTypeSegment}/${fromObjectIdSegment}/associations/${toObjectTypeSegment}?${params.toString()}`);
286
308
  }));
287
- server.registerTool("crm_associations_create", {
309
+ registerMcpTool(server, "crm_associations_create", {
288
310
  description: "Create default association (dry-run by default unless force=true). Supports standard types, engagements, and custom object type IDs.",
289
311
  inputSchema: {
290
312
  ...baseArgsSchema,
@@ -296,7 +318,7 @@ export function registerHubSpotTools(server) {
296
318
  }, (args) => executeTool(args, (ctx, client) => {
297
319
  return maybeWrite(ctx, client, "PUT", `/crm/v4/objects/${encodePathSegment(args.fromObjectType.trim().toLowerCase(), "fromObjectType")}/${encodePathSegment(args.fromObjectId, "fromObjectId")}/associations/default/${encodePathSegment(args.toObjectType.trim().toLowerCase(), "toObjectType")}/${encodePathSegment(args.toObjectId, "toObjectId")}`);
298
320
  }));
299
- server.registerTool("crm_associations_remove", {
321
+ registerMcpTool(server, "crm_associations_remove", {
300
322
  description: "Remove default association (dry-run by default unless force=true). Supports standard types, engagements, and custom object type IDs.",
301
323
  inputSchema: {
302
324
  ...baseArgsSchema,
@@ -308,11 +330,11 @@ export function registerHubSpotTools(server) {
308
330
  }, (args) => executeTool(args, (ctx, client) => {
309
331
  return maybeWrite(ctx, client, "DELETE", `/crm/v4/objects/${encodePathSegment(args.fromObjectType.trim().toLowerCase(), "fromObjectType")}/${encodePathSegment(args.fromObjectId, "fromObjectId")}/associations/default/${encodePathSegment(args.toObjectType.trim().toLowerCase(), "toObjectType")}/${encodePathSegment(args.toObjectId, "toObjectId")}`);
310
332
  }));
311
- server.registerTool("crm_imports_create", {
333
+ registerMcpTool(server, "crm_imports_create", {
312
334
  description: "Create import (dry-run by default unless force=true)",
313
335
  inputSchema: { ...baseArgsSchema, data: z.record(z.string(), z.unknown()) },
314
336
  }, (args) => executeTool(args, (ctx, client) => maybeWrite(ctx, client, "POST", "/crm/v3/imports", args.data)));
315
- server.registerTool("crm_imports_list", {
337
+ registerMcpTool(server, "crm_imports_list", {
316
338
  description: "List import jobs",
317
339
  inputSchema: { ...baseArgsSchema, limit: z.number().int().positive().default(100), after: z.string().optional() },
318
340
  }, (args) => executeTool(args, (_ctx, client) => {
@@ -321,21 +343,21 @@ export function registerHubSpotTools(server) {
321
343
  appendOptional(params, "after", args.after);
322
344
  return client.request(`/crm/v3/imports?${params.toString()}`);
323
345
  }));
324
- server.registerTool("crm_imports_get", {
346
+ registerMcpTool(server, "crm_imports_get", {
325
347
  description: "Get import by ID",
326
348
  inputSchema: { ...baseArgsSchema, importId: z.string().min(1) },
327
349
  }, (args) => executeTool(args, (_ctx, client) => {
328
350
  const importIdSegment = encodePathSegment(args.importId, "importId");
329
351
  return client.request(`/crm/v3/imports/${importIdSegment}`);
330
352
  }));
331
- server.registerTool("crm_imports_errors", {
353
+ registerMcpTool(server, "crm_imports_errors", {
332
354
  description: "Get import errors",
333
355
  inputSchema: { ...baseArgsSchema, importId: z.string().min(1) },
334
356
  }, (args) => executeTool(args, (_ctx, client) => {
335
357
  const importIdSegment = encodePathSegment(args.importId, "importId");
336
358
  return client.request(`/crm/v3/imports/${importIdSegment}/errors`);
337
359
  }));
338
- server.registerTool("crm_owners_list", {
360
+ registerMcpTool(server, "crm_owners_list", {
339
361
  description: "List HubSpot owners",
340
362
  inputSchema: {
341
363
  ...baseArgsSchema,
@@ -350,23 +372,23 @@ export function registerHubSpotTools(server) {
350
372
  appendOptional(params, "email", args.email);
351
373
  return client.request(`/crm/v3/owners/?${params.toString()}`);
352
374
  }));
353
- server.registerTool("crm_custom_schemas_list", {
375
+ registerMcpTool(server, "crm_custom_schemas_list", {
354
376
  description: "List custom object schemas",
355
377
  inputSchema: { ...baseArgsSchema },
356
378
  }, (args) => executeTool(args, (_ctx, client) => client.request("/crm/v3/schemas")));
357
- server.registerTool("crm_custom_schemas_get", {
379
+ registerMcpTool(server, "crm_custom_schemas_get", {
358
380
  description: "Get custom object schema by objectType",
359
381
  inputSchema: { ...baseArgsSchema, objectType: z.string().min(1) },
360
382
  }, (args) => executeTool(args, (_ctx, client) => client.request(`/crm/v3/schemas/${encodePathSegment(args.objectType, "objectType")}`)));
361
- server.registerTool("crm_custom_schemas_create", {
383
+ registerMcpTool(server, "crm_custom_schemas_create", {
362
384
  description: "Create custom object schema (dry-run by default unless force=true)",
363
385
  inputSchema: { ...baseArgsSchema, data: z.record(z.string(), z.unknown()) },
364
386
  }, (args) => executeTool(args, (ctx, client) => maybeWrite(ctx, client, "POST", "/crm/v3/schemas", args.data)));
365
- server.registerTool("crm_custom_schemas_update", {
387
+ registerMcpTool(server, "crm_custom_schemas_update", {
366
388
  description: "Update custom object schema (dry-run by default unless force=true)",
367
389
  inputSchema: { ...baseArgsSchema, objectType: z.string().min(1), data: z.record(z.string(), z.unknown()) },
368
390
  }, (args) => executeTool(args, (ctx, client) => maybeWrite(ctx, client, "PATCH", `/crm/v3/schemas/${encodePathSegment(args.objectType, "objectType")}`, args.data)));
369
- server.registerTool("crm_custom_records_list", {
391
+ registerMcpTool(server, "crm_custom_records_list", {
370
392
  description: "List custom object records by objectType",
371
393
  inputSchema: { ...baseArgsSchema, objectType: z.string().min(1), limit: z.number().int().positive().default(50), after: z.string().optional() },
372
394
  }, (args) => executeTool(args, async (ctx, client) => {
@@ -378,7 +400,7 @@ export function registerHubSpotTools(server) {
378
400
  enrichCustomListResponse(res, portal, args.objectType);
379
401
  return res;
380
402
  }));
381
- server.registerTool("crm_custom_records_get", {
403
+ registerMcpTool(server, "crm_custom_records_get", {
382
404
  description: "Get custom object record by objectType and id",
383
405
  inputSchema: { ...baseArgsSchema, objectType: z.string().min(1), id: z.string().min(1) },
384
406
  }, (args) => executeTool(args, async (ctx, client) => {
@@ -388,7 +410,7 @@ export function registerHubSpotTools(server) {
388
410
  enrichCustomRecordUrl(res, portal, args.objectType);
389
411
  return res;
390
412
  }));
391
- server.registerTool("crm_custom_records_search", {
413
+ registerMcpTool(server, "crm_custom_records_search", {
392
414
  description: "Search custom object records",
393
415
  inputSchema: { ...baseArgsSchema, objectType: z.string().min(1), data: z.record(z.string(), z.unknown()) },
394
416
  }, (args) => executeTool(args, async (ctx, client) => {
@@ -397,7 +419,7 @@ export function registerHubSpotTools(server) {
397
419
  enrichCustomListResponse(res, portal, args.objectType);
398
420
  return res;
399
421
  }));
400
- server.registerTool("crm_custom_records_create", {
422
+ registerMcpTool(server, "crm_custom_records_create", {
401
423
  description: "Create custom object record (dry-run by default unless force=true)",
402
424
  inputSchema: { ...baseArgsSchema, objectType: z.string().min(1), data: z.record(z.string(), z.unknown()) },
403
425
  }, (args) => executeTool(args, async (ctx, client) => {
@@ -407,7 +429,7 @@ export function registerHubSpotTools(server) {
407
429
  enrichCustomRecordUrl(res, portal, args.objectType);
408
430
  return res;
409
431
  }));
410
- server.registerTool("crm_custom_records_update", {
432
+ registerMcpTool(server, "crm_custom_records_update", {
411
433
  description: "Update custom object record (dry-run by default unless force=true)",
412
434
  inputSchema: { ...baseArgsSchema, objectType: z.string().min(1), id: z.string().min(1), data: z.record(z.string(), z.unknown()) },
413
435
  }, (args) => executeTool(args, async (ctx, client) => {
@@ -417,11 +439,11 @@ export function registerHubSpotTools(server) {
417
439
  enrichCustomRecordUrl(res, portal, args.objectType);
418
440
  return res;
419
441
  }));
420
- server.registerTool("crm_custom_records_delete", {
442
+ registerMcpTool(server, "crm_custom_records_delete", {
421
443
  description: "Delete custom object record (dry-run by default unless force=true)",
422
444
  inputSchema: { ...baseArgsSchema, objectType: z.string().min(1), id: z.string().min(1) },
423
445
  }, (args) => executeTool(args, (ctx, client) => maybeWrite(ctx, client, "DELETE", `/crm/v3/objects/${encodePathSegment(args.objectType, "objectType")}/${encodePathSegment(args.id, "id")}`)));
424
- server.registerTool("crm_pipelines_list", {
446
+ registerMcpTool(server, "crm_pipelines_list", {
425
447
  description: "List pipelines for object type",
426
448
  inputSchema: { ...baseArgsSchema, objectType: z.enum(PIPELINE_OBJECT_TYPES) },
427
449
  }, (args) => executeTool(args, (_ctx, client) => {
@@ -429,7 +451,7 @@ export function registerHubSpotTools(server) {
429
451
  const objectTypeSegment = encodePathSegment(objectTypeValue, "objectType");
430
452
  return client.request(`/crm/v3/pipelines/${objectTypeSegment}`);
431
453
  }));
432
- server.registerTool("crm_pipelines_get", {
454
+ registerMcpTool(server, "crm_pipelines_get", {
433
455
  description: "Get one pipeline",
434
456
  inputSchema: { ...baseArgsSchema, objectType: z.enum(PIPELINE_OBJECT_TYPES), pipelineId: z.string().min(1) },
435
457
  }, (args) => executeTool(args, (_ctx, client) => {
@@ -438,7 +460,7 @@ export function registerHubSpotTools(server) {
438
460
  const pipelineIdSegment = encodePathSegment(args.pipelineId, "pipelineId");
439
461
  return client.request(`/crm/v3/pipelines/${objectTypeSegment}/${pipelineIdSegment}`);
440
462
  }));
441
- server.registerTool("hub_api_request", {
463
+ registerMcpTool(server, "hub_api_request", {
442
464
  description: "Raw HubSpot API request with safety controls",
443
465
  inputSchema: {
444
466
  ...baseArgsSchema,
@@ -454,7 +476,7 @@ export function registerHubSpotTools(server) {
454
476
  return maybeWrite(ctx, client, method, args.path, args.data);
455
477
  }));
456
478
  // ── Lists ──────────────────────────────────────────────────────────────
457
- server.registerTool("crm_lists_list", {
479
+ registerMcpTool(server, "crm_lists_list", {
458
480
  description: "List CRM lists with pagination",
459
481
  inputSchema: {
460
482
  ...baseArgsSchema,
@@ -470,7 +492,7 @@ export function registerHubSpotTools(server) {
470
492
  const qs = params.toString();
471
493
  return await client.request(`/crm/v3/lists${qs ? `?${qs}` : ""}`);
472
494
  }));
473
- server.registerTool("crm_lists_get", {
495
+ registerMcpTool(server, "crm_lists_get", {
474
496
  description: "Get a CRM list by ID",
475
497
  inputSchema: {
476
498
  ...baseArgsSchema,
@@ -480,7 +502,7 @@ export function registerHubSpotTools(server) {
480
502
  const listIdSegment = encodePathSegment(args.listId, "listId");
481
503
  return await client.request(`/crm/v3/lists/${listIdSegment}`);
482
504
  }));
483
- server.registerTool("crm_lists_create", {
505
+ registerMcpTool(server, "crm_lists_create", {
484
506
  description: "Create a CRM list (dry-run by default unless force=true)",
485
507
  inputSchema: {
486
508
  ...baseArgsSchema,
@@ -489,7 +511,7 @@ export function registerHubSpotTools(server) {
489
511
  }, (args) => executeTool(args, (ctx, client) => {
490
512
  return maybeWrite(ctx, client, "POST", "/crm/v3/lists", args.data);
491
513
  }));
492
- server.registerTool("crm_lists_update", {
514
+ registerMcpTool(server, "crm_lists_update", {
493
515
  description: "Update a CRM list (dry-run by default unless force=true)",
494
516
  inputSchema: {
495
517
  ...baseArgsSchema,
@@ -500,7 +522,7 @@ export function registerHubSpotTools(server) {
500
522
  const listIdSegment = encodePathSegment(args.listId, "listId");
501
523
  return maybeWrite(ctx, client, "PATCH", `/crm/v3/lists/${listIdSegment}`, args.data);
502
524
  }));
503
- server.registerTool("crm_lists_delete", {
525
+ registerMcpTool(server, "crm_lists_delete", {
504
526
  description: "Delete a CRM list (dry-run by default unless force=true)",
505
527
  inputSchema: {
506
528
  ...baseArgsSchema,
@@ -510,7 +532,7 @@ export function registerHubSpotTools(server) {
510
532
  const listIdSegment = encodePathSegment(args.listId, "listId");
511
533
  return maybeWrite(ctx, client, "DELETE", `/crm/v3/lists/${listIdSegment}`);
512
534
  }));
513
- server.registerTool("crm_lists_memberships", {
535
+ registerMcpTool(server, "crm_lists_memberships", {
514
536
  description: "Get memberships of a CRM list",
515
537
  inputSchema: {
516
538
  ...baseArgsSchema,
@@ -521,7 +543,7 @@ export function registerHubSpotTools(server) {
521
543
  return await client.request(`/crm/v3/lists/${listIdSegment}/memberships`);
522
544
  }));
523
545
  // ── Sequences ──────────────────────────────────────────────────────────
524
- server.registerTool("sales_sequences_list", {
546
+ registerMcpTool(server, "sales_sequences_list", {
525
547
  description: "List sales sequences with pagination",
526
548
  inputSchema: {
527
549
  ...baseArgsSchema,
@@ -537,7 +559,7 @@ export function registerHubSpotTools(server) {
537
559
  const qs = params.toString();
538
560
  return await client.request(`/automation/v4/sequences${qs ? `?${qs}` : ""}`);
539
561
  }));
540
- server.registerTool("sales_sequences_get", {
562
+ registerMcpTool(server, "sales_sequences_get", {
541
563
  description: "Get a sales sequence by ID",
542
564
  inputSchema: {
543
565
  ...baseArgsSchema,
@@ -547,7 +569,7 @@ export function registerHubSpotTools(server) {
547
569
  const sequenceIdSegment = encodePathSegment(args.sequenceId, "sequenceId");
548
570
  return await client.request(`/automation/v4/sequences/${sequenceIdSegment}`);
549
571
  }));
550
- server.registerTool("sales_sequences_enrollments", {
572
+ registerMcpTool(server, "sales_sequences_enrollments", {
551
573
  description: "Get enrollments for a sales sequence",
552
574
  inputSchema: {
553
575
  ...baseArgsSchema,
@@ -558,7 +580,7 @@ export function registerHubSpotTools(server) {
558
580
  return await client.request(`/automation/v4/sequences/${sequenceIdSegment}/enrollments`);
559
581
  }));
560
582
  // ── Reporting ──────────────────────────────────────────────────────────
561
- server.registerTool("reporting_dashboards_list", {
583
+ registerMcpTool(server, "reporting_dashboards_list", {
562
584
  description: "List analytics reports/dashboards with pagination",
563
585
  inputSchema: {
564
586
  ...baseArgsSchema,
@@ -574,7 +596,7 @@ export function registerHubSpotTools(server) {
574
596
  const qs = params.toString();
575
597
  return await client.request(`/analytics/v2/reports${qs ? `?${qs}` : ""}`);
576
598
  }));
577
- server.registerTool("reporting_dashboards_get", {
599
+ registerMcpTool(server, "reporting_dashboards_get", {
578
600
  description: "Get an analytics report/dashboard by ID",
579
601
  inputSchema: {
580
602
  ...baseArgsSchema,
@@ -585,7 +607,7 @@ export function registerHubSpotTools(server) {
585
607
  return await client.request(`/analytics/v2/reports/${dashboardIdSegment}`);
586
608
  }));
587
609
  // ── Exports ────────────────────────────────────────────────────────────
588
- server.registerTool("crm_exports_create", {
610
+ registerMcpTool(server, "crm_exports_create", {
589
611
  description: "Create a CRM export (dry-run by default unless force=true)",
590
612
  inputSchema: {
591
613
  ...baseArgsSchema,
@@ -594,7 +616,7 @@ export function registerHubSpotTools(server) {
594
616
  }, (args) => executeTool(args, (ctx, client) => {
595
617
  return maybeWrite(ctx, client, "POST", "/crm/v3/exports", args.data);
596
618
  }));
597
- server.registerTool("crm_exports_list", {
619
+ registerMcpTool(server, "crm_exports_list", {
598
620
  description: "List CRM exports with pagination",
599
621
  inputSchema: {
600
622
  ...baseArgsSchema,
@@ -610,7 +632,7 @@ export function registerHubSpotTools(server) {
610
632
  const qs = params.toString();
611
633
  return await client.request(`/crm/v3/exports${qs ? `?${qs}` : ""}`);
612
634
  }));
613
- server.registerTool("crm_exports_get", {
635
+ registerMcpTool(server, "crm_exports_get", {
614
636
  description: "Get a CRM export by ID",
615
637
  inputSchema: {
616
638
  ...baseArgsSchema,
@@ -620,7 +642,7 @@ export function registerHubSpotTools(server) {
620
642
  const exportIdSegment = encodePathSegment(args.exportId, "exportId");
621
643
  return await client.request(`/crm/v3/exports/${exportIdSegment}`);
622
644
  }));
623
- server.registerTool("crm_exports_status", {
645
+ registerMcpTool(server, "crm_exports_status", {
624
646
  description: "Get the status of a CRM export",
625
647
  inputSchema: {
626
648
  ...baseArgsSchema,
@@ -631,7 +653,7 @@ export function registerHubSpotTools(server) {
631
653
  return await client.request(`/crm/v3/exports/${exportIdSegment}/status`);
632
654
  }));
633
655
  // ── Pipeline Stages ────────────────────────────────────────────────────
634
- server.registerTool("crm_pipelines_stages", {
656
+ registerMcpTool(server, "crm_pipelines_stages", {
635
657
  description: "List stages for a pipeline",
636
658
  inputSchema: {
637
659
  ...baseArgsSchema,
@@ -645,7 +667,7 @@ export function registerHubSpotTools(server) {
645
667
  return client.request(`/crm/v3/pipelines/${objectTypeSegment}/${pipelineIdSegment}/stages`);
646
668
  }));
647
669
  // ── Property Groups ────────────────────────────────────────────────────
648
- server.registerTool("crm_property_groups_list", {
670
+ registerMcpTool(server, "crm_property_groups_list", {
649
671
  description: "List property groups for an object type",
650
672
  inputSchema: {
651
673
  ...baseArgsSchema,
@@ -656,7 +678,7 @@ export function registerHubSpotTools(server) {
656
678
  const objectTypeSegment = encodePathSegment(objectTypeValue, "objectType");
657
679
  return client.request(`/crm/v3/properties/${objectTypeSegment}/groups`);
658
680
  }));
659
- server.registerTool("crm_property_groups_create", {
681
+ registerMcpTool(server, "crm_property_groups_create", {
660
682
  description: "Create a property group (dry-run by default unless force=true)",
661
683
  inputSchema: {
662
684
  ...baseArgsSchema,
@@ -668,7 +690,7 @@ export function registerHubSpotTools(server) {
668
690
  const objectTypeSegment = encodePathSegment(objectTypeValue, "objectType");
669
691
  return maybeWrite(ctx, client, "POST", `/crm/v3/properties/${objectTypeSegment}/groups`, args.data);
670
692
  }));
671
- server.registerTool("crm_property_groups_update", {
693
+ registerMcpTool(server, "crm_property_groups_update", {
672
694
  description: "Update a property group (dry-run by default unless force=true)",
673
695
  inputSchema: {
674
696
  ...baseArgsSchema,