manage_work_item_link
Add, remove, or update links between work items in Azure DevOps projects using specified relation types, enabling structured task dependencies and workflows.
Instructions
Add or remove a link between work items
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| comment | No | Optional comment explaining the link | |
| newRelationType | No | The new relation type to use when updating a link | |
| operation | Yes | The operation to perform on the link | |
| projectId | Yes | The ID or name of the project | |
| relationType | Yes | The reference name of the relation type (e.g., "System.LinkTypes.Hierarchy-Forward") | |
| sourceWorkItemId | Yes | The ID of the source work item | |
| targetWorkItemId | Yes | The ID of the target work item |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"comment": {
"description": "Optional comment explaining the link",
"type": "string"
},
"newRelationType": {
"description": "The new relation type to use when updating a link",
"type": "string"
},
"operation": {
"description": "The operation to perform on the link",
"enum": [
"add",
"remove",
"update"
],
"type": "string"
},
"projectId": {
"description": "The ID or name of the project",
"type": "string"
},
"relationType": {
"description": "The reference name of the relation type (e.g., \"System.LinkTypes.Hierarchy-Forward\")",
"type": "string"
},
"sourceWorkItemId": {
"description": "The ID of the source work item",
"type": "number"
},
"targetWorkItemId": {
"description": "The ID of the target work item",
"type": "number"
}
},
"required": [
"sourceWorkItemId",
"targetWorkItemId",
"projectId",
"operation",
"relationType"
],
"type": "object"
}
Implementation Reference
- The core handler function that implements the logic to add, remove, or update links between work items using the Azure DevOps Work Item Tracking API.export async function manageWorkItemLink( connection: WebApi, projectId: string, options: ManageWorkItemLinkOptions, ): Promise<WorkItem> { try { const { sourceWorkItemId, targetWorkItemId, operation, relationType, newRelationType, comment, } = options; // Input validation if (!sourceWorkItemId) { throw new Error('Source work item ID is required'); } if (!targetWorkItemId) { throw new Error('Target work item ID is required'); } if (!relationType) { throw new Error('Relation type is required'); } if (operation === 'update' && !newRelationType) { throw new Error('New relation type is required for update operation'); } const witApi = await connection.getWorkItemTrackingApi(); // Create the JSON patch document const document = []; // Construct the relationship URL const relationshipUrl = `${connection.serverUrl}/_apis/wit/workItems/${targetWorkItemId}`; if (operation === 'add' || operation === 'update') { // For 'update', we'll first remove the old link, then add the new one if (operation === 'update') { document.push({ op: 'remove', path: `/relations/+[rel=${relationType};url=${relationshipUrl}]`, }); } // Add the new relationship document.push({ op: 'add', path: '/relations/-', value: { rel: operation === 'update' ? newRelationType : relationType, url: relationshipUrl, ...(comment ? { attributes: { comment } } : {}), }, }); } else if (operation === 'remove') { // Remove the relationship document.push({ op: 'remove', path: `/relations/+[rel=${relationType};url=${relationshipUrl}]`, }); } // Update the work item with the new relationship const updatedWorkItem = await witApi.updateWorkItem( {}, // customHeaders document, sourceWorkItemId, projectId, ); if (!updatedWorkItem) { throw new AzureDevOpsResourceNotFoundError( `Work item '${sourceWorkItemId}' not found`, ); } return updatedWorkItem; } catch (error) { if (error instanceof AzureDevOpsError) { throw error; } throw new Error( `Failed to manage work item link: ${error instanceof Error ? error.message : String(error)}`, ); } }
- Zod schema defining the input validation for the manage_work_item_link tool parameters.export const ManageWorkItemLinkSchema = z.object({ sourceWorkItemId: z.number().describe('The ID of the source work item'), targetWorkItemId: z.number().describe('The ID of the target work item'), projectId: z .string() .optional() .describe(`The ID or name of the project (Default: ${defaultProject})`), organizationId: z .string() .optional() .describe(`The ID or name of the organization (Default: ${defaultOrg})`), operation: z .enum(['add', 'remove', 'update']) .describe('The operation to perform on the link'), relationType: z .string() .describe( 'The reference name of the relation type (e.g., "System.LinkTypes.Hierarchy-Forward")', ), newRelationType: z .string() .optional() .describe('The new relation type to use when updating a link'), comment: z .string() .optional() .describe('Optional comment explaining the link'), });
- src/features/work-items/tool-definitions.ts:36-39 (registration)MCP tool registration/definition including the tool name, description, and converted JSON schema for input.name: 'manage_work_item_link', description: 'Add or remove links between work items', inputSchema: zodToJsonSchema(ManageWorkItemLinkSchema), },
- src/features/work-items/index.ts:127-144 (registration)Dispatcher/registration in the work-items request handler that validates input with schema and invokes the manageWorkItemLink handler.case 'manage_work_item_link': { const args = ManageWorkItemLinkSchema.parse(request.params.arguments); const result = await manageWorkItemLink( connection, args.projectId ?? defaultProject, { sourceWorkItemId: args.sourceWorkItemId, targetWorkItemId: args.targetWorkItemId, operation: args.operation, relationType: args.relationType, newRelationType: args.newRelationType, comment: args.comment, }, ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; }