@azure-devops/mcp 2.1.0-nightly.20250916 → 2.1.0-nightly.20250918

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.
@@ -176,17 +176,18 @@ function configureWikiTools(server, tokenProvider, connectionProvider) {
176
176
  content: z.string().describe("The content of the wiki page in markdown format."),
177
177
  project: z.string().optional().describe("The project name or ID where the wiki is located. If not provided, the default project will be used."),
178
178
  etag: z.string().optional().describe("ETag for editing existing pages (optional, will be fetched if not provided)."),
179
- }, async ({ wikiIdentifier, path, content, project, etag }) => {
179
+ branch: z.string().default("wikiMaster").describe("The branch name for the wiki repository. Defaults to 'wikiMaster' which is the default branch for Azure DevOps wikis."),
180
+ }, async ({ wikiIdentifier, path, content, project, etag, branch = "wikiMaster" }) => {
180
181
  try {
181
182
  const connection = await connectionProvider();
182
183
  const accessToken = await tokenProvider();
183
184
  // Normalize the path
184
185
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
185
186
  const encodedPath = encodeURIComponent(normalizedPath);
186
- // Build the URL for the wiki page API
187
+ // Build the URL for the wiki page API with version descriptor
187
188
  const baseUrl = connection.serverUrl;
188
189
  const projectParam = project || "";
189
- const url = `${baseUrl}/${projectParam}/_apis/wiki/wikis/${wikiIdentifier}/pages?path=${encodedPath}&api-version=7.1`;
190
+ const url = `${baseUrl}/${projectParam}/_apis/wiki/wikis/${wikiIdentifier}/pages?path=${encodedPath}&versionDescriptor.versionType=branch&versionDescriptor.version=${encodeURIComponent(branch)}&api-version=7.1`;
190
191
  // First, try to create a new page (PUT without ETag)
191
192
  try {
192
193
  const createResponse = await fetch(url, {
@@ -3,7 +3,7 @@
3
3
  import { WorkItemExpand } from "azure-devops-node-api/interfaces/WorkItemTrackingInterfaces.js";
4
4
  import { QueryExpand } from "azure-devops-node-api/interfaces/WorkItemTrackingInterfaces.js";
5
5
  import { z } from "zod";
6
- import { batchApiVersion, markdownCommentsApiVersion, getEnumKeys, safeEnumConvert } from "../utils.js";
6
+ import { batchApiVersion, markdownCommentsApiVersion, getEnumKeys, safeEnumConvert, encodeFormattedValue } from "../utils.js";
7
7
  const WORKITEM_TOOLS = {
8
8
  my_work_items: "wit_my_work_items",
9
9
  list_backlogs: "wit_list_backlogs",
@@ -218,6 +218,7 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
218
218
  };
219
219
  }
220
220
  const body = items.map((item, x) => {
221
+ const encodedDescription = encodeFormattedValue(item.description, item.format);
221
222
  const ops = [
222
223
  {
223
224
  op: "add",
@@ -232,12 +233,12 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
232
233
  {
233
234
  op: "add",
234
235
  path: "/fields/System.Description",
235
- value: item.description,
236
+ value: encodedDescription,
236
237
  },
237
238
  {
238
239
  op: "add",
239
240
  path: "/fields/Microsoft.VSTS.TCM.ReproSteps",
240
- value: item.description,
241
+ value: encodedDescription,
241
242
  },
242
243
  {
243
244
  op: "add",
@@ -428,10 +429,10 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
428
429
  try {
429
430
  const connection = await connectionProvider();
430
431
  const workItemApi = await connection.getWorkItemTrackingApi();
431
- const document = fields.map(({ name, value }) => ({
432
+ const document = fields.map(({ name, value, format }) => ({
432
433
  op: "add",
433
434
  path: `/fields/${name}`,
434
- value: value,
435
+ value: encodeFormattedValue(value, format),
435
436
  }));
436
437
  // Check if any field has format === "Markdown" and add the multilineFieldsFormat operation
437
438
  // this should only happen for large text fields, but since we dont't know by field name, lets assume if the users
@@ -512,10 +513,10 @@ function configureWorkItemTools(server, tokenProvider, connectionProvider, userA
512
513
  const uniqueIds = Array.from(new Set(updates.map((update) => update.id)));
513
514
  const body = uniqueIds.map((id) => {
514
515
  const workItemUpdates = updates.filter((update) => update.id === id);
515
- const operations = workItemUpdates.map(({ op, path, value }) => ({
516
+ const operations = workItemUpdates.map(({ op, path, value, format }) => ({
516
517
  op: op,
517
518
  path: path,
518
- value: value,
519
+ value: encodeFormattedValue(value, format),
519
520
  }));
520
521
  // Add format operations for Markdown fields
521
522
  workItemUpdates.forEach(({ path, value, format }) => {
package/dist/utils.js CHANGED
@@ -54,3 +54,16 @@ export function safeEnumConvert(enumObject, key) {
54
54
  }
55
55
  return enumObject[key];
56
56
  }
57
+ /**
58
+ * Encodes `>` and `<` for Markdown formatted fields.
59
+ *
60
+ * @param value The text value to encode
61
+ * @param format The format of the field ('Markdown' or 'Html')
62
+ * @returns The encoded text, or original text if format is not Markdown
63
+ */
64
+ export function encodeFormattedValue(value, format) {
65
+ if (!value || format !== "Markdown")
66
+ return value;
67
+ const result = value.replace(/</g, "&lt;").replace(/>/g, "&gt;");
68
+ return result;
69
+ }
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const packageVersion = "2.1.0-nightly.20250916";
1
+ export const packageVersion = "2.1.0-nightly.20250918";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-devops/mcp",
3
- "version": "2.1.0-nightly.20250916",
3
+ "version": "2.1.0-nightly.20250918",
4
4
  "description": "MCP server for interacting with Azure DevOps",
5
5
  "license": "MIT",
6
6
  "author": "Microsoft Corporation",