@hubspot/cli 8.4.0 → 8.5.0-beta.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.
Files changed (93) hide show
  1. package/api/migrate.js +3 -3
  2. package/bin/cli.js +3 -0
  3. package/commands/app/migrate.js +4 -4
  4. package/commands/getStarted.js +2 -2
  5. package/commands/project/add.js +3 -3
  6. package/commands/project/create.js +10 -7
  7. package/commands/project/delete.js +2 -2
  8. package/commands/project/deploy.js +4 -3
  9. package/commands/project/dev/index.js +5 -4
  10. package/commands/project/info.js +2 -2
  11. package/commands/project/migrate.js +5 -5
  12. package/commands/project/profile/add.js +2 -2
  13. package/commands/project/profile/delete.js +2 -2
  14. package/commands/project/upload.js +3 -3
  15. package/commands/project/validate.js +2 -2
  16. package/commands/project/watch.js +2 -2
  17. package/commands/project.js +6 -3
  18. package/commands/testAccount/create.js +4 -4
  19. package/lang/en.d.ts +11 -0
  20. package/lang/en.js +16 -5
  21. package/lib/app/migrate.js +7 -0
  22. package/lib/constants.d.ts +0 -1
  23. package/lib/constants.js +0 -1
  24. package/lib/doctor/Doctor.js +2 -2
  25. package/lib/getStartedV2Actions.js +2 -2
  26. package/lib/hasFeature.js +1 -2
  27. package/lib/middleware/autoUpdateMiddleware.js +6 -3
  28. package/lib/projects/ProjectLogsManager.js +6 -3
  29. package/lib/projects/create/index.js +2 -2
  30. package/lib/projects/create/legacy.js +2 -2
  31. package/lib/projects/create/v2.js +3 -4
  32. package/lib/projects/delete.js +2 -2
  33. package/lib/projects/deploy.d.ts +1 -1
  34. package/lib/projects/deploy.js +2 -2
  35. package/lib/projects/upload.js +22 -3
  36. package/lib/projects/workspaces.d.ts +42 -0
  37. package/lib/projects/workspaces.js +350 -0
  38. package/lib/prompts/projectsLogsPrompt.js +3 -0
  39. package/lib/theme/cmsDevServerProcess.js +1 -1
  40. package/mcp-server/Tool.d.ts +15 -0
  41. package/mcp-server/Tool.js +53 -0
  42. package/mcp-server/server.js +5 -3
  43. package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +4 -2
  44. package/mcp-server/tools/cms/HsCreateFunctionTool.js +8 -6
  45. package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +4 -2
  46. package/mcp-server/tools/cms/HsCreateModuleTool.js +8 -6
  47. package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +4 -2
  48. package/mcp-server/tools/cms/HsCreateTemplateTool.js +8 -6
  49. package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +4 -2
  50. package/mcp-server/tools/cms/HsFunctionLogsTool.js +8 -6
  51. package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +4 -2
  52. package/mcp-server/tools/cms/HsListFunctionsTool.js +8 -6
  53. package/mcp-server/tools/cms/HsListTool.d.ts +4 -2
  54. package/mcp-server/tools/cms/HsListTool.js +8 -6
  55. package/mcp-server/tools/index.d.ts +3 -2
  56. package/mcp-server/tools/index.js +22 -22
  57. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +6 -4
  58. package/mcp-server/tools/project/AddFeatureToProjectTool.js +8 -6
  59. package/mcp-server/tools/project/CreateProjectTool.d.ts +6 -4
  60. package/mcp-server/tools/project/CreateProjectTool.js +9 -7
  61. package/mcp-server/tools/project/CreateTestAccountTool.d.ts +4 -2
  62. package/mcp-server/tools/project/CreateTestAccountTool.js +20 -8
  63. package/mcp-server/tools/project/DeployProjectTool.d.ts +4 -2
  64. package/mcp-server/tools/project/DeployProjectTool.js +4 -6
  65. package/mcp-server/tools/project/DocFetchTool.d.ts +4 -2
  66. package/mcp-server/tools/project/DocFetchTool.js +8 -6
  67. package/mcp-server/tools/project/DocsSearchTool.d.ts +9 -3
  68. package/mcp-server/tools/project/DocsSearchTool.js +32 -9
  69. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +4 -2
  70. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +8 -6
  71. package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +4 -2
  72. package/mcp-server/tools/project/GetApplicationInfoTool.js +8 -6
  73. package/mcp-server/tools/project/GetBuildLogsTool.d.ts +4 -2
  74. package/mcp-server/tools/project/GetBuildLogsTool.js +8 -6
  75. package/mcp-server/tools/project/GetBuildStatusTool.d.ts +4 -2
  76. package/mcp-server/tools/project/GetBuildStatusTool.js +8 -6
  77. package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -2
  78. package/mcp-server/tools/project/GetConfigValuesTool.js +12 -7
  79. package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +4 -2
  80. package/mcp-server/tools/project/GuidedWalkthroughTool.js +4 -6
  81. package/mcp-server/tools/project/UploadProjectTools.d.ts +4 -2
  82. package/mcp-server/tools/project/UploadProjectTools.js +9 -7
  83. package/mcp-server/tools/project/ValidateProjectTool.d.ts +4 -2
  84. package/mcp-server/tools/project/ValidateProjectTool.js +8 -6
  85. package/mcp-server/tools/project/constants.d.ts +2 -2
  86. package/mcp-server/types.d.ts +0 -7
  87. package/mcp-server/types.js +1 -13
  88. package/mcp-server/utils/logger.d.ts +10 -0
  89. package/mcp-server/utils/logger.js +29 -0
  90. package/mcp-server/utils/toolUsageTracking.js +0 -2
  91. package/package.json +10 -10
  92. package/lib/projects/platformVersion.d.ts +0 -9
  93. package/lib/projects/platformVersion.js +0 -39
