@hubspot/cli 8.10.0 → 8.11.0-beta.0

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 (61) hide show
  1. package/commands/hubdb/list.d.ts +1 -1
  2. package/commands/mcp/setup.d.ts +2 -0
  3. package/commands/mcp/setup.js +29 -1
  4. package/commands/project/appInstallStatus.d.ts +1 -1
  5. package/commands/project/info.d.ts +1 -1
  6. package/commands/project/installApp.d.ts +1 -1
  7. package/commands/project/profile/add.d.ts +2 -1
  8. package/commands/project/profile/add.js +22 -1
  9. package/commands/project/profile/delete.d.ts +1 -1
  10. package/commands/project/upload.js +4 -1
  11. package/commands/project/validate.d.ts +1 -1
  12. package/commands/testAccount/importData.d.ts +1 -1
  13. package/lang/en.d.ts +11 -0
  14. package/lang/en.js +11 -0
  15. package/lib/mcp/setup.d.ts +6 -1
  16. package/lib/mcp/setup.js +29 -18
  17. package/lib/projects/upload.d.ts +1 -1
  18. package/lib/projects/upload.js +4 -8
  19. package/mcp-server/Tool.d.ts +8 -3
  20. package/mcp-server/Tool.js +28 -8
  21. package/mcp-server/server.js +10 -6
  22. package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +2 -2
  23. package/mcp-server/tools/cms/HsCreateFunctionTool.js +10 -17
  24. package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +2 -2
  25. package/mcp-server/tools/cms/HsCreateModuleTool.js +12 -18
  26. package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +2 -2
  27. package/mcp-server/tools/cms/HsCreateTemplateTool.js +8 -10
  28. package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +2 -2
  29. package/mcp-server/tools/cms/HsFunctionLogsTool.js +9 -9
  30. package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +2 -2
  31. package/mcp-server/tools/cms/HsListFunctionsTool.js +7 -7
  32. package/mcp-server/tools/cms/HsListTool.d.ts +2 -2
  33. package/mcp-server/tools/cms/HsListTool.js +6 -10
  34. package/mcp-server/tools/index.js +2 -0
  35. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +2 -2
  36. package/mcp-server/tools/project/AddFeatureToProjectTool.js +8 -9
  37. package/mcp-server/tools/project/AuthAccountTool.d.ts +18 -0
  38. package/mcp-server/tools/project/AuthAccountTool.js +78 -0
  39. package/mcp-server/tools/project/CreateProjectTool.d.ts +2 -2
  40. package/mcp-server/tools/project/CreateProjectTool.js +13 -12
  41. package/mcp-server/tools/project/CreateTestAccountTool.d.ts +2 -2
  42. package/mcp-server/tools/project/CreateTestAccountTool.js +14 -15
  43. package/mcp-server/tools/project/DeployProjectTool.d.ts +2 -2
  44. package/mcp-server/tools/project/DeployProjectTool.js +10 -10
  45. package/mcp-server/tools/project/DocFetchTool.js +1 -1
  46. package/mcp-server/tools/project/DocsSearchTool.js +9 -3
  47. package/mcp-server/tools/project/FindProjectsTool.js +1 -1
  48. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +9 -4
  49. package/mcp-server/tools/project/GetApplicationInfoTool.js +9 -4
  50. package/mcp-server/tools/project/GetBuildLogsTool.js +9 -3
  51. package/mcp-server/tools/project/GetBuildStatusTool.js +9 -3
  52. package/mcp-server/tools/project/GetConfigValuesTool.js +9 -3
  53. package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -1
  54. package/mcp-server/tools/project/UploadProjectTools.d.ts +2 -2
  55. package/mcp-server/tools/project/UploadProjectTools.js +9 -8
  56. package/mcp-server/tools/project/ValidateProjectTool.d.ts +2 -2
  57. package/mcp-server/tools/project/ValidateProjectTool.js +5 -4
  58. package/mcp-server/utils/command.d.ts +25 -2
  59. package/mcp-server/utils/command.js +67 -17
  60. package/mcp-server/utils/toolUsageTracking.js +8 -1
  61. package/package.json +3 -3
@@ -1,9 +1,9 @@
1
1
  import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
3
  import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
4
- import { addFlag, runCommandInDir } from '../../utils/command.js';
5
4
  import { formatTextContent, formatTextContents } from '../../utils/content.js';
6
5
  import { CONTENT_TYPES } from '../../../types/Cms.js';
