@luquimbo/bi-superpowers 3.2.0 → 4.1.1

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.
Files changed (91) hide show
  1. package/.claude-plugin/marketplace.json +5 -3
  2. package/.claude-plugin/plugin.json +28 -2
  3. package/.claude-plugin/skill-manifest.json +22 -6
  4. package/.plugin/plugin.json +1 -1
  5. package/AGENTS.md +53 -36
  6. package/CHANGELOG.md +310 -0
  7. package/README.md +77 -26
  8. package/bin/build-plugin.js +11 -4
  9. package/bin/cli.js +113 -16
  10. package/bin/commands/build-desktop.js +35 -16
  11. package/bin/commands/diff.js +31 -13
  12. package/bin/commands/install.js +7 -3
  13. package/bin/commands/lint.js +40 -26
  14. package/bin/commands/mcp-setup.js +3 -10
  15. package/bin/commands/update-check.js +403 -0
  16. package/bin/lib/generators/claude-plugin.js +162 -6
  17. package/bin/lib/generators/shared.js +29 -33
  18. package/bin/lib/mcp-config.js +168 -12
  19. package/bin/lib/skills.js +115 -27
  20. package/bin/postinstall.js +4 -2
  21. package/bin/utils/mcp-detect.js +2 -2
  22. package/commands/bi-start.md +197 -0
  23. package/commands/pbi-connect.md +43 -65
  24. package/commands/project-kickoff.md +393 -673
  25. package/commands/report-design.md +403 -0
  26. package/desktop-extension/manifest.json +3 -3
  27. package/package.json +7 -5
  28. package/skills/bi-start/SKILL.md +199 -0
  29. package/skills/bi-start/scripts/update-check.js +403 -0
  30. package/skills/pbi-connect/SKILL.md +45 -67
  31. package/skills/pbi-connect/scripts/update-check.js +403 -0
  32. package/skills/project-kickoff/SKILL.md +395 -675
  33. package/skills/project-kickoff/scripts/update-check.js +403 -0
  34. package/skills/report-design/SKILL.md +405 -0
  35. package/skills/report-design/references/cli-commands.md +184 -0
  36. package/skills/report-design/references/cli-setup.md +101 -0
  37. package/skills/report-design/references/close-write-open-pattern.md +80 -0
  38. package/skills/report-design/references/layouts/finance.md +65 -0
  39. package/skills/report-design/references/layouts/generic.md +46 -0
  40. package/skills/report-design/references/layouts/hr.md +48 -0
  41. package/skills/report-design/references/layouts/marketing.md +45 -0
  42. package/skills/report-design/references/layouts/operations.md +44 -0
  43. package/skills/report-design/references/layouts/sales.md +50 -0
  44. package/skills/report-design/references/native-visuals.md +341 -0
  45. package/skills/report-design/references/pbi-desktop-installation.md +87 -0
  46. package/skills/report-design/references/pbir-preview-activation.md +40 -0
  47. package/skills/report-design/references/slicer.md +89 -0
  48. package/skills/report-design/references/textbox.md +101 -0
  49. package/skills/report-design/references/themes/BISuperpowers.json +915 -0
  50. package/skills/report-design/references/troubleshooting.md +135 -0
  51. package/skills/report-design/references/visual-types.md +78 -0
  52. package/skills/report-design/scripts/apply-theme.js +243 -0
  53. package/skills/report-design/scripts/create-visual.js +878 -0
  54. package/skills/report-design/scripts/ensure-pbi-cli.sh +41 -0
  55. package/skills/report-design/scripts/update-check.js +403 -0
  56. package/skills/report-design/scripts/validate-pbir.js +322 -0
  57. package/src/content/base.md +12 -68
  58. package/src/content/mcp-requirements.json +0 -25
  59. package/src/content/routing.md +19 -74
  60. package/src/content/skills/bi-start.md +191 -0
  61. package/src/content/skills/pbi-connect.md +22 -65
  62. package/src/content/skills/project-kickoff.md +372 -673
  63. package/src/content/skills/report-design/SKILL.md +376 -0
  64. package/src/content/skills/report-design/references/cli-commands.md +184 -0
  65. package/src/content/skills/report-design/references/cli-setup.md +101 -0
  66. package/src/content/skills/report-design/references/close-write-open-pattern.md +80 -0
  67. package/src/content/skills/report-design/references/layouts/finance.md +65 -0
  68. package/src/content/skills/report-design/references/layouts/generic.md +46 -0
  69. package/src/content/skills/report-design/references/layouts/hr.md +48 -0
  70. package/src/content/skills/report-design/references/layouts/marketing.md +45 -0
  71. package/src/content/skills/report-design/references/layouts/operations.md +44 -0
  72. package/src/content/skills/report-design/references/layouts/sales.md +50 -0
  73. package/src/content/skills/report-design/references/native-visuals.md +341 -0
  74. package/src/content/skills/report-design/references/pbi-desktop-installation.md +87 -0
  75. package/src/content/skills/report-design/references/pbir-preview-activation.md +40 -0
  76. package/src/content/skills/report-design/references/slicer.md +89 -0
  77. package/src/content/skills/report-design/references/textbox.md +101 -0
  78. package/src/content/skills/report-design/references/themes/BISuperpowers.json +915 -0
  79. package/src/content/skills/report-design/references/troubleshooting.md +135 -0
  80. package/src/content/skills/report-design/references/visual-types.md +78 -0
  81. package/src/content/skills/report-design/scripts/apply-theme.js +243 -0
  82. package/src/content/skills/report-design/scripts/create-visual.js +878 -0
  83. package/src/content/skills/report-design/scripts/ensure-pbi-cli.sh +41 -0
  84. package/src/content/skills/report-design/scripts/validate-pbir.js +322 -0
  85. package/bin/commands/install.test.js +0 -289
  86. package/bin/commands/lint.test.js +0 -103
  87. package/bin/lib/generators/claude-plugin.test.js +0 -111
  88. package/bin/lib/mcp-config.test.js +0 -310
  89. package/bin/lib/microsoft-mcp.test.js +0 -115
  90. package/bin/utils/mcp-detect.test.js +0 -81
  91. package/bin/utils/tui.test.js +0 -127