@@ -1,16 +1,23 @@
1
1
  import { http } from '@hubspot/local-dev-lib/http';
2
2
  import z from 'zod';
3
- import { Tool } from '../../types.js';
3
+ import { Tool } from '../../Tool.js';
4
4
  import { formatTextContents } from '../../utils/content.js';
5
- import { trackToolUsage } from '../../utils/toolUsageTracking.js';
6
5
  import { absoluteCurrentWorkingDirectory, docsSearchQuery, } from './constants.js';
7
6
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
8
7
  import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
9
8
  import { setupHubSpotConfig } from '../../utils/config.js';
10
9
  import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
10
+ const docsSearchLimit = z
11
+ .number()
12
+ .int()
13
+ .min(1)
14
+ .max(20)
15
+ .default(5)
16
+ .describe('Maximum number of results to return.');
11
17
  const inputSchema = {
12
18
  absoluteCurrentWorkingDirectory,
13
19
  docsSearchQuery,
20
+ docsSearchLimit,
14
21
  };
15
22
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
23
  const inputSchemaZodObject = z.object({
@@ -18,12 +25,14 @@ const inputSchemaZodObject = z.object({
18
25
  });
19
26
  const toolName = 'search-docs';
20
27
  export class DocsSearchTool extends Tool {
21
- constructor(mcpServer) {
22
- super(mcpServer);
28
+ constructor(mcpServer, logger) {
29
+ super(mcpServer, logger, toolName);
23
30
  }
24
- async handler({ docsSearchQuery, absoluteCurrentWorkingDirectory, }) {
31
+ getTrackingMeta({ docsSearchQuery, }) {
32
+ return { mode: docsSearchQuery };
33
+ }
34
+ async handler({ docsSearchQuery, docsSearchLimit, absoluteCurrentWorkingDirectory, }) {
25
35
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
26
- await trackToolUsage(toolName, { mode: docsSearchQuery });
27
36
  const accountId = getConfigDefaultAccountIfExists()?.accountId;
28
37
  if (!accountId) {
29
38
  const authErrorMessage = `No account ID found. Please run \`hs account auth\` to configure an account, or set a default account with \`hs account use <account>\``;
@@ -40,13 +49,27 @@ export class DocsSearchTool extends Tool {
40
49
  if (!results || results.length === 0) {
41
50
  return formatTextContents('No documentation found for your query.');
42
51
  }
43
- const formattedResults = results
52
+ // The docs-search API returns duplicate URLs; dedupe to avoid wasting the result limit on repeats
53
+ const seen = new Set();
54
+ const dedupedResults = results.filter(result => {
55
+ if (seen.has(result.url)) {
56
+ return false;
57
+ }
58
+ seen.add(result.url);
59
+ return true;
60
+ });
61
+ const limitedResults = dedupedResults.slice(0, docsSearchLimit);
62
+ const formattedResults = limitedResults
44
63
  .map(result => `**${result.title}**\n${result.description}\nURL: ${result.url}\nScore: ${result.score}\n\n${result.content}\n---\n`)
45
64
  .join('\n');
46
- const successMessage = `Found ${results.length} documentation results:\n\n${formattedResults}`;
65
+ const successMessage = `Found ${dedupedResults.length} results, showing top ${limitedResults.length}:\n\n${formattedResults}`;
47
66
  return formatTextContents(successMessage);
48
67
  }
49
68
  catch (error) {
69
+ this.logger.debug(toolName, {
70
+ message: 'Handler caught error',
71
+ error: error instanceof Error ? error.message : String(error),
72
+ });
50
73
  if (isHubSpotHttpError(error)) {
51
74
  // Handle different status codes
52
75
  return formatTextContents(error.toString());
@@ -64,6 +87,6 @@ export class DocsSearchTool extends Tool {
64
87
  readOnlyHint: true,
65
88
  openWorldHint: true,
66
89
  },
67
- }, this.handler);
90
+ }, input => this.wrappedHandler(input));
68
91
  }
69
92
  }
@@ -1,5 +1,7 @@
1
- import { TextContentResponse, Tool } from '../../types.js';
1
+ import { TextContentResponse } from '../../types.js';
2
+ import { Tool } from '../../Tool.js';
2
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { McpLogger } from '../../utils/logger.js';
3
5
  import { z } from 'zod';
4
6
  declare const inputSchemaZodObject: z.ZodObject<{
5
7
  absoluteCurrentWorkingDirectory: z.ZodString;
@@ -9,7 +11,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
9
11
  }, z.core.$strip>;
10
12
  export type GetApiUsagePatternsByAppIdInputSchema = z.infer<typeof inputSchemaZodObject>;
11
13
  export declare class GetApiUsagePatternsByAppIdTool extends Tool<GetApiUsagePatternsByAppIdInputSchema> {
12
- constructor(mcpServer: McpServer);
14
+ constructor(mcpServer: McpServer, logger: McpLogger);
13
15
  handler({ appId, startDate, endDate, absoluteCurrentWorkingDirectory, }: GetApiUsagePatternsByAppIdInputSchema): Promise<TextContentResponse>;
14
16
  register(): RegisteredTool;
15
17
  }
@@ -1,6 +1,5 @@
1
- import { Tool } from '../../types.js';
1
+ import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
- import { trackToolUsage } from '../../utils/toolUsageTracking.js';
4
3
  import { http } from '@hubspot/local-dev-lib/http';
5
4
  import { formatTextContents } from '../../utils/content.js';
6
5
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
@@ -26,12 +25,11 @@ const inputSchema = {
26
25
  const inputSchemaZodObject = z.object({ ...inputSchema });
27
26
  const toolName = 'get-api-usage-patterns-by-app-id';
28
27
  export class GetApiUsagePatternsByAppIdTool extends Tool {
29
- constructor(mcpServer) {
30
- super(mcpServer);
28
+ constructor(mcpServer, logger) {
29
+ super(mcpServer, logger, toolName);
31
30
  }
32
31
  async handler({ appId, startDate, endDate, absoluteCurrentWorkingDirectory, }) {
33
32
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
34
- await trackToolUsage(toolName);
35
33
  try {
36
34
  // Get account ID from CLI config
37
35
  const accountId = getConfigDefaultAccountIfExists()?.accountId;
@@ -52,6 +50,10 @@ export class GetApiUsagePatternsByAppIdTool extends Tool {
52
50
  return formatTextContents(formattedResult);
53
51
  }
54
52
  catch (error) {
53
+ this.logger.debug(toolName, {
54
+ message: 'Handler caught error',
55
+ error: error instanceof Error ? error.message : String(error),
56
+ });
55
57
  if (isHubSpotHttpError(error)) {
56
58
  // Handle HubSpot-specific HTTP errors
57
59
  return formatTextContents(error.toString());
@@ -68,6 +70,6 @@ export class GetApiUsagePatternsByAppIdTool extends Tool {
68
70
  readOnlyHint: true,
69
71
  openWorldHint: true,
70
72
  },
71
- }, this.handler);
73
+ }, input => this.wrappedHandler(input));
72
74
  }
73
75
  }
@@ -1,12 +1,14 @@
1
- import { TextContentResponse, Tool } from '../../types.js';
1
+ import { TextContentResponse } from '../../types.js';
2
+ import { Tool } from '../../Tool.js';
2
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { McpLogger } from '../../utils/logger.js';
3
5
  import { z } from 'zod';
4
6
  declare const inputSchemaZodObject: z.ZodObject<{
5
7
  absoluteCurrentWorkingDirectory: z.ZodString;
6
8
  }, z.core.$strip>;
7
9
  export type GetApplicationInfoInputSchema = z.infer<typeof inputSchemaZodObject>;
8
10
  export declare class GetApplicationInfoTool extends Tool<GetApplicationInfoInputSchema> {
9
- constructor(mcpServer: McpServer);
11
+ constructor(mcpServer: McpServer, logger: McpLogger);
10
12
  handler({ absoluteCurrentWorkingDirectory, }: GetApplicationInfoInputSchema): Promise<TextContentResponse>;
11
13
  register(): RegisteredTool;
12
14
  }
@@ -1,6 +1,5 @@
1
- import { Tool } from '../../types.js';
1
+ import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
- import { trackToolUsage } from '../../utils/toolUsageTracking.js';
4
3
  import { http } from '@hubspot/local-dev-lib/http';
5
4
  import { formatTextContents } from '../../utils/content.js';
6
5
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
@@ -13,12 +12,11 @@ const inputSchema = { absoluteCurrentWorkingDirectory };
13
12
  const inputSchemaZodObject = z.object({ ...inputSchema });
14
13
  const toolName = 'get-apps-info';
15
14
  export class GetApplicationInfoTool extends Tool {
16
- constructor(mcpServer) {
17
- super(mcpServer);
15
+ constructor(mcpServer, logger) {
16
+ super(mcpServer, logger, toolName);
18
17
  }
19
18
  async handler({ absoluteCurrentWorkingDirectory, }) {
20
19
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
21
- await trackToolUsage(toolName);
22
20
  try {
23
21
  // Get account ID from CLI config
24
22
  const accountId = getConfigDefaultAccountIfExists()?.accountId;
@@ -35,6 +33,10 @@ export class GetApplicationInfoTool extends Tool {
35
33
  return formatTextContents(formattedResult);
36
34
  }
37
35
  catch (error) {
36
+ this.logger.debug(toolName, {
37
+ message: 'Handler caught error',
38
+ error: error instanceof Error ? error.message : String(error),
39
+ });
38
40
  if (isHubSpotHttpError(error)) {
39
41
  // Handle HubSpot-specific HTTP errors
40
42
  return formatTextContents(error.toString());
@@ -51,6 +53,6 @@ export class GetApplicationInfoTool extends Tool {
51
53
  readOnlyHint: true,
52
54
  openWorldHint: true,
53
55
  },
54
- }, this.handler);
56
+ }, input => this.wrappedHandler(input));
55
57
  }
56
58
  }
@@ -1,5 +1,7 @@
1
- import { TextContentResponse, Tool } from '../../types.js';
1
+ import { TextContentResponse } from '../../types.js';
2
+ import { Tool } from '../../Tool.js';
2
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { McpLogger } from '../../utils/logger.js';
3
5
  import { z } from 'zod';
4
6
  declare const inputSchemaZodObject: z.ZodObject<{
5
7
  absoluteProjectPath: z.ZodString;
@@ -14,7 +16,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
14
16
  }, z.core.$strip>;
15
17
  export type GetBuildLogsInputSchema = z.infer<typeof inputSchemaZodObject>;
16
18
  export declare class GetBuildLogsTool extends Tool<GetBuildLogsInputSchema> {
17
- constructor(mcpServer: McpServer);
19
+ constructor(mcpServer: McpServer, logger: McpLogger);
18
20
  handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, logLevel, }: GetBuildLogsInputSchema): Promise<TextContentResponse>;
19
21
  register(): RegisteredTool;
20
22
  }
@@ -1,6 +1,5 @@
1
- import { Tool } from '../../types.js';
1
+ import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
- import { trackToolUsage } from '../../utils/toolUsageTracking.js';
4
3
  import { formatTextContents } from '../../utils/content.js';
5
4
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
6
5
  import { http } from '@hubspot/local-dev-lib/http';
@@ -59,12 +58,11 @@ function formatLogs(logs) {
59
58
  .join('\n');
60
59
  }
61
60
  export class GetBuildLogsTool extends Tool {
62
- constructor(mcpServer) {
63
- super(mcpServer);
61
+ constructor(mcpServer, logger) {
62
+ super(mcpServer, logger, TOOL_NAME);
64
63
  }
65
64
  async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, logLevel, }) {
66
65
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
67
- await trackToolUsage(TOOL_NAME);
68
66
  try {
69
67
  const accountId = getConfigDefaultAccountIfExists()?.accountId;
70
68
  if (!accountId) {
@@ -96,6 +94,10 @@ export class GetBuildLogsTool extends Tool {
96
94
  return formatTextContents(absoluteCurrentWorkingDirectory, output);
97
95
  }
98
96
  catch (error) {
97
+ this.logger.debug(TOOL_NAME, {
98
+ message: 'Handler caught error',
99
+ error: error instanceof Error ? error.message : String(error),
100
+ });
99
101
  let errorMessage;
100
102
  if (isHubSpotHttpError(error)) {
101
103
  errorMessage = error.toString();
@@ -119,6 +121,6 @@ export class GetBuildLogsTool extends Tool {
119
121
  openWorldHint: true,
120
122
  idempotentHint: true,
121
123
  },
122
- }, this.handler);
124
+ }, input => this.wrappedHandler(input));
123
125
  }
124
126
  }
@@ -1,5 +1,7 @@
1
- import { TextContentResponse, Tool } from '../../types.js';
1
+ import { TextContentResponse } from '../../types.js';
2
+ import { Tool } from '../../Tool.js';
2
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { McpLogger } from '../../utils/logger.js';
3
5
  import { z } from 'zod';
4
6
  declare const inputSchemaZodObject: z.ZodObject<{
5
7
  absoluteProjectPath: z.ZodString;
@@ -9,7 +11,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
9
11
  }, z.core.$strip>;
10
12
  export type GetBuildStatusInputSchema = z.infer<typeof inputSchemaZodObject>;
11
13
  export declare class GetBuildStatusTool extends Tool<GetBuildStatusInputSchema> {
12
- constructor(mcpServer: McpServer);
14
+ constructor(mcpServer: McpServer, logger: McpLogger);
13
15
  handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, limit, }: GetBuildStatusInputSchema): Promise<TextContentResponse>;
