github-mcp-demo
github-mcp-demo
A small, working MCP (Model Context Protocol) server that wraps the GitHub REST API as four tools an AI agent can call directly: search repositories, get repository details, list issues, and read a README.
This exists for two reasons:
Portfolio proof — a real, tested MCP server you can point to (GitHub pin, Fiverr/Contra gig samples, Upwork portfolio) that shows exactly what the $99 "custom MCP server" gig delivers.
Reusable boilerplate — the fastest way to deliver a paid job is to copy this folder and swap the API-specific pieces (see "Adapting this for a client" below), not start from a blank file each time.
What it does
Tool | What it calls | What it returns |
|
| Top matching repos: name, stars, description, URL |
|
| Stars, forks, open issues, license, topics |
|
| Open/closed issues, most recently updated first |
|
| Decoded README text (truncated to 6000 chars) |
Setup
npm install
npm run buildThis produces dist/index.js, a standard stdio-based MCP server.
Optional: raise the rate limit
Without a token, GitHub allows 60 unauthenticated API requests/hour per IP, shared across anything else on that network — you'll hit this fast in testing. Set a token for real use:
export GITHUB_TOKEN=ghp_yourPersonalAccessTokenA read-only, no-scopes personal access token is enough for public repos.
Connect to Claude Desktop
Add this to your Claude Desktop config (claude_desktop_config.json):
{
"mcpServers": {
"github-demo": {
"command": "node",
"args": ["/absolute/path/to/github-mcp-demo/dist/index.js"],
"env": {
"GITHUB_TOKEN": "ghp_yourPersonalAccessToken"
}
}
}
}Restart Claude Desktop, then try asking it things like:
"Search GitHub for popular MCP servers written in TypeScript"
"What are the open issues on modelcontextprotocol/typescript-sdk?"
"Show me the README for anthropics/anthropic-sdk-python"
Adapting this for a client (the actual delivery workflow)
This is the part that makes a $99, 48-hour turnaround realistic:
Copy this whole folder, rename it.
In
src/index.ts, replaceGITHUB_API_BASEand the auth header logic ingithubRequest()with the client's API base URL and auth scheme (API key header, Bearer token, Basic auth — same shape, different values).Replace the four
registerTool(...)blocks with tools matching their API's endpoints. Keep the same pattern: a ZodinputSchemafor arguments, a fetch call, a small object shaping the response,textResult(...).npm run build, run it through the same test pattern (spin up an MCP client over stdio, call each tool once, check the output).Deliver
dist/index.js+ a short README with their own Claude Desktop config snippet filled in.
Steps 2–3 are the only genuinely custom work per client — everything else (project scaffold, error handling, stdio wiring, response shaping pattern) is already done.
Notes
Errors from the upstream API (rate limits, 404s, bad auth) are caught and returned as a readable message rather than crashing the server — this matters more than it sounds like once a client is testing it themselves.
get_readmetruncates long files to ~6000 characters so a huge README doesn't eat the calling model's whole context window on one tool call.