search_work_items
Search for work items across Azure DevOps projects using filters, sorting, and faceting for precise results.
Instructions
Search for work items across projects in Azure DevOps
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filters | No | Optional filters to narrow search results | |
| includeFacets | No | Whether to include faceting in results (default: true) | |
| orderBy | No | Options for sorting search results | |
| projectId | Yes | The ID or name of the project to search in | |
| searchText | Yes | The text to search for in work items | |
| skip | No | Number of results to skip for pagination (default: 0) | |
| top | No | Number of results to return (default: 100, max: 1000) |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"filters": {
"additionalProperties": false,
"description": "Optional filters to narrow search results",
"properties": {
"System.AreaPath": {
"description": "Filter by area paths",
"items": {
"type": "string"
},
"type": "array"
},
"System.AssignedTo": {
"description": "Filter by assigned users",
"items": {
"type": "string"
},
"type": "array"
},
"System.State": {
"description": "Filter by work item states (New, Active, Closed, etc.)",
"items": {
"type": "string"
},
"type": "array"
},
"System.TeamProject": {
"description": "Filter by project names",
"items": {
"type": "string"
},
"type": "array"
},
"System.WorkItemType": {
"description": "Filter by work item types (Bug, Task, User Story, etc.)",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"includeFacets": {
"default": true,
"description": "Whether to include faceting in results (default: true)",
"type": "boolean"
},
"orderBy": {
"description": "Options for sorting search results",
"items": {
"additionalProperties": false,
"properties": {
"field": {
"description": "Field to sort by",
"type": "string"
},
"sortOrder": {
"description": "Sort order (ASC/DESC)",
"enum": [
"ASC",
"DESC"
],
"type": "string"
}
},
"required": [
"field",
"sortOrder"
],
"type": "object"
},
"type": "array"
},
"projectId": {
"description": "The ID or name of the project to search in",
"type": "string"
},
"searchText": {
"description": "The text to search for in work items",
"type": "string"
},
"skip": {
"default": 0,
"description": "Number of results to skip for pagination (default: 0)",
"minimum": 0,
"type": "integer"
},
"top": {
"default": 100,
"description": "Number of results to return (default: 100, max: 1000)",
"maximum": 1000,
"minimum": 1,
"type": "integer"
}
},
"required": [
"searchText",
"projectId"
],
"type": "object"
}
Implementation Reference
- The core handler function that executes the search_work_items tool logic, performing an API call to Azure DevOps search endpoint for work items.export async function searchWorkItems( connection: WebApi, options: SearchWorkItemsOptions, ): Promise<WorkItemSearchResponse> { try { // Prepare the search request const searchRequest: WorkItemSearchRequest = { searchText: options.searchText, $skip: options.skip, $top: options.top, filters: { ...(options.projectId ? { 'System.TeamProject': [options.projectId] } : {}), ...options.filters, }, includeFacets: options.includeFacets, $orderBy: options.orderBy, }; // Get the authorization header from the connection const authHeader = await getAuthorizationHeader(); // Extract organization and project from the connection URL const { organization, project } = extractOrgAndProject( connection, options.projectId, ); // Make the search API request // If projectId is provided, include it in the URL, otherwise perform organization-wide search const searchUrl = options.projectId ? `https://almsearch.dev.azure.com/${organization}/${project}/_apis/search/workitemsearchresults?api-version=7.1` : `https://almsearch.dev.azure.com/${organization}/_apis/search/workitemsearchresults?api-version=7.1`; const searchResponse = await axios.post<WorkItemSearchResponse>( searchUrl, searchRequest, { headers: { Authorization: authHeader, 'Content-Type': 'application/json', }, }, ); return searchResponse.data; } catch (error) { // If it's already an AzureDevOpsError, rethrow it if (error instanceof AzureDevOpsError) { throw error; } // Handle axios errors if (axios.isAxiosError(error)) { const status = error.response?.status; const message = error.response?.data?.message || error.message; if (status === 404) { throw new AzureDevOpsResourceNotFoundError( `Resource not found: ${message}`, ); } else if (status === 400) { throw new AzureDevOpsValidationError( `Invalid request: ${message}`, error.response?.data, ); } else if (status === 401 || status === 403) { throw new AzureDevOpsPermissionError(`Permission denied: ${message}`); } else { // For other axios errors, wrap in a generic AzureDevOpsError throw new AzureDevOpsError(`Azure DevOps API error: ${message}`); } // This code is unreachable but TypeScript doesn't know that } // Otherwise, wrap it in a generic error throw new AzureDevOpsError( `Failed to search work items: ${error instanceof Error ? error.message : String(error)}`, ); } }
- Zod schema defining the input parameters and validation for the search_work_items tool.export const SearchWorkItemsSchema = z.object({ searchText: z.string().describe('The text to search for in work items'), organizationId: z .string() .optional() .describe(`The ID or name of the organization (Default: ${defaultOrg})`), projectId: z .string() .optional() .describe( `The ID or name of the project to search in (Default: ${defaultProject}). If not provided, the default project will be used.`, ), filters: z .object({ 'System.TeamProject': z .array(z.string()) .optional() .describe('Filter by project names'), 'System.WorkItemType': z .array(z.string()) .optional() .describe('Filter by work item types (Bug, Task, User Story, etc.)'), 'System.State': z .array(z.string()) .optional() .describe('Filter by work item states (New, Active, Closed, etc.)'), 'System.AssignedTo': z .array(z.string()) .optional() .describe('Filter by assigned users'), 'System.AreaPath': z .array(z.string()) .optional() .describe('Filter by area paths'), }) .optional() .describe('Optional filters to narrow search results'), top: z .number() .int() .min(1) .max(1000) .default(100) .describe('Number of results to return (default: 100, max: 1000)'), skip: z .number() .int() .min(0) .default(0) .describe('Number of results to skip for pagination (default: 0)'), includeFacets: z .boolean() .default(true) .describe('Whether to include faceting in results (default: true)'), orderBy: z .array( z.object({ field: z.string().describe('Field to sort by'), sortOrder: z.enum(['ASC', 'DESC']).describe('Sort order (ASC/DESC)'), }), ) .optional() .describe('Options for sorting search results'), });
- src/features/search/tool-definitions.ts:23-27 (registration)Tool registration entry including name, description, and input schema for search_work_items.{ name: 'search_work_items', description: 'Search for work items across projects in Azure DevOps', inputSchema: zodToJsonSchema(SearchWorkItemsSchema), },
- src/features/search/index.ts:58-64 (handler)Dispatcher case in the request handler that invokes the searchWorkItems function for MCP tool calls.case 'search_work_items': { const args = SearchWorkItemsSchema.parse(request.params.arguments); const result = await searchWorkItems(connection, args); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }], }; }
- src/features/search/types.ts:358-426 (helper)TypeScript interface defining the options for the searchWorkItems function.export interface SearchWorkItemsOptions { /** * The text to search for within work items */ searchText: string; /** * The ID or name of the project to search in * If not provided, search will be performed across the entire organization */ projectId?: string; /** * Optional filters to narrow search results */ filters?: { /** * Filter by project names. Useful for cross-project searches. */ 'System.TeamProject'?: string[]; /** * Filter by work item types (Bug, Task, User Story, etc.) */ 'System.WorkItemType'?: string[]; /** * Filter by work item states (New, Active, Closed, etc.) */ 'System.State'?: string[]; /** * Filter by assigned users */ 'System.AssignedTo'?: string[]; /** * Filter by area paths */ 'System.AreaPath'?: string[]; }; /** * Number of results to return * @default 100 * @minimum 1 * @maximum 1000 */ top?: number; /** * Number of results to skip for pagination * @default 0 * @minimum 0 */ skip?: number; /** * Whether to include faceting in results * @default true */ includeFacets?: boolean; /** * Options for sorting search results * If null, results are sorted by relevance */ orderBy?: SortOption[]; }