6
+ import { HubSpotCommand } from '../../utils/command.js';
7
7
  import { setupHubSpotConfig } from '../../utils/config.js';
8
8
  import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
9
9
  const inputSchema = {
@@ -52,7 +52,7 @@ export class HsCreateModuleTool extends Tool {
52
52
  constructor(mcpServer, logger) {
53
53
  super(mcpServer, logger, toolName);
54
54
  }
55
- async handler({ userSuppliedName, dest, moduleLabel, reactType, contentTypes, global, availableForNewContent, absoluteCurrentWorkingDirectory, }) {
55
+ async handler({ userSuppliedName, dest, moduleLabel, reactType, contentTypes, global, availableForNewContent, absoluteCurrentWorkingDirectory, }, extra) {
56
56
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
57
57
  const content = [];
58
58
  // Always require a name
@@ -74,34 +74,28 @@ export class HsCreateModuleTool extends Tool {
74
74
  };
75
75
  }
76
76
  // Build the command
77
- let command = 'hs cms module create';
77
+ const command = new HubSpotCommand('cms module create');
78
78
  if (userSuppliedName) {
79
- command += ` "${userSuppliedName}"`;
79
+ command.addArg(userSuppliedName);
80
80
  }
81
81
  if (dest) {
82
- command += ` "${dest}"`;
82
+ command.addArg(dest);
83
83
  }
84
- // Add module-specific flags
85
84
  if (moduleLabel) {
86
- command = addFlag(command, 'module-label', moduleLabel);
85
+ command.addFlag('module-label', moduleLabel);
87
86
  }
88
87
  if (reactType !== undefined) {
89
- command = addFlag(command, 'react-type', reactType);
90
- }
91
- if (contentTypes) {
92
- command = addFlag(command, 'content-types', contentTypes);
93
- }
94
- else {
95
- command = addFlag(command, 'content-types', 'ANY');
88
+ command.addFlag('react-type', reactType);
96
89
  }
90
+ command.addFlag('content-types', contentTypes ?? 'ANY');
97
91
  if (global !== undefined) {
98
- command = addFlag(command, 'global', global);
92
+ command.addFlag('global', global);
99
93
  }
100
94
  if (availableForNewContent !== undefined) {
101
- command = addFlag(command, 'available-for-new-content', availableForNewContent);
95
+ command.addFlag('available-for-new-content', availableForNewContent);
102
96
  }
103
97
  try {
104
- const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
98
+ const { stdout, stderr } = await this.runCommand(absoluteCurrentWorkingDirectory, command, extra);
105
99
  return formatTextContents(stdout, stderr);
106
100
  }
107
101
  catch (error) {
@@ -123,6 +117,6 @@ export class HsCreateModuleTool extends Tool {
123
117
  idempotentHint: false,
124
118
  openWorldHint: false,
125
119
  },
126
- }, input => this.wrappedHandler(input));
120
+ }, (input, extra) => this.wrappedHandler(input, extra));
127
121
  }
128
122
  }
@@ -1,5 +1,5 @@
1
1
  import { TextContentResponse } from '../../types.js';
2
- import { Tool } from '../../Tool.js';
2
+ import { Tool, ToolExtra } from '../../Tool.js';
3
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { McpLogger } from '../../utils/logger.js';
5
5
  import { z } from 'zod';
@@ -21,7 +21,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
21
21
  export type HsCreateTemplateInputSchema = z.infer<typeof inputSchemaZodObject>;
22
22
  export declare class HsCreateTemplateTool extends Tool<HsCreateTemplateInputSchema> {
23
23
  constructor(mcpServer: McpServer, logger: McpLogger);
24
- handler({ userSuppliedName, dest, templateType, absoluteCurrentWorkingDirectory, }: HsCreateTemplateInputSchema): Promise<TextContentResponse>;
24
+ handler({ userSuppliedName, dest, templateType, absoluteCurrentWorkingDirectory, }: HsCreateTemplateInputSchema, extra?: ToolExtra): Promise<TextContentResponse>;
25
25
  register(): RegisteredTool;
26
26
  }
27
27
  export {};
@@ -1,10 +1,9 @@
1
1
  import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
3
  import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
4
- import { runCommandInDir } from '../../utils/command.js';
5
4
  import { formatTextContents, formatTextContent } from '../../utils/content.js';
6
- import { addFlag } from '../../utils/command.js';
7
5
  import { TEMPLATE_TYPES } from '../../../types/Cms.js';
6
+ import { HubSpotCommand } from '../../utils/command.js';
8
7
  import { setupHubSpotConfig } from '../../utils/config.js';
