@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.
@@ -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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAsCH;;;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"}
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
  }));
@@ -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;aAC3C;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAW;IAClD,MAAM,GAAG,GAAG,oBAAoB,EAAE,CAAC;IACnC,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,8BAA8B;AAC9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAI5D,wBAAwB;AACxB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG5E;;;GAGG;AACH,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;IAClC,OAAO,EAAE,CAAC;IAEV,MAAM,MAAM,GAAG,eAAe,CAAC;QAC7B,IAAI,EAAE,oCAAoC;QAC1C,OAAO,EAAE,OAAO;QAChB,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,EAAE;SACd;KACF,CAAC,CAAC;IAEH,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAEjC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;QAC/C,OAAO,CAAC,KAAK,CAAC,gEAAgE,EAAE,KAAK,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;AAC9E,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -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;AAUlD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,CAgBvE;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"}
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"}
@@ -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 = 49
20
- const baseToolsCount = 49;
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
@@ -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,yGAAyG;IACzG,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"}
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,3 @@
1
+ import type { ServiceContext } from '../types.js';
2
+ export declare function registerVisualizeTools(server: any, ctx: ServiceContext): void;
3
+ //# sourceMappingURL=visualize-tools.d.ts.map
@@ -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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"}