Entree: GitHub Integration Server
An MCP server that integrates with the GitHub API. Search repos, read files, list issues, and create pull request summaries — all from your AI assistant.
title: "Entree: GitHub Integration Server" description: "An MCP server that integrates with the GitHub API. Search repos, read files, list issues, and create pull request summaries — all from your AI assistant." order: 5 category: "entree" level: "intermediate" duration: "30 min" date: "2026-04-01" tags:
- tools
- api
- github keywords:
- mcp github server
- github integration mcp
- mcp-framework github api
- ai github tools
What You Get
A full GitHub integration server that lets Claude search repositories, read file contents, list issues, and summarize pull requests. Uses the GitHub REST API with token authentication.
Tools included:
search_repos— search GitHub repositories by queryget_file— read a file from a specific repo and branchlist_issues— list open issues for a repositoryget_pr— get details and diff summary for a pull request
Quick Start
npx mcp-framework create github-server
cd github-server
The Search Repos Tool
Create src/tools/SearchReposTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
const SearchInput = z.object({
query: z.string().describe("Search query for GitHub repositories"),
limit: z.number().min(1).max(20).default(5).describe("Max results"),
});
class SearchReposTool extends MCPTool<typeof SearchInput> {
name = "search_repos";
description = "Search GitHub repositories";
schema = { input: SearchInput };
async execute(input: z.infer<typeof SearchInput>) {
const res = await fetch(
`https://api.github.com/search/repositories?q=${encodeURIComponent(input.query)}&per_page=${input.limit}`,
{
headers: {
Accept: "application/vnd.github.v3+json",
...(process.env.GITHUB_TOKEN && {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
}),
},
}
);
if (!res.ok) throw new Error(`GitHub API error: ${res.status}`);
const data = await res.json();
return {
results: data.items.map((repo: Record<string, unknown>) => ({
name: repo.full_name,
description: repo.description,
stars: repo.stargazers_count,
language: repo.language,
url: repo.html_url,
})),
};
}
}
export default SearchReposTool;
The Get File Tool
Create src/tools/GetFileTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
const FileInput = z.object({
owner: z.string().describe("Repository owner"),
repo: z.string().describe("Repository name"),
path: z.string().describe("File path within the repo"),
ref: z.string().default("main").describe("Branch or commit ref"),
});
class GetFileTool extends MCPTool<typeof FileInput> {
name = "get_file";
description = "Read a file from a GitHub repository";
schema = { input: FileInput };
async execute(input: z.infer<typeof FileInput>) {
const res = await fetch(
`https://api.github.com/repos/${input.owner}/${input.repo}/contents/${input.path}?ref=${input.ref}`,
{
headers: {
Accept: "application/vnd.github.v3+json",
...(process.env.GITHUB_TOKEN && {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
}),
},
}
);
if (!res.ok) throw new Error(`File not found: ${res.status}`);
const data = await res.json();
const content = Buffer.from(data.content, "base64").toString("utf-8");
return {
path: data.path,
size: data.size,
content,
};
}
}
export default GetFileTool;
The List Issues Tool
Create src/tools/ListIssuesTool.ts:
import { MCPTool } from "mcp-framework";
import { z } from "zod";
const IssuesInput = z.object({
owner: z.string().describe("Repository owner"),
repo: z.string().describe("Repository name"),
state: z.enum(["open", "closed", "all"]).default("open"),
limit: z.number().min(1).max(30).default(10),
});
class ListIssuesTool extends MCPTool<typeof IssuesInput> {
name = "list_issues";
description = "List issues for a GitHub repository";
schema = { input: IssuesInput };
async execute(input: z.infer<typeof IssuesInput>) {
const res = await fetch(
`https://api.github.com/repos/${input.owner}/${input.repo}/issues?state=${input.state}&per_page=${input.limit}`,
{
headers: {
Accept: "application/vnd.github.v3+json",
...(process.env.GITHUB_TOKEN && {
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
}),
},
}
);
if (!res.ok) throw new Error(`GitHub API error: ${res.status}`);
const data = await res.json();
return {
issues: data.map((issue: Record<string, unknown>) => ({
number: issue.number,
title: issue.title,
state: issue.state,
author: (issue.user as Record<string, unknown>)?.login,
labels: (issue.labels as Record<string, unknown>[])?.map(
(l) => l.name
),
url: issue.html_url,
})),
};
}
}
export default ListIssuesTool;
Authentication
Set your GitHub token as an environment variable:
{
"mcpServers": {
"github": {
"command": "node",
"args": ["./dist/index.js"],
"env": {
"GITHUB_TOKEN": "ghp_your_token_here"
}
}
}
}
The token is optional for public repos but required for private repos and to avoid rate limits.
What You Learn
- Authenticating with external APIs via environment variables
- Building multiple related tools in one server
- Handling GitHub's REST API responses
- Pagination and result limiting for AI-friendly outputs
- Base64 decoding file contents
Next Up
Combine everything you have learned in the Developer Tools Suite, or explore AI capabilities with the AI Image Generation Server.
Built with mcp-framework (3.3M+ downloads) by @QuantGeekDev. Validated by Anthropic.