9
8
  import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
10
9
  const inputSchema = {
@@ -29,7 +28,7 @@ export class HsCreateTemplateTool extends Tool {
29
28
  constructor(mcpServer, logger) {
30
29
  super(mcpServer, logger, toolName);
31
30
  }
32
- async handler({ userSuppliedName, dest, templateType, absoluteCurrentWorkingDirectory, }) {
31
+ async handler({ userSuppliedName, dest, templateType, absoluteCurrentWorkingDirectory, }, extra) {
33
32
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
34
33
  const content = [];
35
34
  // Always require a name
@@ -47,19 +46,18 @@ export class HsCreateTemplateTool extends Tool {
47
46
  };
48
47
  }
49
48
  // Build the command
50
- let command = 'hs cms template create';
49
+ const command = new HubSpotCommand('cms template create');
51
50
  if (userSuppliedName) {
52
- command += ` "${userSuppliedName}"`;
51
+ command.addArg(userSuppliedName);
53
52
  }
54
53
  if (dest) {
55
- command += ` "${dest}"`;
54
+ command.addArg(dest);
56
55
  }
57
- // Add template type flag
58
56
  if (templateType) {
59
- command = addFlag(command, 'template-type', templateType);
57
+ command.addFlag('template-type', templateType);
60
58
  }
61
59
  try {
62
- const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
60
+ const { stdout, stderr } = await this.runCommand(absoluteCurrentWorkingDirectory, command, extra);
63
61
  return formatTextContents(stdout, stderr);
64
62
  }
65
63
  catch (error) {
@@ -81,6 +79,6 @@ export class HsCreateTemplateTool extends Tool {
81
79
  idempotentHint: false,
82
80
  openWorldHint: false,
83
81
  },
84
- }, input => this.wrappedHandler(input));
82
+ }, (input, extra) => this.wrappedHandler(input, extra));
85
83
  }
86
84
  }
@@ -1,5 +1,5 @@
1
1
  import { TextContentResponse } from '../../types.js';
2
- import { Tool } from '../../Tool.js';
2
+ import { Tool, ToolExtra } from '../../Tool.js';
3
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { McpLogger } from '../../utils/logger.js';
5
5
  import { z } from 'zod';
@@ -14,7 +14,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
14
14
  export type HsFunctionLogsInputSchema = z.infer<typeof inputSchemaZodObject>;
15
15
  export declare class HsFunctionLogsTool extends Tool<HsFunctionLogsInputSchema> {
16
16
  constructor(mcpServer: McpServer, logger: McpLogger);
17
- handler({ endpoint, account, latest, compact, limit, absoluteCurrentWorkingDirectory, }: HsFunctionLogsInputSchema): Promise<TextContentResponse>;
17
+ handler({ endpoint, account, latest, compact, limit, absoluteCurrentWorkingDirectory, }: HsFunctionLogsInputSchema, extra?: ToolExtra): Promise<TextContentResponse>;
18
18
  register(): RegisteredTool;
19
19
  }
20
20
  export {};
@@ -1,6 +1,6 @@
1
1
  import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
- import { addFlag, runCommandInDir } from '../../utils/command.js';
3
+ import { HubSpotCommand } from '../../utils/command.js';
4
4
  import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
5
5
  import { formatTextContents } from '../../utils/content.js';
6
6
  import { setupHubSpotConfig } from '../../utils/config.js';
@@ -31,27 +31,27 @@ export class HsFunctionLogsTool extends Tool {
31
31
  constructor(mcpServer, logger) {
32
32
  super(mcpServer, logger, toolName);
33
33
  }
34
- async handler({ endpoint, account, latest, compact, limit, absoluteCurrentWorkingDirectory, }) {
34
+ async handler({ endpoint, account, latest, compact, limit, absoluteCurrentWorkingDirectory, }, extra) {
35
35
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
36
36
  // Ensure endpoint doesn't start with '/'
37
37
  const normalizedEndpoint = endpoint.startsWith('/')
38
38
  ? endpoint.slice(1)
39
39
  : endpoint;
40
- let command = `hs cms function logs ${normalizedEndpoint}`;
40
+ const command = new HubSpotCommand(`cms function logs ${normalizedEndpoint}`);
41
41
  if (latest) {
42
- command = addFlag(command, 'latest', latest);
42
+ command.addFlag('latest', latest);
43
43
  }
44
44
  if (compact) {
45
- command = addFlag(command, 'compact', compact);
45
+ command.addFlag('compact', compact);
46
46
  }
47
47
  if (limit) {
48
- command = addFlag(command, 'limit', limit);
48
+ command.addFlag('limit', limit);
49
49
  }
50
50
  if (account) {
51
- command = addFlag(command, 'account', account);
51
+ command.addFlag('account', account);
52
52
  }
53
53
  try {
54
- const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
54
+ const { stdout, stderr } = await this.runCommand(absoluteCurrentWorkingDirectory, command, extra);
55
55
  return formatTextContents(stdout, stderr);
56
56
  }
57
57
  catch (error) {
@@ -71,6 +71,6 @@ export class HsFunctionLogsTool extends Tool {
71
71
  readOnlyHint: true,
72
72
  openWorldHint: true,
73
73
  },
74
- }, input => this.wrappedHandler(input));
74
+ }, (input, extra) => this.wrappedHandler(input, extra));
75
75
  }
