bi-agent-kit 0.1.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/lib/targets.js ADDED
@@ -0,0 +1,216 @@
1
+ import path from "node:path";
2
+
3
+ function claudeDesktopPath(homedir, platform) {
4
+ if (platform === "darwin") {
5
+ return path.join(homedir, "Library", "Application Support", "Claude", "claude_desktop_config.json");
6
+ }
7
+ if (platform === "win32") {
8
+ const appData = process.env.APPDATA || path.join(homedir, "AppData", "Roaming");
9
+ return path.join(appData, "Claude", "claude_desktop_config.json");
10
+ }
11
+ return null;
12
+ }
13
+
14
+ function vsCodeUserDir(homedir, platform) {
15
+ if (platform === "darwin") {
16
+ return path.join(homedir, "Library", "Application Support", "Code", "User");
17
+ }
18
+ if (platform === "win32") {
19
+ const appData = process.env.APPDATA || path.join(homedir, "AppData", "Roaming");
20
+ return path.join(appData, "Code", "User");
21
+ }
22
+ return path.join(homedir, ".config", "Code", "User");
23
+ }
24
+
25
+ export const TARGET_DEFINITIONS = [
26
+ {
27
+ id: "claude-code",
28
+ rootLevel: true,
29
+ label: "Claude Code (project)",
30
+ shape: "json",
31
+ rootKey: "mcpServers",
32
+ resolve(cwd) {
33
+ return path.join(cwd, ".mcp.json");
34
+ },
35
+ },
36
+ {
37
+ id: "claude-code-user",
38
+ rootLevel: true,
39
+ label: "Claude Code (user)",
40
+ shape: "json",
41
+ rootKey: "mcpServers",
42
+ resolve(cwd, homedir) {
43
+ return path.join(homedir, ".claude.json");
44
+ },
45
+ },
46
+ {
47
+ id: "claude-desktop",
48
+ label: "Claude Desktop (user)",
49
+ shape: "json",
50
+ rootKey: "mcpServers",
51
+ resolve(cwd, homedir, platform) {
52
+ return claudeDesktopPath(homedir, platform);
53
+ },
54
+ },
55
+ {
56
+ id: "cursor-project",
57
+ label: "Cursor (project)",
58
+ shape: "json",
59
+ rootKey: "mcpServers",
60
+ resolve(cwd) {
61
+ return path.join(cwd, ".cursor", "mcp.json");
62
+ },
63
+ },
64
+ {
65
+ id: "cursor-user",
66
+ label: "Cursor (user)",
67
+ shape: "json",
68
+ rootKey: "mcpServers",
69
+ resolve(cwd, homedir) {
70
+ return path.join(homedir, ".cursor", "mcp.json");
71
+ },
72
+ },
73
+ {
74
+ id: "gemini-project",
75
+ label: "Gemini CLI (project)",
76
+ shape: "json",
77
+ rootKey: "mcpServers",
78
+ resolve(cwd) {
79
+ return path.join(cwd, ".gemini", "settings.json");
80
+ },
81
+ },
82
+ {
83
+ id: "gemini-user",
84
+ label: "Gemini CLI (user)",
85
+ shape: "json",
86
+ rootKey: "mcpServers",
87
+ resolve(cwd, homedir) {
88
+ return path.join(homedir, ".gemini", "settings.json");
89
+ },
90
+ },
91
+ {
92
+ id: "copilot-cli-project",
93
+ rootLevel: true,
94
+ label: "GitHub Copilot CLI (project)",
95
+ shape: "json",
96
+ rootKey: "mcpServers",
97
+ resolve(cwd) {
98
+ return path.join(cwd, ".mcp.json");
99
+ },
100
+ },
101
+ {
102
+ id: "copilot-cli-user",
103
+ label: "GitHub Copilot CLI (user)",
104
+ shape: "json",
105
+ rootKey: "mcpServers",
106
+ resolve(cwd, homedir) {
107
+ return path.join(homedir, ".copilot", "mcp-config.json");
108
+ },
109
+ },
110
+ {
111
+ id: "copilot-vscode-workspace",
112
+ label: "GitHub Copilot, VS Code extension (workspace)",
113
+ shape: "json",
114
+ rootKey: "servers",
115
+ resolve(cwd) {
116
+ return path.join(cwd, ".vscode", "mcp.json");
117
+ },
118
+ },
119
+ {
120
+ id: "copilot-vscode-user",
121
+ label: "GitHub Copilot, VS Code extension (user)",
122
+ shape: "json",
123
+ rootKey: "servers",
124
+ resolve(cwd, homedir, platform) {
125
+ const dir = vsCodeUserDir(homedir, platform);
126
+ return dir ? path.join(dir, "mcp.json") : null;
127
+ },
128
+ },
129
+ {
130
+ id: "codex-project",
131
+ label: "OpenAI Codex CLI (project)",
132
+ shape: "toml",
133
+ resolve(cwd) {
134
+ return path.join(cwd, ".codex", "config.toml");
135
+ },
136
+ },
137
+ {
138
+ id: "codex-user",
139
+ label: "OpenAI Codex CLI (user)",
140
+ shape: "toml",
141
+ resolve(cwd, homedir) {
142
+ return path.join(homedir, ".codex", "config.toml");
143
+ },
144
+ },
145
+ {
146
+ id: "windsurf-user",
147
+ label: "Windsurf (user)",
148
+ shape: "json",
149
+ rootKey: "mcpServers",
150
+ resolve(cwd, homedir) {
151
+ return path.join(homedir, ".codeium", "windsurf", "mcp_config.json");
152
+ },
153
+ },
154
+ {
155
+ id: "roo-code-project",
156
+ label: "Roo Code (project)",
157
+ shape: "json",
158
+ rootKey: "mcpServers",
159
+ resolve(cwd) {
160
+ return path.join(cwd, ".roo", "mcp.json");
161
+ },
162
+ },
163
+ {
164
+ id: "junie-project",
165
+ label: "JetBrains Junie (project)",
166
+ shape: "json",
167
+ rootKey: "mcpServers",
168
+ resolve(cwd) {
169
+ return path.join(cwd, ".junie", "mcp", "mcp.json");
170
+ },
171
+ },
172
+ {
173
+ id: "junie-user",
174
+ label: "JetBrains Junie (user)",
175
+ shape: "json",
176
+ rootKey: "mcpServers",
177
+ resolve(cwd, homedir) {
178
+ return path.join(homedir, ".junie", "mcp", "mcp.json");
179
+ },
180
+ },
181
+ ];
182
+
183
+ export function resolveTargets(cwd, homedir, platform) {
184
+ const resolved = [];
185
+ for (const def of TARGET_DEFINITIONS) {
186
+ const absPath = def.resolve(cwd, homedir, platform);
187
+ if (!absPath) continue;
188
+ resolved.push({
189
+ id: def.id,
190
+ label: def.label,
191
+ shape: def.shape,
192
+ rootKey: def.rootKey,
193
+ rootLevel: Boolean(def.rootLevel),
194
+ absPath,
195
+ });
196
+ }
197
+ const groups = new Map();
198
+ for (const target of resolved) {
199
+ if (!groups.has(target.absPath)) {
200
+ groups.set(target.absPath, []);
201
+ }
202
+ groups.get(target.absPath).push(target);
203
+ }
204
+ const deduped = [];
205
+ for (const [absPath, group] of groups) {
206
+ deduped.push({
207
+ absPath,
208
+ shape: group[0].shape,
209
+ rootKey: group[0].rootKey,
210
+ rootLevel: group.some((t) => t.rootLevel),
211
+ targetIds: group.map((t) => t.id),
212
+ labels: group.map((t) => t.label),
213
+ });
214
+ }
215
+ return deduped;
216
+ }
@@ -0,0 +1,79 @@
1
+ import { parse, stringify } from "smol-toml";
2
+
3
+ export function readTomlServers(fileText) {
4
+ if (!fileText || fileText.trim().length === 0) return {};
5
+ const parsed = parse(fileText);
6
+ if (!parsed || typeof parsed !== "object") return {};
7
+ const servers = parsed.mcp_servers;
8
+ if (!servers || typeof servers !== "object") return {};
9
+ return servers;
10
+ }
11
+
12
+ function headerMatches(line, header) {
13
+ const trimmed = line.trim();
14
+ if (trimmed === header) return true;
15
+ if (trimmed.startsWith(header)) {
16
+ const rest = trimmed.slice(header.length).trim();
17
+ return rest.startsWith("#");
18
+ }
19
+ return false;
20
+ }
21
+
22
+ function isBlockBoundary(line, serverKey) {
23
+ const trimmed = line.trim();
24
+ if (!trimmed.startsWith("[")) return false;
25
+ const subTablePrefix = "[mcp_servers." + serverKey + ".";
26
+ const subArrayPrefix = "[[mcp_servers." + serverKey + ".";
27
+ return !trimmed.startsWith(subTablePrefix) && !trimmed.startsWith(subArrayPrefix);
28
+ }
29
+
30
+ function findServerBlockRange(lines, serverKey) {
31
+ const header = "[mcp_servers." + serverKey + "]";
32
+ let start = -1;
33
+ for (let i = 0; i < lines.length; i++) {
34
+ if (headerMatches(lines[i], header)) {
35
+ start = i;
36
+ break;
37
+ }
38
+ }
39
+ if (start === -1) return null;
40
+ let end = lines.length;
41
+ for (let i = start + 1; i < lines.length; i++) {
42
+ if (isBlockBoundary(lines[i], serverKey)) {
43
+ end = i;
44
+ break;
45
+ }
46
+ }
47
+ return { start, end };
48
+ }
49
+
50
+ export function removeTomlServer(fileText, serverKey) {
51
+ if (!fileText) return fileText;
52
+ const lines = fileText.split("\n");
53
+ const range = findServerBlockRange(lines, serverKey);
54
+ if (range === null) return fileText;
55
+ const before = lines.slice(0, range.start);
56
+ const after = lines.slice(range.end);
57
+ while (before.length > 0 && before[before.length - 1].trim() === "") {
58
+ before.pop();
59
+ }
60
+ const combined = before.concat(after);
61
+ return combined.join("\n");
62
+ }
63
+
64
+ export function setTomlServer(fileText, serverKey, serverValue) {
65
+ const withoutOldBlock = removeTomlServer(fileText || "", serverKey);
66
+ const rawSnippet = stringify({ mcp_servers: { [serverKey]: serverValue } });
67
+ // Drop the bare parent [mcp_servers] header line smol-toml emits: appending it
68
+ // to a file that already has one produces invalid TOML (table redefinition),
69
+ // and [mcp_servers.<key>] alone implicitly defines the parent table anyway.
70
+ const snippet = rawSnippet
71
+ .split("\n")
72
+ .filter((line) => line.trim() !== "[mcp_servers]")
73
+ .join("\n");
74
+ const base = withoutOldBlock.length > 0 && !withoutOldBlock.endsWith("\n")
75
+ ? withoutOldBlock + "\n"
76
+ : withoutOldBlock;
77
+ const separator = base.length > 0 ? "\n" : "";
78
+ return base + separator + snippet;
79
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "bi-agent-kit",
3
+ "version": "0.1.0",
4
+ "description": "Installs BI-related MCP server entries into AI coding tool configs, without clobbering anything else already there.",
5
+ "type": "module",
6
+ "bin": {
7
+ "bi-agent-kit": "./bin/cli.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "lib",
12
+ "templates"
13
+ ],
14
+ "engines": {
15
+ "node": ">=20"
16
+ },
17
+ "scripts": {
18
+ "test": "node --test"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "model-context-protocol",
23
+ "business-intelligence",
24
+ "power-bi",
25
+ "dataverse",
26
+ "fabric",
27
+ "dbt",
28
+ "snowflake",
29
+ "postgres",
30
+ "azure",
31
+ "ai-agents",
32
+ "claude-code",
33
+ "cursor",
34
+ "copilot",
35
+ "installer",
36
+ "cli"
37
+ ],
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/KAE-Labs/bi-agent-kit.git"
41
+ },
42
+ "homepage": "https://github.com/KAE-Labs/bi-agent-kit#readme",
43
+ "bugs": {
44
+ "url": "https://github.com/KAE-Labs/bi-agent-kit/issues"
45
+ },
46
+ "author": "KAE Labs LLC (https://kaelabs.dev)",
47
+ "license": "MIT",
48
+ "publishConfig": {
49
+ "provenance": true,
50
+ "access": "public"
51
+ },
52
+ "dependencies": {
53
+ "@clack/prompts": "0.9.1",
54
+ "smol-toml": "1.3.1",
55
+ "jsonc-parser": "3.3.1"
56
+ }
57
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "azure",
3
+ "label": "Azure MCP",
4
+ "description": "Official Microsoft MCP server for Azure resource management (Storage, Key Vault, Cosmos DB, Azure SQL, and more), using the same credential chain as the az CLI. Actively shipping (beta), npm package @azure/mcp.",
5
+ "config": {
6
+ "command": "npx",
7
+ "args": ["-y", "@azure/mcp@latest", "server", "start"],
8
+ "env": {}
9
+ },
10
+ "notes": "Auth uses the standard Azure credential chain (az login, managed identity, or environment-based service principal credentials). No extra config required in this template for interactive use."
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "dataverse",
3
+ "label": "Dataverse MCP",
4
+ "description": "Official Microsoft MCP proxy to the Dataverse hosted MCP endpoint. Generally available, npm package microsoft/dataverse.",
5
+ "config": {
6
+ "command": "npx",
7
+ "args": ["-y", "@microsoft/dataverse", "mcp", "REPLACE_WITH_YOUR_ORG_URL"],
8
+ "env": {}
9
+ },
10
+ "notes": "Replace REPLACE_WITH_YOUR_ORG_URL with your Dataverse environment URL after install, for example https://yourorg.crm.dynamics.com. Auth is interactive OAuth through the prebuilt Dataverse CLI app; a tenant admin must consent to it and enable it per environment first. Tool calls from non Copilot Studio clients bill against Copilot Credits unless the tenant already has qualifying licensing."
11
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "id": "dbt",
3
+ "label": "dbt MCP",
4
+ "description": "Official dbt Labs MCP server for build, run, docs, and lineage operations against a dbt project. Actively maintained, package dbt-mcp launched via uvx.",
5
+ "config": {
6
+ "command": "uvx",
7
+ "args": ["dbt-mcp"],
8
+ "env": {
9
+ "DBT_PROJECT_DIR": "REPLACE_WITH_ABSOLUTE_PATH_TO_DBT_PROJECT",
10
+ "DBT_PATH": "REPLACE_WITH_ABSOLUTE_PATH_TO_DBT_EXECUTABLE"
11
+ }
12
+ },
13
+ "notes": "Requires uv installed (https://docs.astral.sh/uv/). Set DBT_PROJECT_DIR and DBT_PATH for local CLI mode after install, or swap the env block for DBT_HOST, DBT_TOKEN, DBT_ACCOUNT_ID, and DBT_PROD_ENV_ID to use dbt Platform mode instead."
14
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "fabric",
3
+ "label": "Fabric MCP",
4
+ "description": "Official Microsoft Fabric MCP server exposing Fabric REST APIs, OpenAPI specs, item definitions, and workspace operations. Distinct from the fab command line tool, which has no MCP mode. Npm package microsoft/fabric-mcp.",
5
+ "config": {
6
+ "command": "npx",
7
+ "args": ["-y", "@microsoft/fabric-mcp@latest", "server", "start", "--mode", "all"],
8
+ "env": {}
9
+ },
10
+ "notes": "Auth is interactive sign in at runtime, no environment variables required in this template."
11
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "id": "pac-cli",
3
+ "label": "PAC CLI MCP",
4
+ "description": "Built in MCP server inside the Power Platform CLI itself, no separate npm package. Generally available feature.",
5
+ "requiresBinary": "pac",
6
+ "config": {
7
+ "command": "pac",
8
+ "args": ["copilot", "mcp", "--run"],
9
+ "env": {}
10
+ },
11
+ "notes": "Requires the Power Platform CLI to already be installed and on PATH, with an existing pac auth create profile. Search learn.microsoft.com for Power Platform CLI installation if pac is not yet installed."
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "id": "postgres",
3
+ "label": "Postgres MCP",
4
+ "description": "No first-party Postgres MCP server exists; Anthropic's own reference postgres server was moved to the archived, no-longer-maintained servers repo. This is the best-maintained, most widely-adopted community alternative instead: Postgres MCP Pro by Crystal DBA, package postgres-mcp, works against any Postgres database (not tied to a single cloud vendor).",
5
+ "requiresBinary": "uvx",
6
+ "config": {
7
+ "command": "uvx",
8
+ "args": ["postgres-mcp", "--access-mode=restricted"],
9
+ "env": {
10
+ "DATABASE_URI": "REPLACE_WITH_YOUR_POSTGRES_CONNECTION_STRING"
11
+ }
12
+ },
13
+ "notes": "Requires uv installed (https://docs.astral.sh/uv/). DATABASE_URI format is postgresql://username:password@host:5432/dbname. Defaults to --access-mode=restricted (read-only, safe default for production); swap to --access-mode=unrestricted for full read/write access to modify data and schema in development. Docker is also supported and is what the README recommends when Python environment issues are a concern: docker run -i --rm -e DATABASE_URI crystaldba/postgres-mcp --access-mode=restricted, with DATABASE_URI passed via the env block. For full index-tuning and performance-analysis features, also load the pg_stat_statements and hypopg extensions on the target database."
14
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "id": "powerbi",
3
+ "label": "Power BI MCP",
4
+ "description": "Official Microsoft MCP server for Power BI semantic model authoring, TMSL and TOM operations. Public preview, npm package microsoft/powerbi-modeling-mcp.",
5
+ "config": {
6
+ "command": "npx",
7
+ "args": ["-y", "@microsoft/powerbi-modeling-mcp@latest", "--start"],
8
+ "env": {}
9
+ },
10
+ "notes": "Default auth is interactive sign in. For a service principal instead, add AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_CLIENT_SECRET to the env block after install."
11
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "id": "snowflake",
3
+ "label": "Snowflake MCP",
4
+ "description": "Official Snowflake managed MCP server, replacing the deprecated Snowflake-Labs/mcp community project. Remote and hosted inside your Snowflake account; requires an MCP server object already created via CREATE MCP SERVER before this entry will work.",
5
+ "config": {
6
+ "url": "https://REPLACE_WITH_YOUR_ACCOUNT_IDENTIFIER.snowflakecomputing.com/api/v2/databases/REPLACE_WITH_YOUR_DATABASE/schemas/REPLACE_WITH_YOUR_SCHEMA/mcp-servers/REPLACE_WITH_YOUR_MCP_SERVER_NAME",
7
+ "headers": {
8
+ "Authorization": "Bearer REPLACE_WITH_YOUR_PAT_TOKEN"
9
+ }
10
+ },
11
+ "notes": "Remote server, not a local launch. Run CREATE MCP SERVER in Snowflake first to create the server object, then fill in the account identifier, database, schema, and server name in the URL. OAuth 2.0 is the recommended auth method for production; the placeholder above shows the simpler PAT quickstart path with a bearer token."
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "id": "sqlserver",
3
+ "label": "SQL Server MCP",
4
+ "description": "Official Microsoft SQL MCP Server, built on Data API Builder. Covers Azure SQL, SQL Server, PostgreSQL, MySQL, and Cosmos DB. Requires the dab CLI (dotnet tool install microsoft.dataapibuilder) already installed and on PATH.",
5
+ "requiresBinary": "dab",
6
+ "config": {
7
+ "command": "dab",
8
+ "args": ["start", "--mcp-stdio", "role:anonymous", "--loglevel", "error", "--config", "REPLACE_WITH_ABSOLUTE_PATH/dab-config.json"],
9
+ "env": {
10
+ "MSSQL_CONNECTION_STRING": "REPLACE_WITH_YOUR_CONNECTION_STRING"
11
+ }
12
+ },
13
+ "notes": "Requires a dab-config.json file (Data API Builder config) already set up alongside your database, see the Data API Builder quickstart docs. The connection string is referenced from dab-config.json via an env reference, not passed directly as a CLI arg."
14
+ }