14
16
  register(): RegisteredTool;
15
17
  }
@@ -1,6 +1,5 @@
1
- import { Tool } from '../../types.js';
1
+ import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
- import { trackToolUsage } from '../../utils/toolUsageTracking.js';
4
3
  import { formatTextContents } from '../../utils/content.js';
5
4
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
6
5
  import { fetchProjectBuilds, getBuildStatus, } from '@hubspot/local-dev-lib/api/projects';
@@ -104,12 +103,11 @@ function formatBuildDetails(build) {
104
103
  return lines.join('\n');
105
104
  }
106
105
  export class GetBuildStatusTool extends Tool {
107
- constructor(mcpServer) {
108
- super(mcpServer);
106
+ constructor(mcpServer, logger) {
107
+ super(mcpServer, logger, TOOL_NAME);
109
108
  }
110
109
  async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, buildId, limit, }) {
111
110
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
112
- await trackToolUsage(TOOL_NAME);
113
111
  try {
114
112
  const accountId = getConfigDefaultAccountIfExists()?.accountId;
115
113
  if (!accountId) {
@@ -137,6 +135,10 @@ export class GetBuildStatusTool extends Tool {
137
135
  return formatTextContents(absoluteCurrentWorkingDirectory, output);
138
136
  }
139
137
  catch (error) {
138
+ this.logger.debug(TOOL_NAME, {
139
+ message: 'Handler caught error',
140
+ error: error instanceof Error ? error.message : String(error),
141
+ });
140
142
  let errorMessage;
141
143
  if (isHubSpotHttpError(error)) {
142
144
  errorMessage = error.toString();
@@ -160,6 +162,6 @@ export class GetBuildStatusTool extends Tool {
160
162
  openWorldHint: true,
161
163
  idempotentHint: true,
162
164
  },
163
- }, this.handler);
165
+ }, input => this.wrappedHandler(input));
164
166
  }
