@hubspot/cli 7.7.8-experimental.0 → 7.7.10-experimental.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.
- package/commands/mcp/setup.d.ts +2 -1
- package/commands/mcp/setup.js +135 -56
- package/commands/mcp/start.js +17 -21
- package/commands/mcp.js +2 -1
- package/lang/en.d.ts +51 -0
- package/lang/en.js +51 -0
- package/lib/middleware/configMiddleware.js +1 -0
- package/mcp-server/tools/project/AddFeatureToProject.js +3 -1
- package/package.json +1 -1
package/commands/mcp/setup.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ArgumentsCamelCase, Argv } from 'yargs';
|
|
2
2
|
interface MCPSetupArgs {
|
|
3
3
|
targets?: string[];
|
|
4
|
+
addDocsSearch?: boolean;
|
|
4
5
|
}
|
|
5
|
-
declare function handler(
|
|
6
|
+
declare function handler(args: ArgumentsCamelCase<MCPSetupArgs>): Promise<void>;
|
|
6
7
|
declare const _default: {
|
|
7
8
|
command: string[];
|
|
8
9
|
describe: undefined;
|
package/commands/mcp/setup.js
CHANGED
|
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
7
6
|
const child_process_1 = require("child_process");
|
|
8
7
|
const util_1 = require("util");
|
|
9
8
|
const path_1 = __importDefault(require("path"));
|
|
@@ -12,36 +11,65 @@ const os_1 = __importDefault(require("os"));
|
|
|
12
11
|
const SpinniesManager_1 = __importDefault(require("../../lib/ui/SpinniesManager"));
|
|
13
12
|
const exitCodes_1 = require("../../lib/enums/exitCodes");
|
|
14
13
|
const promptUtils_1 = require("../../lib/prompts/promptUtils");
|
|
15
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
16
14
|
const yargsUtils_1 = require("../../lib/yargsUtils");
|
|
15
|
+
const en_1 = require("../../lang/en");
|
|
16
|
+
const errorHandlers_1 = require("../../lib/errorHandlers");
|
|
17
|
+
const logger_1 = require("../../lib/ui/logger");
|
|
17
18
|
const command = ['setup', 'update'];
|
|
18
19
|
const describe = undefined; // Leave hidden for now
|
|
19
20
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
21
|
+
const claudeCode = 'claude-code';
|
|
22
|
+
const claudeDesktop = 'claude-desktop';
|
|
23
|
+
const windsurf = 'windsurf';
|
|
24
|
+
const cursor = 'cursor';
|
|
25
|
+
const mcpServerName = 'hubspot-cli-mcp';
|
|
20
26
|
const supportedTools = [
|
|
21
|
-
{ name:
|
|
22
|
-
{ name:
|
|
23
|
-
{ name:
|
|
27
|
+
{ name: en_1.commands.mcp.setup.claudeCode, value: claudeCode },
|
|
28
|
+
// { name: commands.mcp.setup.claudeDesktop, value: claudeDesktop },
|
|
29
|
+
{ name: en_1.commands.mcp.setup.cursor, value: cursor },
|
|
30
|
+
{ name: en_1.commands.mcp.setup.windsurf, value: windsurf },
|
|
24
31
|
];
|
|
32
|
+
const hsCommand = 'hs';
|
|
33
|
+
const mcpCommandArgs = ['mcp', 'start'];
|
|
25
34
|
function setupBuilder(yargs) {
|
|
26
|
-
yargs
|
|
27
|
-
|
|
35
|
+
yargs
|
|
36
|
+
.option('targets', {
|
|
37
|
+
describe: en_1.commands.mcp.setup.args.targets,
|
|
28
38
|
type: 'array',
|
|
29
39
|
choices: [...supportedTools.map(tool => tool.value)],
|
|
40
|
+
})
|
|
41
|
+
.option('add-docs-search', {
|
|
42
|
+
type: 'boolean',
|
|
30
43
|
});
|
|
31
44
|
return yargs;
|
|
32
45
|
}
|
|
33
46
|
const builder = (0, yargsUtils_1.makeYargsBuilder)(setupBuilder, command, describe, {
|
|
34
47
|
useGlobalOptions: true,
|
|
35
48
|
});
|
|
36
|
-
async function handler(
|
|
49
|
+
async function handler(args) {
|
|
37
50
|
try {
|
|
38
51
|
await import('@modelcontextprotocol/sdk/server/mcp.js');
|
|
39
52
|
}
|
|
40
53
|
catch (e) {
|
|
41
|
-
logger_1.
|
|
54
|
+
logger_1.uiLogger.error(en_1.commands.mcp.setup.errors.needsNode20);
|
|
42
55
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
43
56
|
}
|
|
44
|
-
await addMcpServerToConfig(
|
|
57
|
+
await addMcpServerToConfig(args.targets);
|
|
58
|
+
if (args.addDocsSearch) {
|
|
59
|
+
logger_1.uiLogger.info(en_1.commands.mcp.setup.installingDocSearch);
|
|
60
|
+
await new Promise(() => {
|
|
61
|
+
const childProcess = (0, child_process_1.spawn)(`npx`, ['mint-mcp', 'add', 'hubspot-migration'], {
|
|
62
|
+
stdio: 'inherit',
|
|
63
|
+
});
|
|
64
|
+
childProcess.on('exit', code => {
|
|
65
|
+
if (code !== 0) {
|
|
66
|
+
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
67
|
+
}
|
|
68
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
45
73
|
}
|
|
46
74
|
async function addMcpServerToConfig(targets) {
|
|
47
75
|
try {
|
|
@@ -50,10 +78,12 @@ async function addMcpServerToConfig(targets) {
|
|
|
50
78
|
const { selectedTargets } = await (0, promptUtils_1.promptUser)({
|
|
51
79
|
name: 'selectedTargets',
|
|
52
80
|
type: 'checkbox',
|
|
53
|
-
message:
|
|
81
|
+
message: en_1.commands.mcp.setup.prompts.targets,
|
|
54
82
|
choices: supportedTools,
|
|
55
83
|
validate: (choices) => {
|
|
56
|
-
return choices.length === 0
|
|
84
|
+
return choices.length === 0
|
|
85
|
+
? en_1.commands.mcp.setup.prompts.targetsRequired
|
|
86
|
+
: true;
|
|
57
87
|
},
|
|
58
88
|
});
|
|
59
89
|
derivedTargets = selectedTargets;
|
|
@@ -62,22 +92,25 @@ async function addMcpServerToConfig(targets) {
|
|
|
62
92
|
derivedTargets = targets;
|
|
63
93
|
}
|
|
64
94
|
SpinniesManager_1.default.init();
|
|
65
|
-
if (derivedTargets.includes(
|
|
95
|
+
if (derivedTargets.includes(claudeDesktop)) {
|
|
66
96
|
await runSetupFunction(setupClaudeDesktop);
|
|
67
97
|
}
|
|
68
|
-
if (derivedTargets.includes(
|
|
98
|
+
if (derivedTargets.includes(claudeCode)) {
|
|
69
99
|
await runSetupFunction(setupClaudeCode);
|
|
70
100
|
}
|
|
71
|
-
if (derivedTargets.includes(
|
|
101
|
+
if (derivedTargets.includes(cursor)) {
|
|
72
102
|
await runSetupFunction(setupCursor);
|
|
73
103
|
}
|
|
74
|
-
|
|
104
|
+
if (derivedTargets.includes(windsurf)) {
|
|
105
|
+
await runSetupFunction(setupWindsurf);
|
|
106
|
+
}
|
|
107
|
+
logger_1.uiLogger.info(en_1.commands.mcp.setup.success(derivedTargets));
|
|
75
108
|
}
|
|
76
109
|
catch (error) {
|
|
77
110
|
SpinniesManager_1.default.fail('mcpSetup', {
|
|
78
|
-
text:
|
|
111
|
+
text: en_1.commands.mcp.setup.spinners.failedToConfigure,
|
|
79
112
|
});
|
|
80
|
-
|
|
113
|
+
(0, errorHandlers_1.logError)(error);
|
|
81
114
|
}
|
|
82
115
|
}
|
|
83
116
|
async function runSetupFunction(func) {
|
|
@@ -86,59 +119,60 @@ async function runSetupFunction(func) {
|
|
|
86
119
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
87
120
|
}
|
|
88
121
|
}
|
|
89
|
-
|
|
122
|
+
function setupClaudeDesktop() {
|
|
90
123
|
try {
|
|
91
124
|
const configPath = getClaudeDesktopConfigPath();
|
|
92
125
|
SpinniesManager_1.default.add('claudeDesktop', {
|
|
93
|
-
text:
|
|
126
|
+
text: en_1.commands.mcp.setup.spinners.configuringClaudeDesktop,
|
|
94
127
|
});
|
|
95
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
96
128
|
let config = {};
|
|
97
129
|
// Read existing config if it exists
|
|
98
130
|
if (fs_1.default.existsSync(configPath)) {
|
|
99
131
|
try {
|
|
100
132
|
const configContent = fs_1.default.readFileSync(configPath, 'utf8');
|
|
101
133
|
config = JSON.parse(configContent);
|
|
102
|
-
logger_1.logger.debug(`Found existing Claude Desktop config at ${configPath}`);
|
|
103
134
|
}
|
|
104
135
|
catch (error) {
|
|
105
|
-
|
|
136
|
+
SpinniesManager_1.default.fail('claudeDesktop', {
|
|
137
|
+
text: en_1.commands.mcp.setup.spinners.failedToConfigureClaudeDesktop,
|
|
138
|
+
});
|
|
139
|
+
(0, errorHandlers_1.logError)(error);
|
|
140
|
+
return false;
|
|
106
141
|
}
|
|
107
142
|
}
|
|
108
143
|
else {
|
|
109
144
|
// Create config directory if it doesn't exist
|
|
110
145
|
const configDir = path_1.default.dirname(configPath);
|
|
111
146
|
fs_1.default.mkdirSync(configDir, { recursive: true });
|
|
112
|
-
logger_1.logger.debug(`Created Claude Desktop config directory at ${configDir}`);
|
|
113
147
|
}
|
|
114
148
|
// Initialize mcpServers if it doesn't exist
|
|
115
149
|
if (!config.mcpServers) {
|
|
116
150
|
config.mcpServers = {};
|
|
117
151
|
}
|
|
118
152
|
// Add or update HubSpot CLI MCP server
|
|
119
|
-
config.mcpServers[
|
|
120
|
-
command:
|
|
121
|
-
args:
|
|
153
|
+
config.mcpServers[mcpServerName] = {
|
|
154
|
+
command: hsCommand,
|
|
155
|
+
args: mcpCommandArgs,
|
|
122
156
|
};
|
|
123
157
|
// Write the updated config
|
|
124
158
|
fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
125
159
|
SpinniesManager_1.default.succeed('claudeDesktop', {
|
|
126
|
-
text:
|
|
160
|
+
text: en_1.commands.mcp.setup.spinners.configuredClaudeDesktop,
|
|
127
161
|
});
|
|
128
162
|
return true;
|
|
129
163
|
}
|
|
130
164
|
catch (error) {
|
|
131
165
|
SpinniesManager_1.default.fail('claudeDesktop', {
|
|
132
|
-
text:
|
|
166
|
+
text: en_1.commands.mcp.setup.spinners.failedToConfigureClaudeDesktop,
|
|
133
167
|
});
|
|
134
|
-
|
|
168
|
+
(0, errorHandlers_1.logError)(error);
|
|
135
169
|
return false;
|
|
136
170
|
}
|
|
137
171
|
}
|
|
138
172
|
async function setupClaudeCode() {
|
|
139
173
|
try {
|
|
140
174
|
SpinniesManager_1.default.add('claudeCode', {
|
|
141
|
-
text:
|
|
175
|
+
text: en_1.commands.mcp.setup.spinners.configuringClaudeCode,
|
|
142
176
|
});
|
|
143
177
|
try {
|
|
144
178
|
// Check if claude command is available
|
|
@@ -146,19 +180,19 @@ async function setupClaudeCode() {
|
|
|
146
180
|
// Run claude mcp add command
|
|
147
181
|
const mcpConfig = JSON.stringify({
|
|
148
182
|
type: 'stdio',
|
|
149
|
-
command:
|
|
150
|
-
args:
|
|
183
|
+
command: hsCommand,
|
|
184
|
+
args: mcpCommandArgs,
|
|
151
185
|
});
|
|
152
186
|
const { stdout } = await execAsync('claude mcp list');
|
|
153
|
-
if (stdout.includes(
|
|
187
|
+
if (stdout.includes(mcpServerName)) {
|
|
154
188
|
SpinniesManager_1.default.update('claudeCode', {
|
|
155
|
-
text:
|
|
189
|
+
text: en_1.commands.mcp.setup.spinners.alreadyInstalled,
|
|
156
190
|
});
|
|
157
|
-
await execAsync(
|
|
191
|
+
await execAsync(`claude mcp remove "${mcpServerName}" --scope user`);
|
|
158
192
|
}
|
|
159
|
-
await execAsync(`claude mcp add-json "
|
|
193
|
+
await execAsync(`claude mcp add-json "${mcpServerName}" '${mcpConfig}' --scope user`);
|
|
160
194
|
SpinniesManager_1.default.succeed('claudeCode', {
|
|
161
|
-
text:
|
|
195
|
+
text: en_1.commands.mcp.setup.spinners.configuredClaudeCode,
|
|
162
196
|
});
|
|
163
197
|
return true;
|
|
164
198
|
}
|
|
@@ -166,38 +200,36 @@ async function setupClaudeCode() {
|
|
|
166
200
|
if (error instanceof Error &&
|
|
167
201
|
error.message.includes('claude: command not found')) {
|
|
168
202
|
SpinniesManager_1.default.fail('claudeCode', {
|
|
169
|
-
text:
|
|
203
|
+
text: en_1.commands.mcp.setup.spinners.claudeCodeNotFound,
|
|
170
204
|
});
|
|
171
|
-
logger_1.logger.info(' Install Claude Code CLI to enable this configuration');
|
|
172
205
|
}
|
|
173
206
|
else {
|
|
174
207
|
SpinniesManager_1.default.fail('claudeCode', {
|
|
175
|
-
text:
|
|
208
|
+
text: en_1.commands.mcp.setup.spinners.claudeCodeInstallFailed,
|
|
176
209
|
});
|
|
177
|
-
|
|
210
|
+
(0, errorHandlers_1.logError)(error);
|
|
178
211
|
}
|
|
179
212
|
return false;
|
|
180
213
|
}
|
|
181
214
|
}
|
|
182
215
|
catch (error) {
|
|
183
216
|
SpinniesManager_1.default.fail('claudeCode', {
|
|
184
|
-
text:
|
|
217
|
+
text: en_1.commands.mcp.setup.spinners.claudeCodeInstallFailed,
|
|
185
218
|
});
|
|
186
|
-
|
|
219
|
+
(0, errorHandlers_1.logError)(error);
|
|
187
220
|
return false;
|
|
188
221
|
}
|
|
189
222
|
}
|
|
190
|
-
|
|
223
|
+
function setupCursor() {
|
|
191
224
|
try {
|
|
192
225
|
SpinniesManager_1.default.add('cursor', {
|
|
193
|
-
text:
|
|
226
|
+
text: en_1.commands.mcp.setup.spinners.configuringCursor,
|
|
194
227
|
});
|
|
195
228
|
const cursorConfigPath = path_1.default.join(os_1.default.homedir(), '.cursor', 'mcp.json');
|
|
196
229
|
if (!fs_1.default.existsSync(cursorConfigPath)) {
|
|
197
230
|
SpinniesManager_1.default.succeed('cursor', {
|
|
198
|
-
text:
|
|
231
|
+
text: en_1.commands.mcp.setup.spinners.noCursorMcpFile(cursorConfigPath),
|
|
199
232
|
});
|
|
200
|
-
logger_1.logger.info(' Create a .cursor/mcp.json file in your project to enable Cursor MCP support');
|
|
201
233
|
return false;
|
|
202
234
|
}
|
|
203
235
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -206,32 +238,32 @@ async function setupCursor() {
|
|
|
206
238
|
try {
|
|
207
239
|
const configContent = fs_1.default.readFileSync(cursorConfigPath, 'utf8');
|
|
208
240
|
config = JSON.parse(configContent);
|
|
209
|
-
logger_1.logger.debug(`Found existing Cursor config at ${cursorConfigPath}`);
|
|
210
241
|
}
|
|
211
242
|
catch (error) {
|
|
212
|
-
|
|
243
|
+
(0, errorHandlers_1.logError)(error);
|
|
244
|
+
return false;
|
|
213
245
|
}
|
|
214
246
|
// Initialize mcpServers if it doesn't exist
|
|
215
247
|
if (!config.mcpServers) {
|
|
216
248
|
config.mcpServers = {};
|
|
217
249
|
}
|
|
218
250
|
// Add or update HubSpot CLI MCP server
|
|
219
|
-
config.mcpServers[
|
|
220
|
-
command:
|
|
221
|
-
args:
|
|
251
|
+
config.mcpServers[mcpServerName] = {
|
|
252
|
+
command: hsCommand,
|
|
253
|
+
args: mcpCommandArgs,
|
|
222
254
|
};
|
|
223
255
|
// Write the updated config
|
|
224
256
|
fs_1.default.writeFileSync(cursorConfigPath, JSON.stringify(config, null, 2));
|
|
225
257
|
SpinniesManager_1.default.succeed('cursor', {
|
|
226
|
-
text:
|
|
258
|
+
text: en_1.commands.mcp.setup.spinners.configuredCursor,
|
|
227
259
|
});
|
|
228
260
|
return true;
|
|
229
261
|
}
|
|
230
262
|
catch (error) {
|
|
231
263
|
SpinniesManager_1.default.fail('cursor', {
|
|
232
|
-
text:
|
|
264
|
+
text: en_1.commands.mcp.setup.spinners.failedToConfigureCursor,
|
|
233
265
|
});
|
|
234
|
-
|
|
266
|
+
(0, errorHandlers_1.logError)(error);
|
|
235
267
|
return false;
|
|
236
268
|
}
|
|
237
269
|
}
|
|
@@ -246,4 +278,51 @@ function getClaudeDesktopConfigPath() {
|
|
|
246
278
|
return path_1.default.join(homeDir, '.config', 'claude', 'claude_desktop_config.json');
|
|
247
279
|
}
|
|
248
280
|
}
|
|
281
|
+
function setupWindsurf() {
|
|
282
|
+
try {
|
|
283
|
+
SpinniesManager_1.default.add('cursor', {
|
|
284
|
+
text: en_1.commands.mcp.setup.spinners.configuringWindsurf,
|
|
285
|
+
});
|
|
286
|
+
const windsurf = path_1.default.join(os_1.default.homedir(), '.codeium', 'windsurf', 'mcp_config.json');
|
|
287
|
+
if (!fs_1.default.existsSync(windsurf)) {
|
|
288
|
+
SpinniesManager_1.default.succeed('cursor', {
|
|
289
|
+
text: en_1.commands.mcp.setup.spinners.noWindsurfFile(windsurf),
|
|
290
|
+
});
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
294
|
+
let config = {};
|
|
295
|
+
// Read existing config
|
|
296
|
+
try {
|
|
297
|
+
const configContent = fs_1.default.readFileSync(windsurf, 'utf8');
|
|
298
|
+
config = JSON.parse(configContent);
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
(0, errorHandlers_1.logError)(error);
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
// Initialize mcpServers if it doesn't exist
|
|
305
|
+
if (!config.mcpServers) {
|
|
306
|
+
config.mcpServers = {};
|
|
307
|
+
}
|
|
308
|
+
// Add or update HubSpot CLI MCP server
|
|
309
|
+
config.mcpServers[mcpServerName] = {
|
|
310
|
+
command: hsCommand,
|
|
311
|
+
args: mcpCommandArgs,
|
|
312
|
+
};
|
|
313
|
+
// Write the updated config
|
|
314
|
+
fs_1.default.writeFileSync(windsurf, JSON.stringify(config, null, 2));
|
|
315
|
+
SpinniesManager_1.default.succeed('cursor', {
|
|
316
|
+
text: en_1.commands.mcp.setup.spinners.configuredWindsurf,
|
|
317
|
+
});
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
SpinniesManager_1.default.fail('cursor', {
|
|
322
|
+
text: en_1.commands.mcp.setup.spinners.failedToConfigureWindsurf,
|
|
323
|
+
});
|
|
324
|
+
(0, errorHandlers_1.logError)(error);
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
249
328
|
exports.default = { command, describe, builder, handler };
|
package/commands/mcp/start.js
CHANGED
|
@@ -3,12 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
7
6
|
const child_process_1 = require("child_process");
|
|
8
7
|
const path_1 = __importDefault(require("path"));
|
|
9
8
|
const fs_1 = __importDefault(require("fs"));
|
|
10
9
|
const exitCodes_1 = require("../../lib/enums/exitCodes");
|
|
11
10
|
const yargsUtils_1 = require("../../lib/yargsUtils");
|
|
11
|
+
const logger_1 = require("../../lib/ui/logger");
|
|
12
|
+
const errorHandlers_1 = require("../../lib/errorHandlers");
|
|
13
|
+
const en_1 = require("../../lang/en");
|
|
12
14
|
const command = 'start';
|
|
13
15
|
const describe = undefined; // Leave hidden for now
|
|
14
16
|
function startBuilder(yargs) {
|
|
@@ -22,7 +24,7 @@ async function handler() {
|
|
|
22
24
|
await import('@modelcontextprotocol/sdk/server/mcp.js');
|
|
23
25
|
}
|
|
24
26
|
catch (e) {
|
|
25
|
-
logger_1.
|
|
27
|
+
logger_1.uiLogger.error(en_1.commands.mcp.start.errors.needsNode20);
|
|
26
28
|
process.exit(exitCodes_1.EXIT_CODES.ERROR);
|
|
27
29
|
}
|
|
28
30
|
await startMcpServer();
|
|
@@ -32,13 +34,11 @@ async function startMcpServer() {
|
|
|
32
34
|
const serverPath = path_1.default.join(__dirname, '..', '..', 'mcp-server', 'server.js');
|
|
33
35
|
// Check if server file exists
|
|
34
36
|
if (!fs_1.default.existsSync(serverPath)) {
|
|
35
|
-
logger_1.
|
|
37
|
+
logger_1.uiLogger.error(en_1.commands.mcp.start.errors.serverFileNotFound(serverPath));
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
38
|
-
logger_1.
|
|
39
|
-
logger_1.
|
|
40
|
-
logger_1.logger.info('The server will run in stdio mode for MCP client connections');
|
|
41
|
-
logger_1.logger.info('Press Ctrl+C to stop the server');
|
|
40
|
+
logger_1.uiLogger.info(en_1.commands.mcp.start.startingServer);
|
|
41
|
+
logger_1.uiLogger.info(en_1.commands.mcp.start.stopInstructions);
|
|
42
42
|
// Start the server using ts-node
|
|
43
43
|
const child = (0, child_process_1.spawn)('node', [serverPath], {
|
|
44
44
|
stdio: 'inherit',
|
|
@@ -48,31 +48,27 @@ async function startMcpServer() {
|
|
|
48
48
|
});
|
|
49
49
|
// Handle server process events
|
|
50
50
|
child.on('error', error => {
|
|
51
|
-
|
|
52
|
-
logger_1.
|
|
51
|
+
(0, errorHandlers_1.logError)(error);
|
|
52
|
+
logger_1.uiLogger.error(en_1.commands.mcp.start.errors.failedToStart);
|
|
53
53
|
});
|
|
54
|
-
child.on('close',
|
|
55
|
-
|
|
56
|
-
logger_1.logger.info('MCP server stopped gracefully');
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
logger_1.logger.error(`MCP server exited with code ${code}`);
|
|
60
|
-
}
|
|
54
|
+
child.on('close', () => {
|
|
55
|
+
logger_1.uiLogger.info(en_1.commands.mcp.start.stoppedSuccessfully);
|
|
61
56
|
});
|
|
62
57
|
// Handle graceful shutdown
|
|
63
58
|
process.on('SIGINT', () => {
|
|
64
|
-
logger_1.
|
|
59
|
+
logger_1.uiLogger.info(en_1.commands.mcp.start.shuttingDown);
|
|
65
60
|
child.kill('SIGTERM');
|
|
66
|
-
process.exit(
|
|
61
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
67
62
|
});
|
|
68
63
|
process.on('SIGTERM', () => {
|
|
69
|
-
logger_1.
|
|
64
|
+
logger_1.uiLogger.info(en_1.commands.mcp.start.shuttingDown);
|
|
70
65
|
child.kill('SIGTERM');
|
|
71
|
-
process.exit(
|
|
66
|
+
process.exit(exitCodes_1.EXIT_CODES.SUCCESS);
|
|
72
67
|
});
|
|
73
68
|
}
|
|
74
69
|
catch (error) {
|
|
75
|
-
logger_1.
|
|
70
|
+
logger_1.uiLogger.error(en_1.commands.mcp.start.errors.failedToStart);
|
|
71
|
+
(0, errorHandlers_1.logError)(error);
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
exports.default = { command, describe, builder, handler };
|
package/commands/mcp.js
CHANGED
|
@@ -7,7 +7,8 @@ const start_1 = __importDefault(require("./mcp/start"));
|
|
|
7
7
|
const setup_1 = __importDefault(require("./mcp/setup"));
|
|
8
8
|
const yargsUtils_1 = require("../lib/yargsUtils");
|
|
9
9
|
const command = 'mcp';
|
|
10
|
-
|
|
10
|
+
// Leave this as undefined to hide the command
|
|
11
|
+
const describe = undefined;
|
|
11
12
|
function mcpBuilder(yargs) {
|
|
12
13
|
yargs.command(start_1.default).command(setup_1.default).demandCommand(1, '');
|
|
13
14
|
return yargs;
|
package/lang/en.d.ts
CHANGED
|
@@ -764,6 +764,57 @@ Global configuration replaces hubspot.config.yml, and you will be prompted to mi
|
|
|
764
764
|
};
|
|
765
765
|
readonly tailLogs: (functionPath: string, accountId: string) => string;
|
|
766
766
|
};
|
|
767
|
+
readonly mcp: {
|
|
768
|
+
readonly setup: {
|
|
769
|
+
readonly installingDocSearch: "Adding the docs-search mcp server, please follow the prompt";
|
|
770
|
+
readonly claudeCode: "Claude Code";
|
|
771
|
+
readonly claudeDesktop: "Claude Desktop";
|
|
772
|
+
readonly cursor: "Cursor";
|
|
773
|
+
readonly windsurf: "Windsurf";
|
|
774
|
+
readonly args: {
|
|
775
|
+
readonly targets: "Target applications to configure";
|
|
776
|
+
readonly docsSearch: "Should the docs search mcp server be installed";
|
|
777
|
+
};
|
|
778
|
+
readonly success: (derivedTargets: string[]) => string;
|
|
779
|
+
readonly errors: {
|
|
780
|
+
readonly needsNode20: "This feature requires node >=20";
|
|
781
|
+
};
|
|
782
|
+
readonly spinners: {
|
|
783
|
+
readonly failedToConfigure: "Failed to configure the HubSpot mcp server.";
|
|
784
|
+
readonly configuringClaudeDesktop: "Configuring Claude Desktop...";
|
|
785
|
+
readonly configuredClaudeDesktop: "Configured Claude Desktop";
|
|
786
|
+
readonly configuringClaudeCode: "Configuring Claude Code...";
|
|
787
|
+
readonly configuredClaudeCode: "Configured Claude Code";
|
|
788
|
+
readonly claudeCodeNotFound: "Claude Code not found - skipping configuration";
|
|
789
|
+
readonly claudeCodeInstallFailed: "Claude Code CLI not working - skipping configuration";
|
|
790
|
+
readonly failedToConfigureClaudeDesktop: "Failed to configure Claude Desktop";
|
|
791
|
+
readonly configuringCursor: "Configuring Cursor...";
|
|
792
|
+
readonly noCursorMcpFile: (configFile: string) => string;
|
|
793
|
+
readonly failedToConfigureCursor: "Failed to configure Cursor";
|
|
794
|
+
readonly configuredCursor: "Configured Cursor";
|
|
795
|
+
readonly alreadyInstalled: "HubSpot CLI mcp server already installed, reinstalling";
|
|
796
|
+
readonly configuringWindsurf: "Configuring Cursor...";
|
|
797
|
+
readonly noWindsurfFile: (configFile: string) => string;
|
|
798
|
+
readonly failedToConfigureWindsurf: "Failed to configure Cursor";
|
|
799
|
+
readonly configuredWindsurf: "Configured Windsurf";
|
|
800
|
+
};
|
|
801
|
+
readonly prompts: {
|
|
802
|
+
readonly targets: "[--targets] Which tools would you like to add the HubSpot CLI MCP server to?";
|
|
803
|
+
readonly targetsRequired: "Must choose at least one application to configure.";
|
|
804
|
+
};
|
|
805
|
+
};
|
|
806
|
+
readonly start: {
|
|
807
|
+
readonly errors: {
|
|
808
|
+
readonly needsNode20: "This feature requires node >=20";
|
|
809
|
+
readonly serverFileNotFound: (serverPath: string) => string;
|
|
810
|
+
readonly failedToStart: "Failed to start MCP server";
|
|
811
|
+
};
|
|
812
|
+
readonly startingServer: "Starting HubSpot CLI MCP server...";
|
|
813
|
+
readonly stopInstructions: "Press Ctrl+C to stop the server";
|
|
814
|
+
readonly stoppedSuccessfully: "Stopped successfully.";
|
|
815
|
+
readonly shuttingDown: "Shutting down MCP server...";
|
|
816
|
+
};
|
|
817
|
+
};
|
|
767
818
|
readonly mv: {
|
|
768
819
|
readonly describe: "Move a remote file or folder in HubSpot. This feature is currently in beta and the CLI contract is subject to change.";
|
|
769
820
|
readonly errors: {
|
package/lang/en.js
CHANGED
|
@@ -776,6 +776,57 @@ exports.commands = {
|
|
|
776
776
|
},
|
|
777
777
|
tailLogs: (functionPath, accountId) => `Waiting for log entries for "${functionPath}" on account "${accountId}".\n`,
|
|
778
778
|
},
|
|
779
|
+
mcp: {
|
|
780
|
+
setup: {
|
|
781
|
+
installingDocSearch: 'Adding the docs-search mcp server, please follow the prompt',
|
|
782
|
+
claudeCode: 'Claude Code',
|
|
783
|
+
claudeDesktop: 'Claude Desktop',
|
|
784
|
+
cursor: 'Cursor',
|
|
785
|
+
windsurf: 'Windsurf',
|
|
786
|
+
args: {
|
|
787
|
+
targets: 'Target applications to configure',
|
|
788
|
+
docsSearch: 'Should the docs search mcp server be installed',
|
|
789
|
+
},
|
|
790
|
+
success: (derivedTargets) => `You can now use the HubSpot CLI tools in ${derivedTargets.join(', ')}. ${chalk_1.default.bold('You may need to restart these tools to apply the changes')}.`,
|
|
791
|
+
errors: {
|
|
792
|
+
needsNode20: `This feature requires node >=20`,
|
|
793
|
+
},
|
|
794
|
+
spinners: {
|
|
795
|
+
failedToConfigure: 'Failed to configure the HubSpot mcp server.',
|
|
796
|
+
configuringClaudeDesktop: 'Configuring Claude Desktop...',
|
|
797
|
+
configuredClaudeDesktop: 'Configured Claude Desktop',
|
|
798
|
+
configuringClaudeCode: 'Configuring Claude Code...',
|
|
799
|
+
configuredClaudeCode: 'Configured Claude Code',
|
|
800
|
+
claudeCodeNotFound: 'Claude Code not found - skipping configuration',
|
|
801
|
+
claudeCodeInstallFailed: 'Claude Code CLI not working - skipping configuration',
|
|
802
|
+
failedToConfigureClaudeDesktop: 'Failed to configure Claude Desktop',
|
|
803
|
+
configuringCursor: 'Configuring Cursor...',
|
|
804
|
+
noCursorMcpFile: (configFile) => `No ${configFile} file found - skipping Cursor configuration`,
|
|
805
|
+
failedToConfigureCursor: 'Failed to configure Cursor',
|
|
806
|
+
configuredCursor: 'Configured Cursor',
|
|
807
|
+
alreadyInstalled: 'HubSpot CLI mcp server already installed, reinstalling',
|
|
808
|
+
configuringWindsurf: 'Configuring Cursor...',
|
|
809
|
+
noWindsurfFile: (configFile) => `No ${configFile} file found - skipping Windsurf configuration`,
|
|
810
|
+
failedToConfigureWindsurf: 'Failed to configure Cursor',
|
|
811
|
+
configuredWindsurf: 'Configured Windsurf',
|
|
812
|
+
},
|
|
813
|
+
prompts: {
|
|
814
|
+
targets: '[--targets] Which tools would you like to add the HubSpot CLI MCP server to?',
|
|
815
|
+
targetsRequired: 'Must choose at least one application to configure.',
|
|
816
|
+
},
|
|
817
|
+
},
|
|
818
|
+
start: {
|
|
819
|
+
errors: {
|
|
820
|
+
needsNode20: `This feature requires node >=20`,
|
|
821
|
+
serverFileNotFound: (serverPath) => `MCP server file not found at ${serverPath}`,
|
|
822
|
+
failedToStart: 'Failed to start MCP server',
|
|
823
|
+
},
|
|
824
|
+
startingServer: 'Starting HubSpot CLI MCP server...',
|
|
825
|
+
stopInstructions: 'Press Ctrl+C to stop the server',
|
|
826
|
+
stoppedSuccessfully: 'Stopped successfully.',
|
|
827
|
+
shuttingDown: 'Shutting down MCP server...',
|
|
828
|
+
},
|
|
829
|
+
},
|
|
779
830
|
mv: {
|
|
780
831
|
describe: 'Move a remote file or folder in HubSpot. This feature is currently in beta and the CLI contract is subject to change.',
|
|
781
832
|
errors: {
|
|
@@ -9,7 +9,9 @@ const constants_2 = require("./constants");
|
|
|
9
9
|
const project_1 = require("../../utils/project");
|
|
10
10
|
const inputSchema = {
|
|
11
11
|
absoluteProjectPath: constants_2.absoluteProjectPath,
|
|
12
|
-
addApp: zod_1.z
|
|
12
|
+
addApp: zod_1.z
|
|
13
|
+
.boolean()
|
|
14
|
+
.describe('Should an app be added? If there is no app in the project, and app must be added to add a feature'),
|
|
13
15
|
distribution: zod_1.z
|
|
14
16
|
.optional(zod_1.z.union([
|
|
15
17
|
zod_1.z.literal(constants_1.APP_DISTRIBUTION_TYPES.MARKETPLACE),
|
package/package.json
CHANGED