get_repository
Retrieve detailed information about a GitHub repository, including its README and file structure.
Instructions
Get detailed information about a GitHub repository including README and file structure
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| owner | Yes | Repository owner | |
| repo | Yes | Repository name |
Implementation Reference
- src/tools/repositories.ts:73-186 (handler)The main handler function for the 'get_repository' tool. Fetches repository info via Octokit, retrieves README content, lists root directory structure, and formats everything as markdown.
server.tool( "get_repository", "Get detailed information about a GitHub repository including README and file structure", { owner: z.string().describe("Repository owner"), repo: z.string().describe("Repository name"), }, async ({ owner, repo }) => { try { // Get basic repository info const repoResponse = await octokit.rest.repos.get({ owner, repo, }) const repoData = repoResponse.data // Start building markdown let markdown = `# ${repoData.full_name}\n\n` // Add description if available if (repoData.description) { markdown += `> ${repoData.description}\n\n` } // Add basic stats in a single line markdown += `**Language:** ${repoData.language || "Not specified"} | ` markdown += `**Stars:** ${repoData.stargazers_count} | ` markdown += `**Forks:** ${repoData.forks_count} | ` markdown += `**License:** ${repoData.license?.spdx_id || "None"}\n\n` // Get README content try { const readmeResponse = await octokit.rest.repos.getReadme({ owner, repo, }) // Decode README content from base64 const readmeContent = Buffer.from( readmeResponse.data.content, "base64", ).toString("utf-8") markdown += `## README\n\n` markdown += readmeContent markdown += `\n\n` } catch (readmeError) { markdown += `## README\n\n` markdown += `*No README file found*\n\n` } // Get repository file structure (root directory) try { const contentsResponse = await octokit.rest.repos.getContent({ owner, repo, path: "", }) if (Array.isArray(contentsResponse.data)) { markdown += `## Repository Structure\n\n` // Sort contents: directories first, then files const contents = contentsResponse.data.sort((a, b) => { if (a.type === b.type) return a.name.localeCompare(b.name) return a.type === "dir" ? -1 : 1 }) // Group by type const dirs = contents.filter(item => item.type === "dir") const files = contents.filter(item => item.type === "file") if (dirs.length > 0) { markdown += `### Directories\n` dirs.forEach(dir => { markdown += `- **${dir.name}/**\n` }) markdown += `\n` } if (files.length > 0) { markdown += `### Files\n` files.forEach(file => { const size = file.size ? ` (${(file.size / 1024).toFixed(1)} KB)` : "" markdown += `- ${file.name}${size}\n` }) markdown += `\n` } } } catch (contentsError) { markdown += `## Repository Structure\n\n` markdown += `*Unable to fetch repository contents*\n\n` } // Add essential links at the bottom markdown += `## Links\n\n` markdown += `- **GitHub:** ${repoData.html_url}\n` markdown += `- **Clone:** \`git clone ${repoData.clone_url}\`\n` if (repoData.homepage) { markdown += `- **Website:** ${repoData.homepage}\n` } return { content: [{ type: "text", text: markdown }], } } catch (e: any) { return { content: [{ type: "text", text: `Error: ${e.message}` }], } } }, ) - src/tools/repositories.ts:76-79 (schema)Zod schema defining the input parameters for the 'get_repository' tool: 'owner' (string) and 'repo' (string).
{ owner: z.string().describe("Repository owner"), repo: z.string().describe("Repository name"), }, - src/tools/repositories.ts:73-186 (registration)Registration of the 'get_repository' tool on the MCP server via server.tool() call within the registerRepositoryTools function.
server.tool( "get_repository", "Get detailed information about a GitHub repository including README and file structure", { owner: z.string().describe("Repository owner"), repo: z.string().describe("Repository name"), }, async ({ owner, repo }) => { try { // Get basic repository info const repoResponse = await octokit.rest.repos.get({ owner, repo, }) const repoData = repoResponse.data // Start building markdown let markdown = `# ${repoData.full_name}\n\n` // Add description if available if (repoData.description) { markdown += `> ${repoData.description}\n\n` } // Add basic stats in a single line markdown += `**Language:** ${repoData.language || "Not specified"} | ` markdown += `**Stars:** ${repoData.stargazers_count} | ` markdown += `**Forks:** ${repoData.forks_count} | ` markdown += `**License:** ${repoData.license?.spdx_id || "None"}\n\n` // Get README content try { const readmeResponse = await octokit.rest.repos.getReadme({ owner, repo, }) // Decode README content from base64 const readmeContent = Buffer.from( readmeResponse.data.content, "base64", ).toString("utf-8") markdown += `## README\n\n` markdown += readmeContent markdown += `\n\n` } catch (readmeError) { markdown += `## README\n\n` markdown += `*No README file found*\n\n` } // Get repository file structure (root directory) try { const contentsResponse = await octokit.rest.repos.getContent({ owner, repo, path: "", }) if (Array.isArray(contentsResponse.data)) { markdown += `## Repository Structure\n\n` // Sort contents: directories first, then files const contents = contentsResponse.data.sort((a, b) => { if (a.type === b.type) return a.name.localeCompare(b.name) return a.type === "dir" ? -1 : 1 }) // Group by type const dirs = contents.filter(item => item.type === "dir") const files = contents.filter(item => item.type === "file") if (dirs.length > 0) { markdown += `### Directories\n` dirs.forEach(dir => { markdown += `- **${dir.name}/**\n` }) markdown += `\n` } if (files.length > 0) { markdown += `### Files\n` files.forEach(file => { const size = file.size ? ` (${(file.size / 1024).toFixed(1)} KB)` : "" markdown += `- ${file.name}${size}\n` }) markdown += `\n` } } } catch (contentsError) { markdown += `## Repository Structure\n\n` markdown += `*Unable to fetch repository contents*\n\n` } // Add essential links at the bottom markdown += `## Links\n\n` markdown += `- **GitHub:** ${repoData.html_url}\n` markdown += `- **Clone:** \`git clone ${repoData.clone_url}\`\n` if (repoData.homepage) { markdown += `- **Website:** ${repoData.homepage}\n` } return { content: [{ type: "text", text: markdown }], } } catch (e: any) { return { content: [{ type: "text", text: `Error: ${e.message}` }], } } }, ) - src/tools/repositories.ts:5-69 (helper)Helper function that references get_repository in guidance text when a directory is requested instead of a file. Not the tool itself, but a cross-reference.
function formatDirectoryGuidance( owner: string, repo: string, path: string, entries: Array<{ name: string; path: string; type?: string }>, branch?: string, ): string { const trimmedPath = path.trim() const displayPath = trimmedPath || "(repository root)" const directories = entries .filter(entry => entry.type === "dir") .map(entry => entry.path) .slice(0, 8) const files = entries .filter(entry => entry.type === "file") .map(entry => entry.path) .slice(0, 8) let markdown = `# Directory Requested Instead of File\n\n` markdown += `The path \`${displayPath}\` points to a directory, not a file.\n\n` markdown += `## Recommended Next Calls\n\n` markdown += `- Use \`get_repository\` with \`owner="${owner}"\` and \`repo="${repo}"\` for a repository overview and top-level structure.\n` if (files.length > 0) { const fileExamples = files .slice(0, 3) .map(file => `\`${file}\``) .join(", ") markdown += `- Retry \`get_file_contents\` with a file path from this directory, for example ${fileExamples}.${branch ? ` Keep \`branch="${branch}"\`.` : ""}\n` } if (directories.length > 0) { const directoryExamples = directories .slice(0, 3) .map(dir => `\`${dir}\``) .join(", ") markdown += `- If you want something inside a subdirectory, use one of these as the starting path and add the file name: ${directoryExamples}.\n` } markdown += `\n## Directory Listing\n\n` if (directories.length > 0) { markdown += `### Directories\n` directories.forEach(dir => { markdown += `- ${dir}\n` }) markdown += `\n` } if (files.length > 0) { markdown += `### Files\n` files.forEach(file => { markdown += `- ${file}\n` }) markdown += `\n` } if (directories.length === 0 && files.length === 0) { markdown += `This directory is empty or GitHub did not return any entries.\n` } markdown += `\nOptional resource path if your client supports resources: \`repo://${owner}/${repo}/contents/${trimmedPath}\`` return markdown }