@azure-devops/mcp 1.0.0 → 1.2.0-daily.20250715
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/LICENSE.md +21 -21
- package/README.md +316 -293
- package/dist/index.js +23 -13
- package/dist/prompts.js +35 -10
- package/dist/tools/auth.js +1 -1
- package/dist/tools/builds.js +63 -9
- package/dist/tools/core.js +60 -6
- package/dist/tools/releases.js +13 -7
- package/dist/tools/repos.js +186 -31
- package/dist/tools/search.js +53 -47
- package/dist/tools/testplans.js +12 -18
- package/dist/tools/wiki.js +79 -31
- package/dist/tools/work.js +16 -12
- package/dist/tools/workitems.js +158 -89
- package/dist/tools.js +3 -3
- package/dist/useragent.js +20 -0
- package/dist/utils.js +0 -2
- package/dist/version.js +1 -1
- package/package.json +62 -54
package/dist/tools/testplans.js
CHANGED
|
@@ -7,7 +7,7 @@ const Test_Plan_Tools = {
|
|
|
7
7
|
add_test_cases_to_suite: "testplan_add_test_cases_to_suite",
|
|
8
8
|
test_results_from_build_id: "testplan_show_test_results_from_build_id",
|
|
9
9
|
list_test_cases: "testplan_list_test_cases",
|
|
10
|
-
list_test_plans: "testplan_list_test_plans"
|
|
10
|
+
list_test_plans: "testplan_list_test_plans",
|
|
11
11
|
};
|
|
12
12
|
function configureTestPlanTools(server, tokenProvider, connectionProvider) {
|
|
13
13
|
/*
|
|
@@ -19,7 +19,7 @@ function configureTestPlanTools(server, tokenProvider, connectionProvider) {
|
|
|
19
19
|
filterActivePlans: z.boolean().default(true).describe("Filter to include only active test plans. Defaults to true."),
|
|
20
20
|
includePlanDetails: z.boolean().default(false).describe("Include detailed information about each test plan."),
|
|
21
21
|
continuationToken: z.string().optional().describe("Token to continue fetching test plans from a previous request."),
|
|
22
|
-
}, async ({ project, filterActivePlans, includePlanDetails, continuationToken
|
|
22
|
+
}, async ({ project, filterActivePlans, includePlanDetails, continuationToken }) => {
|
|
23
23
|
const owner = ""; //making owner an empty string untill we can figure out how to get owner id
|
|
24
24
|
const connection = await connectionProvider();
|
|
25
25
|
const testPlanApi = await connection.getTestPlanApi();
|
|
@@ -39,7 +39,7 @@ function configureTestPlanTools(server, tokenProvider, connectionProvider) {
|
|
|
39
39
|
startDate: z.string().optional().describe("The start date of the test plan"),
|
|
40
40
|
endDate: z.string().optional().describe("The end date of the test plan"),
|
|
41
41
|
areaPath: z.string().optional().describe("The area path for the test plan"),
|
|
42
|
-
}, async ({ project, name, iteration, description, startDate, endDate, areaPath
|
|
42
|
+
}, async ({ project, name, iteration, description, startDate, endDate, areaPath }) => {
|
|
43
43
|
const connection = await connectionProvider();
|
|
44
44
|
const testPlanApi = await connection.getTestPlanApi();
|
|
45
45
|
const testPlanToCreate = {
|
|
@@ -52,9 +52,7 @@ function configureTestPlanTools(server, tokenProvider, connectionProvider) {
|
|
|
52
52
|
};
|
|
53
53
|
const createdTestPlan = await testPlanApi.createTestPlan(testPlanToCreate, project);
|
|
54
54
|
return {
|
|
55
|
-
content: [
|
|
56
|
-
{ type: "text", text: JSON.stringify(createdTestPlan, null, 2) },
|
|
57
|
-
],
|
|
55
|
+
content: [{ type: "text", text: JSON.stringify(createdTestPlan, null, 2) }],
|
|
58
56
|
};
|
|
59
57
|
});
|
|
60
58
|
/*
|
|
@@ -69,14 +67,10 @@ function configureTestPlanTools(server, tokenProvider, connectionProvider) {
|
|
|
69
67
|
const connection = await connectionProvider();
|
|
70
68
|
const testApi = await connection.getTestApi();
|
|
71
69
|
// If testCaseIds is an array, convert it to comma-separated string
|
|
72
|
-
const testCaseIdsString = Array.isArray(testCaseIds)
|
|
73
|
-
? testCaseIds.join(",")
|
|
74
|
-
: testCaseIds;
|
|
70
|
+
const testCaseIdsString = Array.isArray(testCaseIds) ? testCaseIds.join(",") : testCaseIds;
|
|
75
71
|
const addedTestCases = await testApi.addTestCasesToSuite(project, planId, suiteId, testCaseIdsString);
|
|
76
72
|
return {
|
|
77
|
-
content: [
|
|
78
|
-
{ type: "text", text: JSON.stringify(addedTestCases, null, 2) },
|
|
79
|
-
],
|
|
73
|
+
content: [{ type: "text", text: JSON.stringify(addedTestCases, null, 2) }],
|
|
80
74
|
};
|
|
81
75
|
});
|
|
82
76
|
/*
|
|
@@ -169,7 +163,7 @@ function configureTestPlanTools(server, tokenProvider, connectionProvider) {
|
|
|
169
163
|
}
|
|
170
164
|
/*
|
|
171
165
|
* Helper function to convert steps text to XML format required
|
|
172
|
-
*/
|
|
166
|
+
*/
|
|
173
167
|
function convertStepsToXml(steps) {
|
|
174
168
|
const stepsLines = steps.split("\n").filter((line) => line.trim() !== "");
|
|
175
169
|
let xmlSteps = `<steps id="0" last="${stepsLines.length}">`;
|
|
@@ -178,10 +172,10 @@ function convertStepsToXml(steps) {
|
|
|
178
172
|
if (stepLine) {
|
|
179
173
|
const stepMatch = stepLine.match(/^(\d+)\.\s*(.+)$/);
|
|
180
174
|
const stepText = stepMatch ? stepMatch[2] : stepLine;
|
|
181
|
-
xmlSteps += `
|
|
182
|
-
<step id="${i + 1}" type="ActionStep">
|
|
183
|
-
<parameterizedString isformatted="true">${escapeXml(stepText)}</parameterizedString>
|
|
184
|
-
<parameterizedString isformatted="true">Verify step completes successfully</parameterizedString>
|
|
175
|
+
xmlSteps += `
|
|
176
|
+
<step id="${i + 1}" type="ActionStep">
|
|
177
|
+
<parameterizedString isformatted="true">${escapeXml(stepText)}</parameterizedString>
|
|
178
|
+
<parameterizedString isformatted="true">Verify step completes successfully</parameterizedString>
|
|
185
179
|
</step>`;
|
|
186
180
|
}
|
|
187
181
|
}
|
|
@@ -190,7 +184,7 @@ function convertStepsToXml(steps) {
|
|
|
190
184
|
}
|
|
191
185
|
/*
|
|
192
186
|
* Helper function to escape XML special characters
|
|
193
|
-
*/
|
|
187
|
+
*/
|
|
194
188
|
function escapeXml(unsafe) {
|
|
195
189
|
return unsafe.replace(/[<>&'"]/g, (c) => {
|
|
196
190
|
switch (c) {
|
package/dist/tools/wiki.js
CHANGED
|
@@ -12,22 +12,46 @@ function configureWikiTools(server, tokenProvider, connectionProvider) {
|
|
|
12
12
|
wikiIdentifier: z.string().describe("The unique identifier of the wiki."),
|
|
13
13
|
project: z.string().optional().describe("The project name or ID where the wiki is located. If not provided, the default project will be used."),
|
|
14
14
|
}, async ({ wikiIdentifier, project }) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
try {
|
|
16
|
+
const connection = await connectionProvider();
|
|
17
|
+
const wikiApi = await connection.getWikiApi();
|
|
18
|
+
const wiki = await wikiApi.getWiki(wikiIdentifier, project);
|
|
19
|
+
if (!wiki) {
|
|
20
|
+
return { content: [{ type: "text", text: "No wiki found" }], isError: true };
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: "text", text: JSON.stringify(wiki, null, 2) }],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: `Error fetching wiki: ${errorMessage}` }],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
21
33
|
});
|
|
22
34
|
server.tool(WIKI_TOOLS.list_wikis, "Retrieve a list of wikis for an organization or project.", {
|
|
23
35
|
project: z.string().optional().describe("The project name or ID to filter wikis. If not provided, all wikis in the organization will be returned."),
|
|
24
36
|
}, async ({ project }) => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
try {
|
|
38
|
+
const connection = await connectionProvider();
|
|
39
|
+
const wikiApi = await connection.getWikiApi();
|
|
40
|
+
const wikis = await wikiApi.getAllWikis(project);
|
|
41
|
+
if (!wikis) {
|
|
42
|
+
return { content: [{ type: "text", text: "No wikis found" }], isError: true };
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: JSON.stringify(wikis, null, 2) }],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text", text: `Error fetching wikis: ${errorMessage}` }],
|
|
52
|
+
isError: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
31
55
|
});
|
|
32
56
|
server.tool(WIKI_TOOLS.list_wiki_pages, "Retrieve a list of wiki pages for a specific wiki and project.", {
|
|
33
57
|
wikiIdentifier: z.string().describe("The unique identifier of the wiki."),
|
|
@@ -35,31 +59,55 @@ function configureWikiTools(server, tokenProvider, connectionProvider) {
|
|
|
35
59
|
top: z.number().default(20).describe("The maximum number of pages to return. Defaults to 20."),
|
|
36
60
|
continuationToken: z.string().optional().describe("Token for pagination to retrieve the next set of pages."),
|
|
37
61
|
pageViewsForDays: z.number().optional().describe("Number of days to retrieve page views for. If not specified, page views are not included."),
|
|
38
|
-
}, async ({ wikiIdentifier, project, top = 20, continuationToken, pageViewsForDays
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
}, async ({ wikiIdentifier, project, top = 20, continuationToken, pageViewsForDays }) => {
|
|
63
|
+
try {
|
|
64
|
+
const connection = await connectionProvider();
|
|
65
|
+
const wikiApi = await connection.getWikiApi();
|
|
66
|
+
const pagesBatchRequest = {
|
|
67
|
+
top,
|
|
68
|
+
continuationToken,
|
|
69
|
+
pageViewsForDays,
|
|
70
|
+
};
|
|
71
|
+
const pages = await wikiApi.getPagesBatch(pagesBatchRequest, project, wikiIdentifier);
|
|
72
|
+
if (!pages) {
|
|
73
|
+
return { content: [{ type: "text", text: "No wiki pages found" }], isError: true };
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: "text", text: JSON.stringify(pages, null, 2) }],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: "text", text: `Error fetching wiki pages: ${errorMessage}` }],
|
|
83
|
+
isError: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
50
86
|
});
|
|
51
87
|
server.tool(WIKI_TOOLS.get_wiki_page_content, "Retrieve wiki page content by wikiIdentifier and path.", {
|
|
52
88
|
wikiIdentifier: z.string().describe("The unique identifier of the wiki."),
|
|
53
89
|
project: z.string().describe("The project name or ID where the wiki is located."),
|
|
54
90
|
path: z.string().describe("The path of the wiki page to retrieve content for."),
|
|
55
91
|
}, async ({ wikiIdentifier, project, path }) => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
92
|
+
try {
|
|
93
|
+
const connection = await connectionProvider();
|
|
94
|
+
const wikiApi = await connection.getWikiApi();
|
|
95
|
+
const stream = await wikiApi.getPageText(project, wikiIdentifier, path, undefined, undefined, true);
|
|
96
|
+
if (!stream) {
|
|
97
|
+
return { content: [{ type: "text", text: "No wiki page content found" }], isError: true };
|
|
98
|
+
}
|
|
99
|
+
const content = await streamToString(stream);
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: JSON.stringify(content, null, 2) }],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
106
|
+
return {
|
|
107
|
+
content: [{ type: "text", text: `Error fetching wiki page content: ${errorMessage}` }],
|
|
108
|
+
isError: true,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
63
111
|
});
|
|
64
112
|
}
|
|
65
113
|
function streamToString(stream) {
|
package/dist/tools/work.js
CHANGED
|
@@ -25,20 +25,22 @@ function configureWorkTools(server, tokenProvider, connectionProvider) {
|
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
catch (error) {
|
|
28
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
28
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
29
29
|
return {
|
|
30
30
|
content: [{ type: "text", text: `Error fetching team iterations: ${errorMessage}` }],
|
|
31
|
-
isError: true
|
|
31
|
+
isError: true,
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
35
|
server.tool(WORK_TOOLS.create_iterations, "Create new iterations in a specified Azure DevOps project.", {
|
|
36
36
|
project: z.string().describe("The name or ID of the Azure DevOps project."),
|
|
37
|
-
iterations: z
|
|
37
|
+
iterations: z
|
|
38
|
+
.array(z.object({
|
|
38
39
|
iterationName: z.string().describe("The name of the iteration to create."),
|
|
39
40
|
startDate: z.string().optional().describe("The start date of the iteration in ISO format (e.g., '2023-01-01T00:00:00Z'). Optional."),
|
|
40
|
-
finishDate: z.string().optional().describe("The finish date of the iteration in ISO format (e.g., '2023-01-31T23:59:59Z'). Optional.")
|
|
41
|
-
}))
|
|
41
|
+
finishDate: z.string().optional().describe("The finish date of the iteration in ISO format (e.g., '2023-01-31T23:59:59Z'). Optional."),
|
|
42
|
+
}))
|
|
43
|
+
.describe("An array of iterations to create. Each iteration must have a name and can optionally have start and finish dates in ISO format."),
|
|
42
44
|
}, async ({ project, iterations }) => {
|
|
43
45
|
try {
|
|
44
46
|
const connection = await connectionProvider();
|
|
@@ -65,20 +67,22 @@ function configureWorkTools(server, tokenProvider, connectionProvider) {
|
|
|
65
67
|
};
|
|
66
68
|
}
|
|
67
69
|
catch (error) {
|
|
68
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
70
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
69
71
|
return {
|
|
70
72
|
content: [{ type: "text", text: `Error creating iterations: ${errorMessage}` }],
|
|
71
|
-
isError: true
|
|
73
|
+
isError: true,
|
|
72
74
|
};
|
|
73
75
|
}
|
|
74
76
|
});
|
|
75
77
|
server.tool(WORK_TOOLS.assign_iterations, "Assign existing iterations to a specific team in a project.", {
|
|
76
78
|
project: z.string().describe("The name or ID of the Azure DevOps project."),
|
|
77
79
|
team: z.string().describe("The name or ID of the Azure DevOps team."),
|
|
78
|
-
iterations: z
|
|
80
|
+
iterations: z
|
|
81
|
+
.array(z.object({
|
|
79
82
|
identifier: z.string().describe("The identifier of the iteration to assign."),
|
|
80
|
-
path: z.string().describe("The path of the iteration to assign, e.g., 'Project/Iteration'.")
|
|
81
|
-
}))
|
|
83
|
+
path: z.string().describe("The path of the iteration to assign, e.g., 'Project/Iteration'."),
|
|
84
|
+
}))
|
|
85
|
+
.describe("An array of iterations to assign. Each iteration must have an identifier and a path."),
|
|
82
86
|
}, async ({ project, team, iterations }) => {
|
|
83
87
|
try {
|
|
84
88
|
const connection = await connectionProvider();
|
|
@@ -99,10 +103,10 @@ function configureWorkTools(server, tokenProvider, connectionProvider) {
|
|
|
99
103
|
};
|
|
100
104
|
}
|
|
101
105
|
catch (error) {
|
|
102
|
-
const errorMessage = error instanceof Error ? error.message :
|
|
106
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
103
107
|
return {
|
|
104
108
|
content: [{ type: "text", text: `Error assigning iterations: ${errorMessage}` }],
|
|
105
|
-
isError: true
|
|
109
|
+
isError: true,
|
|
106
110
|
};
|
|
107
111
|
}
|
|
108
112
|
});
|