@@ -0,0 +1,403 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * update-check — cross-agent version-check helper for bi-superpowers.
4
+ *
5
+ * The SKILL.md preamble (see lib/generators/claude-plugin.js) invokes this
6
+ * script at the start of every skill so the agent can surface an update
7
+ * notice to the user when a newer version is on npm — without hitting the
8
+ * network on every invocation. Cache TTL is 24h; repeated calls inside
9
+ * that window are served from `~/.bi-superpowers/update-state.json`.
10
+ *
11
+ * Output (stdout, one line):
12
+ * UPTODATE when installed >= latest
13
+ * UPDATE_AVAILABLE <installed> <latest> when installed < latest
14
+ * SNOOZED <iso> when user deferred the notice
15
+ *
16
+ * Flags:
17
+ * --force bypass cache (re-fetch npm, ignore snooze TTL)
18
+ * --silent-if-uptodate suppress UPTODATE line (used by the preamble)
19
+ * --silent-if-snoozed suppress SNOOZED line (used by the preamble)
20
+ * --json emit JSON instead of text
21
+ * --snooze 24h|48h|7d|clear set (or clear) the snooze state and exit
22
+ * --reset delete the state file and exit (used post-upgrade)
23
+ * --state-dir <path> override ~/.bi-superpowers/ (for tests)
24
+ * --package-name <name> override the package name (for tests)
25
+ * -h, --help show this help
26
+ *
27
+ * Exit code is always 0 when the script itself ran — errors during the
28
+ * network fetch degrade to "no output" so the caller never blocks. A
29
+ * non-zero exit means a user error (bad flags).
30
+ *
31
+ * Pure helpers (compareVersions, isCacheFresh, isSnoozed,
32
+ * computeNextSnoozeUntil, readState, writeState, fetchLatestVersion) are
33
+ * exported so unit tests can exercise them without spawning child
34
+ * processes or hitting the network.
35
+ */
36
+
37
+ 'use strict';
38
+
39
+ const fs = require('fs');
40
+ const os = require('os');
41
+ const path = require('path');
42
+ const https = require('https');
43
+
44
+ const PACKAGE_NAME = '@luquimbo/bi-superpowers';
45
+ const CACHE_TTL_MS = 1000 * 60 * 60 * 24; // 24 hours
46
+ const HTTPS_TIMEOUT_MS = 5000;
47
+ // Rewritten at generation time when this helper is copied into
48
+ // `skills/<name>/scripts/update-check.js`. In the canonical source under
49
+ // `bin/commands/`, it stays null and we fall back to package.json.
50
+ const BUNDLED_INSTALLED_VERSION = "4.1.1";
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Argument parsing
54
+ // ---------------------------------------------------------------------------
55
+
56
+ function parseArgs(argv) {
57
+ const out = {
58
+ force: false,
59
+ silentIfUptodate: false,
60
+ silentIfSnoozed: false,
61
+ json: false,
62
+ snooze: null,
63
+ reset: false,
64
+ help: false,
65
+ stateDir: null,
66
+ packageName: null,
67
+ installedVersion: null,
68
+ };
69
+ for (let i = 0; i < argv.length; i += 1) {
70
+ const a = argv[i];
71
+ if (a === '--force') out.force = true;
72
+ else if (a === '--silent-if-uptodate') out.silentIfUptodate = true;
73
+ else if (a === '--silent-if-snoozed') out.silentIfSnoozed = true;
74
+ else if (a === '--json') out.json = true;
75
+ else if (a === '--snooze') out.snooze = argv[++i];
76
+ else if (a === '--reset') out.reset = true;
77
+ else if (a === '--state-dir') out.stateDir = argv[++i];
78
+ else if (a === '--package-name') out.packageName = argv[++i];
79
+ else if (a === '--installed-version') out.installedVersion = argv[++i];
80
+ else if (a === '-h' || a === '--help') out.help = true;
81
+ else {
82
+ process.stderr.write(`update-check: unknown flag: ${a}\n`);
83
+ process.exit(1);
84
+ }
85
+ }
86
+ return out;
87
+ }
88
+
89
+ function help() {
90
+ process.stdout.write(
91
+ [
92
+ 'Usage: update-check [options]',
93
+ '',
94
+ 'Prints one of: UPTODATE, UPDATE_AVAILABLE <installed> <latest>, SNOOZED <iso>.',
95
+ '',
96
+ 'Options:',
97
+ ' --force Bypass cache and snooze TTL',
98
+ ' --silent-if-uptodate Skip the UPTODATE line',
99
+ ' --silent-if-snoozed Skip the SNOOZED line',
100
+ ' --json Emit JSON',
101
+ ' --snooze <dur> Set snooze state (24h|48h|7d) or "clear" to reset snooze',
102
+ ' --reset Delete the state file (used after a successful upgrade)',
103
+ ' --state-dir <path> Override ~/.bi-superpowers/ (tests)',
104
+ ' --package-name <name> Override the package name (tests)',
105
+ ' --installed-version <v> Override the installed version (generated skill bundles)',
106
+ ' -h, --help Show this help',
107
+ '',
108
+ ].join('\n')
109
+ );
110
+ }
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // Version comparison (semver-ish: MAJOR.MINOR.PATCH with optional -prerelease)
114
+ // No deps; handles the shapes @luquimbo/bi-superpowers uses today.
115
+ // ---------------------------------------------------------------------------
116
+
117
+ /**
118
+ * Compare two semver strings.
119
+ * Returns -1 if a < b, 0 if equal, 1 if a > b.
120
+ * Pre-release tags (`-alpha.1`) sort before the release per semver.
121
+ */
122
+ function compareVersions(a, b) {
123
+ const parse = (v) => {
124
+ const [main, pre] = String(v).split('-');
125
+ const parts = main.split('.').map((n) => parseInt(n, 10) || 0);
126
+ while (parts.length < 3) parts.push(0);
127
+ return { parts, pre: pre || null };
128
+ };
129
+ const va = parse(a);
130
+ const vb = parse(b);
131
+ for (let i = 0; i < 3; i += 1) {
132
+ if (va.parts[i] !== vb.parts[i]) return va.parts[i] < vb.parts[i] ? -1 : 1;
133
+ }
134
+ // Main equal — pre-release < release.
135
+ if (va.pre && !vb.pre) return -1;
136
+ if (!va.pre && vb.pre) return 1;
137
+ if (va.pre && vb.pre) {
138
+ if (va.pre < vb.pre) return -1;
139
+ if (va.pre > vb.pre) return 1;
140
+ }
141
+ return 0;
142
+ }
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // Cache + snooze state
146
+ // ---------------------------------------------------------------------------
147
+
148
+ function defaultStateDir() {
149
+ return path.join(os.homedir(), '.bi-superpowers');
150
+ }
151
+
152
+ function stateFilePath(stateDir) {
153
+ return path.join(stateDir, 'update-state.json');
154
+ }
155
+
156
+ function readState(stateDir) {
157
+ const filePath = stateFilePath(stateDir);
158
+ if (!fs.existsSync(filePath)) return null;
159
+ try {
160
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
161
+ } catch (_) {
162
+ // Malformed → treat as no cache.
163
+ return null;
164
+ }
165
+ }
166
+
167
+ function writeState(stateDir, state) {
168
+ fs.mkdirSync(stateDir, { recursive: true });
169
+ fs.writeFileSync(stateFilePath(stateDir), JSON.stringify(state, null, 2) + '\n');
170
+ }
171
+
172
+ function resetState(stateDir) {
173
+ const filePath = stateFilePath(stateDir);
174
+ if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
175
+ }
176
+
177
+ function isCacheFresh(state, now, ttlMs) {
178
+ if (!state || !state.checkedAt) return false;
179
+ const checkedAt = Date.parse(state.checkedAt);
180
+ if (!Number.isFinite(checkedAt)) return false;
181
+ return now - checkedAt < ttlMs;
182
+ }
183
+
184
+ function isSnoozed(state, now) {
185
+ if (!state || !state.snoozeUntil) return false;
186
+ const until = Date.parse(state.snoozeUntil);
187
+ if (!Number.isFinite(until)) return false;
188
+ return until > now;
189
+ }
190
+
191
+ // Snooze escalation: 24h → 48h → 7d (capped).
192
+ function computeNextSnoozeUntil(currentLevel, now) {
193
+ const levels = [
194
+ 1000 * 60 * 60 * 24, // 24h
195
+ 1000 * 60 * 60 * 48, // 48h
196
+ 1000 * 60 * 60 * 24 * 7, // 7d
197
+ ];
198
+ const idx = Math.min(Math.max(currentLevel, 0), levels.length - 1);
199
+ return new Date(now + levels[idx]).toISOString();
200
+ }
201
+
202
+ function parseSnoozeArg(arg, now, currentLevel) {
203
+ if (arg === 'clear') return { clear: true };
204
+ if (arg === '24h') return { until: new Date(now + 1000 * 60 * 60 * 24).toISOString(), level: 0 };
205
+ if (arg === '48h') return { until: new Date(now + 1000 * 60 * 60 * 48).toISOString(), level: 1 };
206
+ if (arg === '7d')
207
+ return { until: new Date(now + 1000 * 60 * 60 * 24 * 7).toISOString(), level: 2 };
208
+ if (arg === 'auto')
209
+ return {
210
+ until: computeNextSnoozeUntil(currentLevel, now),
211
+ level: Math.min(currentLevel + 1, 2),
212
+ };
213
+ throw new Error(`invalid --snooze value: ${arg}. Expected 24h|48h|7d|auto|clear.`);
214
+ }
215
+
216
+ // ---------------------------------------------------------------------------
217
+ // npm registry fetch
218
+ // ---------------------------------------------------------------------------
219
+
220
+ /**
221
+ * Fetch the latest published version of a package from the npm registry.
222
+ * Never rejects with a network error — resolves null on timeout / failure
223
+ * so callers always degrade gracefully.
224
+ *
225
+ * @param {string} packageName - e.g. "@luquimbo/bi-superpowers"
226
+ * @returns {Promise<string|null>}
227
+ */
228
+ function fetchLatestVersion(packageName) {
229
+ return new Promise((resolve) => {
230
+ const encoded = packageName.replace('/', '%2F');
231
+ const url = `https://registry.npmjs.org/${encoded}/latest`;
232
+
233
+ const req = https.get(
234
+ url,
235
+ { headers: { Accept: 'application/vnd.npm.install-v1+json' } },
236
+ (res) => {
237
+ if (res.statusCode !== 200) {
238
+ res.resume();
239
+ resolve(null);
240
+ return;
241
+ }
242
+ let body = '';
243
+ res.setEncoding('utf8');
244
+ res.on('data', (chunk) => (body += chunk));
245
+ res.on('end', () => {
246
+ try {
247
+ const json = JSON.parse(body);
248
+ resolve(typeof json.version === 'string' ? json.version : null);
249
+ } catch (_) {
250
+ resolve(null);
251
+ }
252
+ });
253
+ }
254
+ );
255
+ req.on('error', () => resolve(null));
256
+ req.setTimeout(HTTPS_TIMEOUT_MS, () => {
257
+ req.destroy();
258
+ resolve(null);
259
+ });
260
+ });
261
+ }
262
+
263
+ // ---------------------------------------------------------------------------
264
+ // Installed version — read from our own package.json
265
+ // ---------------------------------------------------------------------------
266
+
267
+ function readInstalledVersion(explicitVersion = null) {
268
+ if (explicitVersion) {
269
+ return String(explicitVersion);
270
+ }
271
+ if (BUNDLED_INSTALLED_VERSION) {
272
+ return String(BUNDLED_INSTALLED_VERSION);
273
+ }
274
+ try {
275
+ return require(path.join(__dirname, '..', '..', 'package.json')).version;
276
+ } catch (_) {
277
+ return null;
278
+ }
279
+ }
280
+
281
+ // ---------------------------------------------------------------------------
282
+ // Emit helpers
283
+ // ---------------------------------------------------------------------------
284
+
285
+ function emit(args, kind, payload) {
286
+ if (args.json) {
287
+ process.stdout.write(JSON.stringify({ status: kind, ...payload }) + '\n');
288
+ return;
289
+ }
290
+ if (kind === 'UPTODATE' && args.silentIfUptodate) return;
291
+ if (kind === 'SNOOZED' && args.silentIfSnoozed) return;
292
+
293
+ if (kind === 'UPTODATE') process.stdout.write('UPTODATE\n');
294
+ else if (kind === 'UPDATE_AVAILABLE')
295
+ process.stdout.write(`UPDATE_AVAILABLE ${payload.installed} ${payload.latest}\n`);
296
+ else if (kind === 'SNOOZED') process.stdout.write(`SNOOZED ${payload.until}\n`);
297
+ }
298
+
299
+ // ---------------------------------------------------------------------------
300
+ // main
301
+ // ---------------------------------------------------------------------------
302
+
303
+ async function main() {
304
+ const args = parseArgs(process.argv.slice(2));
305
+ if (args.help) {
306
+ help();
307
+ return;
308
+ }
309
+
310
+ const stateDir = args.stateDir || defaultStateDir();
311
+ const packageName = args.packageName || PACKAGE_NAME;
312
+
313
+ if (args.reset) {
314
+ resetState(stateDir);
315
+ return;
316
+ }
317
+
318
+ if (args.snooze) {
319
+ const now = Date.now();
320
+ const prior = readState(stateDir) || {};
321
+ const parsed = parseSnoozeArg(args.snooze, now, prior.snoozeLevel || 0);
322
+ if (parsed.clear) {
323
+ writeState(stateDir, { ...prior, snoozeUntil: null, snoozeLevel: 0 });
324
+ } else {
325
+ writeState(stateDir, {
326
+ ...prior,
327
+ snoozeUntil: parsed.until,
328
+ snoozeLevel: parsed.level,
329
+ });
330
+ }
331
+ return;
332
+ }
333
+
334
+ const installed = readInstalledVersion(args.installedVersion);
335
+ if (!installed) {
336
+ // Installed version undetermined — nothing useful to report.
337
+ return;
338
+ }
339
+
340
+ const now = Date.now();
341
+ let state = readState(stateDir);
342
+
343
+ // Snooze short-circuits everything except --force.
344
+ if (!args.force && isSnoozed(state, now)) {
345
+ emit(args, 'SNOOZED', { until: state.snoozeUntil });
346
+ return;
347
+ }
348
+
349
+ // Use cached `latest` when the cache is fresh (unless --force).
350
+ let latest = state && state.latest;
351
+ if (args.force || !isCacheFresh(state, now, CACHE_TTL_MS)) {
352
+ const fetched = await fetchLatestVersion(packageName);
353
+ if (fetched) {
354
+ latest = fetched;
355
+ const nextState = {
356
+ installed,
357
+ latest,
358
+ checkedAt: new Date(now).toISOString(),
359
+ snoozeUntil: (state && state.snoozeUntil) || null,
360
+ snoozeLevel: (state && state.snoozeLevel) || 0,
361
+ };
362
+ writeState(stateDir, nextState);
363
+ state = nextState;
364
+ }
365
+ // If fetched is null (network fail), we keep using the previous cache
366
+ // — or emit nothing if there's no cache at all.
367
+ }
368
+
369
+ if (!latest) {
370
+ // No cached value and no fetch — nothing to say.
371
+ return;
372
+ }
373
+
374
+ if (compareVersions(installed, latest) < 0) {
375
+ emit(args, 'UPDATE_AVAILABLE', { installed, latest });
376
+ } else {
377
+ emit(args, 'UPTODATE', { installed, latest });
378
+ }
379
+ }
380
+
381
+ module.exports = {
382
+ parseArgs,
383
+ compareVersions,
384
+ isCacheFresh,
385
+ isSnoozed,
386
+ computeNextSnoozeUntil,
387
+ parseSnoozeArg,
388
+ readState,
389
+ writeState,
390
+ resetState,
391
+ fetchLatestVersion,
392
+ readInstalledVersion,
393
+ CACHE_TTL_MS,
394
+ PACKAGE_NAME,
395
+ };
396
+
397
+ if (require.main === module) {
398
+ main().catch((err) => {
399
+ // Never throw out of the CLI — the preamble must not break skill invocation.
400
+ process.stderr.write(`update-check: ${err.message}\n`);
401
+ process.exit(0);
402
+ });
403
+ }
@@ -1,27 +1,48 @@
1
1
  ---