76
76
  }
@@ -1,5 +1,5 @@
1
1
  import { TextContentResponse } from '../../types.js';
2
- import { Tool } from '../../Tool.js';
2
+ import { Tool, ToolExtra } from '../../Tool.js';
3
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { McpLogger } from '../../utils/logger.js';
5
5
  import { z } from 'zod';
@@ -11,7 +11,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
11
11
  export type HsListFunctionsInputSchema = z.infer<typeof inputSchemaZodObject>;
12
12
  export declare class HsListFunctionsTool extends Tool<HsListFunctionsInputSchema> {
13
13
  constructor(mcpServer: McpServer, logger: McpLogger);
14
- handler({ account, json, absoluteCurrentWorkingDirectory, }: HsListFunctionsInputSchema): Promise<TextContentResponse>;
14
+ handler({ account, json, absoluteCurrentWorkingDirectory, }: HsListFunctionsInputSchema, extra?: ToolExtra): Promise<TextContentResponse>;
15
15
  register(): RegisteredTool;
16
16
  }
17
17
  export {};
@@ -1,6 +1,6 @@
1
1
  import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
- import { addFlag, runCommandInDir } from '../../utils/command.js';
3
+ import { HubSpotCommand } from '../../utils/command.js';
4
4
  import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
5
5
  import { formatTextContents } from '../../utils/content.js';
6
6
  import { setupHubSpotConfig } from '../../utils/config.js';
@@ -23,17 +23,17 @@ export class HsListFunctionsTool extends Tool {
23
23
  constructor(mcpServer, logger) {
24
24
  super(mcpServer, logger, toolName);
25
25
  }
26
- async handler({ account, json, absoluteCurrentWorkingDirectory, }) {
26
+ async handler({ account, json, absoluteCurrentWorkingDirectory, }, extra) {
27
27
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
28
- let command = 'hs cms function list';
28
+ const command = new HubSpotCommand('cms function list');
29
29
  if (json) {
30
- command += ' --json';
30
+ command.addFlag('json', true);
31
31
  }
32
32
  if (account) {
33
- command = addFlag(command, 'account', account);
33
+ command.addFlag('account', account);
34
34
  }
35
35
  try {
36
- const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
36
+ const { stdout, stderr } = await this.runCommand(absoluteCurrentWorkingDirectory, command, extra);
37
37
  return formatTextContents(stdout, stderr);
38
38
  }
39
39
  catch (error) {
@@ -60,6 +60,6 @@ export class HsListFunctionsTool extends Tool {
60
60
  readOnlyHint: true,
61
61
  openWorldHint: true,
62
62
  },
63
- }, input => this.wrappedHandler(input));
63
+ }, (input, extra) => this.wrappedHandler(input, extra));
64
64
  }
65
65
  }
@@ -1,5 +1,5 @@
1
1
  import { TextContentResponse } from '../../types.js';
2
- import { Tool } from '../../Tool.js';
2
+ import { Tool, ToolExtra } from '../../Tool.js';
3
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { McpLogger } from '../../utils/logger.js';
5
5
  import { z } from 'zod';
@@ -11,7 +11,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
11
11
  export type HsListInputSchema = z.infer<typeof inputSchemaZodObject>;
12
12
  export declare class HsListTool extends Tool<HsListInputSchema> {
13
13
  constructor(mcpServer: McpServer, logger: McpLogger);
14
- handler({ path, account, absoluteCurrentWorkingDirectory, }: HsListInputSchema): Promise<TextContentResponse>;
14
+ handler({ path, account, absoluteCurrentWorkingDirectory }: HsListInputSchema, extra?: ToolExtra): Promise<TextContentResponse>;
15
15
  register(): RegisteredTool;
16
16
  }
