@habitusnet/bc365 2.2.6 → 2.2.7
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/CHANGELOG.md +7 -0
- package/lib/cli.js +19 -11
- package/lib/onboard.js +36 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.2.7] — 2026-02-20
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `bc365 onboard --target claude-desktop` writes MCP servers directly into `claude_desktop_config.json`, merging with any existing config and preserving other keys
|
|
9
|
+
- `bc365 switch <profile> --target claude-desktop` does the same from a saved profile
|
|
10
|
+
- Both commands print "Restart Claude Desktop to apply changes." when using the claude-desktop target
|
|
11
|
+
|
|
5
12
|
## [2.2.6] — 2026-02-20
|
|
6
13
|
|
|
7
14
|
### Changed
|
package/lib/cli.js
CHANGED
|
@@ -17,13 +17,14 @@ program
|
|
|
17
17
|
|
|
18
18
|
program
|
|
19
19
|
.command('onboard')
|
|
20
|
-
.description('Auto-discover tenant/environment/company and register MCP servers
|
|
20
|
+
.description('Auto-discover tenant/environment/company and register MCP servers')
|
|
21
21
|
.option('-t, --tenant-id <id>', 'Azure AD tenant ID (skip Graph lookup)')
|
|
22
|
-
.option('-s, --scope <scope>', '
|
|
22
|
+
.option('-s, --scope <scope>', 'Claude Code scope: local, user, or project (default: local)', 'local')
|
|
23
|
+
.option('--target <target>', 'Target: claude-code or claude-desktop (default: claude-code)', 'claude-code')
|
|
23
24
|
.option('-p, --profile <name>', 'Profile name to save (default: tenantId/envName)')
|
|
24
25
|
.action(async (opts) => {
|
|
25
26
|
try {
|
|
26
|
-
await onboard({ tenantId: opts.tenantId, scope: opts.scope, profileName: opts.profile });
|
|
27
|
+
await onboard({ tenantId: opts.tenantId, scope: opts.scope, target: opts.target, profileName: opts.profile });
|
|
27
28
|
} catch (err) {
|
|
28
29
|
console.error(chalk.red(`✗ ${err.message}`));
|
|
29
30
|
process.exit(1);
|
|
@@ -33,7 +34,8 @@ program
|
|
|
33
34
|
program
|
|
34
35
|
.command('switch <profile>')
|
|
35
36
|
.description('Switch active profile (re-registers MCP servers from saved profile)')
|
|
36
|
-
.option('-s, --scope <scope>', '
|
|
37
|
+
.option('-s, --scope <scope>', 'Claude Code scope: local, user, or project (default: local)', 'local')
|
|
38
|
+
.option('--target <target>', 'Target: claude-code or claude-desktop (default: claude-code)', 'claude-code')
|
|
37
39
|
.action(async (profileName, opts) => {
|
|
38
40
|
try {
|
|
39
41
|
const profile = await loadProfile(profileName);
|
|
@@ -41,15 +43,21 @@ program
|
|
|
41
43
|
console.error(chalk.red(`✗ Profile '${profileName}' not found. Run 'bc365 onboard' first.`));
|
|
42
44
|
process.exit(1);
|
|
43
45
|
}
|
|
44
|
-
const {
|
|
45
|
-
const { promisify } = await import('node:util');
|
|
46
|
-
const execFile = promisify(_execFile);
|
|
47
|
-
const { buildMcpConfig } = await import('./onboard.js');
|
|
46
|
+
const { buildMcpConfig, registerWithClaudeDesktop } = await import('./onboard.js');
|
|
48
47
|
const config = buildMcpConfig(profile);
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
if (opts.target === 'claude-desktop') {
|
|
49
|
+
const configPath = await registerWithClaudeDesktop(config);
|
|
50
|
+
console.log(chalk.green(`✓ Switched to profile '${profileName}' → ${configPath}`));
|
|
51
|
+
console.log('Restart Claude Desktop to apply changes.');
|
|
52
|
+
} else {
|
|
53
|
+
const { execFile: _execFile } = await import('node:child_process');
|
|
54
|
+
const { promisify } = await import('node:util');
|
|
55
|
+
const execFile = promisify(_execFile);
|
|
56
|
+
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
57
|
+
await execFile('claude', ['mcp', 'add-json', '-s', opts.scope, name, JSON.stringify(serverConfig)]);
|
|
58
|
+
}
|
|
59
|
+
console.log(chalk.green(`✓ Switched to profile '${profileName}' (scope: ${opts.scope})`));
|
|
51
60
|
}
|
|
52
|
-
console.log(chalk.green(`✓ Switched to profile '${profileName}' (scope: ${opts.scope})`));
|
|
53
61
|
} catch (err) {
|
|
54
62
|
console.error(chalk.red(`✗ ${err.message}`));
|
|
55
63
|
process.exit(1);
|
package/lib/onboard.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { execFile as _execFile } from 'node:child_process';
|
|
2
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
2
5
|
import { promisify } from 'node:util';
|
|
3
6
|
import inquirer from 'inquirer';
|
|
4
7
|
import { getToken } from './auth.js';
|
|
@@ -8,6 +11,13 @@ import { saveProfile } from './profiles.js';
|
|
|
8
11
|
const execFile = promisify(_execFile);
|
|
9
12
|
const BC_API_BASE = 'https://api.businesscentral.dynamics.com/v2.0';
|
|
10
13
|
|
|
14
|
+
export function claudeDesktopConfigPath() {
|
|
15
|
+
if (process.platform === 'win32') {
|
|
16
|
+
return join(process.env.APPDATA, 'Claude', 'claude_desktop_config.json');
|
|
17
|
+
}
|
|
18
|
+
return join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
export function buildMcpConfig(ctx) {
|
|
12
22
|
const { tenantId, envName, companyId } = ctx;
|
|
13
23
|
return {
|
|
@@ -31,8 +41,24 @@ export function buildMcpConfig(ctx) {
|
|
|
31
41
|
};
|
|
32
42
|
}
|
|
33
43
|
|
|
44
|
+
export async function registerWithClaudeDesktop(config) {
|
|
45
|
+
const configPath = claudeDesktopConfigPath();
|
|
46
|
+
let existing = {};
|
|
47
|
+
try {
|
|
48
|
+
existing = JSON.parse(await readFile(configPath, 'utf8'));
|
|
49
|
+
} catch {
|
|
50
|
+
// file doesn't exist yet — start fresh
|
|
51
|
+
}
|
|
52
|
+
const merged = {
|
|
53
|
+
...existing,
|
|
54
|
+
mcpServers: { ...(existing.mcpServers ?? {}), ...config.mcpServers },
|
|
55
|
+
};
|
|
56
|
+
await writeFile(configPath, JSON.stringify(merged, null, 2), 'utf8');
|
|
57
|
+
return configPath;
|
|
58
|
+
}
|
|
59
|
+
|
|
34
60
|
export async function onboard(options = {}) {
|
|
35
|
-
const { tenantId, scope = 'local', profileName } = options;
|
|
61
|
+
const { tenantId, scope = 'local', target = 'claude-code', profileName } = options;
|
|
36
62
|
const token = await getToken();
|
|
37
63
|
|
|
38
64
|
const environments = await getEnvironments(token, { tenantId, type: 'Production' });
|
|
@@ -68,10 +94,16 @@ export async function onboard(options = {}) {
|
|
|
68
94
|
const ctx = { tenantId: selectedEnv.aadTenantId, envName, companyId };
|
|
69
95
|
const config = buildMcpConfig(ctx);
|
|
70
96
|
|
|
71
|
-
|
|
72
|
-
|
|
97
|
+
if (target === 'claude-desktop') {
|
|
98
|
+
const configPath = await registerWithClaudeDesktop(config);
|
|
99
|
+
console.log(`✓ Wrote MCP servers to ${configPath}`);
|
|
100
|
+
console.log('Restart Claude Desktop to apply changes.');
|
|
101
|
+
} else {
|
|
102
|
+
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
103
|
+
await execFile('claude', ['mcp', 'add-json', '-s', scope, name, JSON.stringify(serverConfig)]);
|
|
104
|
+
}
|
|
105
|
+
console.log(`✓ Registered MCP servers (scope: ${scope})`);
|
|
73
106
|
}
|
|
74
|
-
console.log(`✓ Registered MCP servers (scope: ${scope})`);
|
|
75
107
|
|
|
76
108
|
const name = profileName ?? `${selectedEnv.aadTenantId}/${envName}`;
|
|
77
109
|
await saveProfile(name, ctx);
|