165
167
  }
@@ -1,5 +1,7 @@
1
- import { TextContentResponse, Tool } from '../../types.js';
1
+ import { TextContentResponse } from '../../types.js';
2
+ import { Tool } from '../../Tool.js';
2
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { McpLogger } from '../../utils/logger.js';
3
5
  import { z } from 'zod';
4
6
  declare const inputSchemaZodObject: z.ZodObject<{
5
7
  absoluteCurrentWorkingDirectory: z.ZodString;
@@ -8,7 +10,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
8
10
  }, z.core.$strip>;
9
11
  type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
10
12
  export declare class GetConfigValuesTool extends Tool<InputSchemaType> {
11
- constructor(mcpServer: McpServer);
13
+ constructor(mcpServer: McpServer, logger: McpLogger);
12
14
  handler({ platformVersion, featureType, absoluteCurrentWorkingDirectory, }: InputSchemaType): Promise<TextContentResponse>;
13
15
  register(): RegisteredTool;
14
16
  }
@@ -1,10 +1,10 @@
1
- import { Tool } from '../../types.js';
1
+ import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
3
  import { formatTextContents } from '../../utils/content.js';
4
4
  import { absoluteCurrentWorkingDirectory } from './constants.js';
5
5
  import { getIntermediateRepresentationSchema } from '@hubspot/project-parsing-lib/schema';