17
17
  export {};
@@ -1,8 +1,7 @@
1
1
  import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
- import { addFlag } from '../../utils/command.js';
3
+ import { HubSpotCommand } from '../../utils/command.js';
4
4
  import { absoluteCurrentWorkingDirectory } from '../project/constants.js';
5
- import { runCommandInDir } from '../../utils/command.js';
6
5
  import { formatTextContents } from '../../utils/content.js';
7
6
  import { setupHubSpotConfig } from '../../utils/config.js';
8
7
  import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
@@ -24,17 +23,14 @@ export class HsListTool extends Tool {
24
23
  constructor(mcpServer, logger) {
25
24
  super(mcpServer, logger, toolName);
26
25
  }
27
- async handler({ path, account, absoluteCurrentWorkingDirectory, }) {
26
+ async handler({ path, account, absoluteCurrentWorkingDirectory }, extra) {
28
27
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
29
- let command = 'hs cms list';
30
- if (path) {
31
- command += ` ${path}`;
32
- }
28
+ const command = new HubSpotCommand(path ? `cms list ${path}` : 'cms list');
33
29
  if (account) {
34
- command = addFlag(command, 'account', account);
30
+ command.addFlag('account', account);
35
31
  }
36
32
  try {
37
- const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
33
+ const { stdout, stderr } = await this.runCommand(absoluteCurrentWorkingDirectory, command, extra);
38
34
  return formatTextContents(stdout, stderr);
39
35
  }
40
36
  catch (error) {
@@ -61,6 +57,6 @@ export class HsListTool extends Tool {
61
57
  readOnlyHint: true,
62
58
  openWorldHint: true,
63
59
  },
64
- }, input => this.wrappedHandler(input));
60
+ }, (input, extra) => this.wrappedHandler(input, extra));
65
61
  }
66
62
  }
@@ -19,6 +19,7 @@ import { HsListFunctionsTool } from './cms/HsListFunctionsTool.js';
19
19
  import { HsFunctionLogsTool } from './cms/HsFunctionLogsTool.js';
20
20
  import { CreateTestAccountTool } from './project/CreateTestAccountTool.js';
21
21
  import { FindProjectsTool } from './project/FindProjectsTool.js';
22
+ import { AuthAccountTool } from './project/AuthAccountTool.js';
22
23
  export function registerProjectTools(mcpServer, logger) {
23
24
  return [
24
25
  new UploadProjectTools(mcpServer, logger).register(),
@@ -36,6 +37,7 @@ export function registerProjectTools(mcpServer, logger) {
36
37
  new GetBuildLogsTool(mcpServer, logger).register(),
37
38
  new GetBuildStatusTool(mcpServer, logger).register(),
38
39
  new FindProjectsTool(mcpServer, logger).register(),
40
+ new AuthAccountTool(mcpServer, logger).register(),
39
41
  ];
40
42
  }
41
43
  export function registerCmsTools(mcpServer, logger) {
@@ -1,5 +1,5 @@
1
1
  import { TextContentResponse } from '../../types.js';
2
- import { Tool } from '../../Tool.js';
2
+ import { Tool, ToolExtra } from '../../Tool.js';
3
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { McpLogger } from '../../utils/logger.js';
5
5
  import { z } from 'zod';
@@ -32,7 +32,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
32
32
  export type AddFeatureInputSchema = z.infer<typeof inputSchemaZodObject>;
33
33
  export declare class AddFeatureToProjectTool extends Tool<AddFeatureInputSchema> {
34
34
  constructor(mcpServer: McpServer, logger: McpLogger);
35
- handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, distribution, auth, features, addApp, }: AddFeatureInputSchema): Promise<TextContentResponse>;
35
+ handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, distribution, auth, features, addApp, }: AddFeatureInputSchema, extra?: ToolExtra): Promise<TextContentResponse>;
36
36
  register(): RegisteredTool;
37
37
  }
38
38
  export {};
@@ -1,9 +1,8 @@
1
1
  import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
3
  import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, } from '../../../lib/constants.js';
4
- import { addFlag } from '../../utils/command.js';
4
+ import { HubSpotCommand } from '../../utils/command.js';
5
5
  import { absoluteCurrentWorkingDirectory, absoluteProjectPath, features, } from './constants.js';
