@achieveai/azuredevops-mcp 1.2.1 → 1.2.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/dist/Interfaces/Pipelines.js +3 -0
- package/dist/Interfaces/Pipelines.js.map +1 -0
- package/dist/Interfaces/Wiki.js +3 -0
- package/dist/Interfaces/Wiki.js.map +1 -0
- package/dist/Services/AzureDevOpsService.js +6 -5
- package/dist/Services/AzureDevOpsService.js.map +1 -1
- package/dist/Services/BuildService.js +172 -0
- package/dist/Services/BuildService.js.map +1 -0
- package/dist/Services/EntraAuthHandler.js +65 -18
- package/dist/Services/EntraAuthHandler.js.map +1 -1
- package/dist/Services/GitService.js +129 -0
- package/dist/Services/GitService.js.map +1 -1
- package/dist/Services/WikiService.js +90 -0
- package/dist/Services/WikiService.js.map +1 -0
- package/dist/Services/WorkItemService.js +123 -0
- package/dist/Services/WorkItemService.js.map +1 -1
- package/dist/Tools/BuildTools.js +402 -0
- package/dist/Tools/BuildTools.js.map +1 -0
- package/dist/Tools/GitTools.js +187 -41
- package/dist/Tools/GitTools.js.map +1 -1
- package/dist/Tools/WikiTools.js +137 -0
- package/dist/Tools/WikiTools.js.map +1 -0
- package/dist/Tools/WorkItemTools.js +120 -0
- package/dist/Tools/WorkItemTools.js.map +1 -1
- package/dist/config.js +27 -10
- package/dist/config.js.map +1 -1
- package/dist/index.js +297 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,14 +12,28 @@ const TestingCapabilitiesTools_1 = require("./Tools/TestingCapabilitiesTools");
|
|
|
12
12
|
const DevSecOpsTools_1 = require("./Tools/DevSecOpsTools");
|
|
13
13
|
const ArtifactManagementTools_1 = require("./Tools/ArtifactManagementTools");
|
|
14
14
|
const AIAssistedDevelopmentTools_1 = require("./Tools/AIAssistedDevelopmentTools");
|
|
15
|
+
const BuildTools_1 = require("./Tools/BuildTools");
|
|
16
|
+
const WikiTools_1 = require("./Tools/WikiTools");
|
|
15
17
|
const zod_1 = require("zod");
|
|
18
|
+
/** Wrap a value so string-encoded JSON arrays are auto-parsed (some MCP clients send arrays as strings). */
|
|
19
|
+
const coerceArray = (val) => typeof val === 'string' ? JSON.parse(val) : val;
|
|
16
20
|
const EntraAuthHandler_1 = require("./Services/EntraAuthHandler");
|
|
17
21
|
async function main() {
|
|
18
22
|
try {
|
|
19
23
|
// Load configuration
|
|
20
24
|
const azureDevOpsConfig = (0, config_1.getAzureDevOpsConfig)();
|
|
25
|
+
// Initialize token credential auth handler based on auth type
|
|
21
26
|
if (azureDevOpsConfig.auth?.type === 'entra') {
|
|
22
|
-
azureDevOpsConfig.
|
|
27
|
+
azureDevOpsConfig.tokenCredentialAuthHandler = await EntraAuthHandler_1.TokenCredentialAuthHandler.createEntra();
|
|
28
|
+
}
|
|
29
|
+
else if (azureDevOpsConfig.auth?.type === 'azcli') {
|
|
30
|
+
azureDevOpsConfig.tokenCredentialAuthHandler = await EntraAuthHandler_1.TokenCredentialAuthHandler.createAzureCli(azureDevOpsConfig.auth.tenantId);
|
|
31
|
+
}
|
|
32
|
+
else if (azureDevOpsConfig.auth?.type === 'interactive') {
|
|
33
|
+
azureDevOpsConfig.tokenCredentialAuthHandler = await EntraAuthHandler_1.TokenCredentialAuthHandler.createInteractive({
|
|
34
|
+
tenantId: azureDevOpsConfig.auth.tenantId,
|
|
35
|
+
clientId: azureDevOpsConfig.auth.clientId,
|
|
36
|
+
});
|
|
23
37
|
}
|
|
24
38
|
// Load allowed tools
|
|
25
39
|
const allowedTools = (0, config_1.getAllowedTools)();
|
|
@@ -32,6 +46,8 @@ async function main() {
|
|
|
32
46
|
const devSecOpsTools = new DevSecOpsTools_1.DevSecOpsTools(azureDevOpsConfig);
|
|
33
47
|
const artifactManagementTools = new ArtifactManagementTools_1.ArtifactManagementTools(azureDevOpsConfig);
|
|
34
48
|
const aiAssistedDevelopmentTools = new AIAssistedDevelopmentTools_1.AIAssistedDevelopmentTools(azureDevOpsConfig);
|
|
49
|
+
const buildTools = new BuildTools_1.BuildTools(azureDevOpsConfig);
|
|
50
|
+
const wikiTools = new WikiTools_1.WikiTools(azureDevOpsConfig);
|
|
35
51
|
// Create MCP server
|
|
36
52
|
const server = new mcp_js_1.McpServer({
|
|
37
53
|
name: 'azure-devops-mcp',
|
|
@@ -49,7 +65,7 @@ async function main() {
|
|
|
49
65
|
};
|
|
50
66
|
});
|
|
51
67
|
allowedTools.has("getWorkItemById") && server.tool("getWorkItemById", "Get a specific work item by ID with summary and detailed view", {
|
|
52
|
-
id: zod_1.z.number().describe("Work item ID")
|
|
68
|
+
id: zod_1.z.coerce.number().describe("Work item ID")
|
|
53
69
|
}, async (params, extra) => {
|
|
54
70
|
const result = await workItemTools.getWorkItemById({ id: params.id });
|
|
55
71
|
return {
|
|
@@ -61,7 +77,7 @@ async function main() {
|
|
|
61
77
|
});
|
|
62
78
|
allowedTools.has("searchWorkItems") && server.tool("searchWorkItems", "Search for work items by text with summary and organized results", {
|
|
63
79
|
searchText: zod_1.z.string().describe("Text to search for in work items"),
|
|
64
|
-
top: zod_1.z.number().optional().describe("Maximum number of work items to return")
|
|
80
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of work items to return")
|
|
65
81
|
}, async (params, extra) => {
|
|
66
82
|
const result = await workItemTools.searchWorkItems(params);
|
|
67
83
|
return {
|
|
@@ -72,8 +88,8 @@ async function main() {
|
|
|
72
88
|
};
|
|
73
89
|
});
|
|
74
90
|
allowedTools.has("getRecentlyUpdatedWorkItems") && server.tool("getRecentlyUpdatedWorkItems", "Get recently updated work items", {
|
|
75
|
-
top: zod_1.z.number().optional().describe("Maximum number of work items to return"),
|
|
76
|
-
skip: zod_1.z.number().optional().describe("Number of work items to skip")
|
|
91
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of work items to return"),
|
|
92
|
+
skip: zod_1.z.coerce.number().optional().describe("Number of work items to skip")
|
|
77
93
|
}, async (params, extra) => {
|
|
78
94
|
const result = await workItemTools.getRecentlyUpdatedWorkItems(params);
|
|
79
95
|
return {
|
|
@@ -84,7 +100,7 @@ async function main() {
|
|
|
84
100
|
});
|
|
85
101
|
allowedTools.has("getMyWorkItems") && server.tool("getMyWorkItems", "Get work items assigned to you", {
|
|
86
102
|
state: zod_1.z.string().optional().describe("Filter by work item state"),
|
|
87
|
-
top: zod_1.z.number().optional().describe("Maximum number of work items to return")
|
|
103
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of work items to return")
|
|
88
104
|
}, async (params, extra) => {
|
|
89
105
|
const result = await workItemTools.getMyWorkItems(params);
|
|
90
106
|
return {
|
|
@@ -112,7 +128,7 @@ async function main() {
|
|
|
112
128
|
};
|
|
113
129
|
});
|
|
114
130
|
allowedTools.has("updateWorkItem") && server.tool("updateWorkItem", "Update an existing work item", {
|
|
115
|
-
id: zod_1.z.number().describe("ID of the work item to update"),
|
|
131
|
+
id: zod_1.z.coerce.number().describe("ID of the work item to update"),
|
|
116
132
|
fields: zod_1.z.record(zod_1.z.any()).describe("Fields to update on the work item")
|
|
117
133
|
}, async (params, extra) => {
|
|
118
134
|
const result = await workItemTools.updateWorkItem(params);
|
|
@@ -124,7 +140,7 @@ async function main() {
|
|
|
124
140
|
};
|
|
125
141
|
});
|
|
126
142
|
allowedTools.has("addWorkItemComment") && server.tool("addWorkItemComment", "Add a comment to a work item", {
|
|
127
|
-
id: zod_1.z.number().describe("ID of the work item"),
|
|
143
|
+
id: zod_1.z.coerce.number().describe("ID of the work item"),
|
|
128
144
|
text: zod_1.z.string().describe("Comment text")
|
|
129
145
|
}, async (params, extra) => {
|
|
130
146
|
const result = await workItemTools.addWorkItemComment(params);
|
|
@@ -136,7 +152,7 @@ async function main() {
|
|
|
136
152
|
};
|
|
137
153
|
});
|
|
138
154
|
allowedTools.has("updateWorkItemState") && server.tool("updateWorkItemState", "Update the state of a work item", {
|
|
139
|
-
id: zod_1.z.number().describe("ID of the work item"),
|
|
155
|
+
id: zod_1.z.coerce.number().describe("ID of the work item"),
|
|
140
156
|
state: zod_1.z.string().describe("New state for the work item"),
|
|
141
157
|
comment: zod_1.z.string().optional().describe("Comment explaining the state change")
|
|
142
158
|
}, async (params, extra) => {
|
|
@@ -148,7 +164,7 @@ async function main() {
|
|
|
148
164
|
};
|
|
149
165
|
});
|
|
150
166
|
allowedTools.has("assignWorkItem") && server.tool("assignWorkItem", "Assign a work item to a user", {
|
|
151
|
-
id: zod_1.z.number().describe("ID of the work item"),
|
|
167
|
+
id: zod_1.z.coerce.number().describe("ID of the work item"),
|
|
152
168
|
assignedTo: zod_1.z.string().describe("User to assign the work item to")
|
|
153
169
|
}, async (params, extra) => {
|
|
154
170
|
const result = await workItemTools.assignWorkItem(params);
|
|
@@ -162,7 +178,7 @@ async function main() {
|
|
|
162
178
|
"Use prefixes for targetId: WI#123 (work item), PR#456 (pull request), " +
|
|
163
179
|
"BUILD#789 (build), BRANCH#main (branch), COMMIT#abc123 (commit). " +
|
|
164
180
|
"Plain numbers default to work item.", {
|
|
165
|
-
sourceId: zod_1.z.number().describe("ID of the source work item"),
|
|
181
|
+
sourceId: zod_1.z.coerce.number().describe("ID of the source work item"),
|
|
166
182
|
targetId: zod_1.z.string().describe("Target with prefix: WI#123, PR#456, BUILD#789, BRANCH#main, COMMIT#abc, or plain number for work item"),
|
|
167
183
|
linkType: zod_1.z.string().describe("Link type (e.g., System.LinkTypes.Related). For artifact prefixes, this is still required but the actual rel type is auto-set to ArtifactLink."),
|
|
168
184
|
comment: zod_1.z.string().optional().describe("Comment explaining the link"),
|
|
@@ -189,7 +205,7 @@ async function main() {
|
|
|
189
205
|
additionalFields: zod_1.z.record(zod_1.z.any()).optional().describe("Additional fields to set on the work item")
|
|
190
206
|
}),
|
|
191
207
|
zod_1.z.object({
|
|
192
|
-
id: zod_1.z.number().describe("ID of work item to update"),
|
|
208
|
+
id: zod_1.z.coerce.number().describe("ID of work item to update"),
|
|
193
209
|
fields: zod_1.z.record(zod_1.z.any()).describe("Fields to update on the work item")
|
|
194
210
|
})
|
|
195
211
|
])).min(1).describe("Array of work items to create or update")
|
|
@@ -201,6 +217,48 @@ async function main() {
|
|
|
201
217
|
isError: result.isError
|
|
202
218
|
};
|
|
203
219
|
});
|
|
220
|
+
allowedTools.has("getWorkItemsBatch") && server.tool("getWorkItemsBatch", "Get multiple work items by their IDs in a single efficient call", {
|
|
221
|
+
ids: zod_1.z.preprocess(coerceArray, zod_1.z.array(zod_1.z.coerce.number())).describe("Array of work item IDs to retrieve"),
|
|
222
|
+
fields: zod_1.z.preprocess(coerceArray, zod_1.z.array(zod_1.z.string()).optional()).describe("Specific fields to return (e.g., ['System.Title', 'System.State'])"),
|
|
223
|
+
}, async (params) => {
|
|
224
|
+
const result = await workItemTools.getWorkItemsBatch(params);
|
|
225
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
226
|
+
});
|
|
227
|
+
allowedTools.has("getWorkItemRevisions") && server.tool("getWorkItemRevisions", "Get revision/change history for a work item showing all field changes over time", {
|
|
228
|
+
id: zod_1.z.coerce.number().describe("Work item ID"),
|
|
229
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of revisions to return"),
|
|
230
|
+
skip: zod_1.z.coerce.number().optional().describe("Number of revisions to skip"),
|
|
231
|
+
}, async (params) => {
|
|
232
|
+
const result = await workItemTools.getWorkItemRevisions(params);
|
|
233
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
234
|
+
});
|
|
235
|
+
allowedTools.has("getQueryResults") && server.tool("getQueryResults", "Execute a saved WIQL query by its query ID and return the resulting work items", {
|
|
236
|
+
queryId: zod_1.z.string().describe("The GUID of the saved query to execute"),
|
|
237
|
+
}, async (params) => {
|
|
238
|
+
const result = await workItemTools.getQueryResults(params);
|
|
239
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
240
|
+
});
|
|
241
|
+
allowedTools.has("addChildWorkItem") && server.tool("addChildWorkItem", "Create a new work item and link it as a child of an existing parent work item", {
|
|
242
|
+
parentId: zod_1.z.coerce.number().describe("Parent work item ID"),
|
|
243
|
+
workItemType: zod_1.z.string().describe("Type of child work item (e.g., 'Task', 'Bug')"),
|
|
244
|
+
title: zod_1.z.string().describe("Title of the child work item"),
|
|
245
|
+
description: zod_1.z.string().optional().describe("Description"),
|
|
246
|
+
assignedTo: zod_1.z.string().optional().describe("User to assign to"),
|
|
247
|
+
state: zod_1.z.string().optional().describe("Initial state"),
|
|
248
|
+
areaPath: zod_1.z.string().optional().describe("Area path"),
|
|
249
|
+
iterationPath: zod_1.z.string().optional().describe("Iteration path"),
|
|
250
|
+
additionalFields: zod_1.z.record(zod_1.z.any()).optional().describe("Additional fields"),
|
|
251
|
+
}, async (params) => {
|
|
252
|
+
const result = await workItemTools.addChildWorkItem(params);
|
|
253
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
254
|
+
});
|
|
255
|
+
allowedTools.has("unlinkWorkItem") && server.tool("unlinkWorkItem", "Remove a link/relation from a work item by its relation index. Use getWorkItemById first to see the relations and their indices.", {
|
|
256
|
+
id: zod_1.z.coerce.number().describe("Work item ID"),
|
|
257
|
+
relationIndex: zod_1.z.coerce.number().describe("Index of the relation to remove (0-based, from the relations array)"),
|
|
258
|
+
}, async (params) => {
|
|
259
|
+
const result = await workItemTools.unlinkWorkItem(params);
|
|
260
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
261
|
+
});
|
|
204
262
|
// Register Boards & Sprints Tools
|
|
205
263
|
allowedTools.has("getBoards") && server.tool("getBoards", "Get all boards for a team", {
|
|
206
264
|
teamId: zod_1.z.string().optional().describe("Team ID (uses default team if not specified)")
|
|
@@ -237,9 +295,9 @@ async function main() {
|
|
|
237
295
|
allowedTools.has("moveCardOnBoard") && server.tool("moveCardOnBoard", "Move a card on a board", {
|
|
238
296
|
teamId: zod_1.z.string().optional().describe("Team ID (uses default team if not specified)"),
|
|
239
297
|
boardId: zod_1.z.string().describe("ID of the board"),
|
|
240
|
-
workItemId: zod_1.z.number().describe("ID of the work item to move"),
|
|
298
|
+
workItemId: zod_1.z.coerce.number().describe("ID of the work item to move"),
|
|
241
299
|
columnId: zod_1.z.string().describe("ID of the column to move to"),
|
|
242
|
-
position: zod_1.z.number().optional().describe("Position within the column")
|
|
300
|
+
position: zod_1.z.coerce.number().optional().describe("Position within the column")
|
|
243
301
|
}, async (params, extra) => {
|
|
244
302
|
const result = await boardsSprintsTools.moveCardOnBoard(params);
|
|
245
303
|
return {
|
|
@@ -311,8 +369,8 @@ async function main() {
|
|
|
311
369
|
// Register Project Tools
|
|
312
370
|
allowedTools.has("listProjects") && server.tool("listProjects", "List all projects", {
|
|
313
371
|
stateFilter: zod_1.z.enum(['all', 'createPending', 'deleted', 'deleting', 'new', 'unchanged', 'wellFormed']).optional().describe("Filter by project state"),
|
|
314
|
-
top: zod_1.z.number().optional().describe("Maximum number of projects to return"),
|
|
315
|
-
skip: zod_1.z.number().optional().describe("Number of projects to skip")
|
|
372
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of projects to return"),
|
|
373
|
+
skip: zod_1.z.coerce.number().optional().describe("Number of projects to skip")
|
|
316
374
|
}, async (params, extra) => {
|
|
317
375
|
const result = await projectTools.listProjects(params);
|
|
318
376
|
return {
|
|
@@ -349,7 +407,7 @@ async function main() {
|
|
|
349
407
|
});
|
|
350
408
|
allowedTools.has("getAreas") && server.tool("getAreas", "Get areas for a project", {
|
|
351
409
|
projectId: zod_1.z.string().describe("ID of the project"),
|
|
352
|
-
depth: zod_1.z.number().optional().describe("Maximum depth of the area hierarchy")
|
|
410
|
+
depth: zod_1.z.coerce.number().optional().describe("Maximum depth of the area hierarchy")
|
|
353
411
|
}, async (params, extra) => {
|
|
354
412
|
const result = await projectTools.getAreas(params);
|
|
355
413
|
return {
|
|
@@ -464,7 +522,7 @@ async function main() {
|
|
|
464
522
|
allowedTools.has("listBranches") && server.tool("listBranches", "List all branches in a Git repository with optional name pattern filtering and pagination. Returns branch details including name, commit ID, and object ID. Results can be filtered using wildcards (e.g., 'feature/*' for all feature branches). Supports both repository names and IDs.", {
|
|
465
523
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) to list branches from. Repository names are case-insensitive."),
|
|
466
524
|
filter: zod_1.z.string().optional().describe("Optional wildcard pattern to filter branch names (e.g., 'feature/*', 'release/*'). Use this to narrow down results to specific branch types."),
|
|
467
|
-
top: zod_1.z.number().optional().describe("Maximum number of branches to return in the response. Use this to limit large result sets, especially for repositories with many branches.")
|
|
525
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of branches to return in the response. Use this to limit large result sets, especially for repositories with many branches.")
|
|
468
526
|
}, async (params, extra) => {
|
|
469
527
|
const result = await gitTools.listBranches(params);
|
|
470
528
|
return {
|
|
@@ -478,7 +536,7 @@ async function main() {
|
|
|
478
536
|
projectId: zod_1.z.string().optional().describe("Optional project ID or name to limit the search scope to a specific project. Omit to search across all accessible projects."),
|
|
479
537
|
repositoryId: zod_1.z.string().optional().describe("Optional repository ID or name to limit the search to a single repository. Most effective when combined with projectId."),
|
|
480
538
|
fileExtension: zod_1.z.string().optional().describe("Optional file extension to filter results by (e.g., '.js', '.ts', '.cs'). Provide without the dot to search for specific file types."),
|
|
481
|
-
top: zod_1.z.number().optional().describe("Maximum number of search results to return. Use this to limit large result sets for common search terms.")
|
|
539
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of search results to return. Use this to limit large result sets for common search terms.")
|
|
482
540
|
}, async (params, extra) => {
|
|
483
541
|
const result = await gitTools.searchCode(params);
|
|
484
542
|
return {
|
|
@@ -506,8 +564,8 @@ async function main() {
|
|
|
506
564
|
allowedTools.has("getFileContent") && server.tool("getFileContent", "Retrieve the content of a specific file from a Git repository with line numbers (arrow notation) for easy LLM comprehension. Returns formatted content with comprehensive metadata including line ranges, file size, and truncation status. Content is automatically truncated to 200 lines or 8K characters (whichever comes first) for optimal context usage. Use startLine and lineCount parameters to retrieve specific ranges for large files. Optionally specify a branch, tag, or commit to retrieve file content from a specific version. Supports both repository names and IDs.", {
|
|
507
565
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the file. Repository names are case-insensitive."),
|
|
508
566
|
path: zod_1.z.string().describe("The full path to the file within the repository, including filename and extension (e.g., 'src/utils/helpers.js')."),
|
|
509
|
-
startLine: zod_1.z.number().optional().describe("Starting line number (1-based) to begin reading from. Default: 1. Use this to navigate through large files by requesting specific ranges (e.g., startLine=201 for lines starting at 201)."),
|
|
510
|
-
lineCount: zod_1.z.number().optional().describe("Number of lines to return starting from startLine. Default: all lines, Maximum: 200 lines per request. Use this with startLine to retrieve specific sections of large files (e.g., lineCount=100 to get 100 lines)."),
|
|
567
|
+
startLine: zod_1.z.coerce.number().optional().describe("Starting line number (1-based) to begin reading from. Default: 1. Use this to navigate through large files by requesting specific ranges (e.g., startLine=201 for lines starting at 201)."),
|
|
568
|
+
lineCount: zod_1.z.coerce.number().optional().describe("Number of lines to return starting from startLine. Default: all lines, Maximum: 200 lines per request. Use this with startLine to retrieve specific sections of large files (e.g., lineCount=100 to get 100 lines)."),
|
|
511
569
|
versionDescriptor: zod_1.z.object({
|
|
512
570
|
version: zod_1.z.string().optional().describe("The name of the branch (e.g., 'main'), tag, or commit ID to retrieve the file from. Defaults to the default branch if not specified."),
|
|
513
571
|
versionOptions: zod_1.z.string().optional().describe("Additional version options: 'None', 'PreviousChange', 'FirstParent'. Usually leave this undefined."),
|
|
@@ -523,8 +581,8 @@ async function main() {
|
|
|
523
581
|
allowedTools.has("getCommitHistory") && server.tool("getCommitHistory", "Retrieve the commit history for a Git repository with metadata (ID, author, date, message, file changes). Returns a chronological list of commits with summary statistics at the top. Optionally filter to commits affecting a specific file path and use pagination to handle repositories with extensive history. Supports both repository names and IDs.", {
|
|
524
582
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) to get history for. Repository names are case-insensitive."),
|
|
525
583
|
itemPath: zod_1.z.string().optional().describe("Optional path to a specific file or folder to filter commits to only those that modified the specified path."),
|
|
526
|
-
top: zod_1.z.number().optional().describe("Maximum number of commits to return in the response. Use this to limit results for repositories with extensive history."),
|
|
527
|
-
skip: zod_1.z.number().optional().describe("Number of commits to skip before starting to return results. Use with 'top' for implementing pagination through commit history."),
|
|
584
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of commits to return in the response. Use this to limit results for repositories with extensive history."),
|
|
585
|
+
skip: zod_1.z.coerce.number().optional().describe("Number of commits to skip before starting to return results. Use with 'top' for implementing pagination through commit history."),
|
|
528
586
|
projectId: zod_1.z.string().optional().describe("The project ID or name to filter repositories by. If omitted, uses the default project from configuration.")
|
|
529
587
|
}, async (params, extra) => {
|
|
530
588
|
const result = await gitTools.getCommitHistory(params);
|
|
@@ -540,8 +598,8 @@ async function main() {
|
|
|
540
598
|
status: zod_1.z.enum(['abandoned', 'active', 'all', 'completed', 'notSet']).optional().describe("Filter pull requests by their current status: 'active' for open PRs, 'completed' for merged PRs, 'abandoned' for closed/rejected PRs, 'all' for all PRs regardless of status."),
|
|
541
599
|
creatorId: zod_1.z.string().optional().describe("Filter pull requests to only those created by a specific user ID or email address."),
|
|
542
600
|
reviewerId: zod_1.z.string().optional().describe("Filter pull requests to only those where a specific user ID or email address has been assigned as a reviewer."),
|
|
543
|
-
top: zod_1.z.number().optional().describe("Maximum number of pull requests to return in the response. Use this for pagination to handle repositories with many PRs."),
|
|
544
|
-
skip: zod_1.z.number().optional().describe("Number of pull requests to skip before starting to return results. Use with 'top' for implementing pagination.")
|
|
601
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of pull requests to return in the response. Use this for pagination to handle repositories with many PRs."),
|
|
602
|
+
skip: zod_1.z.coerce.number().optional().describe("Number of pull requests to skip before starting to return results. Use with 'top' for implementing pagination.")
|
|
545
603
|
}, async (params, extra) => {
|
|
546
604
|
const result = await gitTools.listPullRequests(params);
|
|
547
605
|
return {
|
|
@@ -566,7 +624,7 @@ async function main() {
|
|
|
566
624
|
});
|
|
567
625
|
allowedTools.has("getPullRequest") && server.tool("getPullRequest", "Fetch comprehensive details about a specific pull request by its ID within a repository. Returns all PR metadata including title, description, status, source and target branches, creator, reviewers, and voting status. Use this to get the full state of a pull request. Supports both repository names and IDs.", {
|
|
568
626
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
569
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request to retrieve. This is the PR number shown in the Azure DevOps UI (e.g., PR #123).")
|
|
627
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request to retrieve. This is the PR number shown in the Azure DevOps UI (e.g., PR #123).")
|
|
570
628
|
}, async (params, extra) => {
|
|
571
629
|
const result = await gitTools.getPullRequest(params);
|
|
572
630
|
return {
|
|
@@ -577,10 +635,10 @@ async function main() {
|
|
|
577
635
|
});
|
|
578
636
|
allowedTools.has("getPullRequestComments") && server.tool("getPullRequestComments", "Retrieve all comment threads and associated comments for a pull request. Returns a summary and organized list of threads including code review comments (with file/line context) and general discussions. Optionally filter to a specific thread by ID or use pagination for PRs with extensive discussions. Supports both repository names and IDs.", {
|
|
579
637
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
580
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request to retrieve comments from. This is the PR number shown in the Azure DevOps UI."),
|
|
581
|
-
threadId: zod_1.z.number().optional().describe("Optional ID of a specific comment thread to retrieve. If provided, only returns the specified thread rather than all threads."),
|
|
582
|
-
top: zod_1.z.number().optional().describe("Maximum number of comment threads to return in the response. Use this for pagination in PRs with many comments."),
|
|
583
|
-
skip: zod_1.z.number().optional().describe("Number of comment threads to skip before starting to return results. Use with 'top' for implementing pagination.")
|
|
638
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request to retrieve comments from. This is the PR number shown in the Azure DevOps UI."),
|
|
639
|
+
threadId: zod_1.z.coerce.number().optional().describe("Optional ID of a specific comment thread to retrieve. If provided, only returns the specified thread rather than all threads."),
|
|
640
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of comment threads to return in the response. Use this for pagination in PRs with many comments."),
|
|
641
|
+
skip: zod_1.z.coerce.number().optional().describe("Number of comment threads to skip before starting to return results. Use with 'top' for implementing pagination.")
|
|
584
642
|
}, async (params, extra) => {
|
|
585
643
|
const result = await gitTools.getPullRequestComments(params);
|
|
586
644
|
return {
|
|
@@ -592,7 +650,7 @@ async function main() {
|
|
|
592
650
|
});
|
|
593
651
|
allowedTools.has("approvePullRequest") && server.tool("approvePullRequest", "Cast an 'Approve' vote on a pull request on behalf of the current authenticated user. This marks the PR as approved by the user and contributes toward satisfying approval requirements defined in branch policies. Equivalent to clicking 'Approve' in the Azure DevOps UI. Supports both repository names and IDs.", {
|
|
594
652
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
595
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request to approve. This is the PR number shown in the Azure DevOps UI (e.g., PR #123).")
|
|
653
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request to approve. This is the PR number shown in the Azure DevOps UI (e.g., PR #123).")
|
|
596
654
|
}, async (params, extra) => {
|
|
597
655
|
const result = await gitTools.approvePullRequest(params);
|
|
598
656
|
return {
|
|
@@ -603,7 +661,7 @@ async function main() {
|
|
|
603
661
|
});
|
|
604
662
|
allowedTools.has("mergePullRequest") && server.tool("mergePullRequest", "Complete a pull request by merging the source branch changes into the target branch. This operation requires that all required reviewers have approved the PR and all branch policies are satisfied. Supports different merge strategies (squash, rebase, etc.) and allows adding a custom commit message. Supports both repository names and IDs.", {
|
|
605
663
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
606
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request to merge. This is the PR number shown in the Azure DevOps UI (e.g., PR #123)."),
|
|
664
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request to merge. This is the PR number shown in the Azure DevOps UI (e.g., PR #123)."),
|
|
607
665
|
mergeStrategy: zod_1.z.enum(['noFastForward', 'rebase', 'rebaseMerge', 'squash']).optional().describe("The strategy to use when merging changes: 'noFastForward' creates a merge commit, 'rebase' updates the source branch commits onto the target branch, 'rebaseMerge' combines rebase with a merge commit, 'squash' combines all changes into a single commit."),
|
|
608
666
|
comment: zod_1.z.string().optional().describe("Optional comment to include in the merge commit message. Use this to provide additional context about the merge beyond the default message.")
|
|
609
667
|
}, async (params, extra) => {
|
|
@@ -617,11 +675,11 @@ async function main() {
|
|
|
617
675
|
// Register new Pull Request Comment Tools
|
|
618
676
|
allowedTools.has("addPullRequestInlineComment") && server.tool("addPullRequestInlineComment", "Add an inline code comment anchored to a SPECIFIC LINE of code in a file. The comment appears directly on that line in the Files tab. WHEN TO USE: Point out specific code issues, suggest improvements to a particular line, or ask questions about specific implementation details. EXAMPLES: 'This variable should be null-checked here', 'Consider using async/await on line 45', 'Why is this hardcoded?'. The system automatically retrieves the correct change tracking ID from the PR diff.", {
|
|
619
677
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
620
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request where the comment will be added. This is the PR number shown in the Azure DevOps UI."),
|
|
678
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request where the comment will be added. This is the PR number shown in the Azure DevOps UI."),
|
|
621
679
|
comment: zod_1.z.string().describe("The text content of the comment to add. Can include markdown formatting. Should be specific to the line of code being commented on."),
|
|
622
680
|
position: zod_1.z.object({
|
|
623
|
-
line: zod_1.z.number().describe("The 1-based line number in the file where the comment should be anchored. Must be a line visible in the PR diff (added, removed, or context line)."),
|
|
624
|
-
offset: zod_1.z.number().describe("The character offset within the line where the comment should be anchored. Typically use 1 for beginning of line.")
|
|
681
|
+
line: zod_1.z.coerce.number().describe("The 1-based line number in the file where the comment should be anchored. Must be a line visible in the PR diff (added, removed, or context line)."),
|
|
682
|
+
offset: zod_1.z.coerce.number().describe("The character offset within the line where the comment should be anchored. Typically use 1 for beginning of line.")
|
|
625
683
|
}).describe("The exact position within the file where the comment will be anchored. Both line and offset are required."),
|
|
626
684
|
path: zod_1.z.string().describe("The full path to the file within the repository that the comment relates to. Must be a file changed in the PR (e.g., '/src/Services/UserService.cs').")
|
|
627
685
|
}, async (params, extra) => {
|
|
@@ -634,7 +692,7 @@ async function main() {
|
|
|
634
692
|
});
|
|
635
693
|
allowedTools.has("addPullRequestFileComment") && server.tool("addPullRequestFileComment", "Add a comment about an ENTIRE FILE (not a specific line). The comment appears at the file level in the Files tab. WHEN TO USE: Discuss overall file structure, architecture decisions, naming conventions, or when feedback applies to the whole file. EXAMPLES: 'This file should be split into smaller modules', 'Consider moving this to a different namespace', 'Great refactoring of this entire service!', 'This file needs unit tests'.", {
|
|
636
694
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
637
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request where the comment will be added. This is the PR number shown in the Azure DevOps UI."),
|
|
695
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request where the comment will be added. This is the PR number shown in the Azure DevOps UI."),
|
|
638
696
|
path: zod_1.z.string().describe("The full path to the file within the repository that the comment relates to. Must be a file changed in the PR (e.g., '/src/Models/User.cs')."),
|
|
639
697
|
comment: zod_1.z.string().describe("The text content of the comment about the entire file. Can include markdown formatting. Should address file-level concerns, not specific lines.")
|
|
640
698
|
}, async (params, extra) => {
|
|
@@ -647,7 +705,7 @@ async function main() {
|
|
|
647
705
|
});
|
|
648
706
|
allowedTools.has("addPullRequestComment") && server.tool("addPullRequestComment", "Add a GENERAL comment about the entire pull request (not tied to any file or code). Appears in the Overview/Conversation tab. WHEN TO USE: Provide overall feedback, discuss architecture, approve/reject the PR, ask general questions, or comment on the PR description. EXAMPLES: 'This feature looks great! LGTM after CI passes', 'Can you add integration tests for this feature?', 'What's the performance impact of these changes?', 'Please update the documentation before merging'.", {
|
|
649
707
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
650
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request where the comment will be added. This is the PR number shown in the Azure DevOps UI."),
|
|
708
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request where the comment will be added. This is the PR number shown in the Azure DevOps UI."),
|
|
651
709
|
comment: zod_1.z.string().describe("The text content of the general comment about the PR. Can include markdown formatting for rich text, code blocks, links, etc. Should address PR-level concerns, not specific files or lines.")
|
|
652
710
|
}, async (params, extra) => {
|
|
653
711
|
const result = await gitTools.addPullRequestComment(params);
|
|
@@ -660,7 +718,7 @@ async function main() {
|
|
|
660
718
|
// Register new Pull Request Diff Tools
|
|
661
719
|
allowedTools.has("getPullRequestFileChanges") && server.tool("getPullRequestFileChanges", "Retrieve detailed file diff information for a specific file changed within a pull request. Returns change metadata including change type (add, edit, delete), before/after content identifiers, and file path information. Optionally filter to a specific file path.", {
|
|
662
720
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
663
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request to examine. This is the PR number shown in the Azure DevOps UI."),
|
|
721
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request to examine. This is the PR number shown in the Azure DevOps UI."),
|
|
664
722
|
path: zod_1.z.string().optional().describe("Optional path to a specific file to return changes for. If omitted, changes for all files will be returned but filtered to match this specific path.")
|
|
665
723
|
}, async (params, extra) => {
|
|
666
724
|
const result = await gitTools.getPullRequestFileChanges(params);
|
|
@@ -672,7 +730,7 @@ async function main() {
|
|
|
672
730
|
});
|
|
673
731
|
allowedTools.has("getPullRequestChangesCount") && server.tool("getPullRequestChangesCount", "Get statistical summary of changes in a pull request, including total count of files changed and breakdowns by change type (added, modified, deleted). Useful for understanding the scope of changes in a PR at a glance.", {
|
|
674
732
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
675
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request to analyze. This is the PR number shown in the Azure DevOps UI.")
|
|
733
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request to analyze. This is the PR number shown in the Azure DevOps UI.")
|
|
676
734
|
}, async (params, extra) => {
|
|
677
735
|
const result = await gitTools.getPullRequestChangesCount(params);
|
|
678
736
|
return {
|
|
@@ -683,9 +741,9 @@ async function main() {
|
|
|
683
741
|
});
|
|
684
742
|
allowedTools.has("getAllPullRequestChanges") && server.tool("getAllPullRequestChanges", "Retrieve a comprehensive list of all file changes in a pull request with pagination support. Returns a summary and table of changed files with change types. Use pagination parameters (top/skip) to handle large PRs with many file changes. This does NOT include diff content - use getPullRequestFileChanges for detailed diffs.", {
|
|
685
743
|
repository: zod_1.z.string().describe("The repository name (e.g., 'MyProject') or ID (GUID) containing the pull request. Repository names are case-insensitive."),
|
|
686
|
-
pullRequestId: zod_1.z.number().describe("The numeric ID of the pull request to retrieve changes for. This is the PR number shown in the Azure DevOps UI."),
|
|
687
|
-
top: zod_1.z.number().optional().describe("Maximum number of change entries to return in a single request. Use this for pagination to avoid large response payloads."),
|
|
688
|
-
skip: zod_1.z.number().optional().describe("Number of change entries to skip before starting to return results. Use with 'top' for implementing pagination.")
|
|
744
|
+
pullRequestId: zod_1.z.coerce.number().describe("The numeric ID of the pull request to retrieve changes for. This is the PR number shown in the Azure DevOps UI."),
|
|
745
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of change entries to return in a single request. Use this for pagination to avoid large response payloads."),
|
|
746
|
+
skip: zod_1.z.coerce.number().optional().describe("Number of change entries to skip before starting to return results. Use with 'top' for implementing pagination.")
|
|
689
747
|
}, async (params, extra) => {
|
|
690
748
|
const result = await gitTools.getAllPullRequestChanges(params);
|
|
691
749
|
return {
|
|
@@ -695,10 +753,61 @@ async function main() {
|
|
|
695
753
|
structuredContent: result.structuredContent
|
|
696
754
|
};
|
|
697
755
|
});
|
|
756
|
+
allowedTools.has("updatePullRequest") && server.tool("updatePullRequest", "Update pull request properties (title, description, status, auto-complete, draft mode, target branch)", {
|
|
757
|
+
repository: zod_1.z.string().describe("Repository name or ID"),
|
|
758
|
+
pullRequestId: zod_1.z.coerce.number().describe("Pull request ID"),
|
|
759
|
+
title: zod_1.z.string().optional().describe("New title for the PR"),
|
|
760
|
+
description: zod_1.z.string().optional().describe("New description for the PR"),
|
|
761
|
+
status: zod_1.z.enum(['active', 'abandoned', 'completed']).optional().describe("New status"),
|
|
762
|
+
autoCompleteSetBy: zod_1.z.string().optional().describe("User ID to set as auto-complete initiator"),
|
|
763
|
+
mergeStrategy: zod_1.z.enum(['noFastForward', 'rebase', 'rebaseMerge', 'squash']).optional().describe("Merge strategy for auto-complete"),
|
|
764
|
+
deleteSourceBranch: zod_1.z.boolean().optional().describe("Delete source branch on completion"),
|
|
765
|
+
isDraft: zod_1.z.boolean().optional().describe("Set PR as draft or publish it"),
|
|
766
|
+
targetRefName: zod_1.z.string().optional().describe("Change target branch (e.g., 'refs/heads/main')"),
|
|
767
|
+
}, async (params) => {
|
|
768
|
+
const result = await gitTools.updatePullRequest(params);
|
|
769
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
770
|
+
});
|
|
771
|
+
allowedTools.has("updatePullRequestReviewers") && server.tool("updatePullRequestReviewers", "Add or remove reviewers on an existing pull request", {
|
|
772
|
+
repository: zod_1.z.string().describe("Repository name or ID"),
|
|
773
|
+
pullRequestId: zod_1.z.coerce.number().describe("Pull request ID"),
|
|
774
|
+
reviewersToAdd: zod_1.z.array(zod_1.z.string()).optional().describe("User IDs or email addresses to add as reviewers"),
|
|
775
|
+
reviewersToRemove: zod_1.z.array(zod_1.z.string()).optional().describe("User IDs or email addresses to remove from reviewers"),
|
|
776
|
+
makeRequired: zod_1.z.boolean().optional().describe("Make added reviewers required (default false)"),
|
|
777
|
+
}, async (params) => {
|
|
778
|
+
const result = await gitTools.updatePullRequestReviewers(params);
|
|
779
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
780
|
+
});
|
|
781
|
+
allowedTools.has("replyToComment") && server.tool("replyToComment", "Reply to an existing comment thread on a pull request", {
|
|
782
|
+
repository: zod_1.z.string().describe("Repository name or ID"),
|
|
783
|
+
pullRequestId: zod_1.z.coerce.number().describe("Pull request ID"),
|
|
784
|
+
threadId: zod_1.z.coerce.number().describe("Thread ID to reply to"),
|
|
785
|
+
comment: zod_1.z.string().describe("Reply text content (supports markdown)"),
|
|
786
|
+
}, async (params) => {
|
|
787
|
+
const result = await gitTools.replyToComment(params);
|
|
788
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
789
|
+
});
|
|
790
|
+
allowedTools.has("updatePullRequestThread") && server.tool("updatePullRequestThread", "Update a comment thread's status (resolve, reactivate, close, etc.)", {
|
|
791
|
+
repository: zod_1.z.string().describe("Repository name or ID"),
|
|
792
|
+
pullRequestId: zod_1.z.coerce.number().describe("Pull request ID"),
|
|
793
|
+
threadId: zod_1.z.coerce.number().describe("Thread ID to update"),
|
|
794
|
+
status: zod_1.z.enum(['active', 'byDesign', 'closed', 'fixed', 'pending', 'unknown', 'wontFix']).describe("New thread status"),
|
|
795
|
+
}, async (params) => {
|
|
796
|
+
const result = await gitTools.updatePullRequestThread(params);
|
|
797
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
798
|
+
});
|
|
799
|
+
allowedTools.has("createBranch") && server.tool("createBranch", "Create a new branch from a source branch name or commit SHA", {
|
|
800
|
+
repository: zod_1.z.string().describe("Repository name or ID"),
|
|
801
|
+
branchName: zod_1.z.string().describe("New branch name (e.g., 'feature/my-feature')"),
|
|
802
|
+
sourceRef: zod_1.z.string().describe("Source branch name (e.g., 'main') or commit SHA to branch from"),
|
|
803
|
+
}, async (params) => {
|
|
804
|
+
const result = await gitTools.createBranch(params);
|
|
805
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
806
|
+
});
|
|
698
807
|
// Register Testing Capabilities Tools
|
|
699
808
|
allowedTools.has("runAutomatedTests") && server.tool("runAutomatedTests", "Execute automated test suites", {
|
|
700
|
-
testSuiteId: zod_1.z.number().optional().describe("ID of the test suite to run"),
|
|
701
|
-
testPlanId: zod_1.z.number().optional().describe("ID of the test plan to run"),
|
|
809
|
+
testSuiteId: zod_1.z.coerce.number().optional().describe("ID of the test suite to run"),
|
|
810
|
+
testPlanId: zod_1.z.coerce.number().optional().describe("ID of the test plan to run"),
|
|
702
811
|
testEnvironment: zod_1.z.string().optional().describe("Environment to run tests in"),
|
|
703
812
|
parallelExecution: zod_1.z.boolean().optional().describe("Whether to run tests in parallel")
|
|
704
813
|
}, async (params, extra) => {
|
|
@@ -710,7 +819,7 @@ async function main() {
|
|
|
710
819
|
};
|
|
711
820
|
});
|
|
712
821
|
allowedTools.has("getTestAutomationStatus") && server.tool("getTestAutomationStatus", "Check status of automated test execution", {
|
|
713
|
-
testRunId: zod_1.z.number().describe("ID of the test run to check status for")
|
|
822
|
+
testRunId: zod_1.z.coerce.number().describe("ID of the test run to check status for")
|
|
714
823
|
}, async (params, extra) => {
|
|
715
824
|
const result = await testingCapabilitiesTools.getTestAutomationStatus(params);
|
|
716
825
|
return {
|
|
@@ -734,7 +843,7 @@ async function main() {
|
|
|
734
843
|
allowedTools.has("createTestDataGenerator") && server.tool("createTestDataGenerator", "Generate test data for automated tests", {
|
|
735
844
|
name: zod_1.z.string().describe("Name of the test data generator"),
|
|
736
845
|
dataSchema: zod_1.z.record(zod_1.z.any()).describe("Schema for the test data to generate"),
|
|
737
|
-
recordCount: zod_1.z.number().optional().describe("Number of records to generate")
|
|
846
|
+
recordCount: zod_1.z.coerce.number().optional().describe("Number of records to generate")
|
|
738
847
|
}, async (params, extra) => {
|
|
739
848
|
const result = await testingCapabilitiesTools.createTestDataGenerator(params);
|
|
740
849
|
return {
|
|
@@ -756,8 +865,8 @@ async function main() {
|
|
|
756
865
|
};
|
|
757
866
|
});
|
|
758
867
|
allowedTools.has("getTestFlakiness") && server.tool("getTestFlakiness", "Analyze and report on test flakiness", {
|
|
759
|
-
testId: zod_1.z.number().optional().describe("ID of a specific test to analyze"),
|
|
760
|
-
testRunIds: zod_1.z.array(zod_1.z.number()).optional().describe("Specific test runs to analyze"),
|
|
868
|
+
testId: zod_1.z.coerce.number().optional().describe("ID of a specific test to analyze"),
|
|
869
|
+
testRunIds: zod_1.z.array(zod_1.z.coerce.number()).optional().describe("Specific test runs to analyze"),
|
|
761
870
|
timeRange: zod_1.z.string().optional().describe("Time range for analysis (e.g., '30d')")
|
|
762
871
|
}, async (params, extra) => {
|
|
763
872
|
const result = await testingCapabilitiesTools.getTestFlakiness(params);
|
|
@@ -779,7 +888,7 @@ async function main() {
|
|
|
779
888
|
};
|
|
780
889
|
});
|
|
781
890
|
allowedTools.has("runTestImpactAnalysis") && server.tool("runTestImpactAnalysis", "Determine which tests to run based on code changes", {
|
|
782
|
-
buildId: zod_1.z.number().describe("ID of the build to analyze"),
|
|
891
|
+
buildId: zod_1.z.coerce.number().describe("ID of the build to analyze"),
|
|
783
892
|
changedFiles: zod_1.z.array(zod_1.z.string()).optional().describe("List of changed files")
|
|
784
893
|
}, async (params, extra) => {
|
|
785
894
|
const result = await testingCapabilitiesTools.runTestImpactAnalysis(params);
|
|
@@ -801,7 +910,7 @@ async function main() {
|
|
|
801
910
|
};
|
|
802
911
|
});
|
|
803
912
|
allowedTools.has("runTestOptimization") && server.tool("runTestOptimization", "Optimize test suite execution for faster feedback", {
|
|
804
|
-
testPlanId: zod_1.z.number().describe("ID of the test plan to optimize"),
|
|
913
|
+
testPlanId: zod_1.z.coerce.number().describe("ID of the test plan to optimize"),
|
|
805
914
|
optimizationGoal: zod_1.z.enum(['time', 'coverage', 'reliability']).describe("Optimization goal")
|
|
806
915
|
}, async (params, extra) => {
|
|
807
916
|
const result = await testingCapabilitiesTools.runTestOptimization(params);
|
|
@@ -824,7 +933,7 @@ async function main() {
|
|
|
824
933
|
};
|
|
825
934
|
});
|
|
826
935
|
allowedTools.has("recordExploratoryTestResults") && server.tool("recordExploratoryTestResults", "Record findings during exploratory testing", {
|
|
827
|
-
sessionId: zod_1.z.number().describe("ID of the exploratory session"),
|
|
936
|
+
sessionId: zod_1.z.coerce.number().describe("ID of the exploratory session"),
|
|
828
937
|
findings: zod_1.z.array(zod_1.z.string()).describe("List of findings to record"),
|
|
829
938
|
attachments: zod_1.z.array(zod_1.z.object({
|
|
830
939
|
name: zod_1.z.string().describe("Name of the attachment"),
|
|
@@ -840,8 +949,8 @@ async function main() {
|
|
|
840
949
|
};
|
|
841
950
|
});
|
|
842
951
|
allowedTools.has("convertFindingsToWorkItems") && server.tool("convertFindingsToWorkItems", "Convert exploratory test findings to work items", {
|
|
843
|
-
sessionId: zod_1.z.number().describe("ID of the exploratory session"),
|
|
844
|
-
findingIds: zod_1.z.array(zod_1.z.number()).describe("IDs of findings to convert"),
|
|
952
|
+
sessionId: zod_1.z.coerce.number().describe("ID of the exploratory session"),
|
|
953
|
+
findingIds: zod_1.z.array(zod_1.z.coerce.number()).describe("IDs of findings to convert"),
|
|
845
954
|
workItemType: zod_1.z.string().optional().describe("Type of work item to create")
|
|
846
955
|
}, async (params, extra) => {
|
|
847
956
|
const result = await testingCapabilitiesTools.convertFindingsToWorkItems(params);
|
|
@@ -1028,7 +1137,7 @@ async function main() {
|
|
|
1028
1137
|
allowedTools.has("getPackageVersions") && server.tool("getPackageVersions", "Get versions of a package in a feed", {
|
|
1029
1138
|
feedId: zod_1.z.string().describe("ID of the feed"),
|
|
1030
1139
|
packageName: zod_1.z.string().describe("Name of the package"),
|
|
1031
|
-
top: zod_1.z.number().optional().describe("Maximum number of versions to return")
|
|
1140
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of versions to return")
|
|
1032
1141
|
}, async (params, extra) => {
|
|
1033
1142
|
const result = await artifactManagementTools.getPackageVersions(params);
|
|
1034
1143
|
return {
|
|
@@ -1092,7 +1201,7 @@ async function main() {
|
|
|
1092
1201
|
allowedTools.has("getContainerImageTags") && server.tool("getContainerImageTags", "Get tags for a container image", {
|
|
1093
1202
|
repositoryName: zod_1.z.string().describe("Name of the container repository"),
|
|
1094
1203
|
imageName: zod_1.z.string().describe("Name of the container image"),
|
|
1095
|
-
top: zod_1.z.number().optional().describe("Maximum number of tags to return")
|
|
1204
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of tags to return")
|
|
1096
1205
|
}, async (params, extra) => {
|
|
1097
1206
|
const result = await artifactManagementTools.getContainerImageTags(params);
|
|
1098
1207
|
return {
|
|
@@ -1167,7 +1276,7 @@ async function main() {
|
|
|
1167
1276
|
});
|
|
1168
1277
|
// AI Assisted Development Tools
|
|
1169
1278
|
allowedTools.has("getAICodeReview") && server.tool("getAICodeReview", "Get AI-based code review suggestions", {
|
|
1170
|
-
pullRequestId: zod_1.z.number().optional().describe("ID of the pull request to review"),
|
|
1279
|
+
pullRequestId: zod_1.z.coerce.number().optional().describe("ID of the pull request to review"),
|
|
1171
1280
|
repositoryId: zod_1.z.string().optional().describe("ID of the repository"),
|
|
1172
1281
|
commitId: zod_1.z.string().optional().describe("ID of the commit to review"),
|
|
1173
1282
|
filePath: zod_1.z.string().optional().describe("Path to the file to review")
|
|
@@ -1182,8 +1291,8 @@ async function main() {
|
|
|
1182
1291
|
allowedTools.has("suggestCodeOptimization") && server.tool("suggestCodeOptimization", "Suggest code optimizations using AI. Supports both repository names and IDs.", {
|
|
1183
1292
|
repository: zod_1.z.string().describe("Repository name (e.g., 'MyProject') or ID (GUID). Repository names are case-insensitive."),
|
|
1184
1293
|
filePath: zod_1.z.string().describe("Path to the file to optimize"),
|
|
1185
|
-
lineStart: zod_1.z.number().optional().describe("Starting line number"),
|
|
1186
|
-
lineEnd: zod_1.z.number().optional().describe("Ending line number"),
|
|
1294
|
+
lineStart: zod_1.z.coerce.number().optional().describe("Starting line number"),
|
|
1295
|
+
lineEnd: zod_1.z.coerce.number().optional().describe("Ending line number"),
|
|
1187
1296
|
optimizationType: zod_1.z.enum(['performance', 'memory', 'readability', 'all']).optional().describe("Type of optimization to focus on")
|
|
1188
1297
|
}, async (params, extra) => {
|
|
1189
1298
|
const result = await aiAssistedDevelopmentTools.suggestCodeOptimization(params);
|
|
@@ -1208,7 +1317,7 @@ async function main() {
|
|
|
1208
1317
|
});
|
|
1209
1318
|
allowedTools.has("getPredictiveBugAnalysis") && server.tool("getPredictiveBugAnalysis", "Predict potential bugs in code changes. Supports both repository names and IDs.", {
|
|
1210
1319
|
repository: zod_1.z.string().describe("Repository name (e.g., 'MyProject') or ID (GUID). Repository names are case-insensitive."),
|
|
1211
|
-
pullRequestId: zod_1.z.number().optional().describe("ID of the pull request"),
|
|
1320
|
+
pullRequestId: zod_1.z.coerce.number().optional().describe("ID of the pull request"),
|
|
1212
1321
|
branch: zod_1.z.string().optional().describe("Branch to analyze"),
|
|
1213
1322
|
filePath: zod_1.z.string().optional().describe("Path to the file to analyze")
|
|
1214
1323
|
}, async (params, extra) => {
|
|
@@ -1233,7 +1342,7 @@ async function main() {
|
|
|
1233
1342
|
};
|
|
1234
1343
|
});
|
|
1235
1344
|
allowedTools.has("getPredictiveEffortEstimation") && server.tool("getPredictiveEffortEstimation", "AI-based effort estimation for work items", {
|
|
1236
|
-
workItemIds: zod_1.z.array(zod_1.z.number()).optional().describe("IDs of work items to estimate"),
|
|
1345
|
+
workItemIds: zod_1.z.array(zod_1.z.coerce.number()).optional().describe("IDs of work items to estimate"),
|
|
1237
1346
|
workItemType: zod_1.z.string().optional().describe("Type of work items to estimate"),
|
|
1238
1347
|
areaPath: zod_1.z.string().optional().describe("Area path to filter work items")
|
|
1239
1348
|
}, async (params, extra) => {
|
|
@@ -1258,7 +1367,7 @@ async function main() {
|
|
|
1258
1367
|
};
|
|
1259
1368
|
});
|
|
1260
1369
|
allowedTools.has("suggestWorkItemRefinements") && server.tool("suggestWorkItemRefinements", "Get AI suggestions for work item refinements", {
|
|
1261
|
-
workItemId: zod_1.z.number().optional().describe("ID of the work item to refine"),
|
|
1370
|
+
workItemId: zod_1.z.coerce.number().optional().describe("ID of the work item to refine"),
|
|
1262
1371
|
workItemType: zod_1.z.string().optional().describe("Type of work item"),
|
|
1263
1372
|
areaPath: zod_1.z.string().optional().describe("Area path to filter work items")
|
|
1264
1373
|
}, async (params, extra) => {
|
|
@@ -1294,7 +1403,7 @@ async function main() {
|
|
|
1294
1403
|
};
|
|
1295
1404
|
});
|
|
1296
1405
|
allowedTools.has("predictBuildFailures") && server.tool("predictBuildFailures", "Predict potential build failures before they occur", {
|
|
1297
|
-
buildDefinitionId: zod_1.z.number().describe("ID of the build definition"),
|
|
1406
|
+
buildDefinitionId: zod_1.z.coerce.number().describe("ID of the build definition"),
|
|
1298
1407
|
lookbackPeriod: zod_1.z.string().optional().describe("Period to analyze for patterns (e.g., '30d')")
|
|
1299
1408
|
}, async (params, extra) => {
|
|
1300
1409
|
const result = await aiAssistedDevelopmentTools.predictBuildFailures(params);
|
|
@@ -1305,9 +1414,9 @@ async function main() {
|
|
|
1305
1414
|
};
|
|
1306
1415
|
});
|
|
1307
1416
|
allowedTools.has("optimizeTestSelection") && server.tool("optimizeTestSelection", "Intelligently select tests to run based on changes", {
|
|
1308
|
-
buildId: zod_1.z.number().describe("ID of the build"),
|
|
1417
|
+
buildId: zod_1.z.coerce.number().describe("ID of the build"),
|
|
1309
1418
|
changedFiles: zod_1.z.array(zod_1.z.string()).optional().describe("List of changed files"),
|
|
1310
|
-
maxTestCount: zod_1.z.number().optional().describe("Maximum number of tests to select")
|
|
1419
|
+
maxTestCount: zod_1.z.coerce.number().optional().describe("Maximum number of tests to select")
|
|
1311
1420
|
}, async (params, extra) => {
|
|
1312
1421
|
const result = await aiAssistedDevelopmentTools.optimizeTestSelection(params);
|
|
1313
1422
|
return {
|
|
@@ -1316,6 +1425,130 @@ async function main() {
|
|
|
1316
1425
|
structuredContent: result.structuredContent
|
|
1317
1426
|
};
|
|
1318
1427
|
});
|
|
1428
|
+
// Register Wiki Tools
|
|
1429
|
+
allowedTools.has("listWikis") && server.tool("listWikis", "List all wikis in the project", {
|
|
1430
|
+
project: zod_1.z.string().optional().describe("Project name or ID (defaults to configured project)"),
|
|
1431
|
+
}, async (params) => {
|
|
1432
|
+
const result = await wikiTools.listWikis(params);
|
|
1433
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1434
|
+
});
|
|
1435
|
+
allowedTools.has("getWiki") && server.tool("getWiki", "Get details about a specific wiki", {
|
|
1436
|
+
wikiIdentifier: zod_1.z.string().describe("Wiki name or ID"),
|
|
1437
|
+
project: zod_1.z.string().optional().describe("Project name or ID"),
|
|
1438
|
+
}, async (params) => {
|
|
1439
|
+
const result = await wikiTools.getWiki(params);
|
|
1440
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1441
|
+
});
|
|
1442
|
+
allowedTools.has("listWikiPages") && server.tool("listWikiPages", "List wiki pages under a path", {
|
|
1443
|
+
wikiIdentifier: zod_1.z.string().describe("Wiki name or ID"),
|
|
1444
|
+
path: zod_1.z.string().optional().describe("Path to list pages under (default: root '/')"),
|
|
1445
|
+
recursionLevel: zod_1.z.string().optional().describe("'oneLevel' (default) or 'full' for all descendants"),
|
|
1446
|
+
project: zod_1.z.string().optional().describe("Project name or ID"),
|
|
1447
|
+
}, async (params) => {
|
|
1448
|
+
const result = await wikiTools.listWikiPages(params);
|
|
1449
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1450
|
+
});
|
|
1451
|
+
allowedTools.has("getWikiPageContent") && server.tool("getWikiPageContent", "Get the content of a wiki page", {
|
|
1452
|
+
wikiIdentifier: zod_1.z.string().describe("Wiki name or ID"),
|
|
1453
|
+
path: zod_1.z.string().optional().describe("Page path (default: root '/')"),
|
|
1454
|
+
project: zod_1.z.string().optional().describe("Project name or ID"),
|
|
1455
|
+
}, async (params) => {
|
|
1456
|
+
const result = await wikiTools.getWikiPageContent(params);
|
|
1457
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1458
|
+
});
|
|
1459
|
+
allowedTools.has("createOrUpdateWikiPage") && server.tool("createOrUpdateWikiPage", "Create or update a wiki page with the given content", {
|
|
1460
|
+
wikiIdentifier: zod_1.z.string().describe("Wiki name or ID"),
|
|
1461
|
+
path: zod_1.z.string().describe("Page path (e.g., '/My Page' or '/Section/Sub Page')"),
|
|
1462
|
+
content: zod_1.z.string().describe("Page content in markdown format"),
|
|
1463
|
+
comment: zod_1.z.string().optional().describe("Optional commit comment for the change"),
|
|
1464
|
+
project: zod_1.z.string().optional().describe("Project name or ID"),
|
|
1465
|
+
}, async (params) => {
|
|
1466
|
+
const result = await wikiTools.createOrUpdateWikiPage(params);
|
|
1467
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1468
|
+
});
|
|
1469
|
+
// Register Build/Pipeline Tools
|
|
1470
|
+
allowedTools.has("getBuilds") && server.tool("getBuilds", "List builds with optional filters (status, result, branch, definition, tags)", {
|
|
1471
|
+
definitions: zod_1.z.preprocess(coerceArray, zod_1.z.array(zod_1.z.coerce.number()).optional()).describe("Filter by definition IDs"),
|
|
1472
|
+
statusFilter: zod_1.z.string().optional().describe("Filter by status: inProgress, completed, cancelling, postponed, notStarted, all"),
|
|
1473
|
+
resultFilter: zod_1.z.string().optional().describe("Filter by result: succeeded, partiallySucceeded, failed, canceled"),
|
|
1474
|
+
branchName: zod_1.z.string().optional().describe("Filter by source branch (e.g., 'refs/heads/main')"),
|
|
1475
|
+
repositoryId: zod_1.z.string().optional().describe("Filter by repository ID"),
|
|
1476
|
+
repositoryType: zod_1.z.string().optional().describe("Repository type (e.g., 'TfsGit')"),
|
|
1477
|
+
requestedFor: zod_1.z.string().optional().describe("Filter by who requested the build"),
|
|
1478
|
+
tagFilters: zod_1.z.preprocess(coerceArray, zod_1.z.array(zod_1.z.string()).optional()).describe("Filter by tags"),
|
|
1479
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of builds to return (default 25)"),
|
|
1480
|
+
queryOrder: zod_1.z.string().optional().describe("Order: startTimeDescending (default) or startTimeAscending"),
|
|
1481
|
+
}, async (params) => {
|
|
1482
|
+
const result = await buildTools.getBuilds(params);
|
|
1483
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1484
|
+
});
|
|
1485
|
+
allowedTools.has("getBuild") && server.tool("getBuild", "Get detailed information about a specific build by ID", {
|
|
1486
|
+
buildId: zod_1.z.coerce.number().describe("Build ID"),
|
|
1487
|
+
}, async (params) => {
|
|
1488
|
+
const result = await buildTools.getBuild(params);
|
|
1489
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1490
|
+
});
|
|
1491
|
+
allowedTools.has("getBuildLog") && server.tool("getBuildLog", "Get build logs. Without logId returns log metadata list; with logId returns specific log content", {
|
|
1492
|
+
buildId: zod_1.z.coerce.number().describe("Build ID"),
|
|
1493
|
+
logId: zod_1.z.coerce.number().optional().describe("Specific log ID to retrieve content for"),
|
|
1494
|
+
startLine: zod_1.z.coerce.number().optional().describe("Start line for log content"),
|
|
1495
|
+
endLine: zod_1.z.coerce.number().optional().describe("End line for log content"),
|
|
1496
|
+
}, async (params) => {
|
|
1497
|
+
const result = await buildTools.getBuildLog(params);
|
|
1498
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1499
|
+
});
|
|
1500
|
+
allowedTools.has("getBuildChanges") && server.tool("getBuildChanges", "Get changes (commits) associated with a build", {
|
|
1501
|
+
buildId: zod_1.z.coerce.number().describe("Build ID"),
|
|
1502
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of changes to return (default 50)"),
|
|
1503
|
+
}, async (params) => {
|
|
1504
|
+
const result = await buildTools.getBuildChanges(params);
|
|
1505
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1506
|
+
});
|
|
1507
|
+
allowedTools.has("getDefinitions") && server.tool("getDefinitions", "List pipeline/build definitions with optional filters", {
|
|
1508
|
+
name: zod_1.z.string().optional().describe("Filter by definition name (wildcard supported)"),
|
|
1509
|
+
repositoryId: zod_1.z.string().optional().describe("Filter by repository ID"),
|
|
1510
|
+
repositoryType: zod_1.z.string().optional().describe("Repository type (e.g., 'TfsGit')"),
|
|
1511
|
+
path: zod_1.z.string().optional().describe("Filter by folder path (e.g., '\\\\folder')"),
|
|
1512
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of definitions to return (default 25)"),
|
|
1513
|
+
includeLatestBuilds: zod_1.z.boolean().optional().describe("Include latest build info for each definition"),
|
|
1514
|
+
}, async (params) => {
|
|
1515
|
+
const result = await buildTools.getDefinitions(params);
|
|
1516
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1517
|
+
});
|
|
1518
|
+
allowedTools.has("getDefinition") && server.tool("getDefinition", "Get detailed information about a specific pipeline/build definition", {
|
|
1519
|
+
definitionId: zod_1.z.coerce.number().describe("Definition ID"),
|
|
1520
|
+
includeLatestBuilds: zod_1.z.boolean().optional().describe("Include latest build info"),
|
|
1521
|
+
}, async (params) => {
|
|
1522
|
+
const result = await buildTools.getDefinition(params);
|
|
1523
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1524
|
+
});
|
|
1525
|
+
allowedTools.has("runPipeline") && server.tool("runPipeline", "Queue/trigger a pipeline run", {
|
|
1526
|
+
definitionId: zod_1.z.coerce.number().describe("Pipeline definition ID to run"),
|
|
1527
|
+
sourceBranch: zod_1.z.string().optional().describe("Source branch (e.g., 'refs/heads/main')"),
|
|
1528
|
+
parameters: zod_1.z.record(zod_1.z.string()).optional().describe("Pipeline parameters as key-value pairs"),
|
|
1529
|
+
}, async (params) => {
|
|
1530
|
+
const result = await buildTools.runPipeline(params);
|
|
1531
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1532
|
+
});
|
|
1533
|
+
allowedTools.has("getBuildArtifacts") && server.tool("getBuildArtifacts", "List artifacts produced by a build", {
|
|
1534
|
+
buildId: zod_1.z.coerce.number().describe("Build ID"),
|
|
1535
|
+
}, async (params) => {
|
|
1536
|
+
const result = await buildTools.getBuildArtifacts(params);
|
|
1537
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1538
|
+
});
|
|
1539
|
+
allowedTools.has("getBuildTimeline") && server.tool("getBuildTimeline", "Get build timeline showing stages, jobs, and tasks with their status", {
|
|
1540
|
+
buildId: zod_1.z.coerce.number().describe("Build ID"),
|
|
1541
|
+
}, async (params) => {
|
|
1542
|
+
const result = await buildTools.getBuildTimeline(params);
|
|
1543
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1544
|
+
});
|
|
1545
|
+
allowedTools.has("getBuildWorkItems") && server.tool("getBuildWorkItems", "Get work items associated with a build", {
|
|
1546
|
+
buildId: zod_1.z.coerce.number().describe("Build ID"),
|
|
1547
|
+
top: zod_1.z.coerce.number().optional().describe("Maximum number of work items to return (default 50)"),
|
|
1548
|
+
}, async (params) => {
|
|
1549
|
+
const result = await buildTools.getBuildWorkItems(params);
|
|
1550
|
+
return { content: result.content, rawData: result.rawData, structuredContent: result.structuredContent };
|
|
1551
|
+
});
|
|
1319
1552
|
// Create a transport (use stdio for simplicity)
|
|
1320
1553
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
1321
1554
|
// Connect to the transport and start listening
|