6
6
  import { mapToInternalType } from '@hubspot/project-parsing-lib/transform';
7
- import { isV2Project } from '../../../lib/projects/platformVersion.js';
7
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
8
8
  import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
9
9
  import { setupHubSpotConfig } from '../../utils/config.js';
10
10
  const inputSchema = {
@@ -22,13 +22,13 @@ const inputSchemaZodObject = z.object({
22
22
  });
23
23
  const toolName = 'get-feature-config-schema';
24
24
  export class GetConfigValuesTool extends Tool {
25
- constructor(mcpServer) {
26
- super(mcpServer);
25
+ constructor(mcpServer, logger) {
26
+ super(mcpServer, logger, toolName);
27
27
  }
28
28
  async handler({ platformVersion, featureType, absoluteCurrentWorkingDirectory, }) {
29
29
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
30
30
  try {
31
- if (!isV2Project(platformVersion)) {
31
+ if (isLegacyProject(platformVersion)) {
32
32
  return formatTextContents(`Can only be used on projects with a minimum platformVersion of 2025.2`);
33
33
  }
34
34
  const accountId = getConfigDefaultAccountIfExists()?.accountId;
@@ -46,7 +46,12 @@ export class GetConfigValuesTool extends Tool {
46
46
  return formatTextContents(JSON.stringify({ config: schema[internalComponentType] }));
47
47
  }
48
48
  }
49
- catch (error) { }
49
+ catch (error) {
50
+ this.logger.debug(toolName, {
51
+ message: 'Handler caught error',
52
+ error: error instanceof Error ? error.message : String(error),
53
+ });
54
+ }
50
55
  return formatTextContents(`Unable to locate JSON schema for type ${featureType}`);
51
56
  }
52
57
  register() {
@@ -60,6 +65,6 @@ export class GetConfigValuesTool extends Tool {
60
65
  readOnlyHint: true,
61
66
  openWorldHint: false,
62
67
  },
63
- }, this.handler);
68
+ }, input => this.wrappedHandler(input));
64
69
  }
