Skip to main content
Glama

githubSearchCode

Search GitHub repository code to find files by path or content patterns, enabling code discovery and pattern identification.

Instructions

Search file content or files by path

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queriesYesResearch queries for githubSearchCode (1-3 queries per call for optimal resource management). Review schema before use for optimal results

Implementation Reference

  • Core execution function for the 'githubSearchCode' tool. Handles bulk queries, invokes GitHub code search API, processes results including file filtering, pagination, and hint generation.
    async function searchMultipleGitHubCode( queries: GitHubCodeSearchQuery[], authInfo?: AuthInfo, sessionId?: string ): Promise<CallToolResult> { return executeBulkOperation( queries, async (query: GitHubCodeSearchQuery, _index: number) => { try { const apiResult = await searchGitHubCodeAPI(query, authInfo, sessionId); const apiError = handleApiError(apiResult, query); if (apiError) return apiError; if (!('data' in apiResult)) { return handleCatchError( new Error('Invalid API response structure'), query ); } // Note: Files are already filtered by shouldIgnoreFile in codeSearch.ts API layer const files = apiResult.data.items.map(item => { const repoName = item.repository?.nameWithOwner; const baseFile = { path: item.path, ...(repoName && { repo: repoName }), ...(item.lastModifiedAt && { lastModifiedAt: item.lastModifiedAt, }), }; if (query.match === 'path') { return baseFile; } return { ...baseFile, text_matches: item.matches.map(match => match.context), }; }); const result: SearchResult = { files }; const repoContext = apiResult.data._researchContext?.repositoryContext; if (repoContext) { result.repositoryContext = repoContext; } // Add pagination info if available const pagination = apiResult.data.pagination; if (pagination) { result.pagination = pagination; } const hasContent = files.length > 0; // Build context for dynamic hints const hasOwnerRepo = !!(query.owner && query.repo); // Generate pagination hints const paginationHints: string[] = []; if (pagination) { const { currentPage, totalPages, totalMatches, perPage, hasMore } = pagination; const startItem = (currentPage - 1) * perPage + 1; const endItem = Math.min(currentPage * perPage, totalMatches); paginationHints.push( `Page ${currentPage}/${totalPages} (showing ${startItem}-${endItem} of ${totalMatches} matches)` ); if (hasMore) { paginationHints.push(`Next: page=${currentPage + 1}`); } if (currentPage > 1) { paginationHints.push(`Previous: page=${currentPage - 1}`); } if (!hasMore) { paginationHints.push('Final page'); } if (totalPages > 2) { paginationHints.push( `Jump to: page=1 (first) or page=${totalPages} (last)` ); } } // Use unified pattern: context for dynamic hints, extraHints for pagination return createSuccessResult( query, result as unknown as Record<string, unknown>, hasContent, TOOL_NAMES.GITHUB_SEARCH_CODE, { hintContext: { hasOwnerRepo, match: query.match }, extraHints: paginationHints, } ); } catch (error) { return handleCatchError(error, query); } }, { toolName: TOOL_NAMES.GITHUB_SEARCH_CODE, keysPriority: [ 'files', 'pagination', 'repositoryContext', 'error', ] satisfies Array<keyof SearchResult>, } ); }
  • Zod schemas defining the input structure and validation for the 'githubSearchCode' tool, including single query and bulk query schemas.
    export const GitHubCodeSearchQuerySchema = BaseQuerySchema.extend({ keywordsToSearch: z .array(z.string()) .min(1) .max(5) .describe(GITHUB_SEARCH_CODE.search.keywordsToSearch), owner: z.string().optional().describe(GITHUB_SEARCH_CODE.scope.owner), repo: z.string().optional().describe(GITHUB_SEARCH_CODE.scope.repo), extension: z .string() .optional() .describe(GITHUB_SEARCH_CODE.filters.extension), filename: z.string().optional().describe(GITHUB_SEARCH_CODE.filters.filename), path: z.string().optional().describe(GITHUB_SEARCH_CODE.filters.path), match: z .enum(['file', 'path']) .optional() .describe(GITHUB_SEARCH_CODE.filters.match), limit: z .number() .int() .min(1) .max(100) .default(10) .optional() .describe(GITHUB_SEARCH_CODE.resultLimit.limit), page: z .number() .int() .min(1) .max(10) .default(1) .optional() .describe(GITHUB_SEARCH_CODE.pagination.page), }); export const GitHubCodeSearchBulkQuerySchema = createBulkQuerySchema( TOOL_NAMES.GITHUB_SEARCH_CODE, GitHubCodeSearchQuerySchema );
  • Registers the 'githubSearchCode' tool with the MCP server, providing schema, description, annotations, and the handler function.
    export function registerGitHubSearchCodeTool( server: McpServer, callback?: ToolInvocationCallback ) { return server.registerTool( TOOL_NAMES.GITHUB_SEARCH_CODE, { description: DESCRIPTIONS[TOOL_NAMES.GITHUB_SEARCH_CODE], inputSchema: GitHubCodeSearchBulkQuerySchema, annotations: { title: 'GitHub Code Search', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, withSecurityValidation( TOOL_NAMES.GITHUB_SEARCH_CODE, async ( args: { queries: GitHubCodeSearchQuery[]; }, authInfo, sessionId ): Promise<CallToolResult> => { const queries = args.queries || []; await invokeCallbackSafely( callback, TOOL_NAMES.GITHUB_SEARCH_CODE, queries ); return searchMultipleGitHubCode(queries, authInfo, sessionId); } ) ); }
  • Key helper function implementing the GitHub Code Search API call, caching, query building, error handling, and result optimization including minification and sanitization.
    export async function searchGitHubCodeAPI( params: GitHubCodeSearchQuery, authInfo?: AuthInfo, sessionId?: string ): Promise<GitHubAPIResponse<OptimizedCodeSearchResult>> { // Cache key excludes context fields (mainResearchGoal, researchGoal, reasoning) // as they don't affect the API response const cacheKey = generateCacheKey( 'gh-api-code', { keywordsToSearch: params.keywordsToSearch, owner: params.owner, repo: params.repo, extension: params.extension, filename: params.filename, path: params.path, match: params.match, limit: params.limit, page: params.page, }, sessionId ); const result = await withDataCache< GitHubAPIResponse<OptimizedCodeSearchResult> >( cacheKey, async () => { return await searchGitHubCodeAPIInternal(params, authInfo); }, { shouldCache: (value: GitHubAPIResponse<OptimizedCodeSearchResult>) => 'data' in value && !(value as { error?: unknown }).error, } ); return result; } async function searchGitHubCodeAPIInternal( params: GitHubCodeSearchQuery, authInfo?: AuthInfo ): Promise<GitHubAPIResponse<OptimizedCodeSearchResult>> { try { const octokit = await getOctokit(authInfo); if (params.keywordsToSearch && params.keywordsToSearch.length > 0) { const validTerms = params.keywordsToSearch.filter( term => term && term.trim() ); if (validTerms.length === 0) { await logSessionError( TOOL_NAMES.GITHUB_SEARCH_CODE, SEARCH_ERRORS.QUERY_EMPTY.code ); return { error: SEARCH_ERRORS.QUERY_EMPTY.message, type: 'http', status: 400, }; } } const query = buildCodeSearchQuery(params); if (!query.trim()) { await logSessionError( TOOL_NAMES.GITHUB_SEARCH_CODE, SEARCH_ERRORS.QUERY_EMPTY.code ); return { error: SEARCH_ERRORS.QUERY_EMPTY.message, type: 'http', status: 400, }; } const perPage = Math.min( typeof params.limit === 'number' ? params.limit : 30, 100 ); const currentPage = params.page || 1; const searchParams: SearchCodeParameters = { q: query, per_page: perPage, page: currentPage, headers: { Accept: 'application/vnd.github.v3.text-match+json', }, }; const result = await octokit.rest.search.code(searchParams); const optimizedResult = await convertCodeSearchResult(result); // GitHub caps at 1000 total results const totalMatches = Math.min(optimizedResult.total_count, 1000); const totalPages = Math.min(Math.ceil(totalMatches / perPage), 10); const hasMore = currentPage < totalPages; return { data: { total_count: optimizedResult.total_count, items: optimizedResult.items, repository: optimizedResult.repository, matchLocations: optimizedResult.matchLocations, minified: optimizedResult.minified, minificationFailed: optimizedResult.minificationFailed, minificationTypes: optimizedResult.minificationTypes, _researchContext: optimizedResult._researchContext, pagination: { currentPage, totalPages, perPage, totalMatches, hasMore, }, }, status: 200, headers: result.headers, }; } catch (error: unknown) { const apiError = handleGitHubAPIError(error); return apiError; } }
  • Tool configuration entry that includes the registration function for 'githubSearchCode', used by the central toolsManager to register all tools.
    export const GITHUB_SEARCH_CODE: ToolConfig = { name: TOOL_NAMES.GITHUB_SEARCH_CODE, description: getDescription(TOOL_NAMES.GITHUB_SEARCH_CODE), isDefault: true, isLocal: false, type: 'search', fn: registerGitHubSearchCodeTool, };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bgauryy/octocode-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server