@mcp-consultant-tools/azure-devops 29.0.0 → 30.0.0-beta.10

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,145 @@
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 a rich visual dashboard. ONLY use this tool when the user explicitly asks for a " +
18
+ "visual, chart, dashboard, or graphic representation of their data (e.g. 'visualize', 'show me a chart', 'create a dashboard'). " +
19
+ "Do NOT use for regular queries — use query-work-items or run-saved-query instead, which are faster. " +
20
+ "Accepts either a WIQL query or a saved query ID (GUID). " +
21
+ "After receiving the response, generate a complete HTML snippet following the design system rules, " +
22
+ "then call render-visualization with the HTML.", {
23
+ project: z.string().describe("The ADO project name"),
24
+ wiql: z.string().optional().describe("WIQL query to fetch work items. Provide either wiql OR queryId, not both. " +
25
+ "Example: SELECT [System.Id], [System.Title], [System.State], " +
26
+ "[System.WorkItemType], [System.AssignedTo] FROM WorkItems WHERE [System.TeamProject] = 'MyProject' " +
27
+ "AND [System.State] <> 'Removed' ORDER BY [System.ChangedDate] DESC"),
28
+ queryId: z.string().optional().describe("Saved query GUID. Provide either queryId OR wiql, not both. " +
29
+ "Found in ADO query URLs: https://dev.azure.com/{org}/{project}/_queries/query/{queryId}/"),
30
+ intent: z.string().describe("What visualization to create. Examples: 'sprint status dashboard', 'burndown chart', " +
31
+ "'team workload by assignee', 'priority breakdown', 'bug trend over time'"),
32
+ theme: z.enum(["light", "dark"]).optional().describe("Color theme (default: light)"),
33
+ maxResults: z.number().optional().describe("Maximum work items to fetch (default: 20 for visualization)"),
34
+ }, async ({ project, wiql, queryId, intent, theme, maxResults }) => {
35
+ try {
36
+ if (!wiql && !queryId) {
37
+ return {
38
+ content: [{ type: "text", text: "Error: Provide either 'wiql' or 'queryId' parameter." }],
39
+ isError: true,
40
+ };
41
+ }
42
+ const effectiveMaxResults = maxResults ?? 20;
43
+ let items;
44
+ if (queryId) {
45
+ // Execute saved query
46
+ const result = await ctx.workItem.runSavedQuery(project, queryId, effectiveMaxResults);
47
+ items = Array.isArray(result) ? result : result?.workItems ?? [];
48
+ }
49
+ else {
50
+ // Execute WIQL query
51
+ const result = await ctx.workItem.queryWorkItems(project, wiql, effectiveMaxResults);
52
+ items = Array.isArray(result) ? result : result?.workItems ?? result;
53
+ }
54
+ const itemCount = Array.isArray(items) ? items.length : 0;
55
+ const org = process.env.AZUREDEVOPS_ORGANIZATION || 'unknown-org';
56
+ const effectiveTheme = theme || 'light';
57
+ return {
58
+ content: [{
59
+ type: "text",
60
+ text: [
61
+ `## Visualization Data (${itemCount} work items)`,
62
+ `**Intent:** ${intent}`,
63
+ `**Theme:** ${effectiveTheme}`,
64
+ `**Organization:** ${org}`,
65
+ `**Project:** ${project}`,
66
+ ``,
67
+ `### Work Item Data`,
68
+ '```json',
69
+ JSON.stringify(items, null, 2),
70
+ '```',
71
+ ``,
72
+ `### Design System Rules`,
73
+ ``,
74
+ DESIGN_SYSTEM_PROMPT,
75
+ ``,
76
+ `### Instructions`,
77
+ ``,
78
+ `Generate a complete HTML snippet following the design system rules above.`,
79
+ `Use the organization "${org}" and project "${project}" to construct work item URLs.`,
80
+ `The visualization intent is: "${intent}"`,
81
+ `Theme: "${effectiveTheme}"`,
82
+ ``,
83
+ `After generating the HTML, call the \`render-visualization\` tool with:`,
84
+ `- \`html\`: the complete HTML snippet`,
85
+ `- \`title\`: a short title for the visualization`,
86
+ ``,
87
+ `Return ONLY the HTML when calling render-visualization. No markdown, no explanation.`,
88
+ ].join('\n'),
89
+ }],
90
+ };
91
+ }
92
+ catch (error) {
93
+ console.error("Error in visualize-data:", error);
94
+ return {
95
+ content: [{ type: "text", text: `Failed to fetch work item data: ${error.message}` }],
96
+ isError: true,
97
+ };
98
+ }
99
+ });
100
+ // Tool 2: Receive generated HTML and render it via MCP App
101
+ registerAppTool(server, "render-visualization", {
102
+ title: "Render Visualization",
103
+ description: "Render generated HTML as an interactive visualization in the MCP App. " +
104
+ "Call this after generating HTML from visualize-data results. " +
105
+ "Pass the complete HTML snippet — it will be sanitized and rendered in an iframe.",
106
+ inputSchema: {
107
+ html: z.string().describe("The complete HTML snippet to render. Must be self-contained with inline CSS and scripts."),
108
+ title: z.string().optional().describe("Short title for the visualization (e.g. 'Sprint Status Dashboard')"),
109
+ },
110
+ _meta: { ui: { resourceUri: workItemsResourceUri } },
111
+ }, async ({ html, title }) => {
112
+ try {
113
+ // Validate: basic HTML check
114
+ if (!html || (!html.includes('<') && !html.includes('>'))) {
115
+ return {
116
+ content: [{
117
+ type: "text",
118
+ text: "Error: The provided content does not appear to be valid HTML. Please regenerate following the design system rules.",
119
+ }],
120
+ isError: true,
121
+ };
122
+ }
123
+ // Strip markdown code fences if the LLM wrapped the HTML
124
+ let cleanHtml = html;
125
+ if (cleanHtml.startsWith('```')) {
126
+ cleanHtml = cleanHtml.replace(/^```(?:html)?\n?/i, '').replace(/\n?```$/i, '').trim();
127
+ }
128
+ // Sanitize
129
+ const sanitized = sanitizeGenUiHtml(cleanHtml);
130
+ const displayTitle = title || 'Visualization';
131
+ return {
132
+ content: [{ type: "text", text: `Rendered: ${displayTitle}` }],
133
+ structuredContent: { type: "genui", html: sanitized, title: displayTitle },
134
+ };
135
+ }
136
+ catch (error) {
137
+ console.error("Error in render-visualization:", error);
138
+ return {
139
+ content: [{ type: "text", text: `Failed to render visualization: ${error.message}` }],
140
+ isError: true,
141
+ };
142
+ }
143
+ });
144
+ }
145
+ //# sourceMappingURL=visualize-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visualize-tools.js","sourceRoot":"","sources":["../../src/tools/visualize-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,MAAM,UAAU,sBAAsB,CAAC,MAAW,EAAE,GAAmB;IACrE,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;IAEnD,4DAA4D;IAC5D,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,0HAA0H;QAC1H,iIAAiI;QACjI,sGAAsG;QACtG,0DAA0D;QAC1D,oGAAoG;QACpG,+CAA+C,EAC/C;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACpD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAClC,4EAA4E;YAC5E,+DAA+D;YAC/D,qGAAqG;YACrG,oEAAoE,CACrE;QACD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CACrC,8DAA8D;YAC9D,0FAA0F,CAC3F;QACD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CACzB,uFAAuF;YACvF,0EAA0E,CAC3E;QACD,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QACpF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6DAA6D,CAAC;KAC1G,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAO,EAAE,EAAE;QACnE,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACtB,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,sDAAsD,EAAE,CAAC;oBACzF,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,mBAAmB,GAAG,UAAU,IAAI,EAAE,CAAC;YAC7C,IAAI,KAAY,CAAC;YAEjB,IAAI,OAAO,EAAE,CAAC;gBACZ,sBAAsB;gBACtB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,CAAC,CAAC;gBACvF,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,MAAc,EAAE,SAAS,IAAI,EAAE,CAAC;YAC5E,CAAC;iBAAM,CAAC;gBACN,qBAAqB;gBACrB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,mBAAmB,CAAC,CAAC;gBACrF,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAE,MAAc,EAAE,SAAS,IAAI,MAAM,CAAC;YAChF,CAAC;YACD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAE1D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,aAAa,CAAC;YAClE,MAAM,cAAc,GAAG,KAAK,IAAI,OAAO,CAAC;YAExC,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE;4BACJ,0BAA0B,SAAS,cAAc;4BACjD,eAAe,MAAM,EAAE;4BACvB,cAAc,cAAc,EAAE;4BAC9B,qBAAqB,GAAG,EAAE;4BAC1B,gBAAgB,OAAO,EAAE;4BACzB,EAAE;4BACF,oBAAoB;4BACpB,SAAS;4BACT,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;4BAC9B,KAAK;4BACL,EAAE;4BACF,yBAAyB;4BACzB,EAAE;4BACF,oBAAoB;4BACpB,EAAE;4BACF,kBAAkB;4BAClB,EAAE;4BACF,2EAA2E;4BAC3E,yBAAyB,GAAG,kBAAkB,OAAO,gCAAgC;4BACrF,iCAAiC,MAAM,GAAG;4BAC1C,WAAW,cAAc,GAAG;4BAC5B,EAAE;4BACF,yEAAyE;4BACzE,uCAAuC;4BACvC,kDAAkD;4BAClD,EAAE;4BACF,sFAAsF;yBACvF,CAAC,IAAI,CAAC,IAAI,CAAC;qBACb,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YACjD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mCAAmC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,2DAA2D;IAC3D,eAAe,CACb,MAAM,EACN,sBAAsB,EACtB;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EACT,wEAAwE;YACxE,+DAA+D;YAC/D,kFAAkF;QACpF,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0FAA0F,CAAC;YACrH,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oEAAoE,CAAC;SAC5G;QACD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,oBAAoB,EAAE,EAAE;KACrD,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAO,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,6BAA6B;YAC7B,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC1D,OAAO;oBACL,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,oHAAoH;yBAC3H,CAAC;oBACF,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,yDAAyD;YACzD,IAAI,SAAS,GAAG,IAAI,CAAC;YACrB,IAAI,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChC,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACxF,CAAC;YAED,WAAW;YACX,MAAM,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;YAE/C,MAAM,YAAY,GAAG,KAAK,IAAI,eAAe,CAAC;YAC9C,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,YAAY,EAAE,EAAE,CAAC;gBAC9D,iBAAiB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE;aAC3E,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;YACvD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mCAAmC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}