powerbi-visuals-tools 7.0.3 → 7.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.
- package/Changelog.md +12 -0
- package/README.md +4 -4
- package/bin/pbiviz.js +12 -0
- package/lib/CommandManager.js +9 -1
- package/lib/ConsoleWriter.js +4 -0
- package/lib/FeatureManager.js +9 -3
- package/lib/VisualManager.js +22 -6
- package/lib/features/BaseFeature.js +1 -0
- package/lib/features/RenderingEvents.js +1 -0
- package/lib/mcp/McpServer.js +125 -0
- package/lib/mcp/tools/availableApis.js +608 -0
- package/lib/mcp/tools/bestPractices.js +391 -0
- package/lib/mcp/tools/certification.js +380 -0
- package/lib/mcp/tools/visualInfo.js +133 -0
- package/lib/mcp/tools/vulnerabilities.js +211 -0
- package/lib/utils.js +27 -0
- package/package.json +18 -15
- package/templates/visuals/_global/.vscode/mcp.json +8 -0
- package/templates/visuals/default/src/visual.ts +17 -4
- package/templates/visuals/rhtml/src/visual.ts +27 -11
- package/templates/visuals/rvisual/src/visual.ts +34 -20
- package/templates/visuals/slicer/src/visual.ts +16 -4
- package/templates/visuals/table/src/visual.ts +14 -1
package/Changelog.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
This page contains information about changes to the PowerBI Visual Tools (pbiviz).
|
|
4
4
|
|
|
5
|
+
## 7.1.1
|
|
6
|
+
* Minor documentation and metadata updates.
|
|
7
|
+
|
|
8
|
+
## 7.1.0
|
|
9
|
+
* Updated packages.
|
|
10
|
+
|
|
11
|
+
## 7.0.4
|
|
12
|
+
* Treated renderingEvents issue as an error when certification-audit and certification-fix are used.
|
|
13
|
+
* Switched to a new webpack plugin.
|
|
14
|
+
* Added rendering events to the visual templates.
|
|
15
|
+
* Updated packages.
|
|
16
|
+
|
|
5
17
|
## 7.0.3
|
|
6
18
|
* Fixed missing validation for `author` object in pbiviz.json. The `author` object with `name` and `email` fields is now required.
|
|
7
19
|
* Updated packages.
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[](https://www.npmjs.com/package/powerbi-visuals-tools)
|
|
2
2
|
[](https://www.npmjs.com/package/powerbi-visuals-tools)
|
|
3
3
|

|
|
4
|
-
[](https://ci.appveyor.com/project/spatney/powerbi-visuals-tools)
|
|
5
5
|
[](https://codeclimate.com/github/Microsoft/PowerBI-visuals-tools)
|
|
6
6
|
|
|
7
7
|
# PowerBI Visual Tools (pbiviz)
|
|
@@ -52,12 +52,12 @@ You can learn more about using these tools in the following guides
|
|
|
52
52
|
|
|
53
53
|
## PowerBI Visuals Tools Changes
|
|
54
54
|
|
|
55
|
-
* [Change Log](https://github.com/Microsoft/PowerBI-visuals-tools/blob/
|
|
55
|
+
* [Change Log](https://github.com/Microsoft/PowerBI-visuals-tools/blob/main/Changelog.md)
|
|
56
56
|
|
|
57
57
|
## Visuals API Changes
|
|
58
58
|
|
|
59
|
-
* [API Change Log](https://github.com/microsoft/PowerBI-visuals-tools/blob/
|
|
59
|
+
* [API Change Log](https://github.com/microsoft/PowerBI-visuals-tools/blob/main/Changelog.md)
|
|
60
60
|
|
|
61
61
|
## Contributing
|
|
62
62
|
|
|
63
|
-
If you would like to contribute please see [How To Contribute](https://github.com/Microsoft/PowerBI-visuals-tools/blob/
|
|
63
|
+
If you would like to contribute please see [How To Contribute](https://github.com/Microsoft/PowerBI-visuals-tools/blob/main/CONTRIBUTING.md).
|
package/bin/pbiviz.js
CHANGED
|
@@ -111,4 +111,16 @@ pbiviz
|
|
|
111
111
|
CommandManager.package(options, rootPath);
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
+
pbiviz
|
|
115
|
+
.command('mcp')
|
|
116
|
+
.description('Start MCP (Model Context Protocol) server for AI assistant integration (Preview)')
|
|
117
|
+
.option('--init', 'Initialize MCP configuration in current project (.vscode/mcp.json)')
|
|
118
|
+
.action((options) => {
|
|
119
|
+
if (options.init) {
|
|
120
|
+
CommandManager.mcpInit(rootPath);
|
|
121
|
+
} else {
|
|
122
|
+
CommandManager.mcp(rootPath);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
114
126
|
program.parse(process.argv);
|
package/lib/CommandManager.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createCertificate } from './CertificateTools.js';
|
|
2
2
|
import ConsoleWriter from './ConsoleWriter.js';
|
|
3
3
|
import VisualManager from './VisualManager.js';
|
|
4
|
+
import { startMcpServer, initMcpConfig } from './mcp/McpServer.js';
|
|
4
5
|
export default class CommandManager {
|
|
5
6
|
static async start(options, rootPath) {
|
|
6
7
|
const webpackOptions = {
|
|
@@ -50,12 +51,13 @@ export default class CommandManager {
|
|
|
50
51
|
verbose: options.verbose,
|
|
51
52
|
fix: options.fix,
|
|
52
53
|
};
|
|
54
|
+
const certificationMode = options.certificationAudit || options.certificationFix;
|
|
53
55
|
const visualManager = new VisualManager(rootPath);
|
|
54
56
|
const visual = await visualManager.prepareVisual(options.pbivizFile);
|
|
55
57
|
await visual.runLintValidation(lintOptions);
|
|
56
58
|
await visual.validateVisual(options.verbose);
|
|
57
59
|
await visual.initializeWebpack(webpackOptions)
|
|
58
|
-
.then(manager => manager.generatePackage(options.verbose));
|
|
60
|
+
.then(manager => manager.generatePackage(options.verbose, certificationMode));
|
|
59
61
|
}
|
|
60
62
|
static new({ force, template }, name, rootPath) {
|
|
61
63
|
const generateOptions = {
|
|
@@ -72,4 +74,10 @@ export default class CommandManager {
|
|
|
72
74
|
static async installCert() {
|
|
73
75
|
await createCertificate();
|
|
74
76
|
}
|
|
77
|
+
static async mcp(rootPath) {
|
|
78
|
+
await startMcpServer(rootPath);
|
|
79
|
+
}
|
|
80
|
+
static async mcpInit(rootPath) {
|
|
81
|
+
await initMcpConfig(rootPath);
|
|
82
|
+
}
|
|
75
83
|
}
|
package/lib/ConsoleWriter.js
CHANGED
|
@@ -42,6 +42,10 @@ export default class ConsoleWriter {
|
|
|
42
42
|
static blank() {
|
|
43
43
|
console.info(preferredChalk.reset(' '));
|
|
44
44
|
}
|
|
45
|
+
/** Outputs a separator line */
|
|
46
|
+
static separator() {
|
|
47
|
+
console.log(preferredChalk.white('--------------------------------'));
|
|
48
|
+
}
|
|
45
49
|
/**
|
|
46
50
|
* Outputs arguments with the "done" tag / colors
|
|
47
51
|
*
|
package/lib/FeatureManager.js
CHANGED
|
@@ -7,21 +7,27 @@ export var Status;
|
|
|
7
7
|
})(Status || (Status = {}));
|
|
8
8
|
export class FeatureManager {
|
|
9
9
|
features = Object.keys(features).map(key => features[key]);
|
|
10
|
-
validate(stage, sourceInstance) {
|
|
10
|
+
validate(stage, sourceInstance, certificationMode = false) {
|
|
11
11
|
const result = {
|
|
12
12
|
status: Status.Success,
|
|
13
13
|
logs: {
|
|
14
14
|
errors: [],
|
|
15
15
|
warnings: [],
|
|
16
16
|
info: [],
|
|
17
|
-
deprecation: []
|
|
17
|
+
deprecation: [],
|
|
18
|
+
certificationErrors: []
|
|
18
19
|
}
|
|
19
20
|
};
|
|
20
21
|
this.features
|
|
21
22
|
.filter(feature => feature.stage == stage)
|
|
22
23
|
.filter(feature => feature.visualFeatureType & sourceInstance.visualFeatureType)
|
|
23
24
|
.filter(feature => !feature.isSupported(sourceInstance))
|
|
24
|
-
.forEach(({ errorMessage, severity }) => {
|
|
25
|
+
.forEach(({ errorMessage, severity, certificationRequired }) => {
|
|
26
|
+
if (certificationMode && certificationRequired && severity === Severity.Warning) {
|
|
27
|
+
result.status = Status.Error;
|
|
28
|
+
result.logs.certificationErrors.push(errorMessage);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
25
31
|
switch (severity) {
|
|
26
32
|
case Severity.Error:
|
|
27
33
|
result.status = Status.Error;
|
package/lib/VisualManager.js
CHANGED
|
@@ -90,12 +90,15 @@ export default class VisualManager {
|
|
|
90
90
|
this.compiler = webpack(this.webpackConfig);
|
|
91
91
|
return this;
|
|
92
92
|
}
|
|
93
|
-
generatePackage(verbose = false) {
|
|
93
|
+
generatePackage(verbose = false, certificationMode = false) {
|
|
94
94
|
const callback = (err, stats) => {
|
|
95
95
|
this.parseCompilationResults(err, stats);
|
|
96
96
|
this.createPackageInstance();
|
|
97
|
-
const logs = this.validatePackage();
|
|
97
|
+
const { status, logs } = this.validatePackage(certificationMode);
|
|
98
98
|
this.outputResults(logs, verbose);
|
|
99
|
+
if (certificationMode && status === Status.Error) {
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
99
102
|
};
|
|
100
103
|
this.compiler.run(callback);
|
|
101
104
|
}
|
|
@@ -144,15 +147,15 @@ export default class VisualManager {
|
|
|
144
147
|
/**
|
|
145
148
|
* Validates the visual package
|
|
146
149
|
*/
|
|
147
|
-
validatePackage() {
|
|
150
|
+
validatePackage(certificationMode = false) {
|
|
148
151
|
const featureManager = new FeatureManager();
|
|
149
|
-
const { logs } = featureManager.validate(Stage.PostBuild, this.package);
|
|
150
|
-
return logs;
|
|
152
|
+
const { status, logs } = featureManager.validate(Stage.PostBuild, this.package, certificationMode);
|
|
153
|
+
return { status, logs };
|
|
151
154
|
}
|
|
152
155
|
/**
|
|
153
156
|
* Outputs the results of the validation
|
|
154
157
|
*/
|
|
155
|
-
outputResults({ errors, deprecation, warnings, info }, verbose) {
|
|
158
|
+
outputResults({ errors, deprecation, warnings, info, certificationErrors }, verbose) {
|
|
156
159
|
const headerMessage = {
|
|
157
160
|
error: `Visual doesn't support some features required for all custom visuals:`,
|
|
158
161
|
deprecation: `Some features are going to be required soon, please update the visual:`,
|
|
@@ -160,6 +163,9 @@ export default class VisualManager {
|
|
|
160
163
|
verboseInfo: `Visual can be improved by adding some features:`,
|
|
161
164
|
shortInfo: `Visual can be improved by adding ${info.length} more optional features.`
|
|
162
165
|
};
|
|
166
|
+
if (certificationErrors.length) {
|
|
167
|
+
this.outputCertificationSection(certificationErrors);
|
|
168
|
+
}
|
|
163
169
|
this.outputLogsWithHeadMessage(headerMessage.error, errors, Severity.Error);
|
|
164
170
|
this.outputLogsWithHeadMessage(headerMessage.deprecation, deprecation, Severity.Deprecation);
|
|
165
171
|
this.outputLogsWithHeadMessage(headerMessage.warning, warnings, Severity.Warning);
|
|
@@ -179,6 +185,16 @@ export default class VisualManager {
|
|
|
179
185
|
ConsoleWriter.error('Unable to load visual info. Please ensure the package is valid.');
|
|
180
186
|
}
|
|
181
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Outputs certification-required issues in a formatted section with separators
|
|
190
|
+
*/
|
|
191
|
+
outputCertificationSection(certificationErrors) {
|
|
192
|
+
ConsoleWriter.separator();
|
|
193
|
+
ConsoleWriter.info('Certification audit:');
|
|
194
|
+
certificationErrors.forEach(error => ConsoleWriter.error(error));
|
|
195
|
+
ConsoleWriter.error(`Found ${certificationErrors.length} certification issue(s). Fix them before submitting for certification.`);
|
|
196
|
+
ConsoleWriter.separator();
|
|
197
|
+
}
|
|
182
198
|
/**
|
|
183
199
|
* Creates a new visual
|
|
184
200
|
*/
|
|
@@ -5,6 +5,7 @@ export default class RenderingEvents {
|
|
|
5
5
|
static severity = Severity.Warning;
|
|
6
6
|
static stage = Stage.PostBuild;
|
|
7
7
|
static visualFeatureType = VisualFeatureType.All;
|
|
8
|
+
static certificationRequired = true;
|
|
8
9
|
static errorMessage = `${this.featureName} - ${this.documentationLink}`;
|
|
9
10
|
static isSupported(packageInstance) {
|
|
10
11
|
const keywords = [".eventService", ".renderingStarted", ".renderingFinished"];
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Power BI Visual CLI - MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Microsoft Corporation
|
|
5
|
+
* All rights reserved.
|
|
6
|
+
* MIT License
|
|
7
|
+
*/
|
|
8
|
+
"use strict";
|
|
9
|
+
import { McpServer as MCPServerSDK } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import fs from "fs-extra";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import ConsoleWriter from "../ConsoleWriter.js";
|
|
15
|
+
import { getBestPractices } from "./tools/bestPractices.js";
|
|
16
|
+
import { checkVulnerabilities } from "./tools/vulnerabilities.js";
|
|
17
|
+
import { prepareCertification } from "./tools/certification.js";
|
|
18
|
+
import { getVisualInfo } from "./tools/visualInfo.js";
|
|
19
|
+
import { getAvailableApis } from "./tools/availableApis.js";
|
|
20
|
+
export class McpServer {
|
|
21
|
+
server;
|
|
22
|
+
rootPath;
|
|
23
|
+
constructor(rootPath) {
|
|
24
|
+
this.rootPath = rootPath;
|
|
25
|
+
this.server = new MCPServerSDK({
|
|
26
|
+
name: "pbiviz-mcp-server",
|
|
27
|
+
version: "1.0.0",
|
|
28
|
+
});
|
|
29
|
+
this.registerTools();
|
|
30
|
+
}
|
|
31
|
+
registerTools() {
|
|
32
|
+
// Tool 1: Get Best Practices
|
|
33
|
+
this.server.tool("get_best_practices", "Returns best practice guidelines for Power BI custom visual development. Covers: API version management, performance optimization (update loop, lazy loading, data processing), security (eval, innerHTML, XSS, sanitization, external call/calls, network request/requests), accessibility (keyboard navigation, high contrast, screen reader, ARIA label/labels), project structure (module/modules, error handling), formatting pane (format model, formatting model), testing (unit test/tests, E2E test/tests, edge case/cases), and documentation (README, changelog, comment/comments).", {}, async () => {
|
|
34
|
+
const practices = await getBestPractices(this.rootPath);
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: "text", text: practices }],
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
// Tool 2: Check Vulnerabilities
|
|
40
|
+
this.server.tool("check_vulnerabilities", "Scans the visual project source code for security vulnerability/vulnerabilities and dangerous code pattern/patterns. Detects: eval(), new Function(), innerHTML assignment, document.write, external fetch/HTTP call/calls, XMLHttpRequest. Also checks for commented-out dangerous code and ESLint configuration. Reports issue/issues by severity (critical, high, medium, low, info) with file path and line number.", {}, async () => {
|
|
41
|
+
const result = await checkVulnerabilities(this.rootPath);
|
|
42
|
+
return {
|
|
43
|
+
content: [{ type: "text", text: result }],
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
// Tool 3: Prepare Certification
|
|
47
|
+
this.server.tool("prepare_certification", "Audits the visual for Power BI certification readiness. Checks: required file/files (pbiviz.json, capabilities.json, package.json, tsconfig.json), visual configuration (name, GUID, version, API version, author, support URL), capability/capabilities (data role/roles, data view mapping/mappings, keyboard focus, highlight support, web access privilege/privileges), and asset/assets (icon.png). Reports pass/fail/warning status for each check.", {}, async () => {
|
|
48
|
+
const result = await prepareCertification(this.rootPath);
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: "text", text: result }],
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
// Tool 4: List Visual Info
|
|
54
|
+
this.server.tool("list_visual_info", "Returns detailed information about the current Power BI visual project. Shows: visual name, display name, GUID, version, API version, author, description, support URL, data role/roles, data view mapping/mappings, format object/objects (setting/settings), supported feature/features (highlight, keyboard focus, landing page, multi-visual selection), dependency/dependencies from package.json, and quick command/commands.", {}, async () => {
|
|
55
|
+
const result = await getVisualInfo(this.rootPath);
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: result }],
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
// Tool 5: Get Available APIs
|
|
61
|
+
this.server.tool("get_available_apis", "Lists available Power BI Visual API/APIs and feature/features with code example/examples and documentation link/links. Categories: 'data' (fetchMoreData, data snapshot, persist property/properties), 'formatting' (color palette, format pane, formatting model, custom color/colors, high contrast), 'interaction' (selection manager, tooltip/tooltips, tooltip service, context menu, launch URL, drill down/drilldown, warning icon), 'utility' (localization, local storage, file download, rendering event/events, modal dialog, authentication), or 'all'.", {
|
|
62
|
+
category: z.string().optional().describe("Filter APIs by category: 'data' (fetchMoreData, persist, snapshot), 'formatting' (color palette, format pane, high contrast), 'interaction' (selection, tooltip/tooltips, context menu, drill down, launch URL, warning icon), 'utility' (localization, storage, download, event/events, dialog, auth), or 'all' (default)")
|
|
63
|
+
}, async ({ category }) => {
|
|
64
|
+
const result = await getAvailableApis(category || "all", this.rootPath);
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: "text", text: result }],
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async start() {
|
|
71
|
+
const transport = new StdioServerTransport();
|
|
72
|
+
await this.server.connect(transport);
|
|
73
|
+
// Keep the server running
|
|
74
|
+
process.on("SIGINT", async () => {
|
|
75
|
+
await this.server.close();
|
|
76
|
+
process.exit(0);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export async function startMcpServer(rootPath) {
|
|
81
|
+
const server = new McpServer(rootPath);
|
|
82
|
+
await server.start();
|
|
83
|
+
}
|
|
84
|
+
const MCP_CONFIG = {
|
|
85
|
+
servers: {
|
|
86
|
+
pbiviz: {
|
|
87
|
+
command: "npx",
|
|
88
|
+
args: ["-y", "powerbi-visuals-tools", "mcp"]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
export async function initMcpConfig(rootPath) {
|
|
93
|
+
const vscodeDir = path.join(rootPath, ".vscode");
|
|
94
|
+
const mcpConfigPath = path.join(vscodeDir, "mcp.json");
|
|
95
|
+
try {
|
|
96
|
+
ConsoleWriter.warning("MCP support in pbiviz is currently in Preview.");
|
|
97
|
+
ConsoleWriter.info("The command surface, available tools, and configuration format may change in future releases without backward-compatibility guarantees.");
|
|
98
|
+
ConsoleWriter.blank();
|
|
99
|
+
// Check if mcp.json already exists
|
|
100
|
+
if (fs.existsSync(mcpConfigPath)) {
|
|
101
|
+
ConsoleWriter.warning("MCP configuration already exists at .vscode/mcp.json");
|
|
102
|
+
ConsoleWriter.info("To reconfigure, delete the file and run this command again.");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
// Create .vscode directory if it doesn't exist
|
|
106
|
+
fs.ensureDirSync(vscodeDir);
|
|
107
|
+
// Write mcp.json
|
|
108
|
+
fs.writeJsonSync(mcpConfigPath, MCP_CONFIG, { spaces: 4 });
|
|
109
|
+
ConsoleWriter.done("MCP configuration created successfully!");
|
|
110
|
+
ConsoleWriter.blank();
|
|
111
|
+
ConsoleWriter.info("Created: .vscode/mcp.json");
|
|
112
|
+
ConsoleWriter.blank();
|
|
113
|
+
ConsoleWriter.info("Next steps:");
|
|
114
|
+
ConsoleWriter.info("1. Restart VS Code to activate MCP server");
|
|
115
|
+
ConsoleWriter.info("2. Open Copilot Chat and ask questions like:");
|
|
116
|
+
ConsoleWriter.info(' - "Check my visual for certification readiness"');
|
|
117
|
+
ConsoleWriter.info(' - "What are the best practices for Power BI visuals?"');
|
|
118
|
+
ConsoleWriter.info(' - "Show me available APIs for tooltips"');
|
|
119
|
+
ConsoleWriter.blank();
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
ConsoleWriter.error(`Failed to create MCP configuration: ${(error instanceof Error) ? error.message : String(error)}`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
}
|