@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.
@@ -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) {
@@ -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
- const connection = await connectionProvider();
16
- const wikiApi = await connection.getWikiApi();
17
- const wiki = await wikiApi.getWiki(wikiIdentifier, project);
18
- return {
19
- content: [{ type: "text", text: JSON.stringify(wiki, null, 2) }],
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
- const connection = await connectionProvider();
26
- const wikiApi = await connection.getWikiApi();
27
- const wikis = await wikiApi.getAllWikis(project);
28
- return {
29
- content: [{ type: "text", text: JSON.stringify(wikis, null, 2) }],
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
- const connection = await connectionProvider();
40
- const wikiApi = await connection.getWikiApi();
41
- const pagesBatchRequest = {
42
- top,
43
- continuationToken,
44
- pageViewsForDays,
45
- };
46
- const pages = await wikiApi.getPagesBatch(pagesBatchRequest, project, wikiIdentifier);
47
- return {
48
- content: [{ type: "text", text: JSON.stringify(pages, null, 2) }],
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
- const connection = await connectionProvider();
57
- const wikiApi = await connection.getWikiApi();
58
- const stream = await wikiApi.getPageText(project, wikiIdentifier, path, undefined, undefined, true);
59
- const content = await streamToString(stream);
60
- return {
61
- content: [{ type: "text", text: JSON.stringify(content, null, 2) }],
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) {
@@ -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 : 'Unknown error occurred';
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.array(z.object({
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
- })).describe("An array of iterations to create. Each iteration must have a name and can optionally have start and finish dates in ISO format.")
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 : 'Unknown error occurred';
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.array(z.object({
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
- })).describe("An array of iterations to assign. Each iteration must have an identifier and a path."),
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 : 'Unknown error occurred';
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
  });