2
2
  name: "pbi-connect"
3
- description: "Use when the user asks about Power BI MCP Connection Skill, especially phrases like \"connect Power BI\", \"modeling mcp\", \"Power BI Desktop\", \"conectar Power BI\", \"can't connect to Power BI\"."
4
- version: "3.2.0"
3
+ description: "Use when the user asks about Power BI MCP Connection Skill, especially phrases like \"connect Power BI\", \"PBI connection\", \"MCP connection\", \"Power BI MCP\", \"modeling mcp\", \"Power BI Modeling MCP\"."
4
+ version: "4.1.1"
5
5
  ---
6
6
 
7
7
  <!-- Generated by BI Agent Superpowers. Edit src/content/skills/pbi-connect.md instead. -->
8
8
 
9
+ <!-- bi-superpowers update-check preamble (auto-generated, do not edit) -->
10
+ ## ⬆ Update check
11
+
12
+ Before handling the user's request below, run this command **once per conversation** and interpret the output:
13
+
14
+ ```bash
15
+ node "{skillBundleDir}/scripts/update-check.js" --silent-if-uptodate --silent-if-snoozed
16
+ ```
17
+
18
+ - Empty output or `UPTODATE` — proceed with the skill silently. No message.
19
+ - `UPDATE_AVAILABLE <installed> <latest>` — tell the user exactly once this conversation, before diving into the skill:
20
+ > "Hay **bi-superpowers v{latest}** disponible (estás en v{installed}). Actualizá con `super upgrade` (o `/plugin update bi-superpowers` en Claude Code) cuando te venga bien."
21
+
22
+ Then continue with the skill below.
23
+ - `SNOOZED <iso>` — proceed silently.
24
+
25
+ If the command fails (missing binary, permissions, offline), ignore the error and proceed with the skill. The update check must never block the user's request.
26
+
27
+ ---
28
+ <!-- /bi-superpowers update-check preamble -->
29
+
9
30
  # Power BI MCP Connection Skill
