@mcp-consultant-tools/azure-devops 29.0.0 → 30.0.0-beta.2
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/build/genui/design-system-prompt.d.ts +8 -0
- package/build/genui/design-system-prompt.d.ts.map +1 -0
- package/build/genui/design-system-prompt.js +166 -0
- package/build/genui/design-system-prompt.js.map +1 -0
- package/build/genui/sanitize-html.d.ts +12 -0
- package/build/genui/sanitize-html.d.ts.map +1 -0
- package/build/genui/sanitize-html.js +26 -0
- package/build/genui/sanitize-html.js.map +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +7 -0
- package/build/index.js.map +1 -1
- package/build/tools/index.d.ts +1 -0
- package/build/tools/index.d.ts.map +1 -1
- package/build/tools/index.js +5 -2
- package/build/tools/index.js.map +1 -1
- package/build/tools/visualize-tools.d.ts +3 -0
- package/build/tools/visualize-tools.d.ts.map +1 -0
- package/build/tools/visualize-tools.js +124 -0
- package/build/tools/visualize-tools.js.map +1 -0
- package/build/ui/work-items-app.html +5 -5
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design System Prompt for Generative UI
|
|
3
|
+
*
|
|
4
|
+
* Delivered to the host LLM as part of the visualize-data tool response.
|
|
5
|
+
* The host LLM follows these rules when generating HTML for render-visualization.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DESIGN_SYSTEM_PROMPT: string;
|
|
8
|
+
//# sourceMappingURL=design-system-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-system-prompt.d.ts","sourceRoot":"","sources":["../../src/genui/design-system-prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,oBAAoB,QA8JzB,CAAC"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design System Prompt for Generative UI
|
|
3
|
+
*
|
|
4
|
+
* Delivered to the host LLM as part of the visualize-data tool response.
|
|
5
|
+
* The host LLM follows these rules when generating HTML for render-visualization.
|
|
6
|
+
*/
|
|
7
|
+
export const DESIGN_SYSTEM_PROMPT = `
|
|
8
|
+
## Design System for HTML Visualization
|
|
9
|
+
|
|
10
|
+
You are generating an HTML snippet that will be rendered inside an MCP App iframe.
|
|
11
|
+
Follow these rules precisely to produce consistent, attractive, interactive output.
|
|
12
|
+
|
|
13
|
+
### Structure
|
|
14
|
+
- Return a single root \`<div>\` element containing all content.
|
|
15
|
+
- Do NOT include \`<html>\`, \`<head>\`, or \`<body>\` tags.
|
|
16
|
+
- All CSS must be inline via \`<style>\` tags within the snippet.
|
|
17
|
+
- All JavaScript must be inline via \`<script>\` tags (no \`src\` except Chart.js CDN).
|
|
18
|
+
- Maximum content width: 800px, centered with \`margin: 0 auto\`.
|
|
19
|
+
|
|
20
|
+
### Typography
|
|
21
|
+
- Font: \`system-ui, -apple-system, "Segoe UI", Roboto, sans-serif\`
|
|
22
|
+
- Base font size: 14px
|
|
23
|
+
- Headings: 20px (h2), 16px (h3), 14px bold (h4)
|
|
24
|
+
- Line height: 1.5
|
|
25
|
+
|
|
26
|
+
### Theme — CSS Variables (CRITICAL)
|
|
27
|
+
Always define CSS variables for BOTH light and dark themes using \`prefers-color-scheme\`.
|
|
28
|
+
This ensures the visualization adapts to the host app's theme automatically.
|
|
29
|
+
|
|
30
|
+
\`\`\`css
|
|
31
|
+
:root {
|
|
32
|
+
--bg: #FFFFFF;
|
|
33
|
+
--surface: #F8F9FA;
|
|
34
|
+
--text: #1A1A1A;
|
|
35
|
+
--text-secondary: #6B7280;
|
|
36
|
+
--border: #E5E7EB;
|
|
37
|
+
--link: #0078D4;
|
|
38
|
+
--hover: #F0F4FF;
|
|
39
|
+
}
|
|
40
|
+
@media (prefers-color-scheme: dark) {
|
|
41
|
+
:root {
|
|
42
|
+
--bg: #1E1E1E;
|
|
43
|
+
--surface: #2D2D2D;
|
|
44
|
+
--text: #E5E7EB;
|
|
45
|
+
--text-secondary: #9CA3AF;
|
|
46
|
+
--border: #404040;
|
|
47
|
+
--link: #4DA6FF;
|
|
48
|
+
--hover: #2A2D35;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
\`\`\`
|
|
52
|
+
|
|
53
|
+
If the theme parameter is explicitly "dark", ALSO duplicate the dark values as the default
|
|
54
|
+
(outside the media query) so dark mode always applies regardless of system setting.
|
|
55
|
+
|
|
56
|
+
**Use these CSS variables for ALL colors.** Never hardcode \`#1A1A1A\` or \`#FFFFFF\` directly.
|
|
57
|
+
Example: \`color: var(--text)\`, \`background: var(--surface)\`, \`border-color: var(--border)\`.
|
|
58
|
+
|
|
59
|
+
### ADO State Colors (fixed — work on both light and dark)
|
|
60
|
+
- New: #007ACC (blue)
|
|
61
|
+
- Active / In Progress: #009900 (green)
|
|
62
|
+
- Resolved: #FF9D00 (amber)
|
|
63
|
+
- Closed / Done / Completed: #6B7280 (grey)
|
|
64
|
+
- Removed: #CC0000 (red)
|
|
65
|
+
|
|
66
|
+
### Work Item Type Colors (fixed)
|
|
67
|
+
- Epic: #FF7B00
|
|
68
|
+
- Feature: #773B93
|
|
69
|
+
- User Story: #009CCC
|
|
70
|
+
- Bug: #CC293D
|
|
71
|
+
- Task: #F2CB1D
|
|
72
|
+
|
|
73
|
+
### Layout
|
|
74
|
+
- Use CSS Flexbox or Grid for layout.
|
|
75
|
+
- Root div: \`background: var(--bg); color: var(--text); padding: 24px\`
|
|
76
|
+
- Cards: \`border-radius: 8px; border: 1px solid var(--border); padding: 16px; background: var(--surface)\`
|
|
77
|
+
- Card grid: \`display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px\`
|
|
78
|
+
- Section spacing: \`margin-bottom: 24px\`
|
|
79
|
+
|
|
80
|
+
### KPI Cards
|
|
81
|
+
For summary metrics, use KPI cards at the top:
|
|
82
|
+
\`\`\`html
|
|
83
|
+
<div style="text-align:center; padding:16px; background:var(--surface); border-radius:8px; border:1px solid var(--border)">
|
|
84
|
+
<div style="font-size:28px; font-weight:700; color:var(--text)">42</div>
|
|
85
|
+
<div style="font-size:12px; color:var(--text-secondary); text-transform:uppercase; letter-spacing:0.5px">Total Items</div>
|
|
86
|
+
</div>
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
### Tables
|
|
90
|
+
- Full width, border-collapse
|
|
91
|
+
- Header: \`background:var(--surface); font-weight:600; text-align:left; padding:8px 12px; border-bottom:2px solid var(--border); color:var(--text)\`
|
|
92
|
+
- Cells: \`padding:8px 12px; border-bottom:1px solid var(--border); color:var(--text)\`
|
|
93
|
+
- Hover: \`background:var(--hover)\`
|
|
94
|
+
- Add sortable column headers with onclick handlers when appropriate
|
|
95
|
+
|
|
96
|
+
### Charts (IMPORTANT — loading order)
|
|
97
|
+
- For complex charts: use Chart.js from CDN.
|
|
98
|
+
- **CRITICAL loading pattern**: Chart.js loads asynchronously. You MUST wait for it before initializing charts:
|
|
99
|
+
\`\`\`html
|
|
100
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
101
|
+
<canvas id="myChart" style="max-height:300px"></canvas>
|
|
102
|
+
<script>
|
|
103
|
+
(function initChart() {
|
|
104
|
+
if (typeof Chart === 'undefined') {
|
|
105
|
+
setTimeout(initChart, 50);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
new Chart(document.getElementById('myChart'), { /* config */ });
|
|
109
|
+
})();
|
|
110
|
+
</script>
|
|
111
|
+
\`\`\`
|
|
112
|
+
- Never put chart initialization code in the same \`<script>\` tag as the CDN import.
|
|
113
|
+
- Always set \`responsive: true\` and \`maintainAspectRatio: false\` in Chart.js options.
|
|
114
|
+
- For Chart.js text colors, use: \`color: getComputedStyle(document.documentElement).getPropertyValue('--text').trim()\`
|
|
115
|
+
- For Chart.js grid colors, use the \`--border\` variable similarly.
|
|
116
|
+
- For simple visuals (donut, progress bars): prefer inline SVG over Chart.js (no loading delay).
|
|
117
|
+
- Use the ADO state/type colors defined above for data series.
|
|
118
|
+
|
|
119
|
+
### Interactivity
|
|
120
|
+
|
|
121
|
+
#### Clickable Work Item Links
|
|
122
|
+
Every work item ID must be a clickable link opening in a new tab:
|
|
123
|
+
\`\`\`html
|
|
124
|
+
<a href="https://dev.azure.com/{org}/{project}/_workitems/edit/{id}" target="_blank"
|
|
125
|
+
style="color:var(--link); text-decoration:none; font-weight:600">#{id}</a>
|
|
126
|
+
\`\`\`
|
|
127
|
+
|
|
128
|
+
#### CSV Download Button
|
|
129
|
+
Include a download button that generates a CSV from the displayed data:
|
|
130
|
+
\`\`\`html
|
|
131
|
+
<button onclick="downloadCsv()" style="padding:6px 14px; background:var(--link); color:white;
|
|
132
|
+
border:none; border-radius:4px; cursor:pointer; font-size:13px">Download CSV</button>
|
|
133
|
+
\`\`\`
|
|
134
|
+
The \`downloadCsv()\` function should:
|
|
135
|
+
1. Build CSV string from the data
|
|
136
|
+
2. Create a Blob and object URL
|
|
137
|
+
3. Trigger download via a temporary \`<a>\` element with \`download\` attribute
|
|
138
|
+
|
|
139
|
+
#### Sortable Tables
|
|
140
|
+
Add sort functionality to table headers:
|
|
141
|
+
- Click to sort ascending, click again for descending
|
|
142
|
+
- Show sort indicator (arrow) in the active column header
|
|
143
|
+
- Implement in a \`<script>\` tag using DOM manipulation
|
|
144
|
+
|
|
145
|
+
### Security (CRITICAL)
|
|
146
|
+
- **HTML-escape ALL data values** before embedding. Titles, names, descriptions — everything from the data JSON must be escaped:
|
|
147
|
+
\`\`\`javascript
|
|
148
|
+
function esc(str) { const d = document.createElement('div'); d.textContent = String(str ?? ''); return d.innerHTML; }
|
|
149
|
+
\`\`\`
|
|
150
|
+
- Use the \`esc()\` function for every data value rendered into HTML.
|
|
151
|
+
- Never use \`eval()\` or the \`Function()\` constructor.
|
|
152
|
+
- Never load scripts from domains other than \`cdn.jsdelivr.net\`.
|
|
153
|
+
- Never submit data to external URLs.
|
|
154
|
+
|
|
155
|
+
### Content Structure
|
|
156
|
+
1. **Title bar**: Visualization title + item count + download CSV button
|
|
157
|
+
2. **KPI cards**: Key metrics in a grid (total, by state, etc.)
|
|
158
|
+
3. **Primary visualization**: Chart or visual that matches the intent
|
|
159
|
+
4. **Data table**: Sortable table with all items, work item IDs as links
|
|
160
|
+
5. **Footer**: "Generated by MCP Apps" + timestamp
|
|
161
|
+
|
|
162
|
+
### Output Format
|
|
163
|
+
Return ONLY the HTML snippet. No markdown fences, no explanation, no preamble.
|
|
164
|
+
The HTML must be self-contained and render correctly when injected via innerHTML.
|
|
165
|
+
`.trim();
|
|
166
|
+
//# sourceMappingURL=design-system-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-system-prompt.js","sourceRoot":"","sources":["../../src/genui/design-system-prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8JnC,CAAC,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight HTML sanitizer for LLM-generated visualization HTML.
|
|
3
|
+
*
|
|
4
|
+
* Primary threat: prompt injection via work item data (e.g., a title containing <script>).
|
|
5
|
+
* The design system prompt instructs the LLM to HTML-escape data values (primary defense).
|
|
6
|
+
* This sanitizer is the secondary defense layer.
|
|
7
|
+
*
|
|
8
|
+
* Allows: inline scripts, Chart.js CDN, event handlers (needed for interactivity).
|
|
9
|
+
* Strips: external scripts (non-CDN), iframes, objects, embeds, base, meta, external forms.
|
|
10
|
+
*/
|
|
11
|
+
export declare function sanitizeGenUiHtml(html: string): string;
|
|
12
|
+
//# sourceMappingURL=sanitize-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-html.d.ts","sourceRoot":"","sources":["../../src/genui/sanitize-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBtD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight HTML sanitizer for LLM-generated visualization HTML.
|
|
3
|
+
*
|
|
4
|
+
* Primary threat: prompt injection via work item data (e.g., a title containing <script>).
|
|
5
|
+
* The design system prompt instructs the LLM to HTML-escape data values (primary defense).
|
|
6
|
+
* This sanitizer is the secondary defense layer.
|
|
7
|
+
*
|
|
8
|
+
* Allows: inline scripts, Chart.js CDN, event handlers (needed for interactivity).
|
|
9
|
+
* Strips: external scripts (non-CDN), iframes, objects, embeds, base, meta, external forms.
|
|
10
|
+
*/
|
|
11
|
+
const ALLOWED_SCRIPT_SRC_PATTERN = /^https:\/\/cdn\.jsdelivr\.net\//;
|
|
12
|
+
const DANGEROUS_ELEMENTS_PATTERN = /<(iframe|object|embed|base|meta)\b[^>]*>[\s\S]*?<\/\1>|<(iframe|object|embed|base|meta)\b[^>]*\/?>/gi;
|
|
13
|
+
const EXTERNAL_FORM_ACTION_PATTERN = /<form\b([^>]*)\baction\s*=\s*["'](https?:\/\/[^"']*)["']([^>]*)>/gi;
|
|
14
|
+
export function sanitizeGenUiHtml(html) {
|
|
15
|
+
let sanitized = html;
|
|
16
|
+
// Strip dangerous elements (with or without closing tags)
|
|
17
|
+
sanitized = sanitized.replace(DANGEROUS_ELEMENTS_PATTERN, '');
|
|
18
|
+
// Strip external script sources — keep inline scripts and Chart.js CDN
|
|
19
|
+
sanitized = sanitized.replace(/<script\b([^>]*)\bsrc\s*=\s*["']([^"']*)["']([^>]*)>/gi, (match, _before, src) => {
|
|
20
|
+
return ALLOWED_SCRIPT_SRC_PATTERN.test(src) ? match : '<!-- stripped external script -->';
|
|
21
|
+
});
|
|
22
|
+
// Strip forms with external actions (keep the form tag but remove the action)
|
|
23
|
+
sanitized = sanitized.replace(EXTERNAL_FORM_ACTION_PATTERN, '<form$1$3>');
|
|
24
|
+
return sanitized;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=sanitize-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize-html.js","sourceRoot":"","sources":["../../src/genui/sanitize-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,0BAA0B,GAAG,iCAAiC,CAAC;AAErE,MAAM,0BAA0B,GAAG,sGAAsG,CAAC;AAE1I,MAAM,4BAA4B,GAAG,oEAAoE,CAAC;AAE1G,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,SAAS,GAAG,IAAI,CAAC;IAErB,0DAA0D;IAC1D,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;IAE9D,uEAAuE;IACvE,SAAS,GAAG,SAAS,CAAC,OAAO,CAC3B,wDAAwD,EACxD,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE;QACtB,OAAO,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,mCAAmC,CAAC;IAC5F,CAAC,CACF,CAAC;IAEF,8EAA8E;IAC9E,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,4BAA4B,EAAE,YAAY,CAAC,CAAC;IAE1E,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AA6CH;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,CAK1D;AAGD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -27,6 +27,13 @@ function registerUiResources(server) {
|
|
|
27
27
|
uri: resourceUri,
|
|
28
28
|
mimeType: RESOURCE_MIME_TYPE,
|
|
29
29
|
text: await fs.readFile(htmlPath, "utf-8"),
|
|
30
|
+
_meta: {
|
|
31
|
+
ui: {
|
|
32
|
+
csp: {
|
|
33
|
+
resourceDomains: ["https://cdn.jsdelivr.net"],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
30
37
|
},
|
|
31
38
|
],
|
|
32
39
|
}));
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD;;GAEG;AACH,SAAS,mBAAmB,CAAC,MAAW;IACtC,MAAM,WAAW,GAAG,qBAAqB,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,qBAAqB,CAAC,CAAC;IAE7E,mBAAmB,CACjB,MAAM,EACN,WAAW,EACX,WAAW,EACX,EAAE,QAAQ,EAAE,kBAAkB,EAAE,EAChC,KAAK,IAAI,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE;YACR;gBACE,GAAG,EAAE,WAAW;gBAChB,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/build/tools/index.d.ts
CHANGED
|
@@ -11,4 +11,5 @@ export { registerBuildTools } from './build-tools.js';
|
|
|
11
11
|
export { registerVariableGroupTools } from './variable-group-tools.js';
|
|
12
12
|
export { registerSyncTools } from './sync-tools.js';
|
|
13
13
|
export { registerChecklistTools } from './checklist-tools.js';
|
|
14
|
+
export { registerVisualizeTools } from './visualize-tools.js';
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAWlD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAiBvE;AAED,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/build/tools/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { registerBuildTools } from './build-tools.js';
|
|
|
6
6
|
import { registerVariableGroupTools } from './variable-group-tools.js';
|
|
7
7
|
import { registerSyncTools } from './sync-tools.js';
|
|
8
8
|
import { registerChecklistTools } from './checklist-tools.js';
|
|
9
|
+
import { registerVisualizeTools } from './visualize-tools.js';
|
|
9
10
|
export function registerAllTools(server, ctx) {
|
|
10
11
|
registerConfigurationTools(server, ctx);
|
|
11
12
|
registerWikiTools(server, ctx);
|
|
@@ -15,9 +16,10 @@ export function registerAllTools(server, ctx) {
|
|
|
15
16
|
registerVariableGroupTools(server, ctx);
|
|
16
17
|
registerSyncTools(server, ctx);
|
|
17
18
|
registerChecklistTools(server, ctx);
|
|
19
|
+
registerVisualizeTools(server, ctx);
|
|
18
20
|
// Log registration summary
|
|
19
|
-
// 1 config + 11 wiki + 10 work-item + 6 PR-read + 3 build + 2 variable-group + 8 sync + 8 checklist =
|
|
20
|
-
const baseToolsCount =
|
|
21
|
+
// 1 config + 11 wiki + 10 work-item + 6 PR-read + 3 build + 2 variable-group + 8 sync + 8 checklist + 2 visualize = 51
|
|
22
|
+
const baseToolsCount = 51;
|
|
21
23
|
const prWriteToolsCount = getPrWriteToolCount();
|
|
22
24
|
const totalToolsCount = baseToolsCount + prWriteToolsCount;
|
|
23
25
|
console.error(`azure-devops tools registered: ${totalToolsCount} tools (${baseToolsCount} base + ${prWriteToolsCount} PR write)`);
|
|
@@ -30,4 +32,5 @@ export { registerBuildTools } from './build-tools.js';
|
|
|
30
32
|
export { registerVariableGroupTools } from './variable-group-tools.js';
|
|
31
33
|
export { registerSyncTools } from './sync-tools.js';
|
|
32
34
|
export { registerChecklistTools } from './checklist-tools.js';
|
|
35
|
+
export { registerVisualizeTools } from './visualize-tools.js';
|
|
33
36
|
//# sourceMappingURL=index.js.map
|
package/build/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,UAAU,gBAAgB,CAAC,MAAW,EAAE,GAAmB;IAC/D,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACxC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,wBAAwB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACxC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEpC,2BAA2B;IAC3B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,MAAM,UAAU,gBAAgB,CAAC,MAAW,EAAE,GAAmB;IAC/D,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACxC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,wBAAwB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACxC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEpC,2BAA2B;IAC3B,uHAAuH;IACvH,MAAM,cAAc,GAAG,EAAE,CAAC;IAC1B,MAAM,iBAAiB,GAAG,mBAAmB,EAAE,CAAC;IAChD,MAAM,eAAe,GAAG,cAAc,GAAG,iBAAiB,CAAC;IAC3D,OAAO,CAAC,KAAK,CAAC,kCAAkC,eAAe,WAAW,cAAc,WAAW,iBAAiB,YAAY,CAAC,CAAC;AACpI,CAAC;AAED,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visualize-tools.d.ts","sourceRoot":"","sources":["../../src/tools/visualize-tools.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAiI7E"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visualization Tools — Generative UI via MCP Apps
|
|
3
|
+
*
|
|
4
|
+
* Two-tool pattern:
|
|
5
|
+
* 1. visualize-data: Fetches work items, returns data + design system prompt to host LLM
|
|
6
|
+
* 2. render-visualization: Receives LLM-generated HTML, sanitizes it, returns structuredContent
|
|
7
|
+
*
|
|
8
|
+
* The host LLM generates the HTML using its own subscription — no API key, no extra cost.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { registerAppTool } from '@modelcontextprotocol/ext-apps/server';
|
|
12
|
+
import { DESIGN_SYSTEM_PROMPT } from '../genui/design-system-prompt.js';
|
|
13
|
+
import { sanitizeGenUiHtml } from '../genui/sanitize-html.js';
|
|
14
|
+
export function registerVisualizeTools(server, ctx) {
|
|
15
|
+
const workItemsResourceUri = "ui://ado/work-items";
|
|
16
|
+
// Tool 1: Fetch data and instruct host LLM to generate HTML
|
|
17
|
+
server.tool("visualize-data", "Fetch work item data and prepare it for interactive visualization. Returns raw data + design system rules. " +
|
|
18
|
+
"After receiving this response, you MUST generate a complete HTML snippet following the design system rules, " +
|
|
19
|
+
"then call the render-visualization tool with the generated HTML. Do not skip the render step.", {
|
|
20
|
+
project: z.string().describe("The ADO project name"),
|
|
21
|
+
wiql: z.string().describe("WIQL query to fetch work items. Example: SELECT [System.Id], [System.Title], [System.State], " +
|
|
22
|
+
"[System.WorkItemType], [System.AssignedTo] FROM WorkItems WHERE [System.TeamProject] = 'MyProject' " +
|
|
23
|
+
"AND [System.State] <> 'Removed' ORDER BY [System.ChangedDate] DESC"),
|
|
24
|
+
intent: z.string().describe("What visualization to create. Examples: 'sprint status dashboard', 'burndown chart', " +
|
|
25
|
+
"'team workload by assignee', 'priority breakdown', 'bug trend over time'"),
|
|
26
|
+
theme: z.enum(["light", "dark"]).optional().describe("Color theme (default: light)"),
|
|
27
|
+
maxResults: z.number().optional().describe("Maximum work items to fetch (default: 20 for visualization)"),
|
|
28
|
+
}, async ({ project, wiql, intent, theme, maxResults }) => {
|
|
29
|
+
try {
|
|
30
|
+
const effectiveMaxResults = maxResults ?? 20;
|
|
31
|
+
const result = await ctx.workItem.queryWorkItems(project, wiql, effectiveMaxResults);
|
|
32
|
+
const items = Array.isArray(result) ? result : result?.workItems ?? result;
|
|
33
|
+
const itemCount = Array.isArray(items) ? items.length : 0;
|
|
34
|
+
const org = process.env.AZUREDEVOPS_ORGANIZATION || 'unknown-org';
|
|
35
|
+
const effectiveTheme = theme || 'light';
|
|
36
|
+
return {
|
|
37
|
+
content: [{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: [
|
|
40
|
+
`## Visualization Data (${itemCount} work items)`,
|
|
41
|
+
`**Intent:** ${intent}`,
|
|
42
|
+
`**Theme:** ${effectiveTheme}`,
|
|
43
|
+
`**Organization:** ${org}`,
|
|
44
|
+
`**Project:** ${project}`,
|
|
45
|
+
``,
|
|
46
|
+
`### Work Item Data`,
|
|
47
|
+
'```json',
|
|
48
|
+
JSON.stringify(items, null, 2),
|
|
49
|
+
'```',
|
|
50
|
+
``,
|
|
51
|
+
`### Design System Rules`,
|
|
52
|
+
``,
|
|
53
|
+
DESIGN_SYSTEM_PROMPT,
|
|
54
|
+
``,
|
|
55
|
+
`### Instructions`,
|
|
56
|
+
``,
|
|
57
|
+
`Generate a complete HTML snippet following the design system rules above.`,
|
|
58
|
+
`Use the organization "${org}" and project "${project}" to construct work item URLs.`,
|
|
59
|
+
`The visualization intent is: "${intent}"`,
|
|
60
|
+
`Theme: "${effectiveTheme}"`,
|
|
61
|
+
``,
|
|
62
|
+
`After generating the HTML, call the \`render-visualization\` tool with:`,
|
|
63
|
+
`- \`html\`: the complete HTML snippet`,
|
|
64
|
+
`- \`title\`: a short title for the visualization`,
|
|
65
|
+
``,
|
|
66
|
+
`Return ONLY the HTML when calling render-visualization. No markdown, no explanation.`,
|
|
67
|
+
].join('\n'),
|
|
68
|
+
}],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error("Error in visualize-data:", error);
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: `Failed to fetch work item data: ${error.message}` }],
|
|
75
|
+
isError: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
// Tool 2: Receive generated HTML and render it via MCP App
|
|
80
|
+
registerAppTool(server, "render-visualization", {
|
|
81
|
+
title: "Render Visualization",
|
|
82
|
+
description: "Render generated HTML as an interactive visualization in the MCP App. " +
|
|
83
|
+
"Call this after generating HTML from visualize-data results. " +
|
|
84
|
+
"Pass the complete HTML snippet — it will be sanitized and rendered in an iframe.",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
html: z.string().describe("The complete HTML snippet to render. Must be self-contained with inline CSS and scripts."),
|
|
87
|
+
title: z.string().optional().describe("Short title for the visualization (e.g. 'Sprint Status Dashboard')"),
|
|
88
|
+
},
|
|
89
|
+
_meta: { ui: { resourceUri: workItemsResourceUri } },
|
|
90
|
+
}, async ({ html, title }) => {
|
|
91
|
+
try {
|
|
92
|
+
// Validate: basic HTML check
|
|
93
|
+
if (!html || (!html.includes('<') && !html.includes('>'))) {
|
|
94
|
+
return {
|
|
95
|
+
content: [{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: "Error: The provided content does not appear to be valid HTML. Please regenerate following the design system rules.",
|
|
98
|
+
}],
|
|
99
|
+
isError: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// Strip markdown code fences if the LLM wrapped the HTML
|
|
103
|
+
let cleanHtml = html;
|
|
104
|
+
if (cleanHtml.startsWith('```')) {
|
|
105
|
+
cleanHtml = cleanHtml.replace(/^```(?:html)?\n?/i, '').replace(/\n?```$/i, '').trim();
|
|
106
|
+
}
|
|
107
|
+
// Sanitize
|
|
108
|
+
const sanitized = sanitizeGenUiHtml(cleanHtml);
|
|
109
|
+
const displayTitle = title || 'Visualization';
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: "text", text: `Rendered: ${displayTitle}` }],
|
|
112
|
+
structuredContent: { type: "genui", html: sanitized, title: displayTitle },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
console.error("Error in render-visualization:", error);
|
|
117
|
+
return {
|
|
118
|
+
content: [{ type: "text", text: `Failed to render visualization: ${error.message}` }],
|
|
119
|
+
isError: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=visualize-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visualize-tools.js","sourceRoot":"","sources":["../../src/tools/visualize-tools.ts"],"names":[],"mappings":"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"}
|