mcp-consultant-tools 8.0.0 → 9.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.
- package/README.md +152 -6
- package/build/AzureDevOpsService.js +77 -27
- package/build/GitHubEnterpriseService.js +1100 -0
- package/build/index.js +1058 -0
- package/build/utils/ghe-formatters.js +330 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MCP Consultant Tools
|
|
2
2
|
|
|
3
|
-
A Model Context Protocol (MCP) server providing intelligent access to PowerPlatform/Dataverse, Azure DevOps, Figma, Azure Application Insights, Azure Log Analytics,
|
|
3
|
+
A Model Context Protocol (MCP) server providing intelligent access to PowerPlatform/Dataverse, Azure DevOps, Figma, Azure Application Insights, Azure Log Analytics, Azure SQL Database, and GitHub Enterprise through an AI-friendly interface.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
@@ -18,10 +18,11 @@ This MCP server enables AI assistants to:
|
|
|
18
18
|
- **Application Insights** (10 tools): Query telemetry, analyze exceptions, monitor performance, troubleshoot issues
|
|
19
19
|
- **Log Analytics** (10 tools): Query Azure Functions logs, analyze errors, monitor function performance, search workspace logs
|
|
20
20
|
- **Azure SQL Database** (9 tools): Explore database schema, query tables safely with read-only access, investigate database structure
|
|
21
|
+
- **GitHub Enterprise** (22 tools): Access source code, commits, branches, pull requests, correlate with deployed plugins and ADO work items
|
|
21
22
|
|
|
22
23
|
All integrations are **optional** - configure only the services you need.
|
|
23
24
|
|
|
24
|
-
**Total:
|
|
25
|
+
**Total: 138 MCP tools & 28 prompts** providing comprehensive access to your development and operations lifecycle.
|
|
25
26
|
|
|
26
27
|
## Known limitations
|
|
27
28
|
- Cannot create Model-Driven-Apps
|
|
@@ -92,7 +93,16 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
|
|
|
92
93
|
"AZURE_SQL_DATABASE": "yourdatabase",
|
|
93
94
|
"AZURE_SQL_USERNAME": "your-username",
|
|
94
95
|
"AZURE_SQL_PASSWORD": "your-password",
|
|
95
|
-
"AZURE_SQL_USE_AZURE_AD": "false"
|
|
96
|
+
"AZURE_SQL_USE_AZURE_AD": "false",
|
|
97
|
+
|
|
98
|
+
"GHE_URL": "https://github.yourcompany.com",
|
|
99
|
+
"GHE_PAT": "ghp_your_personal_access_token",
|
|
100
|
+
"GHE_AUTH_METHOD": "pat",
|
|
101
|
+
"GHE_REPOS": "[{\"id\":\"plugin-core\",\"owner\":\"yourorg\",\"repo\":\"PluginCore\",\"defaultBranch\":\"release/9.0\",\"active\":true}]",
|
|
102
|
+
"GHE_ENABLE_CACHE": "true",
|
|
103
|
+
"GHE_CACHE_TTL": "300",
|
|
104
|
+
"GHE_ENABLE_WRITE": "false",
|
|
105
|
+
"GHE_ENABLE_CREATE": "false"
|
|
96
106
|
}
|
|
97
107
|
}
|
|
98
108
|
}
|
|
@@ -147,7 +157,16 @@ Create `.vscode/mcp.json` in your project:
|
|
|
147
157
|
"AZURE_SQL_DATABASE": "yourdatabase",
|
|
148
158
|
"AZURE_SQL_USERNAME": "your-username",
|
|
149
159
|
"AZURE_SQL_PASSWORD": "your-password",
|
|
150
|
-
"AZURE_SQL_USE_AZURE_AD": "false"
|
|
160
|
+
"AZURE_SQL_USE_AZURE_AD": "false",
|
|
161
|
+
|
|
162
|
+
"GHE_URL": "https://github.yourcompany.com",
|
|
163
|
+
"GHE_PAT": "ghp_your_personal_access_token",
|
|
164
|
+
"GHE_AUTH_METHOD": "pat",
|
|
165
|
+
"GHE_REPOS": "[{\"id\":\"plugin-core\",\"owner\":\"yourorg\",\"repo\":\"PluginCore\",\"defaultBranch\":\"release/9.0\",\"active\":true}]",
|
|
166
|
+
"GHE_ENABLE_CACHE": "true",
|
|
167
|
+
"GHE_CACHE_TTL": "300",
|
|
168
|
+
"GHE_ENABLE_WRITE": "false",
|
|
169
|
+
"GHE_ENABLE_CREATE": "false"
|
|
151
170
|
}
|
|
152
171
|
}
|
|
153
172
|
}
|
|
@@ -291,9 +310,70 @@ Reload VS Code window after saving.
|
|
|
291
310
|
- `appinsights-get-availability` - Get availability test results and uptime stats
|
|
292
311
|
- `appinsights-get-custom-events` - Get custom application events
|
|
293
312
|
|
|
313
|
+
### Log Analytics (10 tools)
|
|
314
|
+
|
|
315
|
+
- `loganalytics-list-workspaces` - List all configured Log Analytics workspaces
|
|
316
|
+
- `loganalytics-get-metadata` - Get workspace schema (tables and columns)
|
|
317
|
+
- `loganalytics-execute-query` - Execute custom KQL queries
|
|
318
|
+
- `loganalytics-get-function-logs` - Get Azure Function logs with filtering
|
|
319
|
+
- `loganalytics-get-function-errors` - Get function error logs with exception details
|
|
320
|
+
- `loganalytics-get-function-stats` - Get execution statistics (count, success rate)
|
|
321
|
+
- `loganalytics-get-function-invocations` - Get function invocation records
|
|
322
|
+
- `loganalytics-get-recent-events` - Get recent events from any table
|
|
323
|
+
- `loganalytics-search-logs` - Search logs across tables
|
|
324
|
+
- `loganalytics-test-workspace-access` - Validate workspace access
|
|
325
|
+
|
|
326
|
+
### Azure SQL Database (9 tools)
|
|
327
|
+
|
|
328
|
+
- `sql-test-connection` - Test database connectivity
|
|
329
|
+
- `sql-list-tables` - List all tables with row counts and sizes
|
|
330
|
+
- `sql-list-views` - List all views
|
|
331
|
+
- `sql-list-stored-procedures` - List all stored procedures
|
|
332
|
+
- `sql-list-triggers` - List all triggers
|
|
333
|
+
- `sql-list-functions` - List all user-defined functions
|
|
334
|
+
- `sql-get-table-schema` - Get complete table schema (columns, indexes, FKs)
|
|
335
|
+
- `sql-get-object-definition` - Get SQL definition for views, procedures, functions, triggers
|
|
336
|
+
- `sql-execute-query` - Execute SELECT queries safely with validation
|
|
337
|
+
|
|
338
|
+
### GitHub Enterprise (22 tools)
|
|
339
|
+
|
|
340
|
+
**Repository & Branch Management:**
|
|
341
|
+
- `ghe-list-repos` - List all configured repositories
|
|
342
|
+
- `ghe-list-branches` - List all branches for a repository
|
|
343
|
+
- `ghe-get-default-branch` - Auto-detect default branch with typo handling
|
|
344
|
+
- `ghe-get-branch-details` - Get detailed branch information
|
|
345
|
+
- `ghe-compare-branches` - Compare two branches and show differences
|
|
346
|
+
- `ghe-search-repos` - Search repositories by name or description
|
|
347
|
+
|
|
348
|
+
**File Operations:**
|
|
349
|
+
- `ghe-get-file` - Get file content from a specific branch
|
|
350
|
+
- `ghe-search-code` - Search code across repositories
|
|
351
|
+
- `ghe-list-files` - List files in a directory
|
|
352
|
+
- `ghe-get-directory-structure` - Get recursive directory tree structure
|
|
353
|
+
- `ghe-get-file-history` - Get commit history for a specific file
|
|
354
|
+
|
|
355
|
+
**Commit & History:**
|
|
356
|
+
- `ghe-get-commits` - Get commit history for a branch
|
|
357
|
+
- `ghe-get-commit-details` - Get detailed information about a specific commit
|
|
358
|
+
- `ghe-search-commits` - Search commits by message or hash (supports #1234 work item refs)
|
|
359
|
+
- `ghe-get-commit-diff` - Get detailed diff for a commit
|
|
360
|
+
|
|
361
|
+
**Pull Requests:**
|
|
362
|
+
- `ghe-list-pull-requests` - List pull requests for a repository
|
|
363
|
+
- `ghe-get-pull-request` - Get detailed pull request information
|
|
364
|
+
- `ghe-get-pr-files` - Get files changed in a pull request
|
|
365
|
+
|
|
366
|
+
**Write Operations (disabled by default):**
|
|
367
|
+
- `ghe-create-branch` - Create a new branch (requires GHE_ENABLE_CREATE=true)
|
|
368
|
+
- `ghe-update-file` - Update file content (requires GHE_ENABLE_WRITE=true)
|
|
369
|
+
- `ghe-create-file` - Create a new file (requires GHE_ENABLE_CREATE=true)
|
|
370
|
+
|
|
371
|
+
**Cache Management:**
|
|
372
|
+
- `ghe-clear-cache` - Clear cached GitHub API responses
|
|
373
|
+
|
|
294
374
|
## Available Prompts
|
|
295
375
|
|
|
296
|
-
The server includes **
|
|
376
|
+
The server includes **28 prompts** that provide formatted, context-rich output:
|
|
297
377
|
|
|
298
378
|
**PowerPlatform:**
|
|
299
379
|
- `entity-overview` - Comprehensive entity overview
|
|
@@ -319,15 +399,42 @@ The server includes **18 prompts** that provide formatted, context-rich output:
|
|
|
319
399
|
- `appinsights-availability-report` - Availability and uptime report
|
|
320
400
|
- `appinsights-troubleshooting-guide` - Comprehensive troubleshooting guide combining all telemetry
|
|
321
401
|
|
|
402
|
+
**Log Analytics:**
|
|
403
|
+
- `loganalytics-workspace-summary` - Workspace health overview with all functions
|
|
404
|
+
- `loganalytics-function-troubleshooting` - Comprehensive function troubleshooting report
|
|
405
|
+
- `loganalytics-function-performance-report` - Performance analysis with recommendations
|
|
406
|
+
- `loganalytics-logs-report` - Formatted logs with insights for any table
|
|
407
|
+
|
|
322
408
|
**Azure SQL Database:**
|
|
323
409
|
- `sql-database-overview` - Comprehensive database schema overview with all objects
|
|
324
410
|
- `sql-table-details` - Detailed table report with columns, indexes, and relationships
|
|
325
411
|
- `sql-query-results` - Formatted query results with column headers
|
|
326
412
|
|
|
413
|
+
**GitHub Enterprise:**
|
|
414
|
+
- `ghe-repo-overview` - Repository overview with branch analysis and recent commits
|
|
415
|
+
- `ghe-code-search-report` - Formatted code search results with relevance scoring
|
|
416
|
+
- `ghe-branch-comparison-report` - Branch comparison with deployment checklist
|
|
417
|
+
- `ghe-troubleshooting-guide` - Bug troubleshooting with cross-service correlation (ADO + GHE + PowerPlatform)
|
|
418
|
+
- `ghe-deployment-report` - Deployment-ready report with rollback plan
|
|
419
|
+
|
|
327
420
|
## Documentation
|
|
328
421
|
|
|
422
|
+
### Per-Integration Documentation
|
|
423
|
+
|
|
424
|
+
Comprehensive documentation for each integration with setup, tools, prompts, examples, best practices, and troubleshooting:
|
|
425
|
+
|
|
426
|
+
- **[PowerPlatform/Dataverse](docs/documentation/POWERPLATFORM.md)** - 76 tools, 9 prompts (entity metadata, plugins, workflows, customization API)
|
|
427
|
+
- **[Azure DevOps](docs/documentation/AZURE_DEVOPS.md)** - 11 tools, 4 prompts (wikis, work items, WIQL queries)
|
|
428
|
+
- **[Figma](docs/documentation/FIGMA.md)** - 2 tools (design data extraction, AI-friendly format)
|
|
429
|
+
- **[Application Insights](docs/documentation/APPLICATION_INSIGHTS.md)** - 10 tools, 5 prompts (telemetry, exceptions, performance, dependencies)
|
|
430
|
+
- **[Log Analytics](docs/documentation/LOG_ANALYTICS.md)** - 10 tools, 5 prompts (Azure Functions logs, KQL queries, function diagnostics)
|
|
431
|
+
- **[Azure SQL Database](docs/documentation/AZURE_SQL.md)** - 9 tools, 3 prompts (schema exploration, read-only querying)
|
|
432
|
+
- **[GitHub Enterprise](docs/documentation/GITHUB_ENTERPRISE.md)** - 22 tools, 5 prompts (source code, commits, branches, PRs, code correlation)
|
|
433
|
+
|
|
434
|
+
### General Documentation
|
|
435
|
+
|
|
329
436
|
- **[SETUP.md](SETUP.md)** - Complete setup guide with credentials, troubleshooting, and security
|
|
330
|
-
- **[TOOLS.md](TOOLS.md)** - Full reference for all
|
|
437
|
+
- **[TOOLS.md](TOOLS.md)** - Full reference for all 138 tools and 28 prompts
|
|
331
438
|
- **[USAGE.md](USAGE.md)** - Examples and use cases for all integrations
|
|
332
439
|
- **[CLAUDE.md](CLAUDE.md)** - Architecture details and development guide
|
|
333
440
|
|
|
@@ -429,6 +536,20 @@ All integrations are optional and can be configured independently:
|
|
|
429
536
|
- Read-only access to telemetry data
|
|
430
537
|
- Entra ID recommended for production (higher rate limits)
|
|
431
538
|
|
|
539
|
+
**Log Analytics:**
|
|
540
|
+
- Supports Entra ID (OAuth) or API Key authentication
|
|
541
|
+
- Read-only access to workspace logs
|
|
542
|
+
- Can share credentials with Application Insights (automatic fallback)
|
|
543
|
+
- Entra ID recommended for production (higher rate limits)
|
|
544
|
+
|
|
545
|
+
**GitHub Enterprise:**
|
|
546
|
+
- Supports Personal Access Token (PAT) or GitHub App authentication
|
|
547
|
+
- PAT authentication is simpler (recommended for individual use)
|
|
548
|
+
- GitHub App authentication for organization-wide deployments (higher rate limits)
|
|
549
|
+
- Write operations disabled by default (enable with environment flags)
|
|
550
|
+
- Response caching with configurable TTL (default: 5 minutes)
|
|
551
|
+
- Required scopes for PAT: `repo` (required), `read:org` (optional)
|
|
552
|
+
|
|
432
553
|
See [SETUP.md](SETUP.md#security-best-practices) for security best practices.
|
|
433
554
|
|
|
434
555
|
## Examples
|
|
@@ -479,6 +600,31 @@ AI: [uses sql-execute-query tool with "SELECT TOP 10 * FROM dbo.Users WHERE IsAc
|
|
|
479
600
|
Returns formatted query results with column headers
|
|
480
601
|
```
|
|
481
602
|
|
|
603
|
+
### Troubleshoot bugs with GitHub Enterprise cross-service correlation
|
|
604
|
+
|
|
605
|
+
```
|
|
606
|
+
User: "Investigate bug reported in ADO work item #1234"
|
|
607
|
+
AI: [uses ghe-troubleshooting-guide prompt]
|
|
608
|
+
1. Gets work item details from Azure DevOps
|
|
609
|
+
2. Searches GitHub commits for "AB#1234" references
|
|
610
|
+
3. Retrieves changed code files
|
|
611
|
+
4. Checks deployed plugin assembly in PowerPlatform
|
|
612
|
+
5. Analyzes Application Insights exceptions
|
|
613
|
+
Returns comprehensive troubleshooting report with code changes, deployment status, and runtime errors
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
```
|
|
617
|
+
User: "Search GitHub for ContactPlugin implementation"
|
|
618
|
+
AI: [uses ghe-search-code tool]
|
|
619
|
+
Returns code search results with file paths and line numbers
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
```
|
|
623
|
+
User: "Compare release/9.0 and main branches"
|
|
624
|
+
AI: [uses ghe-branch-comparison-report prompt]
|
|
625
|
+
Returns formatted comparison with deployment checklist
|
|
626
|
+
```
|
|
627
|
+
|
|
482
628
|
See [USAGE.md](USAGE.md) for more examples.
|
|
483
629
|
|
|
484
630
|
## Development
|
|
@@ -30,7 +30,7 @@ export class AzureDevOpsService {
|
|
|
30
30
|
/**
|
|
31
31
|
* Make an authenticated request to the Azure DevOps API
|
|
32
32
|
*/
|
|
33
|
-
async makeRequest(endpoint, method = 'GET', data, useSearchUrl = false) {
|
|
33
|
+
async makeRequest(endpoint, method = 'GET', data, useSearchUrl = false, customHeaders) {
|
|
34
34
|
try {
|
|
35
35
|
const baseUrl = useSearchUrl ? this.searchUrl : this.baseUrl;
|
|
36
36
|
const url = `${baseUrl}/${endpoint}`;
|
|
@@ -40,7 +40,8 @@ export class AzureDevOpsService {
|
|
|
40
40
|
headers: {
|
|
41
41
|
'Authorization': this.authHeader,
|
|
42
42
|
'Content-Type': method === 'PATCH' ? 'application/json-patch+json' : 'application/json',
|
|
43
|
-
'Accept': 'application/json'
|
|
43
|
+
'Accept': 'application/json',
|
|
44
|
+
...customHeaders // Merge custom headers (can override defaults)
|
|
44
45
|
},
|
|
45
46
|
data
|
|
46
47
|
});
|
|
@@ -158,33 +159,67 @@ export class AzureDevOpsService {
|
|
|
158
159
|
*/
|
|
159
160
|
async getWikiPage(project, wikiId, pagePath, includeContent = true) {
|
|
160
161
|
this.validateProject(project);
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
162
|
+
// Always normalize paths to wiki format (removes .md, converts dashes to spaces)
|
|
163
|
+
// This ensures consistent behavior regardless of input format
|
|
164
|
+
const wikiPath = this.convertGitPathToWikiPath(pagePath);
|
|
165
|
+
// Log conversion if the path was changed (for debugging)
|
|
166
|
+
if (wikiPath !== pagePath) {
|
|
167
|
+
console.error(`Normalized wiki path: ${pagePath} -> ${wikiPath}`);
|
|
168
|
+
}
|
|
169
|
+
// Use axios directly to access response headers (for ETag)
|
|
170
|
+
const url = `${this.baseUrl}/${project}/_apis/wiki/wikis/${wikiId}/pages?path=${encodeURIComponent(wikiPath)}&includeContent=${includeContent}&api-version=${this.apiVersion}`;
|
|
171
|
+
try {
|
|
172
|
+
const axiosResponse = await axios({
|
|
173
|
+
method: 'GET',
|
|
174
|
+
url,
|
|
175
|
+
headers: {
|
|
176
|
+
'Authorization': this.authHeader,
|
|
177
|
+
'Content-Type': 'application/json',
|
|
178
|
+
'Accept': 'application/json'
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
const response = axiosResponse.data;
|
|
182
|
+
// Extract ETag from response headers (needed for updates)
|
|
183
|
+
const etag = axiosResponse.headers['etag'] || axiosResponse.headers['ETag'];
|
|
184
|
+
// The API returns the page data directly (not wrapped in a 'page' property)
|
|
185
|
+
return {
|
|
186
|
+
id: response.id,
|
|
187
|
+
path: response.path,
|
|
188
|
+
content: response.content,
|
|
189
|
+
gitItemPath: response.gitItemPath,
|
|
190
|
+
subPages: response.subPages || [],
|
|
191
|
+
url: response.url,
|
|
192
|
+
remoteUrl: response.remoteUrl,
|
|
193
|
+
version: etag, // Include ETag for use with updateWikiPage
|
|
194
|
+
project,
|
|
195
|
+
wikiId
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
// Handle errors similar to makeRequest
|
|
200
|
+
const errorDetails = error.response?.data?.message || error.response?.data || error.message;
|
|
201
|
+
console.error('Azure DevOps API request failed:', {
|
|
202
|
+
url,
|
|
203
|
+
status: error.response?.status,
|
|
204
|
+
error: errorDetails
|
|
205
|
+
});
|
|
206
|
+
if (error.response?.status === 401) {
|
|
207
|
+
throw new Error('Azure DevOps authentication failed. Please check your PAT token and permissions.');
|
|
208
|
+
}
|
|
209
|
+
if (error.response?.status === 403) {
|
|
210
|
+
throw new Error('Azure DevOps access denied. Please check your PAT scopes and project permissions.');
|
|
211
|
+
}
|
|
212
|
+
if (error.response?.status === 404) {
|
|
213
|
+
throw new Error(`Wiki page not found: ${wikiPath} (original input: ${pagePath})`);
|
|
214
|
+
}
|
|
215
|
+
throw new Error(`Azure DevOps API request failed: ${error.message} - ${JSON.stringify(errorDetails)}`);
|
|
168
216
|
}
|
|
169
|
-
const response = await this.makeRequest(`${project}/_apis/wiki/wikis/${wikiId}/pages?path=${encodeURIComponent(wikiPath)}&includeContent=${includeContent}&api-version=${this.apiVersion}`);
|
|
170
|
-
// The API returns the page data directly (not wrapped in a 'page' property)
|
|
171
|
-
return {
|
|
172
|
-
id: response.id,
|
|
173
|
-
path: response.path,
|
|
174
|
-
content: response.content,
|
|
175
|
-
gitItemPath: response.gitItemPath,
|
|
176
|
-
subPages: response.subPages || [],
|
|
177
|
-
url: response.url,
|
|
178
|
-
remoteUrl: response.remoteUrl,
|
|
179
|
-
project,
|
|
180
|
-
wikiId
|
|
181
|
-
};
|
|
182
217
|
}
|
|
183
218
|
/**
|
|
184
219
|
* Create a new wiki page
|
|
185
220
|
* @param project The project name
|
|
186
221
|
* @param wikiId The wiki identifier
|
|
187
|
-
* @param pagePath The path for the new page
|
|
222
|
+
* @param pagePath The path for the new page (will be normalized to wiki format)
|
|
188
223
|
* @param content The markdown content
|
|
189
224
|
* @returns Created page information
|
|
190
225
|
*/
|
|
@@ -193,7 +228,13 @@ export class AzureDevOpsService {
|
|
|
193
228
|
if (!this.config.enableWikiWrite) {
|
|
194
229
|
throw new Error('Wiki write operations are disabled. Set AZUREDEVOPS_ENABLE_WIKI_WRITE=true to enable.');
|
|
195
230
|
}
|
|
196
|
-
|
|
231
|
+
// Always normalize paths to wiki format (removes .md, converts dashes to spaces)
|
|
232
|
+
const wikiPath = this.convertGitPathToWikiPath(pagePath);
|
|
233
|
+
// Log conversion if the path was changed (for debugging)
|
|
234
|
+
if (wikiPath !== pagePath) {
|
|
235
|
+
console.error(`Normalized wiki path for creation: ${pagePath} -> ${wikiPath}`);
|
|
236
|
+
}
|
|
237
|
+
const response = await this.makeRequest(`${project}/_apis/wiki/wikis/${wikiId}/pages?path=${encodeURIComponent(wikiPath)}&api-version=${this.apiVersion}`, 'PUT', { content });
|
|
197
238
|
return {
|
|
198
239
|
id: response.page?.id,
|
|
199
240
|
path: response.page?.path,
|
|
@@ -206,9 +247,9 @@ export class AzureDevOpsService {
|
|
|
206
247
|
* Update an existing wiki page
|
|
207
248
|
* @param project The project name
|
|
208
249
|
* @param wikiId The wiki identifier
|
|
209
|
-
* @param pagePath The path to the page
|
|
250
|
+
* @param pagePath The path to the page (will be normalized to wiki format)
|
|
210
251
|
* @param content The updated markdown content
|
|
211
|
-
* @param version The ETag/version for optimistic concurrency
|
|
252
|
+
* @param version The ETag/version for optimistic concurrency (recommended to prevent conflicts)
|
|
212
253
|
* @returns Updated page information
|
|
213
254
|
*/
|
|
214
255
|
async updateWikiPage(project, wikiId, pagePath, content, version) {
|
|
@@ -216,7 +257,16 @@ export class AzureDevOpsService {
|
|
|
216
257
|
if (!this.config.enableWikiWrite) {
|
|
217
258
|
throw new Error('Wiki write operations are disabled. Set AZUREDEVOPS_ENABLE_WIKI_WRITE=true to enable.');
|
|
218
259
|
}
|
|
219
|
-
|
|
260
|
+
// Always normalize paths to wiki format (removes .md, converts dashes to spaces)
|
|
261
|
+
const wikiPath = this.convertGitPathToWikiPath(pagePath);
|
|
262
|
+
// Log conversion if the path was changed (for debugging)
|
|
263
|
+
if (wikiPath !== pagePath) {
|
|
264
|
+
console.error(`Normalized wiki path for update: ${pagePath} -> ${wikiPath}`);
|
|
265
|
+
}
|
|
266
|
+
// Add If-Match header if version is provided (for optimistic concurrency control)
|
|
267
|
+
const customHeaders = version ? { 'If-Match': version } : undefined;
|
|
268
|
+
const response = await this.makeRequest(`${project}/_apis/wiki/wikis/${wikiId}/pages?path=${encodeURIComponent(wikiPath)}&api-version=${this.apiVersion}`, 'PUT', { content }, false, // useSearchUrl
|
|
269
|
+
customHeaders);
|
|
220
270
|
return {
|
|
221
271
|
id: response.page?.id,
|
|
222
272
|
path: response.page?.path,
|