10
31
 
11
32
  ## Trigger
12
33
  Activate this skill when user mentions:
13
34
  - "connect Power BI", "PBI connection", "MCP connection", "Power BI MCP"
14
- - "modeling mcp", "remote mcp", "fabric mcp"
15
- - "Power BI Desktop", "PBIP", "semantic model", "Fabric workspace"
16
- - "conectar Power BI", "MCP de Power BI", "Fabric MCP"
35
+ - "modeling mcp", "Power BI Modeling MCP"
36
+ - "Power BI Desktop", "PBIP", "semantic model"
37
+ - "conectar Power BI", "MCP de Power BI", "modeling mcp"
17
38
  - "can't connect to Power BI", "connection error", "MCP not working"
18
39
 
19
40
  ## Identity
20
- You are a **Power BI MCP Connection Specialist**. Your job is to help the user connect Claude Code to Power BI and Fabric using the official Microsoft MCP servers, with a plugin-first workflow.
41
+ You are a **Power BI MCP Connection Specialist**. Your job is to help the user connect their AI agent to Power BI Desktop using the official Microsoft MCP servers shipped with bi-superpowers, with a plugin-first workflow.
21
42
 
22
43
  ## MANDATORY RULES
23
44
  1. **PLUGIN-FIRST.** Prefer `.mcp.json` in the Claude Code plugin root.