6
- import { runCommandInDir } from '../../utils/command.js';
7
6
  import { formatTextContents, formatTextContent } from '../../utils/content.js';
8
7
  import { setupHubSpotConfig } from '../../utils/config.js';
9
8
  import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
@@ -32,19 +31,19 @@ export class AddFeatureToProjectTool extends Tool {
32
31
  constructor(mcpServer, logger) {
33
32
  super(mcpServer, logger, toolName);
34
33
  }
35
- async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, distribution, auth, features, addApp, }) {
34
+ async handler({ absoluteProjectPath, absoluteCurrentWorkingDirectory, distribution, auth, features, addApp, }, extra) {
36
35
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
37
36
  try {
38
- let command = `hs project add`;
37
+ const command = new HubSpotCommand('project add');
39
38
  const content = [];
40
39
  if (distribution) {
41
- command = addFlag(command, 'distribution', distribution);
40
+ command.addFlag('distribution', distribution);
42
41
  }
43
42
  else if (addApp) {
44
43
  content.push(formatTextContent(`Ask the user how they would you like to distribute the app. Options are ${APP_DISTRIBUTION_TYPES.MARKETPLACE} and ${APP_DISTRIBUTION_TYPES.PRIVATE}`));
45
44
  }
46
45
  if (auth) {
47
- command = addFlag(command, 'auth', auth);
46
+ command.addFlag('auth', auth);
48
47
  }
49
48
  else if (addApp) {
50
49
  content.push(formatTextContent(`Ask the user which auth type they would like to use. Options are ${APP_AUTH_TYPES.STATIC} and ${APP_AUTH_TYPES.OAUTH}`));
@@ -55,8 +54,8 @@ export class AddFeatureToProjectTool extends Tool {
55
54
  };
56
55
  }
57
56
  // If features isn't provided, pass an empty array to bypass the prompt
58
- command = addFlag(command, 'features', features || []);
59
- const { stdout, stderr } = await runCommandInDir(absoluteProjectPath, command);
57
+ command.addFlag('features', features || []);
58
+ const { stdout, stderr } = await this.runCommand(absoluteProjectPath, command, extra);
60
59
  return formatTextContents(stdout, stderr);
61
60
  }
62
61
  catch (error) {
@@ -79,6 +78,6 @@ export class AddFeatureToProjectTool extends Tool {
79
78
  idempotentHint: false,
80
79
  openWorldHint: false,
81
80
  },
82
- }, input => this.wrappedHandler(input));
81
+ }, (input, extra) => this.wrappedHandler(input, extra));
83
82
  }
