get-repo-context
Retrieve all files from a GitHub repository to provide context for AI models, with options to filter by file extensions and exclude specific paths.
Instructions
Get all files from a GitHub repository to use as context
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| owner | Yes | GitHub repository owner/organization name | |
| repo | Yes | GitHub repository name | |
| maxFiles | No | Maximum number of files to include (default: 50) | |
| fileExtensions | No | File extensions to include (e.g., ['js', 'ts', 'md']) | |
| excludePaths | No | Paths to exclude (e.g., ['node_modules', 'dist']) |
Implementation Reference
- src/index.ts:94-152 (handler)The main execution handler for the 'get-repo-context' tool. It fetches all files recursively from the GitHub repository, applies filters based on maxFiles, fileExtensions, and excludePaths, retrieves content for selected files, and returns formatted markdown text blocks.async ({ owner, repo, maxFiles = 50, fileExtensions = [], excludePaths = ['node_modules', 'dist', 'build'] }) => { try { console.error(`Fetching files from ${owner}/${repo}...`); const allFiles = await getAllFiles(owner, repo); console.error(`Found ${allFiles.length} total files in the repository`); let filteredFiles = allFiles.filter(file => { if (excludePaths.some(excludePath => file.path.includes(excludePath))) { return false; } if (fileExtensions.length > 0) { const extension = file.path.split('.').pop() || ''; return fileExtensions.includes(extension); } return true; }); filteredFiles = filteredFiles.slice(0, maxFiles); console.error(`Selected ${filteredFiles.length} files after filtering`); const fileContents: { path: string; content: string | null }[] = []; for (const file of filteredFiles) { if (file.type === 'file') { const content = await getFileContent(owner, repo, file.path); fileContents.push({ path: file.path, content }); } } const formattedContent = fileContents .filter(file => file.content !== null) .map(file => `File: ${file.path}\n\n\`\`\`\n${file.content}\n\`\`\`\n\n`) .join('---\n\n'); return { content: [ { type: "text", text: `Repository Context for ${owner}/${repo}:\n\n${formattedContent}`, }, ], }; } catch (error) { console.error("Error fetching repository context:", error); return { content: [ { type: "text", text: `Error fetching repository context: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } },
- src/index.ts:87-93 (schema)Input schema defined using Zod for the tool parameters: owner (string), repo (string), maxFiles (number, optional), fileExtensions (array of strings, optional), excludePaths (array of strings, optional).{ owner: z.string().describe("GitHub repository owner/organization name"), repo: z.string().describe("GitHub repository name"), maxFiles: z.number().optional().describe("Maximum number of files to include (default: 50)"), fileExtensions: z.array(z.string()).optional().describe("File extensions to include (e.g., ['js', 'ts', 'md'])"), excludePaths: z.array(z.string()).optional().describe("Paths to exclude (e.g., ['node_modules', 'dist'])"), },
- src/index.ts:84-153 (registration)Registration of the 'get-repo-context' tool using server.tool(), including name, description, input schema, and handler function.server.tool( "get-repo-context", "Get all files from a GitHub repository to use as context", { owner: z.string().describe("GitHub repository owner/organization name"), repo: z.string().describe("GitHub repository name"), maxFiles: z.number().optional().describe("Maximum number of files to include (default: 50)"), fileExtensions: z.array(z.string()).optional().describe("File extensions to include (e.g., ['js', 'ts', 'md'])"), excludePaths: z.array(z.string()).optional().describe("Paths to exclude (e.g., ['node_modules', 'dist'])"), }, async ({ owner, repo, maxFiles = 50, fileExtensions = [], excludePaths = ['node_modules', 'dist', 'build'] }) => { try { console.error(`Fetching files from ${owner}/${repo}...`); const allFiles = await getAllFiles(owner, repo); console.error(`Found ${allFiles.length} total files in the repository`); let filteredFiles = allFiles.filter(file => { if (excludePaths.some(excludePath => file.path.includes(excludePath))) { return false; } if (fileExtensions.length > 0) { const extension = file.path.split('.').pop() || ''; return fileExtensions.includes(extension); } return true; }); filteredFiles = filteredFiles.slice(0, maxFiles); console.error(`Selected ${filteredFiles.length} files after filtering`); const fileContents: { path: string; content: string | null }[] = []; for (const file of filteredFiles) { if (file.type === 'file') { const content = await getFileContent(owner, repo, file.path); fileContents.push({ path: file.path, content }); } } const formattedContent = fileContents .filter(file => file.content !== null) .map(file => `File: ${file.path}\n\n\`\`\`\n${file.content}\n\`\`\`\n\n`) .join('---\n\n'); return { content: [ { type: "text", text: `Repository Context for ${owner}/${repo}:\n\n${formattedContent}`, }, ], }; } catch (error) { console.error("Error fetching repository context:", error); return { content: [ { type: "text", text: `Error fetching repository context: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }, );
- src/index.ts:60-77 (helper)Helper function getAllFiles() that recursively lists all files in the repository by traversing directories using GitHub API.async function getAllFiles(owner: string, repo: string, path: string = ""): Promise<{ path: string, type: string }[]> { const contents = await getRepoContents(owner, repo, path); let allFiles: { path: string, type: string }[] = []; for (const item of contents) { if (item.type === 'file') { allFiles.push({ path: item.path, type: 'file' }); } else if (item.type === 'dir') { const subFiles = await getAllFiles(owner, repo, item.path); allFiles = [...allFiles, ...subFiles]; } } return allFiles; }
- src/index.ts:18-37 (helper)Helper function getRepoContents() that fetches contents of a specific path in the repo using Octokit.async function getRepoContents(owner: string, repo: string, path: string = ""): Promise<any[]> { try { const response = await octokit.repos.getContent({ owner, repo, path, }); if (Array.isArray(response.data)) { return response.data; } else if (response.data && 'type' in response.data) { return [response.data]; } return []; } catch (error) { console.error(`Error getting repo contents for ${owner}/${repo}/${path}:`, error); return []; } }
- src/index.ts:39-58 (helper)Helper function getFileContent() that retrieves the base64-decoded content of a specific file.async function getFileContent(owner: string, repo: string, path: string): Promise<string | null> { try { const response = await octokit.repos.getContent({ owner, repo, path, }); if ('content' in response.data && 'encoding' in response.data) { if (response.data.encoding === 'base64') { return Buffer.from(response.data.content, 'base64').toString('utf-8'); } } return null; } catch (error) { console.error(`Error getting file content for ${owner}/${repo}/${path}:`, error); return null; } }