@habitusnet/bc365 2.2.5 → 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 CHANGED
@@ -2,6 +2,19 @@
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
+
12
+ ## [2.2.6] — 2026-02-20
13
+
14
+ ### Changed
15
+ - README rewritten: two-command quick start, scope table, skills section, multi-tenant workflow, troubleshooting
16
+ - SETUP.md updated: removed stale v1/`--output` references, updated multi-tenant section for `bc365 switch`
17
+
5
18
  ## [2.2.5] — 2026-02-20
6
19
 
7
20
  ### Changed
package/README.md CHANGED
@@ -1,103 +1,149 @@
1
- # bc365 — MCP Config Manager for Business Central
1
+ # bc365
2
2
 
3
- `@habitusnet/bc365` is a CLI that connects Claude Code to Microsoft Dynamics 365 Business Central auto-discovering your environments, registering MCP servers, and installing BC-aware Claude skills.
4
-
5
- ## Quick Start
3
+ > Connect Claude Code to Microsoft Dynamics 365 Business Central in two commands.
6
4
 
7
5
  ```bash
8
6
  npx @habitusnet/bc365 onboard
7
+ claude plugin install habitusnet/bc365-skills
9
8
  ```
10
9
 
11
- Sign in with your Microsoft account. The CLI discovers your tenant, environments, and companies automatically, checks your BC permissions, and registers both MCP servers with Claude Code.
10
+ ---
12
11
 
13
- Then install the Claude Code skill bundle:
12
+ ## What It Does
14
13
 
15
- ```bash
16
- claude plugin install habitusnet/bc365-skills
17
- ```
14
+ `bc365 onboard` signs you in with Microsoft, discovers your BC environments and companies, and registers two MCP servers directly with Claude Code:
15
+
16
+ | MCP Server | Purpose |
17
+ |------------|---------|
18
+ | `bc-data` | Read and write BC data — customers, items, orders, G/L entries via OData |
19
+ | `bc-admin` | Manage environments, apps, feature flags, and user sessions |
20
+
21
+ `claude plugin install habitusnet/bc365-skills` adds three Claude skills that tell Claude how to use those servers effectively.
22
+
23
+ ---
24
+
25
+ ## Prerequisites
18
26
 
