githubSearchRepositories
Search GitHub repositories in bulk with parallel queries, filters by language, stars, forks, topics, and more. Automatically retries with fallback parameters if no results found, optimizing research workflows. Execute up to 5 searches simultaneously.
Instructions
Search GitHub repositories using GitHub CLI.
BULK QUERY MODE:
queries: array of up to 5 different search queries for parallel execution
Each query can have fallbackParams for automatic retry with modified parameters
Optimizes research workflow by executing multiple searches simultaneously
Fallback logic automatically broadens search if no results found
Use for comprehensive research - query different repos, languages, or approaches in one call.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| queries | Yes | Array of up to 5 different search queries for parallel execution |
Implementation Reference
- Core handler function that processes multiple queries, expands them if needed, calls the GitHub API via searchGitHubReposAPI, handles results and errors, and formats the output.async function searchMultipleGitHubRepos( queries: GitHubReposSearchQuery[], authInfo?: AuthInfo, sessionId?: string ): Promise<CallToolResult> { const expandedQueries = expandQueriesWithBothSearchTypes(queries); return executeBulkOperation( expandedQueries, async (query: GitHubReposSearchQuery, _index: number) => { try { const apiResult = await searchGitHubReposAPI( query, authInfo, sessionId ); const apiError = handleApiError(apiResult, query); if (apiError) return apiError; const repositories = 'data' in apiResult ? apiResult.data.repositories || [] : ([] satisfies SimplifiedRepository[]); const customHints = generateSearchSpecificHints( query, repositories.length > 0 ); return createSuccessResult( query, { repositories }, repositories.length > 0, 'GITHUB_SEARCH_REPOSITORIES', customHints ); } catch (error) { return handleCatchError(error, query); } }, { toolName: TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES, keysPriority: ['repositories', 'error'] satisfies Array< keyof RepoSearchResult >, } ); }
- Executes the actual GitHub repository search using Octokit, builds the query, processes results into simplified repositories, sorts by stars and update date.async function searchGitHubReposAPIInternal( params: GitHubReposSearchQuery, authInfo?: AuthInfo ): Promise< GitHubAPIResponse<{ repositories: SimplifiedRepository[]; }> > { try { const octokit = await getOctokit(authInfo); const query = buildRepoSearchQuery(params); if (!query.trim()) { await logSessionError( TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES, SEARCH_ERRORS.QUERY_EMPTY.code ); return { error: SEARCH_ERRORS.QUERY_EMPTY.message, type: 'http', status: 400, }; } const searchParams: SearchReposParameters = { q: query, per_page: Math.min(params.limit || 30, 100), page: 1, }; if (params.sort && params.sort !== 'best-match') { searchParams.sort = params.sort as SearchReposParameters['sort']; } const result = await octokit.rest.search.repos(searchParams); const repositories = result.data.items .map((repo: RepoSearchResultItem) => { const fullName = repo.full_name; const parts = fullName.split('/'); const owner = parts[0] || ''; const repoName = parts[1] || ''; return { owner, repo: repoName, stars: repo.stargazers_count || 0, description: repo.description ? repo.description.length > 150 ? repo.description.substring(0, 150) + '...' : repo.description : 'No description', url: repo.html_url, updatedAt: new Date(repo.updated_at).toLocaleDateString('en-GB'), }; }) .sort((a: SimplifiedRepository, b: SimplifiedRepository) => { if (b.stars !== a.stars) { return b.stars - a.stars; } const dateA = new Date(a.updatedAt.split('/').reverse().join('-')); const dateB = new Date(b.updatedAt.split('/').reverse().join('-')); return dateB.getTime() - dateA.getTime(); }); return { data: { repositories, }, status: 200, headers: result.headers, }; } catch (error: unknown) { return handleGitHubAPIError(error); } }
- Zod schema for input validation of GitHub repository search queries, including fields like keywordsToSearch, topicsToSearch, filters, sort, limit.export const GitHubReposSearchQuerySchema = createBulkQuerySchema( TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES, GitHubReposSearchSingleQuerySchema );
- packages/octocode-mcp/src/tools/github_search_repos.ts:21-61 (registration)Registers the 'githubSearchRepositories' tool on the MCP server with name, description, input schema, annotations, and security-wrapped handler.export function registerSearchGitHubReposTool( server: McpServer, callback?: ToolInvocationCallback ) { return server.registerTool( TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES, { description: DESCRIPTIONS[TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES], inputSchema: GitHubReposSearchQuerySchema, annotations: { title: 'GitHub Repository Search', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, withSecurityValidation( TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES, async ( args: { queries: GitHubReposSearchQuery[]; }, authInfo, sessionId ): Promise<CallToolResult> => { const queries = args.queries || []; if (callback) { try { await callback(TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES, queries); } catch { // ignore } } return searchMultipleGitHubRepos(queries, authInfo, sessionId); } ) ); }
- Tool configuration for githubSearchRepositories, including name, description, and reference to the registration function.export const GITHUB_SEARCH_REPOSITORIES: ToolConfig = { name: TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES, description: getDescription(TOOL_NAMES.GITHUB_SEARCH_REPOSITORIES), isDefault: true, type: 'search', fn: registerSearchGitHubReposTool, };