65
70
  }
@@ -1,5 +1,7 @@
1
- import { TextContentResponse, Tool } from '../../types.js';
1
+ import { TextContentResponse } from '../../types.js';
2
+ import { Tool } from '../../Tool.js';
2
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { McpLogger } from '../../utils/logger.js';
3
5
  import { z } from 'zod';
4
6
  declare const inputSchemaZodObject: z.ZodObject<{
5
7
  absoluteCurrentWorkingDirectory: z.ZodString;
@@ -12,7 +14,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
12
14
  }, z.core.$strip>;
13
15
  type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
14
16
  export declare class GuidedWalkthroughTool extends Tool<InputSchemaType> {
15
- constructor(mcpServer: McpServer);
17
+ constructor(mcpServer: McpServer, logger: McpLogger);
16
18
  handler({ command, absoluteCurrentWorkingDirectory, }: InputSchemaType): Promise<TextContentResponse>;
17
19
  register(): RegisteredTool;
18
20
  }
@@ -1,8 +1,7 @@
1
- import { Tool } from '../../types.js';
1
+ import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
3
  import { execAsync } from '../../utils/command.js';
4
4
  import { formatTextContents } from '../../utils/content.js';
5
- import { trackToolUsage } from '../../utils/toolUsageTracking.js';
6
5
  import { absoluteCurrentWorkingDirectory } from './constants.js';
7
6
  import { setupHubSpotConfig } from '../../utils/config.js';
8
7
  const nextCommands = {
@@ -24,12 +23,11 @@ const inputSchemaZodObject = z.object({
24
23
  });
25
24
  const toolName = 'guided-walkthrough-cli';
26
25
  export class GuidedWalkthroughTool extends Tool {
27
- constructor(mcpServer) {
28
- super(mcpServer);
26
+ constructor(mcpServer, logger) {
27
+ super(mcpServer, logger, toolName);
29
28
  }
30
29
  async handler({ command, absoluteCurrentWorkingDirectory, }) {
31
30
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
32
- await trackToolUsage(toolName);
33
31
  if (command) {
34
32
  const { stdout } = await execAsync(`${command} --help`);
35
33
  return formatTextContents(`Display this help output for the user amd wait for them to acknowledge: ${stdout}. ${nextCommands[command] ? `Once they are ready, A good command to look at next is ${nextCommands[command]}` : ''}`);
@@ -45,6 +43,6 @@ export class GuidedWalkthroughTool extends Tool {
45
43
  readOnlyHint: true,
46
44
  openWorldHint: false,
47
45
  },
48
- }, this.handler);
46
+ }, input => this.wrappedHandler(input));
49
47
  }
