cursor-azure-devops-mcp
Advanced tools
Comparing version
@@ -217,2 +217,77 @@ import * as azdev from 'azure-devops-node-api'; | ||
/** | ||
* Get all links associated with a work item (parent, child, related, etc.) | ||
* @param workItemId The ID of the work item | ||
* @returns Object with work item links grouped by relationship type | ||
*/ | ||
async getWorkItemLinks(workItemId) { | ||
await this.initialize(); | ||
if (!this.workItemClient) { | ||
throw new Error('Work item client not initialized'); | ||
} | ||
// Get work item with relations | ||
const workItem = await this.workItemClient.getWorkItem(workItemId, undefined, undefined, 4 // 4 = WorkItemExpand.Relations in the SDK | ||
); | ||
if (!workItem || !workItem.relations) { | ||
return {}; | ||
} | ||
// Filter for work item link relations (exclude attachments and hyperlinks) | ||
const linkRelations = workItem.relations.filter((relation) => relation.rel.includes('Link') && | ||
relation.rel !== 'AttachedFile' && | ||
relation.rel !== 'Hyperlink'); | ||
// Group relations by relationship type | ||
const groupedRelations = {}; | ||
linkRelations.forEach((relation) => { | ||
const relType = relation.rel; | ||
// Extract work item ID from URL | ||
// URL format is typically like: https://dev.azure.com/{org}/{project}/_apis/wit/workItems/{id} | ||
let targetId = 0; | ||
try { | ||
const urlParts = relation.url.split('/'); | ||
targetId = parseInt(urlParts[urlParts.length - 1], 10); | ||
} | ||
catch (error) { | ||
console.error('Failed to extract work item ID from URL:', relation.url); | ||
} | ||
if (!groupedRelations[relType]) { | ||
groupedRelations[relType] = []; | ||
} | ||
const workItemLink = { | ||
...relation, | ||
targetId, | ||
title: relation.attributes?.name || `Work Item ${targetId}`, | ||
}; | ||
groupedRelations[relType].push(workItemLink); | ||
}); | ||
return groupedRelations; | ||
} | ||
/** | ||
* Get all linked work items with their full details | ||
* @param workItemId The ID of the work item to get links from | ||
* @returns Array of work items that are linked to the specified work item | ||
*/ | ||
async getLinkedWorkItems(workItemId) { | ||
await this.initialize(); | ||
if (!this.workItemClient) { | ||
throw new Error('Work item client not initialized'); | ||
} | ||
// First get all links | ||
const linkGroups = await this.getWorkItemLinks(workItemId); | ||
// Extract all target IDs from all link groups | ||
const linkedIds = []; | ||
Object.values(linkGroups).forEach(links => { | ||
links.forEach(link => { | ||
if (link.targetId > 0) { | ||
linkedIds.push(link.targetId); | ||
} | ||
}); | ||
}); | ||
// If no linked items found, return empty array | ||
if (linkedIds.length === 0) { | ||
return []; | ||
} | ||
// Get the full work item details for all linked items | ||
const linkedWorkItems = await this.getWorkItems(linkedIds); | ||
return linkedWorkItems; | ||
} | ||
/** | ||
* Get detailed changes for a pull request | ||
@@ -219,0 +294,0 @@ */ |
@@ -350,2 +350,30 @@ #!/usr/bin/env node | ||
}); | ||
// New tool for work item links | ||
server.tool('azure_devops_work_item_links', 'Get links for a specific work item', { | ||
id: z.number().describe('Work item ID'), | ||
}, async ({ id }) => { | ||
const result = await azureDevOpsService.getWorkItemLinks(id); | ||
return { | ||
content: [ | ||
{ | ||
type: 'text', | ||
text: JSON.stringify(result, null, 2), | ||
}, | ||
], | ||
}; | ||
}); | ||
// New tool for linked work items with full details | ||
server.tool('azure_devops_linked_work_items', 'Get all linked work items with their full details', { | ||
id: z.number().describe('Work item ID'), | ||
}, async ({ id }) => { | ||
const result = await azureDevOpsService.getLinkedWorkItems(id); | ||
return { | ||
content: [ | ||
{ | ||
type: 'text', | ||
text: JSON.stringify(result, null, 2), | ||
}, | ||
], | ||
}; | ||
}); | ||
// New tool for pull request changes with file contents | ||
@@ -550,2 +578,4 @@ server.tool('azure_devops_pull_request_changes', 'Get detailed code changes for a pull request', { | ||
console.error('- azure_devops_work_item_attachments: Get attachments for a work item'); | ||
console.error('- azure_devops_work_item_links: Get links for a work item'); | ||
console.error('- azure_devops_linked_work_items: Get all linked work items with their full details'); | ||
console.error('- azure_devops_pull_request_changes: Get detailed code changes for a pull request'); | ||
@@ -552,0 +582,0 @@ console.error('- azure_devops_pull_request_file_content: Get content of a specific file in chunks (for large files)'); |
@@ -160,2 +160,30 @@ #!/usr/bin/env node | ||
}); | ||
// New tool for work item links | ||
server.tool('azure_devops_work_item_links', 'Get links for a specific work item', { | ||
id: z.number().describe('Work item ID'), | ||
}, async ({ id }) => { | ||
const result = await azureDevOpsService.getWorkItemLinks(id); | ||
return { | ||
content: [ | ||
{ | ||
type: 'text', | ||
text: JSON.stringify(result, null, 2), | ||
}, | ||
], | ||
}; | ||
}); | ||
// New tool for linked work items with full details | ||
server.tool('azure_devops_linked_work_items', 'Get all linked work items with their full details', { | ||
id: z.number().describe('Work item ID'), | ||
}, async ({ id }) => { | ||
const result = await azureDevOpsService.getLinkedWorkItems(id); | ||
return { | ||
content: [ | ||
{ | ||
type: 'text', | ||
text: JSON.stringify(result, null, 2), | ||
}, | ||
], | ||
}; | ||
}); | ||
// New tool for pull request changes with file contents | ||
@@ -162,0 +190,0 @@ server.tool('azure_devops_pull_request_changes', 'Get detailed code changes for a pull request', { |
{ | ||
"name": "cursor-azure-devops-mcp", | ||
"version": "1.0.5", | ||
"version": "1.0.6", | ||
"description": "MCP Server for Cursor IDE-Azure DevOps Integration", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
115222
4.81%2396
5.88%