84
83
  }
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { McpLogger } from '../../utils/logger.js';
4
+ import { Tool, ToolExtra } from '../../Tool.js';
5
+ import { TextContentResponse } from '../../types.js';
6
+ declare const inputSchemaZodObject: z.ZodObject<{
7
+ absoluteCurrentWorkingDirectory: z.ZodString;
8
+ accountId: z.ZodOptional<z.ZodNumber>;
9
+ name: z.ZodOptional<z.ZodString>;
10
+ setAsDefault: z.ZodOptional<z.ZodBoolean>;
11
+ }, z.core.$strip>;
12
+ export type AuthAccountInputSchema = z.infer<typeof inputSchemaZodObject>;
13
+ export declare class AuthAccountTool extends Tool<AuthAccountInputSchema> {
14
+ constructor(mcpServer: McpServer, logger: McpLogger);
15
+ handler({ absoluteCurrentWorkingDirectory, accountId, name, setAsDefault, }: AuthAccountInputSchema, extra?: ToolExtra): Promise<TextContentResponse>;
16
+ register(): RegisteredTool;
17
+ }
18
+ export {};
@@ -0,0 +1,78 @@
1
+ import { z } from 'zod';
2
+ import { Tool } from '../../Tool.js';
3
+ import { formatTextContents } from '../../utils/content.js';
4
+ import { HubSpotCommand } from '../../utils/command.js';
5
+ import { setupHubSpotConfig } from '../../utils/config.js';
6
+ import { absoluteCurrentWorkingDirectory } from './constants.js';
7
+ import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
8
+ const inputSchema = {
9
+ absoluteCurrentWorkingDirectory,
10
+ accountId: z
11
+ .number()
12
+ .optional()
13
+ .describe('The HubSpot portal ID to authenticate.'),
14
+ name: z
15
+ .string()
16
+ .optional()
17
+ .describe('A name to assign to this account in the HubSpot CLI config. Defaults to the portal name if not provided.'),
18
+ setAsDefault: z
19
+ .boolean()
20
+ .optional()
21
+ .describe('Set this account as the default for CLI operations. Defaults to true when not specified.'),
22
+ };
23
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
+ const inputSchemaZodObject = z.object({ ...inputSchema });
25
+ const toolName = 'auth-account';
26
+ export class AuthAccountTool extends Tool {
27
+ constructor(mcpServer, logger) {
28
+ super(mcpServer, logger, toolName);
29
+ }
30
+ async handler({ absoluteCurrentWorkingDirectory, accountId, name, setAsDefault, }, extra) {
31
+ setupHubSpotConfig(absoluteCurrentWorkingDirectory);
32
+ const command = new HubSpotCommand('account auth');
33
+ if (name) {
34
+ command.addFlag('name', name);
35
+ }
36
+ else {
37
+ command.addFlag('use-default-name', 'true');
38
+ }
39
+ if (accountId !== undefined) {
40
+ command.addFlag('account', accountId);
41
+ }
42
+ command.addFlag('default', setAsDefault === false ? 'false' : 'true');
43
+ try {
44
+ const { stdout, stderr } = await this.runCommand(absoluteCurrentWorkingDirectory, command, extra);
45
+ return formatTextContents(stdout, stderr);
46
+ }
47
+ catch (error) {
48
+ this.logger.debug(toolName, {
49
+ message: 'Handler caught error running hs account auth',
50
+ error: error instanceof Error ? error.message : String(error),
51
+ });
52
+ return formatTextContents(getErrorMessage(error));
53
+ }
54
+ }
55
+ register() {
56
+ return this.mcpServer.registerTool(toolName, {
57
+ title: 'Authenticate a HubSpot Account',
58
+ description: 'Authenticates a HubSpot account with the CLI using `hs account auth`.\n\n' +
59
+ 'WHEN TO USE:\n' +
60
+ '- The user wants to add or authenticate a HubSpot account\n' +
61
+ '- Any other tool reports that no account is configured\n' +
62
+ '- The user asks how to connect their HubSpot account to the CLI\n\n' +
63
+ 'WORKFLOW:\n' +
64
+ '1. Call this tool — it opens a browser tab for the user to authorize\n' +
65
+ '2. The user clicks "Connect to CLI" in the browser\n' +
66
+ '3. Auth completes automatically via WebSocket\n' +
67
+ '4. Retry any operation that was blocked by missing auth\n\n' +
68
+ 'setAsDefault defaults to true. Pass setAsDefault: false to keep an existing default account.',
69
+ inputSchema,
70
+ annotations: {
71
+ readOnlyHint: false,
72
+ destructiveHint: false,
73
+ idempotentHint: false,
74
+ openWorldHint: true,
75
+ },
76
+ }, (input, extra) => this.wrappedHandler(input, extra));
77
+ }
78
+ }
@@ -1,5 +1,5 @@
1
1
  import { TextContentResponse } from '../../types.js';
2
- import { Tool } from '../../Tool.js';
2
+ import { Tool, ToolExtra } from '../../Tool.js';
3
3
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { McpLogger } from '../../utils/logger.js';
5
5
  import { z } from 'zod';
@@ -36,7 +36,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
36
36
  export type CreateProjectInputSchema = z.infer<typeof inputSchemaZodObject>;
37
37
  export declare class CreateProjectTool extends Tool<CreateProjectInputSchema> {
38
38
  constructor(mcpServer: McpServer, logger: McpLogger);
39
- handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }: CreateProjectInputSchema): Promise<TextContentResponse>;
39
+ handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }: CreateProjectInputSchema, extra?: ToolExtra): Promise<TextContentResponse>;
40
40
  register(): RegisteredTool;
41
41
  }
42
42
  export {};
@@ -1,9 +1,8 @@
1
1
  import { Tool } from '../../Tool.js';
2
2
  import { z } from 'zod';
3
3
  import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, EMPTY_PROJECT, PROJECT_WITH_APP, } from '../../../lib/constants.js';
4
- import { addFlag } from '../../utils/command.js';
4
+ import { HubSpotCommand } from '../../utils/command.js';
5
5
  import { absoluteCurrentWorkingDirectory, features } from './constants.js';
6
- import { runCommandInDir } from '../../utils/command.js';
7
6
  import { formatTextContents, formatTextContent } from '../../utils/content.js';
8
7
  import { setupHubSpotConfig } from '../../utils/config.js';
9
8
  import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