24
- 2. **OFFICIAL SERVERS ONLY.** Recommend `powerbi-remote`, `fabric-mcp-server`, and `powerbi-modeling-mcp`.
45
+ 2. **OFFICIAL SERVERS ONLY.** Use `powerbi-modeling-mcp` (local) and `microsoft-learn` (HTTP). Do not invent or recommend unofficial MCPs.
25
46
  3. **WINDOWS LIMITATION.** Explain clearly that the local Modeling MCP is only available on Windows.
26
47
  4. **NO PORT INVENTION.** Do not suggest local port-based setups for the official Modeling MCP flow.
27
48
  5. **ONE QUESTION AT A TIME.** Follow the wizard pattern.
@@ -36,13 +57,12 @@ Start with:
36
57
  POWER BI MCP CONNECTION
37
58
  =======================
38
59
 
39
- I'll help you connect Claude Code using the official Microsoft MCP servers.
60
+ I'll help you connect your AI agent using the official Microsoft MCP servers.
40
61
 
41
62
  What do you need?
42
63
 
43
- 1. Connect to Power BI Desktop / PBIP on this machine
44
- 2. Connect to a remote Power BI or Fabric workspace
45
- 3. Verify that my plugin `.mcp.json` is configured correctly
64
+ 1. Connect to Power BI Desktop on this machine (Windows)
65
+ 2. Verify that my plugin `.mcp.json` is configured correctly
46
66
  ```
47
67
 
48
68
  ---
@@ -83,19 +103,14 @@ If the user wants a config example, show:
83
103
 
84
104
  ```json
