get_all_repositories_tree
Retrieve a hierarchical tree view of files and directories across multiple Azure DevOps repositories within a project, enabling users to explore repository structures and locate files efficiently.
Instructions
Displays a hierarchical tree view of files and directories across multiple Azure DevOps repositories within a project, based on their default branches
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| organizationId | No | The ID or name of the Azure DevOps organization (Default: mycompany) | |
| projectId | No | The ID or name of the project (Default: MyProject) | |
| repositoryPattern | No | Repository name pattern (wildcard characters allowed) to filter which repositories are included | |
| depth | No | Maximum depth to traverse within each repository (0 = unlimited) | |
| pattern | No | File pattern (wildcard characters allowed) to filter files by within each repository |
Implementation Reference
- Core handler function that retrieves the tree structure of files/directories across multiple repositories in an Azure DevOps project, supporting depth limits, repository patterns, and file filtering.export async function getAllRepositoriesTree( connection: WebApi, options: GetAllRepositoriesTreeOptions, ): Promise<AllRepositoriesTreeResponse> { try { const gitApi = await connection.getGitApi(); let repositories: GitRepository[] = []; // Get all repositories in the project repositories = await gitApi.getRepositories(options.projectId); // Filter repositories by name pattern if specified if (options.repositoryPattern) { repositories = repositories.filter((repo) => minimatch(repo.name || '', options.repositoryPattern || '*'), ); } // Initialize results array const results: RepositoryTreeResponse[] = []; // Process each repository for (const repo of repositories) { try { // Get default branch ref const defaultBranch = repo.defaultBranch; if (!defaultBranch) { // Skip repositories with no default branch results.push({ name: repo.name || 'Unknown', tree: [], stats: { directories: 0, files: 0 }, error: 'No default branch found', }); continue; } // Clean the branch name (remove refs/heads/ prefix) const branchRef = defaultBranch.replace('refs/heads/', ''); // Initialize tree items array and counters const treeItems: RepositoryTreeItem[] = []; const stats = { directories: 0, files: 0 }; // Determine the recursion level and processing approach const depth = options.depth !== undefined ? options.depth : 0; // Default to 0 (max depth) if (depth === 0) { // For max depth (0), use server-side recursion for better performance const allItems = await gitApi.getItems( repo.id || '', options.projectId, '/', VersionControlRecursionType.Full, // Use full recursion true, false, false, false, { version: branchRef, versionType: GitVersionType.Branch, }, ); // Filter out the root item itself and bad items const itemsToProcess = allItems.filter( (item) => item.path !== '/' && item.gitObjectType !== GitObjectType.Bad, ); // Process all items at once (they're already retrieved recursively) processItemsNonRecursive( itemsToProcess, treeItems, stats, options.pattern, ); } else { // For limited depth, use the regular recursive approach // Get items at the root level const rootItems = await gitApi.getItems( repo.id || '', options.projectId, '/', VersionControlRecursionType.OneLevel, true, false, false, false, { version: branchRef, versionType: GitVersionType.Branch, }, ); // Filter out the root item itself and bad items const itemsToProcess = rootItems.filter( (item) => item.path !== '/' && item.gitObjectType !== GitObjectType.Bad, ); // Process the root items and their children (up to specified depth) await processItems( gitApi, repo.id || '', options.projectId, itemsToProcess, branchRef, treeItems, stats, 1, depth, options.pattern, ); } // Add repository tree to results results.push({ name: repo.name || 'Unknown', tree: treeItems, stats, }); } catch (repoError) { // Handle errors for individual repositories results.push({ name: repo.name || 'Unknown', tree: [], stats: { directories: 0, files: 0 }, error: `Error processing repository: ${repoError instanceof Error ? repoError.message : String(repoError)}`, }); } } return { repositories: results }; } catch (error) { if (error instanceof AzureDevOpsError) { throw error; } throw new Error( `Failed to get repository tree: ${error instanceof Error ? error.message : String(error)}`, ); } }
- Zod schema defining the input parameters for the get_all_repositories_tree tool.export const GetAllRepositoriesTreeSchema = z.object({ organizationId: z .string() .optional() .describe( `The ID or name of the Azure DevOps organization (Default: ${defaultOrg})`, ), projectId: z .string() .optional() .describe(`The ID or name of the project (Default: ${defaultProject})`), repositoryPattern: z .string() .optional() .describe( 'Repository name pattern (wildcard characters allowed) to filter which repositories are included', ), depth: z .number() .int() .min(0) .max(10) .optional() .default(0) .describe( 'Maximum depth to traverse within each repository (0 = unlimited)', ), pattern: z .string() .optional() .describe( 'File pattern (wildcard characters allowed) to filter files by within each repository', ), });
- src/features/repositories/tool-definitions.ts:40-45 (registration)Tool definition registration including name, description, and input schema conversion for MCP tool list.{ name: 'get_all_repositories_tree', description: 'Displays a hierarchical tree view of files and directories across multiple Azure DevOps repositories within a project, based on their default branches', inputSchema: zodToJsonSchema(GetAllRepositoriesTreeSchema), },
- src/features/repositories/index.ts:141-164 (registration)Request handler switch case that parses arguments with schema, calls the handler, formats output as ASCII tree, and returns response.case 'get_all_repositories_tree': { const args = GetAllRepositoriesTreeSchema.parse(request.params.arguments); const result = await getAllRepositoriesTree(connection, { ...args, projectId: args.projectId ?? defaultProject, organizationId: args.organizationId ?? defaultOrg, }); // Format the output as plain text tree representation let formattedOutput = ''; for (const repo of result.repositories) { formattedOutput += formatRepositoryTree( repo.name, repo.tree, repo.stats, repo.error, ); formattedOutput += '\n'; // Add blank line between repositories } return { content: [{ type: 'text', text: formattedOutput }], }; }
- TypeScript interface matching the schema for handler options.export interface GetAllRepositoriesTreeOptions { organizationId: string; projectId: string; repositoryPattern?: string; depth?: number; pattern?: string; }