@mcp-consultant-tools/azure-devops 1.0.0

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.
@@ -0,0 +1,183 @@
1
+ export interface AzureDevOpsConfig {
2
+ organization: string;
3
+ pat: string;
4
+ projects: string[];
5
+ apiVersion?: string;
6
+ enableWorkItemWrite?: boolean;
7
+ enableWorkItemDelete?: boolean;
8
+ enableWikiWrite?: boolean;
9
+ }
10
+ export interface AdoApiCollectionResponse<T> {
11
+ value: T[];
12
+ count?: number;
13
+ [key: string]: any;
14
+ }
15
+ export declare class AzureDevOpsService {
16
+ private config;
17
+ private baseUrl;
18
+ private searchUrl;
19
+ private authHeader;
20
+ private apiVersion;
21
+ constructor(config: AzureDevOpsConfig);
22
+ /**
23
+ * Validate that a project is in the allowed list
24
+ */
25
+ private validateProject;
26
+ /**
27
+ * Make an authenticated request to the Azure DevOps API
28
+ */
29
+ private makeRequest;
30
+ /**
31
+ * Convert a git path (returned by search) to a wiki path (used by get-page API)
32
+ * Git paths use dashes and .md extensions: /Release-Notes/Page-Name.md
33
+ * Wiki paths use spaces and no extensions: /Release Notes/Page Name
34
+ * @param gitPath The git path from search results
35
+ * @returns The wiki path for use with get-page API
36
+ */
37
+ private convertGitPathToWikiPath;
38
+ /**
39
+ * Count occurrences of a string in content
40
+ * @param content The content to search in
41
+ * @param searchStr The string to search for
42
+ * @returns Number of occurrences
43
+ */
44
+ private countOccurrences;
45
+ /**
46
+ * Get locations where a string appears in content
47
+ * @param content The content to search in
48
+ * @param searchStr The string to search for
49
+ * @returns Formatted string showing line numbers and context
50
+ */
51
+ private getMatchLocations;
52
+ /**
53
+ * Generate a unified diff showing changes
54
+ * @param oldContent Original content
55
+ * @param newContent Updated content
56
+ * @param oldStr The string that was replaced
57
+ * @param newStr The replacement string
58
+ * @returns Formatted diff output
59
+ */
60
+ private generateUnifiedDiff;
61
+ /**
62
+ * Escape special regex characters
63
+ * @param str String to escape
64
+ * @returns Escaped string safe for use in regex
65
+ */
66
+ private escapeRegExp;
67
+ /**
68
+ * Truncate a string for display
69
+ * @param str String to truncate
70
+ * @param maxLen Maximum length
71
+ * @returns Truncated string with ellipsis if needed
72
+ */
73
+ private truncate;
74
+ /**
75
+ * Get all wikis in a project
76
+ * @param project The project name
77
+ * @returns List of wikis in the project
78
+ */
79
+ getWikis(project: string): Promise<any>;
80
+ /**
81
+ * Search wiki pages across projects
82
+ * @param searchText The text to search for
83
+ * @param project Optional project filter
84
+ * @param maxResults Maximum number of results (default: 25)
85
+ * @returns Search results with highlighted content
86
+ */
87
+ searchWikiPages(searchText: string, project?: string, maxResults?: number): Promise<any>;
88
+ /**
89
+ * Get a specific wiki page with content
90
+ * @param project The project name
91
+ * @param wikiId The wiki identifier (ID or name)
92
+ * @param pagePath The path to the page (e.g., "/Setup/Authentication")
93
+ * Accepts both wiki paths (with spaces) and git paths (with dashes and .md)
94
+ * @param includeContent Include page content (default: true)
95
+ * @returns Wiki page with content and metadata
96
+ */
97
+ getWikiPage(project: string, wikiId: string, pagePath: string, includeContent?: boolean): Promise<any>;
98
+ /**
99
+ * Create a new wiki page
100
+ * @param project The project name
101
+ * @param wikiId The wiki identifier
102
+ * @param pagePath The path for the new page (will be normalized to wiki format)
103
+ * @param content The markdown content
104
+ * @returns Created page information
105
+ */
106
+ createWikiPage(project: string, wikiId: string, pagePath: string, content: string): Promise<any>;
107
+ /**
108
+ * Update an existing wiki page
109
+ * @param project The project name
110
+ * @param wikiId The wiki identifier
111
+ * @param pagePath The path to the page (will be normalized to wiki format)
112
+ * @param content The updated markdown content
113
+ * @param version The ETag/version for optimistic concurrency (recommended to prevent conflicts)
114
+ * @returns Updated page information
115
+ */
116
+ updateWikiPage(project: string, wikiId: string, pagePath: string, content: string, version?: string): Promise<any>;
117
+ /**
118
+ * Replace a specific string in a wiki page without rewriting entire content
119
+ * @param project The project name
120
+ * @param wikiId The wiki identifier
121
+ * @param pagePath The path to the page (will be normalized to wiki format)
122
+ * @param oldStr The exact string to replace
123
+ * @param newStr The replacement string
124
+ * @param replaceAll If true, replace all occurrences; if false, old_str must be unique
125
+ * @param description Optional description of the change for audit logging
126
+ * @returns Result with diff, occurrence count, version, and message
127
+ */
128
+ strReplaceWikiPage(project: string, wikiId: string, pagePath: string, oldStr: string, newStr: string, replaceAll?: boolean, description?: string): Promise<any>;
129
+ /**
130
+ * Get a work item by ID with full details
131
+ * @param project The project name
132
+ * @param workItemId The work item ID
133
+ * @returns Complete work item details
134
+ */
135
+ getWorkItem(project: string, workItemId: number): Promise<any>;
136
+ /**
137
+ * Query work items using WIQL (Work Item Query Language)
138
+ * @param project The project name
139
+ * @param wiql The WIQL query string
140
+ * @param maxResults Maximum number of results (default: 200)
141
+ * @returns Work items matching the query
142
+ */
143
+ queryWorkItems(project: string, wiql: string, maxResults?: number): Promise<any>;
144
+ /**
145
+ * Get comments/discussion for a work item
146
+ * @param project The project name
147
+ * @param workItemId The work item ID
148
+ * @returns List of comments
149
+ */
150
+ getWorkItemComments(project: string, workItemId: number): Promise<any>;
151
+ /**
152
+ * Add a comment to a work item
153
+ * @param project The project name
154
+ * @param workItemId The work item ID
155
+ * @param commentText The comment text (supports markdown)
156
+ * @returns Created comment information
157
+ */
158
+ addWorkItemComment(project: string, workItemId: number, commentText: string): Promise<any>;
159
+ /**
160
+ * Update a work item using JSON Patch operations
161
+ * @param project The project name
162
+ * @param workItemId The work item ID
163
+ * @param patchOperations Array of JSON Patch operations
164
+ * @returns Updated work item
165
+ */
166
+ updateWorkItem(project: string, workItemId: number, patchOperations: any[]): Promise<any>;
167
+ /**
168
+ * Create a new work item
169
+ * @param project The project name
170
+ * @param workItemType The work item type (e.g., "Bug", "Task", "User Story")
171
+ * @param fields Object with field values (e.g., { "System.Title": "Bug title" })
172
+ * @returns Created work item
173
+ */
174
+ createWorkItem(project: string, workItemType: string, fields: any): Promise<any>;
175
+ /**
176
+ * Delete a work item
177
+ * @param project The project name
178
+ * @param workItemId The work item ID
179
+ * @returns Deletion confirmation
180
+ */
181
+ deleteWorkItem(project: string, workItemId: number): Promise<any>;
182
+ }
183
+ //# sourceMappingURL=AzureDevOpsService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AzureDevOpsService.d.ts","sourceRoot":"","sources":["../src/AzureDevOpsService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,596 @@
1
+ import axios from 'axios';
2
+ export class AzureDevOpsService {
3
+ config;
4
+ baseUrl;
5
+ searchUrl;
6
+ authHeader;
7
+ apiVersion;
8
+ constructor(config) {
9
+ this.config = {
10
+ ...config,
11
+ apiVersion: config.apiVersion || '7.1',
12
+ enableWorkItemWrite: config.enableWorkItemWrite ?? false,
13
+ enableWorkItemDelete: config.enableWorkItemDelete ?? false,
14
+ enableWikiWrite: config.enableWikiWrite ?? false
15
+ };
16
+ this.baseUrl = `https://dev.azure.com/${this.config.organization}`;
17
+ this.searchUrl = `https://almsearch.dev.azure.com/${this.config.organization}`;
18
+ this.apiVersion = this.config.apiVersion;
19
+ // Encode PAT for Basic Auth (format is :PAT encoded in base64)
20
+ this.authHeader = `Basic ${Buffer.from(`:${this.config.pat}`).toString('base64')}`;
21
+ }
22
+ /**
23
+ * Validate that a project is in the allowed list
24
+ */
25
+ validateProject(project) {
26
+ if (!this.config.projects.includes(project)) {
27
+ throw new Error(`Project '${project}' is not in the allowed projects list. Allowed projects: ${this.config.projects.join(', ')}`);
28
+ }
29
+ }
30
+ /**
31
+ * Make an authenticated request to the Azure DevOps API
32
+ */
33
+ async makeRequest(endpoint, method = 'GET', data, useSearchUrl = false, customHeaders) {
34
+ try {
35
+ const baseUrl = useSearchUrl ? this.searchUrl : this.baseUrl;
36
+ const url = `${baseUrl}/${endpoint}`;
37
+ const response = await axios({
38
+ method,
39
+ url,
40
+ headers: {
41
+ 'Authorization': this.authHeader,
42
+ 'Content-Type': method === 'PATCH' ? 'application/json-patch+json' : 'application/json',
43
+ 'Accept': 'application/json',
44
+ ...customHeaders // Merge custom headers (can override defaults)
45
+ },
46
+ data
47
+ });
48
+ return response.data;
49
+ }
50
+ catch (error) {
51
+ const errorDetails = error.response?.data?.message || error.response?.data || error.message;
52
+ console.error('Azure DevOps API request failed:', {
53
+ endpoint,
54
+ method,
55
+ status: error.response?.status,
56
+ statusText: error.response?.statusText,
57
+ error: errorDetails
58
+ });
59
+ // Provide user-friendly error messages
60
+ if (error.response?.status === 401) {
61
+ throw new Error('Azure DevOps authentication failed. Please check your PAT token and permissions.');
62
+ }
63
+ if (error.response?.status === 403) {
64
+ throw new Error('Azure DevOps access denied. Please check your PAT scopes and project permissions.');
65
+ }
66
+ if (error.response?.status === 404) {
67
+ throw new Error(`Azure DevOps resource not found: ${endpoint}`);
68
+ }
69
+ throw new Error(`Azure DevOps API request failed: ${error.message} - ${JSON.stringify(errorDetails)}`);
70
+ }
71
+ }
72
+ // ==================== WIKI OPERATIONS ====================
73
+ /**
74
+ * Convert a git path (returned by search) to a wiki path (used by get-page API)
75
+ * Git paths use dashes and .md extensions: /Release-Notes/Page-Name.md
76
+ * Wiki paths use spaces and no extensions: /Release Notes/Page Name
77
+ * @param gitPath The git path from search results
78
+ * @returns The wiki path for use with get-page API
79
+ */
80
+ convertGitPathToWikiPath(gitPath) {
81
+ return gitPath
82
+ .replace(/\.md$/, '') // Remove .md extension
83
+ .replace(/-/g, ' ') // Replace ALL dashes with spaces
84
+ .replace(/%2D/gi, '-'); // Decode %2D back to - (actual dashes in page names)
85
+ }
86
+ /**
87
+ * Count occurrences of a string in content
88
+ * @param content The content to search in
89
+ * @param searchStr The string to search for
90
+ * @returns Number of occurrences
91
+ */
92
+ countOccurrences(content, searchStr) {
93
+ const regex = new RegExp(this.escapeRegExp(searchStr), 'g');
94
+ const matches = content.match(regex);
95
+ return matches ? matches.length : 0;
96
+ }
97
+ /**
98
+ * Get locations where a string appears in content
99
+ * @param content The content to search in
100
+ * @param searchStr The string to search for
101
+ * @returns Formatted string showing line numbers and context
102
+ */
103
+ getMatchLocations(content, searchStr) {
104
+ const lines = content.split('\n');
105
+ const matches = [];
106
+ lines.forEach((line, index) => {
107
+ if (line.includes(searchStr)) {
108
+ matches.push(`Line ${index + 1}: ${this.truncate(line.trim(), 100)}`);
109
+ }
110
+ });
111
+ const maxDisplay = 10;
112
+ const result = matches.slice(0, maxDisplay).join('\n');
113
+ if (matches.length > maxDisplay) {
114
+ return result + `\n... and ${matches.length - maxDisplay} more`;
115
+ }
116
+ return result;
117
+ }
118
+ /**
119
+ * Generate a unified diff showing changes
120
+ * @param oldContent Original content
121
+ * @param newContent Updated content
122
+ * @param oldStr The string that was replaced
123
+ * @param newStr The replacement string
124
+ * @returns Formatted diff output
125
+ */
126
+ generateUnifiedDiff(oldContent, newContent, oldStr, newStr) {
127
+ const oldLines = oldContent.split('\n');
128
+ const newLines = newContent.split('\n');
129
+ // Find changed lines
130
+ const changedLineNumbers = [];
131
+ oldLines.forEach((line, index) => {
132
+ if (line.includes(oldStr)) {
133
+ changedLineNumbers.push(index);
134
+ }
135
+ });
136
+ // Build diff output
137
+ const diffLines = [];
138
+ changedLineNumbers.forEach(lineNum => {
139
+ diffLines.push(`@@ Line ${lineNum + 1} @@`);
140
+ diffLines.push(`- ${oldLines[lineNum]}`);
141
+ diffLines.push(`+ ${newLines[lineNum]}`);
142
+ diffLines.push('');
143
+ });
144
+ return diffLines.join('\n');
145
+ }
146
+ /**
147
+ * Escape special regex characters
148
+ * @param str String to escape
149
+ * @returns Escaped string safe for use in regex
150
+ */
151
+ escapeRegExp(str) {
152
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
153
+ }
154
+ /**
155
+ * Truncate a string for display
156
+ * @param str String to truncate
157
+ * @param maxLen Maximum length
158
+ * @returns Truncated string with ellipsis if needed
159
+ */
160
+ truncate(str, maxLen) {
161
+ return str.length > maxLen ? str.substring(0, maxLen) + '...' : str;
162
+ }
163
+ /**
164
+ * Get all wikis in a project
165
+ * @param project The project name
166
+ * @returns List of wikis in the project
167
+ */
168
+ async getWikis(project) {
169
+ this.validateProject(project);
170
+ const response = await this.makeRequest(`${project}/_apis/wiki/wikis?api-version=${this.apiVersion}`);
171
+ return {
172
+ project,
173
+ totalCount: response.value.length,
174
+ wikis: response.value.map((wiki) => ({
175
+ id: wiki.id,
176
+ name: wiki.name,
177
+ type: wiki.type,
178
+ url: wiki.url,
179
+ projectId: wiki.projectId,
180
+ repositoryId: wiki.repositoryId,
181
+ mappedPath: wiki.mappedPath
182
+ }))
183
+ };
184
+ }
185
+ /**
186
+ * Search wiki pages across projects
187
+ * @param searchText The text to search for
188
+ * @param project Optional project filter
189
+ * @param maxResults Maximum number of results (default: 25)
190
+ * @returns Search results with highlighted content
191
+ */
192
+ async searchWikiPages(searchText, project, maxResults = 25) {
193
+ if (project) {
194
+ this.validateProject(project);
195
+ }
196
+ const searchBody = {
197
+ searchText,
198
+ $top: maxResults,
199
+ $skip: 0
200
+ };
201
+ // Add project filter if specified
202
+ if (project) {
203
+ searchBody.filters = {
204
+ Project: [project]
205
+ };
206
+ }
207
+ const response = await this.makeRequest(`_apis/search/wikisearchresults?api-version=${this.apiVersion}`, 'POST', searchBody, true // Use search URL
208
+ );
209
+ return {
210
+ searchText,
211
+ project: project || 'all',
212
+ totalCount: response.count || 0,
213
+ results: (response.results || []).map((result) => {
214
+ const gitPath = result.path;
215
+ const wikiPath = this.convertGitPathToWikiPath(gitPath);
216
+ return {
217
+ fileName: result.fileName,
218
+ gitPath: gitPath, // Original git path (for reference)
219
+ path: wikiPath, // Wiki path (for get-page API) - kept as 'path' for backward compatibility
220
+ wikiName: result.wiki?.name,
221
+ wikiId: result.wiki?.id,
222
+ project: result.project?.name,
223
+ highlights: result.hits?.map((hit) => hit.highlights).flat() || []
224
+ };
225
+ })
226
+ };
227
+ }
228
+ /**
229
+ * Get a specific wiki page with content
230
+ * @param project The project name
231
+ * @param wikiId The wiki identifier (ID or name)
232
+ * @param pagePath The path to the page (e.g., "/Setup/Authentication")
233
+ * Accepts both wiki paths (with spaces) and git paths (with dashes and .md)
234
+ * @param includeContent Include page content (default: true)
235
+ * @returns Wiki page with content and metadata
236
+ */
237
+ async getWikiPage(project, wikiId, pagePath, includeContent = true) {
238
+ this.validateProject(project);
239
+ // Always normalize paths to wiki format (removes .md, converts dashes to spaces)
240
+ // This ensures consistent behavior regardless of input format
241
+ const wikiPath = this.convertGitPathToWikiPath(pagePath);
242
+ // Log conversion if the path was changed (for debugging)
243
+ if (wikiPath !== pagePath) {
244
+ console.error(`Normalized wiki path: ${pagePath} -> ${wikiPath}`);
245
+ }
246
+ // Use axios directly to access response headers (for ETag)
247
+ const url = `${this.baseUrl}/${project}/_apis/wiki/wikis/${wikiId}/pages?path=${encodeURIComponent(wikiPath)}&includeContent=${includeContent}&api-version=${this.apiVersion}`;
248
+ try {
249
+ const axiosResponse = await axios({
250
+ method: 'GET',
251
+ url,
252
+ headers: {
253
+ 'Authorization': this.authHeader,
254
+ 'Content-Type': 'application/json',
255
+ 'Accept': 'application/json'
256
+ }
257
+ });
258
+ const response = axiosResponse.data;
259
+ // Extract ETag from response headers (needed for updates)
260
+ const etag = axiosResponse.headers['etag'] || axiosResponse.headers['ETag'];
261
+ // The API returns the page data directly (not wrapped in a 'page' property)
262
+ return {
263
+ id: response.id,
264
+ path: response.path,
265
+ content: response.content,
266
+ gitItemPath: response.gitItemPath,
267
+ subPages: response.subPages || [],
268
+ url: response.url,
269
+ remoteUrl: response.remoteUrl,
270
+ version: etag, // Include ETag for use with updateWikiPage
271
+ project,
272
+ wikiId
273
+ };
274
+ }
275
+ catch (error) {
276
+ // Handle errors similar to makeRequest
277
+ const errorDetails = error.response?.data?.message || error.response?.data || error.message;
278
+ console.error('Azure DevOps API request failed:', {
279
+ url,
280
+ status: error.response?.status,
281
+ error: errorDetails
282
+ });
283
+ if (error.response?.status === 401) {
284
+ throw new Error('Azure DevOps authentication failed. Please check your PAT token and permissions.');
285
+ }
286
+ if (error.response?.status === 403) {
287
+ throw new Error('Azure DevOps access denied. Please check your PAT scopes and project permissions.');
288
+ }
289
+ if (error.response?.status === 404) {
290
+ throw new Error(`Wiki page not found: ${wikiPath} (original input: ${pagePath})`);
291
+ }
292
+ throw new Error(`Azure DevOps API request failed: ${error.message} - ${JSON.stringify(errorDetails)}`);
293
+ }
294
+ }
295
+ /**
296
+ * Create a new wiki page
297
+ * @param project The project name
298
+ * @param wikiId The wiki identifier
299
+ * @param pagePath The path for the new page (will be normalized to wiki format)
300
+ * @param content The markdown content
301
+ * @returns Created page information
302
+ */
303
+ async createWikiPage(project, wikiId, pagePath, content) {
304
+ this.validateProject(project);
305
+ if (!this.config.enableWikiWrite) {
306
+ throw new Error('Wiki write operations are disabled. Set AZUREDEVOPS_ENABLE_WIKI_WRITE=true to enable.');
307
+ }
308
+ // Always normalize paths to wiki format (removes .md, converts dashes to spaces)
309
+ const wikiPath = this.convertGitPathToWikiPath(pagePath);
310
+ // Log conversion if the path was changed (for debugging)
311
+ if (wikiPath !== pagePath) {
312
+ console.error(`Normalized wiki path for creation: ${pagePath} -> ${wikiPath}`);
313
+ }
314
+ const response = await this.makeRequest(`${project}/_apis/wiki/wikis/${wikiId}/pages?path=${encodeURIComponent(wikiPath)}&api-version=${this.apiVersion}`, 'PUT', { content });
315
+ return {
316
+ id: response.page?.id,
317
+ path: response.page?.path,
318
+ gitItemPath: response.page?.gitItemPath,
319
+ project,
320
+ wikiId
321
+ };
322
+ }
323
+ /**
324
+ * Update an existing wiki page
325
+ * @param project The project name
326
+ * @param wikiId The wiki identifier
327
+ * @param pagePath The path to the page (will be normalized to wiki format)
328
+ * @param content The updated markdown content
329
+ * @param version The ETag/version for optimistic concurrency (recommended to prevent conflicts)
330
+ * @returns Updated page information
331
+ */
332
+ async updateWikiPage(project, wikiId, pagePath, content, version) {
333
+ this.validateProject(project);
334
+ if (!this.config.enableWikiWrite) {
335
+ throw new Error('Wiki write operations are disabled. Set AZUREDEVOPS_ENABLE_WIKI_WRITE=true to enable.');
336
+ }
337
+ // Always normalize paths to wiki format (removes .md, converts dashes to spaces)
338
+ const wikiPath = this.convertGitPathToWikiPath(pagePath);
339
+ // Log conversion if the path was changed (for debugging)
340
+ if (wikiPath !== pagePath) {
341
+ console.error(`Normalized wiki path for update: ${pagePath} -> ${wikiPath}`);
342
+ }
343
+ // Add If-Match header if version is provided (for optimistic concurrency control)
344
+ const customHeaders = version ? { 'If-Match': version } : undefined;
345
+ const response = await this.makeRequest(`${project}/_apis/wiki/wikis/${wikiId}/pages?path=${encodeURIComponent(wikiPath)}&api-version=${this.apiVersion}`, 'PUT', { content }, false, // useSearchUrl
346
+ customHeaders);
347
+ return {
348
+ id: response.page?.id,
349
+ path: response.page?.path,
350
+ gitItemPath: response.page?.gitItemPath,
351
+ project,
352
+ wikiId
353
+ };
354
+ }
355
+ /**
356
+ * Replace a specific string in a wiki page without rewriting entire content
357
+ * @param project The project name
358
+ * @param wikiId The wiki identifier
359
+ * @param pagePath The path to the page (will be normalized to wiki format)
360
+ * @param oldStr The exact string to replace
361
+ * @param newStr The replacement string
362
+ * @param replaceAll If true, replace all occurrences; if false, old_str must be unique
363
+ * @param description Optional description of the change for audit logging
364
+ * @returns Result with diff, occurrence count, version, and message
365
+ */
366
+ async strReplaceWikiPage(project, wikiId, pagePath, oldStr, newStr, replaceAll = false, description) {
367
+ this.validateProject(project);
368
+ // 1. Validate write permission
369
+ if (!this.config.enableWikiWrite) {
370
+ throw new Error('Wiki write operations are disabled. Set AZUREDEVOPS_ENABLE_WIKI_WRITE=true to enable.');
371
+ }
372
+ // 2. Fetch current page content and version (auto-fetch latest)
373
+ const currentPage = await this.getWikiPage(project, wikiId, pagePath, true);
374
+ const currentContent = currentPage.content;
375
+ const currentVersion = currentPage.version;
376
+ // 3. Count occurrences of old_str
377
+ const occurrences = this.countOccurrences(currentContent, oldStr);
378
+ if (occurrences === 0) {
379
+ throw new Error(`String not found in page.\n\n` +
380
+ `Looking for: "${this.truncate(oldStr, 200)}"\n\n` +
381
+ `Page excerpt:\n${this.truncate(currentContent, 500)}`);
382
+ }
383
+ if (occurrences > 1 && !replaceAll) {
384
+ throw new Error(`String appears ${occurrences} times in the page. ` +
385
+ `Either provide more context to make old_str unique, or set replace_all=true.\n\n` +
386
+ `Matching locations:\n${this.getMatchLocations(currentContent, oldStr)}`);
387
+ }
388
+ // 4. Perform replacement
389
+ const regex = new RegExp(this.escapeRegExp(oldStr), replaceAll ? 'g' : '');
390
+ const newContent = currentContent.replace(regex, newStr);
391
+ // 5. Validate replacement succeeded
392
+ if (newContent === currentContent) {
393
+ throw new Error('Replacement failed - content unchanged');
394
+ }
395
+ // 6. Update wiki page with version conflict retry
396
+ let updateResult;
397
+ try {
398
+ updateResult = await this.updateWikiPage(project, wikiId, pagePath, newContent, currentVersion);
399
+ }
400
+ catch (error) {
401
+ // Version conflict - retry once with fresh version
402
+ if (error.message.includes('412') || error.message.includes('version') || error.message.includes('conflict')) {
403
+ console.error('Version conflict detected, retrying with fresh version...');
404
+ const freshPage = await this.getWikiPage(project, wikiId, pagePath, true);
405
+ const freshContent = freshPage.content;
406
+ const freshVersion = freshPage.version;
407
+ // Re-apply replacement to fresh content
408
+ const freshRegex = new RegExp(this.escapeRegExp(oldStr), replaceAll ? 'g' : '');
409
+ const freshNewContent = freshContent.replace(freshRegex, newStr);
410
+ updateResult = await this.updateWikiPage(project, wikiId, pagePath, freshNewContent, freshVersion);
411
+ }
412
+ else {
413
+ throw error;
414
+ }
415
+ }
416
+ // 7. Generate diff output
417
+ const diff = this.generateUnifiedDiff(currentContent, newContent, oldStr, newStr);
418
+ // 8. Return result with diff
419
+ return {
420
+ success: true,
421
+ diff,
422
+ occurrences: replaceAll ? occurrences : 1,
423
+ version: currentVersion,
424
+ message: `Successfully replaced ${replaceAll ? occurrences : 1} occurrence(s)`,
425
+ ...updateResult
426
+ };
427
+ }
428
+ // ==================== WORK ITEM OPERATIONS ====================
429
+ /**
430
+ * Get a work item by ID with full details
431
+ * @param project The project name
432
+ * @param workItemId The work item ID
433
+ * @returns Complete work item details
434
+ */
435
+ async getWorkItem(project, workItemId) {
436
+ this.validateProject(project);
437
+ const response = await this.makeRequest(`${project}/_apis/wit/workitems/${workItemId}?$expand=all&api-version=${this.apiVersion}`);
438
+ return {
439
+ id: response.id,
440
+ rev: response.rev,
441
+ url: response.url,
442
+ fields: response.fields,
443
+ relations: response.relations || [],
444
+ _links: response._links,
445
+ commentVersionRef: response.commentVersionRef,
446
+ project
447
+ };
448
+ }
449
+ /**
450
+ * Query work items using WIQL (Work Item Query Language)
451
+ * @param project The project name
452
+ * @param wiql The WIQL query string
453
+ * @param maxResults Maximum number of results (default: 200)
454
+ * @returns Work items matching the query
455
+ */
456
+ async queryWorkItems(project, wiql, maxResults = 200) {
457
+ this.validateProject(project);
458
+ // Execute WIQL query
459
+ const queryResult = await this.makeRequest(`${project}/_apis/wit/wiql?api-version=${this.apiVersion}`, 'POST', { query: wiql });
460
+ if (!queryResult.workItems || queryResult.workItems.length === 0) {
461
+ return {
462
+ query: wiql,
463
+ project,
464
+ totalCount: 0,
465
+ workItems: []
466
+ };
467
+ }
468
+ // Get work item IDs (limit to maxResults)
469
+ const workItemIds = queryResult.workItems
470
+ .slice(0, maxResults)
471
+ .map((wi) => wi.id);
472
+ // Batch get full work item details
473
+ const workItems = await this.makeRequest(`${project}/_apis/wit/workitemsbatch?api-version=${this.apiVersion}`, 'POST', {
474
+ ids: workItemIds,
475
+ $expand: 'all'
476
+ });
477
+ return {
478
+ query: wiql,
479
+ project,
480
+ totalCount: workItems.value.length,
481
+ workItems: workItems.value
482
+ };
483
+ }
484
+ /**
485
+ * Get comments/discussion for a work item
486
+ * @param project The project name
487
+ * @param workItemId The work item ID
488
+ * @returns List of comments
489
+ */
490
+ async getWorkItemComments(project, workItemId) {
491
+ this.validateProject(project);
492
+ const response = await this.makeRequest(`${project}/_apis/wit/workItems/${workItemId}/comments?api-version=${this.apiVersion}`);
493
+ return {
494
+ workItemId,
495
+ project,
496
+ totalCount: response.totalCount || response.value.length,
497
+ comments: response.value.map((comment) => ({
498
+ id: comment.id,
499
+ text: comment.text,
500
+ createdBy: comment.createdBy?.displayName,
501
+ createdDate: comment.createdDate,
502
+ modifiedBy: comment.modifiedBy?.displayName,
503
+ modifiedDate: comment.modifiedDate,
504
+ url: comment.url
505
+ }))
506
+ };
507
+ }
508
+ /**
509
+ * Add a comment to a work item
510
+ * @param project The project name
511
+ * @param workItemId The work item ID
512
+ * @param commentText The comment text (supports markdown)
513
+ * @returns Created comment information
514
+ */
515
+ async addWorkItemComment(project, workItemId, commentText) {
516
+ this.validateProject(project);
517
+ if (!this.config.enableWorkItemWrite) {
518
+ throw new Error('Work item write operations are disabled. Set AZUREDEVOPS_ENABLE_WORK_ITEM_WRITE=true to enable.');
519
+ }
520
+ const response = await this.makeRequest(`${project}/_apis/wit/workItems/${workItemId}/comments?api-version=${this.apiVersion}`, 'POST', { text: commentText });
521
+ return {
522
+ id: response.id,
523
+ workItemId,
524
+ project,
525
+ text: response.text,
526
+ createdBy: response.createdBy?.displayName,
527
+ createdDate: response.createdDate
528
+ };
529
+ }
530
+ /**
531
+ * Update a work item using JSON Patch operations
532
+ * @param project The project name
533
+ * @param workItemId The work item ID
534
+ * @param patchOperations Array of JSON Patch operations
535
+ * @returns Updated work item
536
+ */
537
+ async updateWorkItem(project, workItemId, patchOperations) {
538
+ this.validateProject(project);
539
+ if (!this.config.enableWorkItemWrite) {
540
+ throw new Error('Work item write operations are disabled. Set AZUREDEVOPS_ENABLE_WORK_ITEM_WRITE=true to enable.');
541
+ }
542
+ const response = await this.makeRequest(`${project}/_apis/wit/workitems/${workItemId}?api-version=${this.apiVersion}`, 'PATCH', patchOperations);
543
+ return {
544
+ id: response.id,
545
+ rev: response.rev,
546
+ fields: response.fields,
547
+ project
548
+ };
549
+ }
550
+ /**
551
+ * Create a new work item
552
+ * @param project The project name
553
+ * @param workItemType The work item type (e.g., "Bug", "Task", "User Story")
554
+ * @param fields Object with field values (e.g., { "System.Title": "Bug title" })
555
+ * @returns Created work item
556
+ */
557
+ async createWorkItem(project, workItemType, fields) {
558
+ this.validateProject(project);
559
+ if (!this.config.enableWorkItemWrite) {
560
+ throw new Error('Work item write operations are disabled. Set AZUREDEVOPS_ENABLE_WORK_ITEM_WRITE=true to enable.');
561
+ }
562
+ // Convert fields object to JSON Patch operations
563
+ const patchOperations = Object.keys(fields).map(field => ({
564
+ op: 'add',
565
+ path: `/fields/${field}`,
566
+ value: fields[field]
567
+ }));
568
+ const response = await this.makeRequest(`${project}/_apis/wit/workitems/$${workItemType}?api-version=${this.apiVersion}`, 'PATCH', patchOperations);
569
+ return {
570
+ id: response.id,
571
+ rev: response.rev,
572
+ fields: response.fields,
573
+ url: response._links?.html?.href,
574
+ project
575
+ };
576
+ }
577
+ /**
578
+ * Delete a work item
579
+ * @param project The project name
580
+ * @param workItemId The work item ID
581
+ * @returns Deletion confirmation
582
+ */
583
+ async deleteWorkItem(project, workItemId) {
584
+ this.validateProject(project);
585
+ if (!this.config.enableWorkItemDelete) {
586
+ throw new Error('Work item delete operations are disabled. Set AZUREDEVOPS_ENABLE_WORK_ITEM_DELETE=true to enable.');
587
+ }
588
+ await this.makeRequest(`${project}/_apis/wit/workitems/${workItemId}?api-version=${this.apiVersion}`, 'DELETE');
589
+ return {
590
+ workItemId,
591
+ project,
592
+ deleted: true
593
+ };
594
+ }
595
+ }
596
+ //# sourceMappingURL=AzureDevOpsService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AzureDevOpsService.js","sourceRoot":"","sources":["../src/AzureDevOpsService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @mcp-consultant-tools/azure-devops
4
+ *
5
+ * MCP server for Azure DevOps integration.
6
+ * Provides wikis, work items, and project management capabilities.
7
+ */
8
+ import { AzureDevOpsService } from "./AzureDevOpsService.js";
9
+ /**
10
+ * Register Azure DevOps tools and prompts to an MCP server
11
+ * @param server - The MCP server instance
12
+ * @param azureDevOpsService - Optional pre-configured AzureDevOpsService (for testing or custom configs)
13
+ */
14
+ export declare function registerAzureDevOpsTools(server: any, azureDevOpsService?: AzureDevOpsService): void;
15
+ /**
16
+ * Export service class for direct usage
17
+ */
18
+ export { AzureDevOpsService } from "./AzureDevOpsService.js";
19
+ export type { AzureDevOpsConfig } from "./AzureDevOpsService.js";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAIH,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,GAAG,EAAE,kBAAkB,CAAC,EAAE,kBAAkB,QAuC5F;AAED;;GAEG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC"}
package/build/index.js ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @mcp-consultant-tools/azure-devops
4
+ *
5
+ * MCP server for Azure DevOps integration.
6
+ * Provides wikis, work items, and project management capabilities.
7
+ */
8
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
+ import { createMcpServer, createEnvLoader } from "@mcp-consultant-tools/core";
10
+ import { AzureDevOpsService } from "./AzureDevOpsService.js";
11
+ /**
12
+ * Register Azure DevOps tools and prompts to an MCP server
13
+ * @param server - The MCP server instance
14
+ * @param azureDevOpsService - Optional pre-configured AzureDevOpsService (for testing or custom configs)
15
+ */
16
+ export function registerAzureDevOpsTools(server, azureDevOpsService) {
17
+ let service = azureDevOpsService || null;
18
+ function getAzureDevOpsService() {
19
+ if (!service) {
20
+ const missingConfig = [];
21
+ if (!process.env.AZUREDEVOPS_ORGANIZATION)
22
+ missingConfig.push("AZUREDEVOPS_ORGANIZATION");
23
+ if (!process.env.AZUREDEVOPS_PAT)
24
+ missingConfig.push("AZUREDEVOPS_PAT");
25
+ if (!process.env.AZUREDEVOPS_PROJECTS)
26
+ missingConfig.push("AZUREDEVOPS_PROJECTS");
27
+ if (missingConfig.length > 0) {
28
+ throw new Error(`Missing required Azure DevOps configuration: ${missingConfig.join(", ")}. ` +
29
+ `Set environment variables for organization, PAT, and allowed projects.`);
30
+ }
31
+ const config = {
32
+ organization: process.env.AZUREDEVOPS_ORGANIZATION,
33
+ pat: process.env.AZUREDEVOPS_PAT,
34
+ projects: process.env.AZUREDEVOPS_PROJECTS.split(",").map(p => p.trim()),
35
+ apiVersion: process.env.AZUREDEVOPS_API_VERSION || "7.1",
36
+ enableWorkItemWrite: process.env.AZUREDEVOPS_ENABLE_WORK_ITEM_WRITE === "true",
37
+ enableWorkItemDelete: process.env.AZUREDEVOPS_ENABLE_WORK_ITEM_DELETE === "true",
38
+ enableWikiWrite: process.env.AZUREDEVOPS_ENABLE_WIKI_WRITE === "true",
39
+ };
40
+ service = new AzureDevOpsService(config);
41
+ console.error("Azure DevOps service initialized");
42
+ }
43
+ return service;
44
+ }
45
+ // TODO: Extract and register all Azure DevOps tools here
46
+ // Tools include: wikis, work items, and search
47
+ // This will be filled during meta-package creation phase
48
+ console.error("Azure DevOps tools registered (tool extraction pending)");
49
+ }
50
+ /**
51
+ * Export service class for direct usage
52
+ */
53
+ export { AzureDevOpsService } from "./AzureDevOpsService.js";
54
+ /**
55
+ * Standalone CLI server (when run directly)
56
+ */
57
+ if (import.meta.url === `file://${process.argv[1]}`) {
58
+ const loadEnv = createEnvLoader();
59
+ loadEnv();
60
+ const server = createMcpServer({
61
+ name: "@mcp-consultant-tools/azure-devops",
62
+ version: "1.0.0",
63
+ capabilities: {
64
+ tools: {},
65
+ },
66
+ });
67
+ registerAzureDevOpsTools(server);
68
+ const transport = new StdioServerTransport();
69
+ server.connect(transport).catch((error) => {
70
+ console.error("Failed to start Azure DevOps MCP server:", error);
71
+ process.exit(1);
72
+ });
73
+ console.error("@mcp-consultant-tools/azure-devops server running on stdio");
74
+ }
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@mcp-consultant-tools/azure-devops",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Azure DevOps integration - wikis, work items, and project management",
5
+ "type": "module",
6
+ "main": "./build/index.js",
7
+ "types": "./build/index.d.ts",
8
+ "bin": {
9
+ "mcp-azuredevops": "./build/index.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./build/index.js",
14
+ "types": "./build/index.d.ts"
15
+ }
16
+ },
17
+ "files": [
18
+ "build",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "clean": "rm -rf build *.tsbuildinfo",
24
+ "prepublishOnly": "npm run build"
25
+ },
26
+ "keywords": [
27
+ "mcp",
28
+ "model-context-protocol",
29
+ "azure-devops",
30
+ "devops",
31
+ "wikis",
32
+ "work-items",
33
+ "azure"
34
+ ],
35
+ "author": "Michal Sobieraj",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/klemensms/mcp-consultant-tools.git",
40
+ "directory": "packages/azure-devops"
41
+ },
42
+ "engines": {
43
+ "node": ">=16.0.0"
44
+ },
45
+ "dependencies": {
46
+ "@mcp-consultant-tools/core": "^1.0.0",
47
+ "@modelcontextprotocol/sdk": "^1.0.4",
48
+ "axios": "^1.8.3",
49
+ "zod": "^3.24.1"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^22.10.5",
53
+ "typescript": "^5.8.2"
54
+ }
55
+ }