enhanced-ado-mcp-server
Version:
Enhanced ADO MCP Server - Azure DevOps work item management via Model Context Protocol with AI-powered tools, REST API integration, and intelligent automation
249 lines (204 loc) • 6.25 kB
Markdown
Patterns for building and querying work item hierarchies.
The most reliable approach is to query hierarchies level-by-level using `[System.Parent]`.
- ✅ Full ORDER BY support
- ✅ Different filters per level
- ✅ Better error handling
- ✅ Clear progress tracking
```sql
SELECT [System.Id]
FROM WorkItems
WHERE [System.AreaPath] UNDER 'MyProject\\MyArea'
AND [System.WorkItemType] IN ('Epic', 'Key Result')
AND ([System.Parent] = '' OR [System.Parent] IS NULL)
AND [System.State] NOT IN ('Removed', 'Done')
ORDER BY [System.Title]
```
### 2. Get Direct Children
```sql
SELECT [System.Id]
FROM WorkItems
WHERE [System.Parent] = 12345
AND [System.State] NOT IN ('Removed', 'Done')
ORDER BY [System.WorkItemType], [System.Title]
```
### 3. Build Tree Recursively
```javascript
async function buildHierarchy(parentId) {
// Get children
const children = await wiqlQuery({
WiqlQuery: `SELECT [System.Id] FROM WorkItems WHERE [System.Parent] = ${parentId}`,
IncludeFields: ["System.Title", "System.State", "System.WorkItemType", "System.Parent"]
});
// Recursively get their children
for (const child of children.workItems) {
child.children = await buildHierarchy(child.id);
}
return children.workItems;
}
```
```json
{
"wiqlQuery": "SELECT [System.Id] FROM WorkItems WHERE [System.AreaPath] UNDER 'MyProject\\MyArea' AND ([System.Parent] = '' OR [System.Parent] IS NULL) AND [System.State] NOT IN ('Removed', 'Done')",
"includeFields": ["System.Title", "System.State", "System.WorkItemType", "System.Parent"],
"maxResults": 100
}
```
```json
{
"wiqlQuery": "SELECT [System.Id] FROM WorkItems WHERE [System.Parent] = ${rootId}",
"includeFields": ["System.Title", "System.State", "System.WorkItemType", "System.Parent"],
"maxResults": 200
}
```
Repeat Step 2 for each child until no more children found.
```json
{
"workItemIds": [12345],
"includeParents": true,
"includeChildren": true,
"maxDepth": 5,
"includeRelationships": true,
"includeHistory": false
}
```
Tool: `wit-get-work-item-context-package`
```json
{
"workItemIds": [100, 101, 102],
"includeParent": true,
"includeChildren": true,
"includeExtendedFields": true
}
```
Tool: `wit-get-work-items-context-batch`
```json
{
"workItemIds": [100, 101, 102, 103]
}
```
Tool: `wit-validate-hierarchy`
**Returns:**
- Type compatibility (parent-child type rules)
- State consistency
- Orphaned items
- Circular references
## Finding Hierarchy Issues
### Find Orphaned Items
```sql
SELECT [System.Id]
FROM WorkItems
WHERE [System.AreaPath] UNDER 'MyProject'
AND [System.WorkItemType] IN ('Task', 'Product Backlog Item', 'Feature')
AND ([System.Parent] = '' OR [System.Parent] IS NULL)
AND [System.State] NOT IN ('Removed', 'Done')
ORDER BY [System.WorkItemType], [System.CreatedDate] DESC
```
### Find Items with Invalid Parents
```sql
-- First get all item IDs
SELECT [System.Id] FROM WorkItems WHERE [System.AreaPath] UNDER 'MyProject'
-- Then validate each item's parent exists
-- (Use wit-validate-hierarchy for automatic checking)
```
### Find Childless Parents
```sql
-- Get potential parents
SELECT [System.Id] FROM WorkItems
WHERE [System.WorkItemType] IN ('Epic', 'Feature')
AND [System.State] = 'Active'
-- For each, check if it has children
SELECT [System.Id] FROM WorkItems WHERE [System.Parent] = ${potentialParentId}
```
```sql
SELECT [System.Id]
FROM WorkItemLinks
WHERE [Source].[System.Id] = 12345
AND [System.Links.LinkType] = 'System.LinkTypes.Hierarchy-Forward'
MODE (Recursive)
```
**⚠️ Limitations:**
- No ORDER BY support
- Returns source/target pairs
- Complex result parsing
- Hard to filter on target fields
**Use Case:** When you need ALL descendants quickly and will sort in code.
```json
{
"includeFields": [
"System.Title",
"System.State",
"System.WorkItemType",
"System.Parent" // Essential for hierarchy
]
}
```
```sql
WHERE [System.State] NOT IN ('Removed', 'Done', 'Completed', 'Closed', 'Resolved')
```
### 3. Limit Recursion Depth
```javascript
async function buildHierarchy(parentId, maxDepth = 5, currentDepth = 0) {
if (currentDepth >= maxDepth) return [];
// ... continue recursion
}
```
```javascript
// Instead of querying one parent at a time
const parentIds = [100, 101, 102];
const allChildren = await Promise.all(
parentIds.map(id => getChildren(id))
);
```
```
Epic (no parent)
└─ Feature (parent: Epic)
└─ Product Backlog Item (parent: Feature)
└─ Task (parent: PBI)
```
### Key Result → Epic → Feature
```
Key Result (no parent)
└─ Epic (parent: Key Result)
└─ Feature (parent: Epic)
```
### Flat Structure
```
Product Backlog Item (no parent)
└─ Task (parent: PBI)
```
## Validation Rules
Common parent-child type rules:
- Epic can have: Feature, Product Backlog Item
- Feature can have: Product Backlog Item, Task
- Product Backlog Item can have: Task, Bug
- Task can have: (typically no children)
- Bug can have: Task
**Use `wit-validate-hierarchy` to check these automatically.**
## Performance Tips
1. **Query by level** rather than recursive WorkItemLinks
2. **Limit maxDepth** to avoid infinite loops
3. **Use MaxResults** to prevent huge datasets
4. **Cache parent lookups** to avoid duplicate queries
5. **Batch operations** when processing multiple hierarchies