@l4yercak3/cli 1.2.8 → 1.2.10

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.
@@ -17,7 +17,9 @@
17
17
  "Bash(git push:*)",
18
18
  "Bash(session\" errors when trying to use features.\n\nNow the login command validates the session with the backend first.\nIf validation fails, it clears the local session and prompts for\nfresh login, avoiding the confusing loop.\n\nšŸ¤– Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
19
19
  "Bash(npm run build:*)",
20
- "Bash(npm version:*)"
20
+ "Bash(npm version:*)",
21
+ "Bash(npm run lint:fix:*)",
22
+ "Bash(cat:*)"
21
23
  ]
22
24
  }
23
25
  }
package/bin/cli.js CHANGED
@@ -17,6 +17,7 @@ const spreadCommand = require('../src/commands/spread');
17
17
  const apiKeysCommand = require('../src/commands/api-keys');
18
18
  const upgradeCommand = require('../src/commands/upgrade');
19
19
  const mcpServerCommand = require('../src/commands/mcp-server');
20
+ const mcpSetupCommand = require('../src/commands/mcp-setup');
20
21
 
21
22
  // Create CLI program
22
23
  const program = new Command();
@@ -72,6 +73,11 @@ program
72
73
  .description(mcpServerCommand.description)
73
74
  .action(mcpServerCommand.handler);
74
75
 
76
+ program
77
+ .command(mcpSetupCommand.command)
78
+ .description(mcpSetupCommand.description)
79
+ .action(mcpSetupCommand.handler);
80
+
75
81
  // Show logo and welcome message if no command provided