@@ -37,30 +36,32 @@ export class CreateProjectTool extends Tool {
37
36
  constructor(mcpServer, logger) {
38
37
  super(mcpServer, logger, toolName);
39
38
  }
40
- async handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }) {
39
+ async handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }, extra) {
41
40
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
42
- let command = addFlag('hs project create', 'platform-version', PLATFORM_VERSIONS.v2026_03);
41
+ const command = new HubSpotCommand('project create', [
42
+ { name: 'platform-version', value: PLATFORM_VERSIONS.v2026_03 },
43
+ ]);
43
44
  const content = [];
44
45
  if (name) {
45
- command = addFlag(command, 'name', name);
46
+ command.addFlag('name', name);
46
47
  }
47
48
  else {
48
49
  content.push(formatTextContent(`Ask the user what they would like to name the project.`));
49
50
  }
50
51
  if (destination) {
51
- command = addFlag(command, 'dest', destination);
52
+ command.addFlag('dest', destination);
52
53
  }
53
54
  if (projectBase) {
54
- command = addFlag(command, 'project-base', projectBase);
55
+ command.addFlag('project-base', projectBase);
55
56
  }
56
57
  if (distribution) {
57
- command = addFlag(command, 'distribution', distribution);
58
+ command.addFlag('distribution', distribution);
58
59
  }
59
60
  else if (projectBase === PROJECT_WITH_APP) {
60
61
  content.push(formatTextContent(`Ask the user how they would you like to distribute the app? Options are ${APP_DISTRIBUTION_TYPES.MARKETPLACE} and ${APP_DISTRIBUTION_TYPES.PRIVATE}`));
61
62
  }
62
63
  if (auth) {
63
- command = addFlag(command, 'auth', auth);
64
+ command.addFlag('auth', auth);
64
65
  }
65
66
  else if (projectBase === PROJECT_WITH_APP) {
66
67
  content.push(formatTextContent(`Ask the user which auth type they would like to use? Options are ${APP_AUTH_TYPES.STATIC} and ${APP_AUTH_TYPES.OAUTH}`));
@@ -71,9 +72,9 @@ export class CreateProjectTool extends Tool {
71
72
  };
72
73
  }
73
74
  // Always pass features, even if it is an empty array to bypass the prompts
74
- command = addFlag(command, 'features', features || []);
75
+ command.addFlag('features', features || []);
75
76
  try {
76
- const { stdout, stderr } = await runCommandInDir(absoluteCurrentWorkingDirectory, command);
77
+ const { stdout, stderr } = await this.runCommand(absoluteCurrentWorkingDirectory, command, extra);
77
78
  return formatTextContents(stdout, stderr);
78
79
  }
79
80
  catch (error) {
@@ -95,6 +96,6 @@ export class CreateProjectTool extends Tool {
95
96
  idempotentHint: false,
96
97
  openWorldHint: false,
97
98
  },
98
- }, input => this.wrappedHandler(input));
99
+ }, (input, extra) => this.wrappedHandler(input, extra));
99
100
  }
100
101
  }
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { McpLogger } from '../../utils/logger.js';
4
4
  import { TextContentResponse } from '../../types.js';
5
- import { Tool } from '../../Tool.js';
5
+ import { Tool, ToolExtra } from '../../Tool.js';
6
6
  declare const createTestAccountInputSchema: z.ZodObject<{
7
7
  absoluteCurrentWorkingDirectory: z.ZodString;
8
8
  configPath: z.ZodOptional<z.ZodString>;
@@ -47,7 +47,7 @@ declare const createTestAccountInputSchema: z.ZodObject<{
47
47
  export type CreateTestAccountInputSchema = z.infer<typeof createTestAccountInputSchema>;
48
48
  export declare class CreateTestAccountTool extends Tool<CreateTestAccountInputSchema> {
49
49
  constructor(mcpServer: McpServer, logger: McpLogger);
50
- handler({ absoluteCurrentWorkingDirectory, name, description, marketingLevel, opsLevel, serviceLevel, salesLevel, contentLevel, commerceLevel, configPath, }: CreateTestAccountInputSchema): Promise<TextContentResponse>;
50
+ handler({ absoluteCurrentWorkingDirectory, name, description, marketingLevel, opsLevel, serviceLevel, salesLevel, contentLevel, commerceLevel, configPath, }: CreateTestAccountInputSchema, extra?: ToolExtra): Promise<TextContentResponse>;
51
51
  register(): RegisteredTool;
52
52
  }
53
53
  export {};