50
48
  }
@@ -1,6 +1,8 @@
1
1
  import z from 'zod';
2
2
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import { TextContentResponse, Tool } from '../../types.js';
3
+ import { McpLogger } from '../../utils/logger.js';
4
+ import { TextContentResponse } from '../../types.js';
5
+ import { Tool } from '../../Tool.js';
4
6
  declare const inputSchemaZodObject: z.ZodObject<{
5
7
  absoluteProjectPath: z.ZodString;
6
8
  absoluteCurrentWorkingDirectory: z.ZodString;
@@ -9,7 +11,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
9
11
  }, z.z.core.$strip>;
10
12
  type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
11
13
  export declare class UploadProjectTools extends Tool<InputSchemaType> {
12
- constructor(mcpServer: McpServer);
14
+ constructor(mcpServer: McpServer, logger: McpLogger);
13
15
  handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, profile, uploadMessage, }: InputSchemaType): Promise<TextContentResponse>;
14
16
  register(): RegisteredTool;
15
17
  }
@@ -2,11 +2,10 @@ import path from 'path';
2
2
  import z from 'zod';
3
3
  import { getAllHsProfiles } from '@hubspot/project-parsing-lib/profiles';
4
4
  import { getProjectConfig } from '../../../lib/projects/config.js';
5
- import { Tool } from '../../types.js';
5
+ import { Tool } from '../../Tool.js';
6
6
  import { runCommandInDir } from '../../utils/command.js';
7
7
  import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constants.js';
8
8
  import { formatTextContent, formatTextContents } from '../../utils/content.js';
9
- import { trackToolUsage } from '../../utils/toolUsageTracking.js';
10
9
  import { addFlag } from '../../utils/command.js';
11
10
  import { setupHubSpotConfig } from '../../utils/config.js';
12
11
  const inputSchema = {
@@ -17,7 +16,7 @@ const inputSchema = {
17
16
  .describe('A 1 sentence message that concisely describes the changes that are being uploaded.'),
18
17
  profile: z
19
18
  .optional(z.string())
20
- .describe('CRITICAL: If the user has not explicitly specified a profile name, you MUST ask them which profile to use. NEVER automatically choose a profile based on files you see in the directory (e.g., seeing "hsprofile.prod.json" does NOT mean you should use "prod"). The profile to be used for the upload. All projects configured to use profiles must specify a profile when uploading. Profile files have the following format: "hsprofile.<profile>.json".'),
19
+ .describe('The profile to use for the upload. Only required for projects configured with profiles. If the project uses profiles and the user has not specified one, ask them rather than inferring from filenames in the directory. NEVER automatically choose a profile based on files you see. Profile files have the format: "hsprofile.<profile>.json".'),
21
20
  };
22
21
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
23
22
  const inputSchemaZodObject = z.object({
@@ -25,12 +24,11 @@ const inputSchemaZodObject = z.object({
25
24
  });
26
25
  const toolName = 'upload-project';
27
26
  export class UploadProjectTools extends Tool {
28
- constructor(mcpServer) {
29
- super(mcpServer);
27
+ constructor(mcpServer, logger) {
28
+ super(mcpServer, logger, toolName);
30
29
  }
31
30
  async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, profile, uploadMessage, }) {
32
31
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
33
- await trackToolUsage(toolName);
34
32
  let command = addFlag('hs project upload', 'force-create', true);
35
33
  const content = [];
36
34
  if (uploadMessage) {
@@ -49,6 +47,10 @@ export class UploadProjectTools extends Tool {
49
47
  }
50
48
  }
51
49
  catch (e) {
50
+ this.logger.debug(toolName, {
51
+ message: 'Handler caught error checking for profiles',
52
+ error: e instanceof Error ? e.message : String(e),
53
+ });
52
54
  // If any of these checks fail, the safest thing to do is to assume there are no profiles.
53
55
  hasProfiles = false;
54
56
  }
@@ -78,6 +80,6 @@ export class UploadProjectTools extends Tool {
78
80
  idempotentHint: true,
79
81
  openWorldHint: true,
80
82
  },
81
- }, this.handler);
83
+ }, input => this.wrappedHandler(input));
82
84
  }
83
85
  }
@@ -1,5 +1,7 @@
1
- import { TextContentResponse, Tool } from '../../types.js';
1
+ import { TextContentResponse } from '../../types.js';
2
+ import { Tool } from '../../Tool.js';
2
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { McpLogger } from '../../utils/logger.js';
3
5
  import { z } from 'zod';
