@azure-devops/mcp 2.8.0-nightly.20260706 → 2.8.0-nightly.20260710
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/tools/test-plans.js +18 -2
- package/dist/tools/work-items.js +59 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/tools/test-plans.js
CHANGED
|
@@ -474,6 +474,22 @@ function configureTestPlanTools(server, tokenProvider, connectionProvider, userA
|
|
|
474
474
|
}
|
|
475
475
|
});
|
|
476
476
|
}
|
|
477
|
+
/*
|
|
478
|
+
* Format step content by converting Markdown markers to HTML and wrapping in the ADO rich text
|
|
479
|
+
* envelope. The entire HTML string is then XML-escaped for storage in the parameterizedString
|
|
480
|
+
* element, which is the format Azure DevOps expects for rendered step content.
|
|
481
|
+
*/
|
|
482
|
+
function formatStepContent(text) {
|
|
483
|
+
// Convert Markdown markers to HTML tags (** before * and __ before _ to avoid conflicts)
|
|
484
|
+
const htmlContent = text
|
|
485
|
+
.replace(/\*\*(.+?)\*\*/g, "<b>$1</b>")
|
|
486
|
+
.replace(/\*(.+?)\*/g, "<i>$1</i>")
|
|
487
|
+
.replace(/__(.+?)__/g, "<u>$1</u>")
|
|
488
|
+
.replace(/`(.+?)`/g, "<code>$1</code>")
|
|
489
|
+
.replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g, '<a href="$2">$1</a>');
|
|
490
|
+
// Wrap in ADO rich text envelope and XML-escape the entire HTML string
|
|
491
|
+
return escapeXml(`${htmlContent}`);
|
|
492
|
+
}
|
|
477
493
|
/*
|
|
478
494
|
* Helper function to convert steps text to XML format required
|
|
479
495
|
*/
|
|
@@ -491,8 +507,8 @@ function convertStepsToXml(steps) {
|
|
|
491
507
|
const expectedText = expectedPart || "Verify step completes successfully";
|
|
492
508
|
xmlSteps += `
|
|
493
509
|
<step id="${i + 1}" type="ActionStep">
|
|
494
|
-
<parameterizedString isformatted="true">${
|
|
495
|
-
<parameterizedString isformatted="true">${
|
|
510
|
+
<parameterizedString isformatted="true">${formatStepContent(stepText)}</parameterizedString>
|
|
511
|
+
<parameterizedString isformatted="true">${formatStepContent(expectedText)}</parameterizedString>
|
|
496
512
|
</step>`;
|
|
497
513
|
}
|
|
498
514
|
}
|
package/dist/tools/work-items.js
CHANGED
|
@@ -63,6 +63,14 @@ function getLinkTypeFromName(name) {
|
|
|
63
63
|
throw new Error(`Unknown link type: ${name}`);
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
+
function getArtifactLinkAttributeName(linkType) {
|
|
67
|
+
switch (linkType) {
|
|
68
|
+
case "Wiki":
|
|
69
|
+
return "Wiki Page";
|
|
70
|
+
default:
|
|
71
|
+
return linkType;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
66
74
|
function configureWorkItemTools(server, tokenProvider, connectionProvider, userAgentProvider) {
|
|
67
75
|
server.tool(WORKITEM_TOOLS.list_backlogs, "Receive a list of backlogs for a given project and team. If a project or team is not specified, you will be prompted to select one.", {
|
|
68
76
|
project: z.string().optional().describe("The name or ID of the Azure DevOps project. Reuse from prior context if already known. If not provided, a project selection prompt will be shown."),
|
|
@@ -1057,6 +1065,16 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
|
|
|
1057
1065
|
commitId: z.string().optional().describe("The commit SHA hash. Required when linkType is 'Fixed in Commit'."),
|
|
1058
1066
|
pullRequestId: z.coerce.number().min(1).optional().describe("The pull request ID. Required when linkType is 'Pull Request'."),
|
|
1059
1067
|
buildId: z.coerce.number().min(1).optional().describe("The build ID. Required when linkType is 'Build', 'Found in build', or 'Integrated in build'."),
|
|
1068
|
+
wikiId: z.string().optional().describe("The wiki ID (GUID). Required when linkType is 'Wiki'."),
|
|
1069
|
+
pageId: z.coerce
|
|
1070
|
+
.number()
|
|
1071
|
+
.min(1)
|
|
1072
|
+
.optional()
|
|
1073
|
+
.describe("The numeric wiki page ID from the browser URL (e.g., '98' in '.../wikis/Contoso.wiki/98/What-is-Contoso'). When provided for 'Wiki' links, the full page path is resolved automatically via the API. Takes precedence over 'pagePath'."),
|
|
1074
|
+
pagePath: z
|
|
1075
|
+
.string()
|
|
1076
|
+
.optional()
|
|
1077
|
+
.describe("The full wiki page path from the wiki root (e.g., '/Home/What-is-Contoso'). Required when linkType is 'Wiki' and 'pageId' is not provided. Must be the complete path, not just the page name from the URL."),
|
|
1060
1078
|
linkType: z
|
|
1061
1079
|
.enum([
|
|
1062
1080
|
"Branch",
|
|
@@ -1077,7 +1095,7 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
|
|
|
1077
1095
|
.default("Branch")
|
|
1078
1096
|
.describe("Type of artifact link, defaults to 'Branch'. This determines both the link type and how to build the VSTFS URI from individual components."),
|
|
1079
1097
|
comment: z.string().optional().describe("Comment to include with the artifact link."),
|
|
1080
|
-
}, async ({ workItemId, project, artifactUri, projectId, repositoryId, branchName, commitId, pullRequestId, buildId, linkType, comment }) => {
|
|
1098
|
+
}, async ({ workItemId, project, artifactUri, projectId, repositoryId, branchName, commitId, pullRequestId, buildId, wikiId, pageId, pagePath, linkType, comment }) => {
|
|
1081
1099
|
try {
|
|
1082
1100
|
const connection = await connectionProvider();
|
|
1083
1101
|
let resolvedProject = project;
|
|
@@ -1134,6 +1152,45 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
|
|
|
1134
1152
|
}
|
|
1135
1153
|
finalArtifactUri = `vstfs:///Build/Build/${encodeURIComponent(buildId.toString())}`;
|
|
1136
1154
|
break;
|
|
1155
|
+
case "Wiki": {
|
|
1156
|
+
if (!projectId || !wikiId) {
|
|
1157
|
+
return {
|
|
1158
|
+
content: [{ type: "text", text: "For 'Wiki' links, 'projectId', 'wikiId', and 'pagePath' are required." }],
|
|
1159
|
+
isError: true,
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
let resolvedPagePath = pagePath;
|
|
1163
|
+
if (pageId !== undefined) {
|
|
1164
|
+
// Look up the actual page path by page ID to get the full path
|
|
1165
|
+
const orgUrl = connection.serverUrl;
|
|
1166
|
+
const accessToken = await tokenProvider();
|
|
1167
|
+
const pageResponse = await fetch(`${orgUrl}/${encodeURIComponent(resolvedProject)}/_apis/wiki/wikis/${encodeURIComponent(wikiId)}/pages/${pageId}?api-version=7.1`, {
|
|
1168
|
+
headers: {
|
|
1169
|
+
"Authorization": `Bearer ${accessToken}`,
|
|
1170
|
+
"User-Agent": userAgentProvider(),
|
|
1171
|
+
},
|
|
1172
|
+
});
|
|
1173
|
+
if (!pageResponse.ok) {
|
|
1174
|
+
return {
|
|
1175
|
+
content: [{ type: "text", text: `Failed to look up wiki page ID ${pageId}: ${pageResponse.statusText}` }],
|
|
1176
|
+
isError: true,
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
const pageData = await pageResponse.json();
|
|
1180
|
+
resolvedPagePath = pageData.path;
|
|
1181
|
+
}
|
|
1182
|
+
if (!resolvedPagePath) {
|
|
1183
|
+
return {
|
|
1184
|
+
content: [{ type: "text", text: "For 'Wiki' links, 'pageId' or 'pagePath' is required." }],
|
|
1185
|
+
isError: true,
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
// Strip leading slash, then encode each segment joined by %2F
|
|
1189
|
+
const normalizedPath = resolvedPagePath.startsWith("/") ? resolvedPagePath.slice(1) : resolvedPagePath;
|
|
1190
|
+
const encodedPath = normalizedPath.split("/").map(encodeURIComponent).join("%2F");
|
|
1191
|
+
finalArtifactUri = `vstfs:///Wiki/WikiPage/${encodeURIComponent(projectId)}%2F${encodeURIComponent(wikiId)}%2F${encodedPath}`;
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1137
1194
|
default:
|
|
1138
1195
|
return {
|
|
1139
1196
|
content: [{ type: "text", text: `URI building from components is not supported for link type '${linkType}'. Please provide the full 'artifactUri' instead.` }],
|
|
@@ -1150,7 +1207,7 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
|
|
|
1150
1207
|
rel: "ArtifactLink",
|
|
1151
1208
|
url: finalArtifactUri,
|
|
1152
1209
|
attributes: {
|
|
1153
|
-
name: linkType,
|
|
1210
|
+
name: getArtifactLinkAttributeName(linkType),
|
|
1154
1211
|
...(comment && { comment }),
|
|
1155
1212
|
},
|
|
1156
1213
|
},
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const packageVersion = "2.8.0-nightly.
|
|
1
|
+
export const packageVersion = "2.8.0-nightly.20260710";
|