76
82
  if (process.argv.length === 2) {
77
83
  console.log(''); // initial spacing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@l4yercak3/cli",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
4
4
  "description": "Icing on the L4yercak3 - The sweet finishing touch for your Layer Cake integration",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -15,13 +15,66 @@
15
15
 
16
16
  const { startServer } = require('../mcp/server');
17
17
 
18
+ /**
19
+ * Check if running in interactive terminal (manual invocation)
20
+ * vs being called by an MCP client (piped stdin/stdout)
21
+ */
22
+ function isInteractiveTerminal() {
23
+ return process.stdin.isTTY && process.stdout.isTTY;
24
+ }
25
+
26
+ /**
27
+ * Show setup instructions when run manually
28
+ */
29
+ function showManualInvocationHelp() {
30
+ // Use stderr since stdout is reserved for MCP protocol
31
+ console.error('');
32
+ console.error('╔══════════════════════════════════════════════════════════════╗');
33
+ console.error('ā•‘ L4YERCAK3 MCP Server - Setup Guide ā•‘');
34
+ console.error('ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•');
35
+ console.error('');
36
+ console.error('This command starts the MCP server for AI assistant integration.');
37
+ console.error('It\'s typically called by your MCP client, not run directly.');
38
+ console.error('');
39
+ console.error('šŸ“¦ Claude Code (CLI):');
40
+ console.error(' l4yercak3 mcp-setup');
41
+ console.error(' # or manually:');
42
+ console.error(' claude mcp add l4yercak3 -- npx @l4yercak3/cli mcp-server');
43
+ console.error('');
44
+ console.error('šŸ–„ļø Claude Desktop:');
45
+ console.error(' Add to ~/Library/Application Support/Claude/claude_desktop_config.json:');
46
+ console.error(' {');
47
+ console.error(' "mcpServers": {');
48
+ console.error(' "l4yercak3": {');
49
+ console.error(' "command": "npx",');
50
+ console.error(' "args": ["@l4yercak3/cli", "mcp-server"]');
51
+ console.error(' }');
52
+ console.error(' }');
53
+ console.error(' }');
54
+ console.error('');
55
+ console.error('šŸ”Œ Other MCP Clients (Cursor, Cody, Continue, etc.):');
56
+ console.error(' Command: npx @l4yercak3/cli mcp-server');
57
+ console.error(' Transport: stdio');
58
+ console.error('');
59
+ console.error('šŸ’” Requirements:');
60
+ console.error(' • Logged in to L4YERCAK3 (l4yercak3 login)');
61
+ console.error('');
62
+ }
63
+
18
64
  module.exports = {
19
65
  command: 'mcp-server',
20
- description: 'Start the MCP server for Claude Code integration',
66
+ description: 'Start the MCP server for AI assistant integration',
21
67
  handler: async () => {
22
68
  // Note: All output goes to stderr because stdout is used for MCP protocol
23
69
  // console.error is used intentionally here
24
70
 
71
+ // If running in an interactive terminal (not piped), show help
72
+ if (isInteractiveTerminal()) {
73
+ showManualInvocationHelp();
74
+ console.error('Starting server anyway (press Ctrl+C to exit)...');
75
+ console.error('');
76
+ }
77
+
25
78
  try {
26
79
  await startServer();
27
80
  } catch (error) {
@@ -0,0 +1,510 @@
1
+ /**
2
+ * MCP Setup Command
3
+ *
4
+ * Configures MCP clients to use the L4YERCAK3 MCP server.
5
+ * Supports Claude Code CLI, Claude Desktop, and other MCP-compatible clients.
6
+ *
7
+ * @module commands/mcp-setup
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const os = require('os');
13
+ const { execSync } = require('child_process');
14
+ const chalk = require('chalk');
15
+ const inquirer = require('inquirer');
16
+ const configManager = require('../config/config-manager');
17
+
18
+ /**
19
+ * Check if Claude CLI is installed
20
+ */
21
+ function isClaudeInstalled() {
22
+ try {
23
+ execSync('claude --version', { stdio: 'pipe' });
24
+ return true;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Check if MCP server is already configured in Claude
32
+ */
33
+ function isMcpConfigured() {
34
+ try {
35
+ const result = execSync('claude mcp list', {
36
+ stdio: 'pipe',
37
+ encoding: 'utf8'
38
+ });
39
+ return result.includes('l4yercak3');
40
+ } catch {
41
+ return false;
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Configure Claude MCP with l4yercak3 server
47
+ */
48
+ async function configureMcp(scope = 'user') {
49
+ const scopeFlag = scope === 'project' ? '--scope project' : '';
50
+ const command = `claude mcp add l4yercak3 ${scopeFlag} -- npx @l4yercak3/cli mcp-server`.trim();
51
+
52
+ try {
53
+ execSync(command, { stdio: 'inherit' });
54
+ return true;
55
+ } catch (error) {
56
+ console.error(chalk.red(`Failed to configure MCP: ${error.message}`));
57
+ return false;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Remove existing MCP configuration from Claude Code
63
+ */
64
+ function removeMcpConfig() {
65
+ try {
66
+ execSync('claude mcp remove l4yercak3', { stdio: 'pipe' });
67
+ return true;
68
+ } catch {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Get Claude Desktop config path based on platform
75
+ */
76
+ function getClaudeDesktopConfigPath() {
77
+ const platform = os.platform();
78
+ const home = os.homedir();
79
+
80
+ if (platform === 'darwin') {
81
+ return path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
82
+ } else if (platform === 'win32') {
83
+ return path.join(process.env.APPDATA || home, 'Claude', 'claude_desktop_config.json');
84
+ } else {
85
+ // Linux
86
+ return path.join(home, '.config', 'Claude', 'claude_desktop_config.json');
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Get the full path to npx executable
92
+ * Claude Desktop needs absolute paths since it doesn't inherit shell PATH
93
+ */
94
+ function getNpxPath() {
95
+ try {
96
+ const npxPath = execSync('which npx', { stdio: 'pipe', encoding: 'utf8' }).trim();
97
+ return npxPath || 'npx';
98
+ } catch {
99
+ // Fallback to common locations
100
+ const commonPaths = [
101
+ '/usr/local/bin/npx',
102
+ '/opt/homebrew/bin/npx',
103
+ '/usr/bin/npx',
104
+ path.join(os.homedir(), '.nvm/versions/node', 'current', 'bin', 'npx'),
105
+ ];
106
+
107
+ for (const p of commonPaths) {
108
+ if (fs.existsSync(p)) {
109
+ return p;
110
+ }
111
+ }
112
+
113
+ return 'npx'; // Last resort fallback
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Get the full path to l4yercak3 CLI if globally installed
119
+ * Returns null if not found
120
+ */
121
+ function getL4yercak3Path() {
122
+ try {
123
+ const cliPath = execSync('which l4yercak3', { stdio: 'pipe', encoding: 'utf8' }).trim();
124
+ return cliPath || null;
125
+ } catch {
126
+ return null;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Get the best command configuration for Claude Desktop
132
+ * Prefers globally installed l4yercak3 over npx for reliability
133
+ */
134
+ function getClaudeDesktopCommand() {
135
+ const l4yercak3Path = getL4yercak3Path();
136
+
137
+ if (l4yercak3Path) {
138
+ // Use globally installed CLI directly (more reliable)
139
+ return {
140
+ command: l4yercak3Path,
141
+ args: ['mcp-server'],
142
+ description: `${l4yercak3Path} mcp-server`
143
+ };
144
+ }
145
+
146
+ // Fall back to npx
147
+ const npxPath = getNpxPath();
148
+ return {
149
+ command: npxPath,
150
+ args: ['@l4yercak3/cli', 'mcp-server'],
151
+ description: `${npxPath} @l4yercak3/cli mcp-server`
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Check if Claude Desktop config exists
157
+ */
158
+ function hasClaudeDesktopConfig() {
159
+ return fs.existsSync(getClaudeDesktopConfigPath());
160
+ }
161
+
162
+ /**
163
+ * Configure Claude Desktop with l4yercak3 MCP server
164
+ */
165
+ function configureClaudeDesktop() {
166
+ const configPath = getClaudeDesktopConfigPath();
167
+ let config = { mcpServers: {} };
168
+
169
+ // Read existing config if it exists
170
+ if (fs.existsSync(configPath)) {
171
+ try {
172
+ const content = fs.readFileSync(configPath, 'utf8');
173
+ config = JSON.parse(content);
174
+ if (!config.mcpServers) {
175
+ config.mcpServers = {};
176
+ }
177
+ } catch {
178
+ // If parsing fails, start fresh but preserve the file structure
179
+ config = { mcpServers: {} };
180
+ }
181
+ } else {
182
+ // Ensure directory exists
183
+ const configDir = path.dirname(configPath);
184
+ if (!fs.existsSync(configDir)) {
185
+ fs.mkdirSync(configDir, { recursive: true });
186
+ }
187
+ }
188
+
189
+ // Add l4yercak3 server with full path
190
+ // Claude Desktop doesn't inherit shell PATH, so we need absolute paths
191
+ const cmdConfig = getClaudeDesktopCommand();
192
+
193
+ config.mcpServers.l4yercak3 = {
194
+ command: cmdConfig.command,
195
+ args: cmdConfig.args
196
+ };
197
+
198
+ // Write config
199
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
200
+ return { configPath, commandDescription: cmdConfig.description };
201
+ }
202
+
203
+ /**
204
+ * Remove l4yercak3 from Claude Desktop config
205
+ */
206
+ function removeClaudeDesktopConfig() {
207
+ const configPath = getClaudeDesktopConfigPath();
208
+
209
+ if (!fs.existsSync(configPath)) {
210
+ return false;
211
+ }
212
+
213
+ try {
214
+ const content = fs.readFileSync(configPath, 'utf8');
215
+ const config = JSON.parse(content);
216
+
217
+ if (config.mcpServers && config.mcpServers.l4yercak3) {
218
+ delete config.mcpServers.l4yercak3;
219
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
220
+ return true;
221
+ }
222
+ } catch {
223
+ return false;
224
+ }
225
+
226
+ return false;
227
+ }
228
+
229
+ /**
230
+ * Check if l4yercak3 is configured in Claude Desktop
231
+ */
232
+ function isClaudeDesktopConfigured() {
233
+ const configPath = getClaudeDesktopConfigPath();
234
+
235
+ if (!fs.existsSync(configPath)) {
236
+ return false;
237
+ }
238
+
239
+ try {
240
+ const content = fs.readFileSync(configPath, 'utf8');
241
+ const config = JSON.parse(content);
242
+ return config.mcpServers && config.mcpServers.l4yercak3;
243
+ } catch {
244
+ return false;
245
+ }
246
+ }
247
+
248
+ module.exports = {
249
+ command: 'mcp-setup',
250
+ description: 'Configure MCP clients to use the L4YERCAK3 server',
251
+ handler: async () => {
252
+ console.log('');
253
+ console.log(chalk.bold.hex('#9F7AEA')('šŸ”§ L4YERCAK3 MCP Setup\n'));
254
+
255
+ // Check if logged in
256
+ const session = configManager.getSession();
257
+ if (!session) {
258
+ console.log(chalk.yellow('āš ļø Not logged in to L4YERCAK3'));
259
+ console.log(chalk.gray(' Run `l4yercak3 login` first to authenticate.\n'));
260
+ console.log(chalk.gray(' The MCP server needs your session to access L4YERCAK3 features.'));
261
+ process.exit(1);
262
+ }
263
+
264
+ console.log(chalk.green('āœ“ Logged in as: ') + chalk.white(session.email || session.userId));
265
+ console.log('');
266
+
267
+ // Detect available clients
268
+ const hasClaudeCli = isClaudeInstalled();
269
+ const hasClaudeDesktop = hasClaudeDesktopConfig() || fs.existsSync(path.dirname(getClaudeDesktopConfigPath()));
270
+
271
+ // Build client choices
272
+ const clientChoices = [];
273
+
274
+ if (hasClaudeCli) {
275
+ const configured = isMcpConfigured();
276
+ clientChoices.push({
277
+ name: `Claude Code (CLI)${configured ? chalk.gray(' - already configured') : ''}`,
278
+ value: 'claude-code',
279
+ configured
280
+ });
281
+ }
282
+
283
+ clientChoices.push({
284
+ name: `Claude Desktop${isClaudeDesktopConfigured() ? chalk.gray(' - already configured') : ''}`,
285
+ value: 'claude-desktop',
286
+ configured: isClaudeDesktopConfigured()
287
+ });
288
+
289
+ clientChoices.push({
290
+ name: 'Other MCP client (show manual instructions)',
291
+ value: 'other'
292
+ });
293
+
294
+ // Ask which client to configure
295
+ const { client } = await inquirer.prompt([
296
+ {
297
+ type: 'list',
298
+ name: 'client',
299
+ message: 'Which MCP client would you like to configure?',
300
+ choices: clientChoices,
301
+ },
302
+ ]);
303
+
304
+ console.log('');
305
+
306
+ if (client === 'claude-code') {
307
+ await setupClaudeCode();
308
+ } else if (client === 'claude-desktop') {
309
+ await setupClaudeDesktop();
310
+ } else {
311
+ showOtherClientInstructions();
312
+ }
313
+ },
314
+ };
315
+
316
+ /**
317
+ * Setup Claude Code CLI
318
+ */
319
+ async function setupClaudeCode() {
320
+ const alreadyConfigured = isMcpConfigured();
321
+
322
+ if (alreadyConfigured) {
323
+ const { action } = await inquirer.prompt([
324
+ {
325
+ type: 'list',
326
+ name: 'action',
327
+ message: 'L4YERCAK3 is already configured. What would you like to do?',
328
+ choices: [
329
+ { name: 'Keep existing configuration', value: 'keep' },
330
+ { name: 'Reconfigure (remove and re-add)', value: 'reconfigure' },
331
+ { name: 'Remove configuration', value: 'remove' },
332
+ ],
333
+ },
334
+ ]);
335
+
336
+ if (action === 'keep') {
337
+ console.log(chalk.gray('\nKeeping existing configuration.'));
338
+ showUsageInstructions('Claude Code');
339
+ return;
340
+ }
341
+
342
+ if (action === 'remove') {
343
+ removeMcpConfig();
344
+ console.log(chalk.green('\nāœ“ L4YERCAK3 MCP server removed from Claude Code'));
345
+ return;
346
+ }
347
+
348
+ removeMcpConfig();
349
+ console.log(chalk.gray('Removed existing configuration...'));
350
+ }
351
+
352
+ // Ask for scope
353
+ const { scope } = await inquirer.prompt([
354
+ {
355
+ type: 'list',
356
+ name: 'scope',
357
+ message: 'Where should the MCP server be configured?',
358
+ choices: [
359
+ { name: 'User (global) - Available in all projects', value: 'user' },
360
+ { name: 'Project - Only for current directory', value: 'project' },
361
+ ],
362
+ default: 'user',
363
+ },
364
+ ]);
365
+
366
+ console.log('');
367
+ console.log(chalk.gray('Configuring Claude Code...'));
368
+
369
+ const success = await configureMcp(scope);
370
+
371
+ if (success) {
372
+ console.log('');
373
+ console.log(chalk.green.bold('āœ“ L4YERCAK3 MCP server configured for Claude Code!\n'));
374
+ showUsageInstructions('Claude Code');
375
+ } else {
376
+ console.log('');
377
+ console.log(chalk.red('Failed to configure MCP server.'));
378
+ console.log(chalk.gray('\nYou can try manual configuration:'));
379
+ console.log(chalk.cyan(' claude mcp add l4yercak3 -- npx @l4yercak3/cli mcp-server'));
380
+ }
381
+ }
382
+
383
+ /**
384
+ * Setup Claude Desktop
385
+ */
386
+ async function setupClaudeDesktop() {
387
+ const alreadyConfigured = isClaudeDesktopConfigured();
388
+
389
+ if (alreadyConfigured) {
390
+ const { action } = await inquirer.prompt([
391
+ {
392
+ type: 'list',
393
+ name: 'action',
394
+ message: 'L4YERCAK3 is already configured. What would you like to do?',
395
+ choices: [
396
+ { name: 'Keep existing configuration', value: 'keep' },
397
+ { name: 'Reconfigure', value: 'reconfigure' },
398
+ { name: 'Remove configuration', value: 'remove' },
399
+ ],
400
+ },
401
+ ]);
402
+
403
+ if (action === 'keep') {
404
+ console.log(chalk.gray('\nKeeping existing configuration.'));
405
+ showUsageInstructions('Claude Desktop');
406
+ return;
407
+ }
408
+
409
+ if (action === 'remove') {
410
+ removeClaudeDesktopConfig();
411
+ console.log(chalk.green('\nāœ“ L4YERCAK3 MCP server removed from Claude Desktop'));
412
+ console.log(chalk.gray(' Restart Claude Desktop for changes to take effect.'));
413
+ return;
414
+ }
415
+ }
416
+
417
+ console.log(chalk.gray('Configuring Claude Desktop...'));
418
+
419
+ try {
420
+ const { configPath, commandDescription } = configureClaudeDesktop();
421
+ console.log('');
422
+ console.log(chalk.green.bold('āœ“ L4YERCAK3 MCP server configured for Claude Desktop!\n'));
423
+ console.log(chalk.gray(` Config: ${configPath}`));
424
+ console.log(chalk.gray(` Command: ${commandDescription}`));
425
+ console.log(chalk.yellow('\n āš ļø Restart Claude Desktop for changes to take effect.'));
426
+ console.log(chalk.gray(' (Using absolute path since Claude Desktop doesn\'t inherit your shell PATH)\n'));
427
+ showUsageInstructions('Claude Desktop');
428
+ } catch (error) {
429
+ console.log('');
430
+ console.log(chalk.red(`Failed to configure Claude Desktop: ${error.message}`));
431
+ showClaudeDesktopManualInstructions();
432
+ }
433
+ }
434
+
435
+ /**
436
+ * Show manual instructions for Claude Desktop
437
+ */
438
+ function showClaudeDesktopManualInstructions() {
439
+ const configPath = getClaudeDesktopConfigPath();
440
+ const cmdConfig = getClaudeDesktopCommand();
441
+
442
+ console.log(chalk.gray('\nManual configuration:'));
443
+ console.log(chalk.gray(` Edit: ${configPath}`));
444
+ console.log('');
445
+ console.log(chalk.white(' Add to mcpServers (use absolute paths):'));
446
+ console.log(chalk.cyan(' {'));
447
+ console.log(chalk.cyan(' "mcpServers": {'));
448
+ console.log(chalk.cyan(' "l4yercak3": {'));
449
+ console.log(chalk.cyan(` "command": "${cmdConfig.command}",`));
450
+ console.log(chalk.cyan(` "args": ${JSON.stringify(cmdConfig.args)}`));
451
+ console.log(chalk.cyan(' }'));
452
+ console.log(chalk.cyan(' }'));
453
+ console.log(chalk.cyan(' }'));
454
+ console.log('');
455
+ console.log(chalk.gray(' Note: Claude Desktop doesn\'t inherit your shell PATH.'));
456
+ console.log(chalk.gray(` Find paths with: ${chalk.cyan('which l4yercak3')} or ${chalk.cyan('which npx')}`));
457
+ console.log('');
458
+ }
459
+
460
+ /**
461
+ * Show instructions for other MCP clients
462
+ */
463
+ function showOtherClientInstructions() {
464
+ console.log(chalk.bold('šŸ”Œ Manual MCP Configuration\n'));
465
+
466
+ console.log(chalk.white(' Server command:'));
467
+ console.log(chalk.cyan(' npx @l4yercak3/cli mcp-server\n'));
468
+
469
+ console.log(chalk.white(' Transport: ') + chalk.cyan('stdio\n'));
470
+
471
+ console.log(chalk.white(' Compatible clients include:'));
472
+ console.log(chalk.gray(' • Cursor'));
473
+ console.log(chalk.gray(' • Cody (Sourcegraph)'));
474
+ console.log(chalk.gray(' • Continue'));
475
+ console.log(chalk.gray(' • Zed'));
476
+ console.log(chalk.gray(' • Any MCP-compatible AI assistant'));
477
+ console.log('');
478
+
479
+ console.log(chalk.white(' JSON configuration format:'));
480
+ console.log(chalk.cyan(' {'));
481
+ console.log(chalk.cyan(' "command": "npx",'));
482
+ console.log(chalk.cyan(' "args": ["@l4yercak3/cli", "mcp-server"],'));
483
+ console.log(chalk.cyan(' "transport": "stdio"'));
484
+ console.log(chalk.cyan(' }'));
485
+ console.log('');
486
+
487
+ console.log(chalk.gray(' Refer to your client\'s documentation for where to add this config.\n'));
488
+ }
489
+
490
+ /**
491
+ * Show usage instructions after setup
492
+ */
493
+ function showUsageInstructions(clientName = 'your AI assistant') {
494
+ console.log(chalk.bold('šŸ“– How to use:\n'));
495
+
496
+ console.log(chalk.white(` In ${clientName}, you can now:`));
497
+ console.log(chalk.gray(' • Ask Claude to list your L4YERCAK3 contacts, projects, or invoices'));
498
+ console.log(chalk.gray(' • Create or update CRM records through natural language'));
499
+ console.log(chalk.gray(' • Get project integration help with context from your L4YERCAK3 data'));
500
+ console.log('');
501
+
502
+ console.log(chalk.white(' Example prompts:'));
503
+ console.log(chalk.cyan(' "Show me my recent contacts in L4YERCAK3"'));
504
+ console.log(chalk.cyan(' "Create a new project called Website Redesign"'));
505
+ console.log(chalk.cyan(' "What invoices are pending?"'));
506
+ console.log('');
507
+
508
+ console.log(chalk.gray(' The MCP server runs automatically when needed.'));
509
+ console.log(chalk.gray(' Your session stays active until you run `l4yercak3 logout`.\n'));
510
+ }
@@ -522,6 +522,8 @@ async function handleSpread() {
522
522
  githubRepo: detection.github.isGitHub ? `${detection.github.owner}/${detection.github.repo}` : undefined,
523
523
  githubBranch: detection.github.branch || 'main',
524
524
  },
525
+ // Don't generate a new API key if user already has one configured
526
+ skipApiKeyGeneration: apiKey === null,
525
527
  };
526
528
 
527
529
  const registrationResult = await backendClient.registerApplication(registrationData);
@@ -583,9 +585,9 @@ async function handleSpread() {
583
585
  applicationId = registrationResult.applicationId;
584
586
  console.log(chalk.green(` āœ… Application registered with L4YERCAK3\n`));
585
587
 
586
- // If backend returned a new API key, use it
588
+ // Show API key if backend generated one
587
589
  if (registrationResult.apiKey && registrationResult.apiKey.key) {
588
- console.log(chalk.gray(` API key generated: ${registrationResult.apiKey.prefix}`));
590
+ console.log(chalk.gray(` API key: ${registrationResult.apiKey.prefix}`));
589
591
  }
590
592
  }
591
593
  } catch (regError) {
@@ -464,11 +464,11 @@ Looks at database schemas, types, and common patterns.`,
464
464
  },
465
465
  },
466
466
  requiresAuth: true,
467
- handler: async (params, authContext) => {
467
+ handler: async (params, authContext) =>
468
468
  // This tool provides suggestions based on common patterns
469
469
  // In a real implementation, it would analyze actual project files
470
470
 
471
- return {
471
+ ({
472
472
  suggestions: [
473
473
  {
474
474
  localModel: 'User',
@@ -509,8 +509,8 @@ Looks at database schemas, types, and common patterns.`,
509
509
  'Use l4yercak3_add_model_mapping to add mappings you want',
510
510
  'Customize field mappings as needed for your schema',
511
511
  ],
512
- };
513
- },
512
+ })
513
+ ,
514
514
  },
515
515
  ],
516
516
  };
@@ -195,8 +195,7 @@ Use this when the user needs to login but hasn't yet.`,
195
195
  properties: {},
196
196
  },
197
197
  requiresAuth: false,
198
- handler: async () => {
199
- return {
198
+ handler: async () => ({
200
199
  instructions: [
201
200
  '1. Open a terminal in this project directory',
202
201
  '2. Run: l4yercak3 login',
@@ -209,8 +208,7 @@ Use this when the user needs to login but hasn't yet.`,
209
208
  '2. Then run: l4yercak3 login',
210
209
  ],
211
210
  documentation: 'https://docs.l4yercak3.com/cli/authentication',
212
- };
213
- },
211
+ }),
214
212
  },
215
213
 
216
214
  // ========================================