4
6
  declare const inputSchemaZodObject: z.ZodObject<{
5
7
  absoluteProjectPath: z.ZodString;
@@ -7,7 +9,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
7
9
  }, z.core.$strip>;
8
10
  export type CreateProjectInputSchema = z.infer<typeof inputSchemaZodObject>;
9
11
  export declare class ValidateProjectTool extends Tool<CreateProjectInputSchema> {
10
- constructor(mcpServer: McpServer);
12
+ constructor(mcpServer: McpServer, logger: McpLogger);
11
13
  handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, }: CreateProjectInputSchema): Promise<TextContentResponse>;
12
14
  register(): RegisteredTool;
13
15
  }
@@ -1,9 +1,8 @@
1
- import { Tool } from '../../types.js';
1
+ import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
3
  import { absoluteCurrentWorkingDirectory, absoluteProjectPath, } from './constants.js';
4
4
  import { runCommandInDir } from '../../utils/command.js';
5
5
  import { formatTextContents } from '../../utils/content.js';
6
- import { trackToolUsage } from '../../utils/toolUsageTracking.js';
7
6
  import { setupHubSpotConfig } from '../../utils/config.js';
8
7
  import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
9
8
  const inputSchema = {
@@ -14,17 +13,20 @@ const inputSchema = {
14
13
  const inputSchemaZodObject = z.object({ ...inputSchema });
15
14
  const toolName = 'validate-project';
16
15
  export class ValidateProjectTool extends Tool {
17
- constructor(mcpServer) {
18
- super(mcpServer);
16
+ constructor(mcpServer, logger) {
17
+ super(mcpServer, logger, toolName);
19
18
  }
20
19
  async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, }) {
21
20
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
22
- await trackToolUsage(toolName);
23
21
  try {
24
22
  const { stdout, stderr } = await runCommandInDir(absoluteProjectPath, 'hs project validate');
25
23
  return formatTextContents(stdout, stderr);
26
24
  }
27
25
  catch (error) {
26
+ this.logger.debug(toolName, {
27
+ message: 'Handler caught error',
28
+ error: error instanceof Error ? error.message : String(error),
29
+ });
28
30
  return formatTextContents(getErrorMessage(error));
29
31
  }
30
32
  }
@@ -37,6 +39,6 @@ export class ValidateProjectTool extends Tool {
37
39
  readOnlyHint: true,
38
40
  openWorldHint: false,
39
41
  },
40
- }, this.handler);
42
+ }, input => this.wrappedHandler(input));
41
43
  }
42
44
  }
@@ -8,11 +8,11 @@ export declare const features: z.ZodOptional<z.ZodArray<z.ZodEnum<{
8
8
  "workflow-action-tool": "workflow-action-tool";
9
9
  page: "page";
10
10
  webhooks: "webhooks";
11
- "workflow-action": "workflow-action";
12
11
  "app-function": "app-function";
13
- "app-function-endpoint": "app-function-endpoint";
14
12
  "app-object": "app-object";
15
13
  scim: "scim";
14
+ "workflow-action": "workflow-action";
15
+ "app-function-endpoint": "app-function-endpoint";
16
16
  }>>>;
17
17
  export declare const docsSearchQuery: z.ZodString;
18
18
  export declare const docUrl: z.ZodString;
@@ -1,10 +1,3 @@
1
- import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- export declare class Tool<InputSchema, ResponseType = TextContentResponse> {
3
- protected mcpServer: McpServer;
4
- constructor(mcpServer: McpServer);
5
- register(): RegisteredTool;
6
- handler(input: InputSchema): ResponseType | Promise<ResponseType>;
7
- }
8
1
  export type TextContent = {
9
2
  type: 'text';
10
3
  text: string;
@@ -1,13 +1 @@
1
- export class Tool {
2
- mcpServer;
3
- constructor(mcpServer) {
4
- this.mcpServer = mcpServer;
5
- }
6
- register() {
7
- throw new Error('Must implement register');
8
- }
9
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
10
- handler(input) {
11
- throw new Error('Must implement handler');
12
- }
13
- }
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare class McpLogger {
3
+ private mcpServer;
4
+ constructor(mcpServer: McpServer);
5
+ private log;
6
+ debug(logger: string, data: unknown): void;
7
+ info(logger: string, data: unknown): void;
8
+ warn(logger: string, data: unknown): void;
9
+ error(logger: string, data: unknown): void;
10
+ }