85
105
  {
86
- "powerbi-remote": {
87
- "type": "http",
88
- "url": "https://api.fabric.microsoft.com/v1/mcp/powerbi"
89
- },
90
- "fabric-mcp-server": {
91
- "type": "stdio",
92
- "command": "npx",
93
- "args": ["-y", "@microsoft/fabric-mcp@latest", "server", "start", "--mode", "all"]
94
- },
95
106
  "powerbi-modeling-mcp": {
96
107
  "type": "stdio",
97
108
  "command": "node",
98
109
  "args": ["${CLAUDE_PLUGIN_ROOT}/bin/mcp/powerbi-modeling-launcher.js"]
110
+ },
111
+ "microsoft-learn": {
112
+ "type": "http",
113
+ "url": "https://learn.microsoft.com/api/mcp"
99
114
  }
100
115
  }
101
116
  ```
@@ -120,51 +135,18 @@ Say:
120
135
 
121
136
  ```text
122
137
  The official local Power BI Modeling MCP is only available on Windows.
123
- You can still work with:
124
-
125
- - powerbi-remote
126
- - fabric-mcp-server
127
138
 
128
- If you need local Desktop editing, you'll need a Windows environment.
139
+ You still have `microsoft-learn` (HTTP) available on every platform for
140
+ docs, and you can work with Power BI files using the skills library.
141
+ For live editing of a local semantic model, you need a Windows environment.
129
142
  ```
130
143
 
131
144
  ---
132
145
 
133
- ## PHASE 2: Remote Power BI / Fabric
146
+ ## PHASE 2: Verify Plugin Config
134
147
 
135
148
  If the user chooses option 2:
136
149
 
137
- ```text
138
- REMOTE / FABRIC MCP
139
- ===================
140
-
141
- This path uses the Microsoft-hosted and Microsoft-published MCP servers.
142
-
143
- Default servers:
144
- - powerbi-remote
145
- - fabric-mcp-server
146
- ```
147
-
148
- Guide them to:
149
-
150
- 1. Run `bi-superpowers mcp-setup`
151
- 2. Verify `.mcp.json` contains the official endpoint and Fabric package
152
- 3. Authenticate in the environment required by their MCP client
153
- 4. Restart or refresh Claude Code
154
-
155
- If they ask what gets configured, show:
156
-
157
- ```text
158
- powerbi-remote -> https://api.fabric.microsoft.com/v1/mcp/powerbi
159
- fabric-mcp-server -> npx -y @microsoft/fabric-mcp@latest server start --mode all
160
- ```
161
-
162
- ---
163
-
164
- ## PHASE 3: Verify Plugin Config
165
-
166
- If the user chooses option 3:
167
-
168
150
  Check these files in order:
169
151
 
170
152
  1. `.claude-plugin/plugin.json`
@@ -174,9 +156,8 @@ Check these files in order:
174
156
  Confirm:
175
157
 
176
158
  - plugin name is `bi-superpowers`
177
- - `.mcp.json` includes `powerbi-remote`
178
- - `.mcp.json` includes `fabric-mcp-server`
179
159
  - `.mcp.json` includes `powerbi-modeling-mcp`
160
+ - `.mcp.json` includes `microsoft-learn`
180
161
 
181
162
  If anything is missing, recommend:
182
163
 
@@ -200,7 +181,7 @@ claude --plugin-dir .
200
181
  | Modeling MCP missing on Windows | Install the Microsoft extension in VS Code or Cursor |
201
182
  | Modeling MCP installed manually | Set `BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH` |
202
183
  | Plugin not loading MCPs | Re-run `bi-superpowers mcp-setup` and restart Claude Code |
203
- | macOS/Linux local modeling request | Redirect to `powerbi-remote` or `fabric-mcp-server` |
184
+ | macOS/Linux local modeling request | Use `microsoft-learn` for docs; live editing requires Windows |
204
185
  | User asks about Excel MCP | Explain Excel remains supported through skills and library content, not a default MCP |
205
186
 
206
187
  ---
@@ -212,7 +193,7 @@ claude --plugin-dir .
212
193
  | Recommend `uvx` for Modeling MCP | Not the official Microsoft installation path | Use the official executable via the local launcher |
213
194
  | Ask the user to find a localhost port | Not required in the new flow | Use the official Modeling MCP launcher |
214
195
  | Put plugin MCP config in `.claude/settings.json` first | Plugin-first flow uses `.mcp.json` | Prefer `.mcp.json` at the plugin root |
215
- | Block non-Windows users entirely | Remote/Fabric MCPs still work | Continue with `powerbi-remote` and `fabric-mcp-server` |
196
+ | Invent unofficial MCPs (remote, fabric, etc.) | This plugin only ships 2 official MCPs | Only use the 2 official MCPs we ship (`powerbi-modeling-mcp` and `microsoft-learn`) |
216
197
 
217
198
  ---
218
199
 
@@ -227,15 +208,12 @@ Adjust depth based on `config.json → experienceLevel`:
227
208
 
228
209
  ## Related Skills
229
210
 
230
- - `/dax` — Write DAX measures via MCP connection
231
- - `/model-documenter` — Document the connected model
232
- - `/fabric-scripts` — Fabric automation via MCP
211
+ - `/project-kickoff` — Analyze a BI project and plan next steps
233
212
 
234
213
  ---
235
214
 
236
215
  ## RELATED RESOURCES
237
216
 
238
217
  - [Power BI MCP overview](https://learn.microsoft.com/en-us/power-bi/developer/mcp/mcp-servers-overview)
239
- - [Remote Power BI MCP quickstart](https://learn.microsoft.com/en-us/power-bi/developer/mcp/remote-mcp-server-get-started)
240
- - [Power BI Modeling MCP](https://github.com/microsoft/powerbi-modeling-mcp)
241
- - [Microsoft Fabric MCP Server](https://github.com/microsoft/mcp/tree/main/servers/Fabric.Mcp.Server)
218
+ - [Power BI Modeling MCP on GitHub](https://github.com/microsoft/powerbi-modeling-mcp)
219
+ - [Microsoft Learn MCP](https://learn.microsoft.com/en-us/training/support/mcp)