19
- **Prerequisites:**
20
- - Claude Code installed (`npm install -g @anthropic-ai/claude-code`)
21
- - Microsoft 365 / Azure AD account with access to Business Central
22
- - Business Central environment with `D365 BUS FULL ACCESS` permission set
27
+ - [Claude Code](https://docs.anthropic.com/claude-code) installed
28
+ - Node.js 20
29
+ - Microsoft 365 account with access to Business Central
30
+ - `D365 BUS FULL ACCESS` permission set in BC
23
31
 
24
32
  ---
25
33
 
26
34
  ## Installation
27
35
 
36
+ ### Global install (recommended)
37
+
28
38
  ```bash
29
39
  npm install -g @habitusnet/bc365
40
+ bc365 onboard
30
41
  ```
31
42
 
32
- Or use without installing:
43
+ ### One-off (no install)
33
44
 
34
45
  ```bash
35
46
  npx @habitusnet/bc365 onboard
36
47
  ```
37
48
 
38
- ## What `bc365 onboard` Does
49
+ ---
50
+
51
+ ## Onboarding
52
+
53
+ ```bash
54
+ bc365 onboard
55
+ ```
39
56
 
40
- 1. Opens a Microsoft device code login in your browser
41
- 2. Discovers your BC environments and companies
42
- 3. Checks your permission sets
43
- 4. Registers two MCP servers with Claude Code (`claude mcp add-json -s local`):
44
- - **`bc-data`** — query and update BC data via OData (customers, items, orders, G/L entries)
45
- - **`bc-admin`** — manage environments, apps, feature flags, and sessions
57
+ 1. A device code URL is printed — open it in your browser and sign in with your Microsoft account
58
+ 2. The CLI discovers your tenant, environments, and companies
59
+ 3. Checks your BC permission sets and warns if anything is missing
60
+ 4. Registers `bc-data` and `bc-admin` with Claude Code
46
61
 
47
- Servers are registered at local scope (`.claude/settings.local.json`, gitignored and per-user). Pass `--scope` to override:
62
+ Servers are registered at **local scope** by default — stored in `.claude/settings.local.json`, gitignored, per-user. Use `--scope` to change this:
48
63
 
49
64
  | Scope | Stored in | Use when |
50
65
  |-------|-----------|----------|
51
- | `local` (default) | `.claude/settings.local.json` | Per-user, gitignored — recommended |
66
+ | `local` *(default)* | `.claude/settings.local.json` | Per-user, gitignored — recommended |
52
67
  | `user` | `~/.claude.json` | All projects for this user |
53
68
  | `project` | `.mcp.json` | Shared team config, committed to git |
54
69
 
55
70
  ```bash
56
- bc365 onboard # local scope (default)
57
- bc365 onboard --scope project # writes .mcp.json
58
- bc365 switch habitusnet-prod # re-register saved profile at local scope
59
- bc365 switch habitusnet-prod --scope user # re-register at user scope
71
+ bc365 onboard # local scope (default)
72
+ bc365 onboard --scope project # writes .mcp.json for the whole team
60
73
  ```
61
74
 
62
- ## Claude Code Skills
63
-
64
- After onboarding, install the companion skill bundle:
75
+ After onboarding, install the skill bundle:
65
76
 
66
77
  ```bash
67
78
  claude plugin install habitusnet/bc365-skills
68
79
  ```
69
80
 
70
- This gives Claude three skills:
81
+ ---
82
+
83
+ ## Claude Skills
71
84
 
72
- | Skill | Description |
73
- |-------|-------------|
74
- | `bc-query` | Query and update BC data — OData filters, expand for line items, pagination |
75
- | `bc-admin` | Manage environments, apps, feature flags, sessions |
76
- | `bc-diagnose` | Interpret BC HTTP/OData errors and suggest fixes |
85
+ The [`habitusnet/bc365-skills`](https://github.com/habitusnet/bc365-skills) plugin teaches Claude how to use the MCP servers:
77
86
 
78
- Skills are also bundled in this package under `skills/` for offline use.
87
+ | Skill | What it covers |
88
+ |-------|----------------|
89
+ | `bc-query` | OData filters, `$expand` for line items, pagination, write operations |
90
+ | `bc-admin` | Environment inspection, app update workflow, feature flags, session management |
91
+ | `bc-diagnose` | HTTP/OData error interpretation, permission set reference, diagnostic workflow |
79
92
 
80
- ## Commands
93
+ Skills are also bundled in this package under `skills/` for offline access.
94
+
95
+ ---
96
+
97
+ ## Multi-Tenant Usage (Agencies)
98
+
99
+ Each `bc365 onboard` run saves a profile. Switch between clients without re-authenticating:
100
+
101
+ ```bash
102
+ # Onboard client A (saves profile automatically)
103
+ bc365 onboard
104
+
105
+ # Later: switch to client B
106
+ bc365 switch client-b-profile
107
+
108
+ # List all saved profiles
109
+ bc365 profiles
110
+ ```
111
+
112
+ `bc365 switch` accepts the same `--scope` flag as `onboard`.
113
+
114
+ ---
115
+
116
+ ## All Commands
81
117
 
82
118
  | Command | Description |
83
119
  |---------|-------------|
84
- | `bc365 onboard [-s local\|user\|project]` | Discover and register MCP servers |
120
+ | `bc365 onboard [-s local\|user\|project]` | Discover tenant/env/company and register MCP servers |
85
121
  | `bc365 switch <profile> [-s local\|user\|project]` | Re-register servers from a saved profile |
86
122
  | `bc365 profiles` | List saved profiles |
87
123
  | `bc365 check` | Check latest npm versions of bc365 packages |
88
124
 
89
- ## Multi-Tenant Usage
90
-
91
- For agencies managing multiple clients, see [SETUP.md](SETUP.md#multi-tenant-usage-agencies).
125
+ ---
92
126
 
93
127
  ## MCP Servers
94
128
 
95
- | Server | Package | Purpose |
96
- |--------|---------|---------|
97
- | `bc-data` | [`@habitusnet/mcp-business-central`](https://github.com/habitusnet/mcp-business-central) | OData read/write on BC entities |
98
- | `bc-admin` | [`habitusnet/d365bc-admin-mcp`](https://github.com/habitusnet/d365bc-admin-mcp) | BC Admin Center API |
129
+ Both servers are vendored mirrors with daily upstream sync and security scanning:
130
+
131
+ | Server | Upstream | npm command |
132
+ |--------|----------|-------------|
133
+ | `bc-admin` | [`habitusnet/d365bc-admin-mcp`](https://github.com/habitusnet/d365bc-admin-mcp) | `d365bc-admin-mcp` |
134
+ | `bc-data` | [`habitusnet/mcp-business-central`](https://github.com/habitusnet/mcp-business-central) | `npx @habitusnet/mcp-business-central` |
135
+
136
+ ---
137
+
138
+ ## Troubleshooting
139
+
140
+ **Auth errors (`401`)** — run `az login` to refresh Azure CLI credentials, or re-run `bc365 onboard`.
141
+
142
+ **Missing permissions warning** — ask your BC admin to assign `D365 BUS FULL ACCESS` in Settings → Users → Permission Sets.
99
143
 
100
- Both are vendored mirrors with daily upstream sync and security scanning.
144
+ **`claude: command not found`** Claude Code must be installed and on your PATH before running `bc365 onboard`.
145
+
146
+ ---
101
147
 
102
148
  ## License
103
149
 
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 with Claude Code')
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>', 'Configuration scope: local, user, or project (default: local)', 'local')
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>', 'Configuration scope: local, user, or project (default: local)', 'local')
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 { execFile: _execFile } = await import('node:child_process');
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
- for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
50
- await execFile('claude', ['mcp', 'add-json', '-s', opts.scope, name, JSON.stringify(serverConfig)]);
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
- for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
72
- await execFile('claude', ['mcp', 'add-json', '-s', scope, name, JSON.stringify(serverConfig)]);
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@habitusnet/bc365",
3
- "version": "2.2.5",
3
+ "version": "2.2.7",
4
4
  "description": "Smart onboarding CLI and MCP config manager for Business Central",
5
5
  "type": "module",
6
6
  "bin": {