github-directory-mcp
An MCP server that enables AI assistants to list GitHub repositories for a user or organization and list directories within a repository via the GitHub REST API.
README
github-directory-mcp
An MCP (Model Context Protocol) server, written in TypeScript, that gives an AI assistant two tools for querying GitHub: listing a user/org's repositories, and listing the directories inside a repo.
This README covers MCP from first principles through to this project's internals, running it, and extending it.
Table of contents
- What is MCP
- How the protocol actually works
- Transports: stdio vs HTTP
- What this project does
- Project layout
- Setup from scratch
- Tool reference
- Accessing the server
- Troubleshooting
- Advanced: extending this server
- Security notes
Quick command reference
Every command actually needed to build, run, register, and debug this server, in one place. Run
these from a normal terminal (VS Code integrated terminal or system PowerShell) in the project
folder, C:\Users\banda\OneDrive\Desktop\Mcp — not a sandboxed/CI shell.
These are wired up as real npm run scripts in package.json — not just copy-paste text:
# One-time setup
npm install
cp .env.example .env # then paste your GITHUB_TOKEN into .env
# Build (re-run after any src/index.ts edit)
npm run build
# Register with Claude Code (one-time; restart the session afterwards)
npm run register
# Manual visual testing via MCP Inspector
npm run inspector
# Same, but skip the session-token requirement (fixes stale-tab proxy errors)
npm run inspector:noauth
# Raw run (server just listens on stdio; used for scripted JSON-RPC testing)
npm start
# Verify GITHUB_TOKEN is valid
npm run check-token
# Find + stop whatever is holding the Inspector's ports (6274 UI / 6277 proxy)
netstat -ano | findstr "6274 6277"
Stop-Process -Id <PID> -Force
| Script | What it runs |
|---|---|
npm run build |
tsc — compiles src/index.ts → dist/index.js |
npm start |
node dist/index.js — raw stdio server |
npm run dev |
build then start, in one step |
npm run inspector |
Launches MCP Inspector against the built server |
npm run inspector:noauth |
Same, with DANGEROUSLY_OMIT_AUTH=true (via cross-env, so it works on Windows too) |
npm run register |
claude mcp add github-directory -- node dist/index.js |
npm run check-token |
Hits GET /user with your GITHUB_TOKEN and prints the resolved account or the raw error |
1. What is MCP
Model Context Protocol is an open standard (created by Anthropic, now used across the industry) that defines a common way for an AI application — a chat client, an IDE assistant, an agent — to discover and call external capabilities, without every AI vendor and every tool vendor needing a custom integration for each other.
Before MCP: if you wanted Claude to talk to GitHub, Slack, a database, and a filesystem, someone had to write four bespoke integrations inside the AI application, each with its own auth handling, its own API shape, its own way of describing what it can do.
With MCP: each of those four things (GitHub, Slack, DB, filesystem) is wrapped in a small standalone program called an MCP server. Any MCP-compatible client (Claude Code, Claude Desktop, other agent frameworks) can talk to any MCP server using the same protocol. The server describes its own capabilities at connection time — the client doesn't need prior knowledge of what a "GitHub server" looks like.
The analogy people reach for is USB-C for AI: one physical/logical connector, many devices behind it, no per-device custom cable.
The three primitives MCP servers expose
| Primitive | What it is | Example in this project |
|---|---|---|
| Tools | Functions the model can call, with typed inputs/outputs. The model decides when to call them. | list_github_repositories, list_github_directories |
| Resources | Read-only data the client can attach to context (files, query results). Not used in this project. | — |
| Prompts | Reusable prompt templates the server offers. Not used in this project. | — |
This project only implements tools, which is the most common case — "let the model call a function and get a result back."
2. How the protocol actually works
Under the hood, MCP is JSON-RPC 2.0 — a simple, transport-agnostic RPC format where every
message is a JSON object with a method, optional params, and an id to match requests to
responses.
A session looks like this:
Client Server (this project)
|--- initialize ------------------------->| client says "here's my protocol version/capabilities"
|<-- initialize result -------------------| server replies with its name/version/capabilities
|--- notifications/initialized ---------->| client confirms handshake is done
|
|--- tools/list -------------------------->| client asks "what tools do you have?"
|<-- tools/list result -------------------| server returns tool names + JSON Schema for each input
|
|--- tools/call (list_github_repositories)->| client invokes a tool with arguments
|<-- tools/call result --------------------| server runs it, returns text/structured content
Every tool advertises an input schema (we use Zod to define it, which the SDK
converts to JSON Schema automatically). This is what lets the calling model know it must supply
owner and repo as strings for list_github_directories, for instance — the schema is enforced
before your tool code even runs (see src/index.ts's .min(1) validators, which reject empty
strings with a clear error instead of letting a malformed request reach the GitHub API).
3. Transports: stdio vs HTTP
MCP defines the message format (JSON-RPC) separately from the transport (how bytes physically move between client and server). Two transports matter in practice:
- stdio (what this project uses): the client spawns your server as a child process and talks to
it over its stdin/stdout. Zero networking, zero ports, zero auth needed — the client owns the
process. This is the right choice for a local tool a single user runs on their own machine, which
is what
claude mcp add ... -- node dist/index.jsdoes. - Streamable HTTP: the server runs independently (its own process, possibly remote), and clients connect to it over HTTP. Needed when the server is shared, long-running, or not co-located with the client. Requires you to think about auth, since now it's a network-reachable service.
This project only implements stdio (see StdioServerTransport in src/index.ts). If you ever need
to expose it to multiple remote clients, that's the piece you'd swap out — the tool logic itself
wouldn't change.
4. What this project does
Two tools, both backed directly by the GitHub REST API (no
GitHub SDK dependency — just fetch):
list_github_repositories— callsGET /users/{owner}/repos(falling back toGET /orgs/{owner}/reposif that 404s), orGET /user/reposwhenowneris omitted and a token is set. Returnsfull_name, description, privacy/fork flags, and URL for each repo.list_github_directories— callsGET /repos/{owner}/{repo}/contents/{path}for a shallow listing, orGET /repos/{owner}/{repo}/git/trees/{ref}?recursive=1(filtered totype: "tree") for a full recursive directory walk.
Both accept an optional GITHUB_TOKEN (read from .env via dotenv) which is sent as a
Bearer token — required for your own private repos / own-account listing, and generally useful to
avoid GitHub's 60 req/hour unauthenticated rate limit (jumps to 5000 req/hour authenticated).
5. Project layout
Mcp/
├── src/index.ts Server source: tool definitions, GitHub API calls, stdio bootstrap
├── dist/index.js Compiled output — this is what actually gets executed
├── .env Your real GITHUB_TOKEN (git-ignored, never commit)
├── .env.example Template for .env (safe to commit)
├── .gitignore Excludes node_modules/, dist/, .env, Repository_token.txt
├── repositories.txt A saved snapshot of a list_github_repositories run
├── package.json Scripts: build (tsc), start, dev
└── tsconfig.json TypeScript compiler config (NodeNext modules, ES2022 target)
6. Setup from scratch
Requirements: Node.js 18+ (this was built and tested on Node 25).
cd "C:\Users\banda\OneDrive\Desktop\Mcp"
npm install
cp .env.example .env
Edit .env and paste in a GitHub token:
GITHUB_TOKEN=github_pat_xxxxxxxxxxxxxxxxxxxx
(Generate one at github.com → Settings → Developer settings → Personal access tokens. Fine-grained, read-only "Contents" + "Metadata" repo permissions are enough for these two tools.)
Build:
npm run build
This compiles src/index.ts → dist/index.js via tsc. Re-run this any time you edit src/index.ts.
7. Tool reference
list_github_repositories
| Param | Type | Required | Notes |
|---|---|---|---|
owner |
string | no | Username or org. Omit to list the authenticated user's own repos (needs GITHUB_TOKEN). |
perPage |
number 1-100 | no | Default 30. |
page |
number | no | Default 1. |
list_github_directories
| Param | Type | Required | Notes |
|---|---|---|---|
owner |
string | yes | e.g. "anthropics". Must be non-empty (validated). |
repo |
string | yes | e.g. "claude-code". Must be non-empty (validated). |
path |
string | no | Default: repo root. |
ref |
string | no | Branch/tag/SHA. Default: repo's default branch. |
recursive |
boolean | no | Default false. true walks the entire tree via the Git Trees API. |
Note: both owner and repo must actually be provided — if you ask something vague like "list
my repo's directories" without naming a repo, the calling model may send empty strings, which now
fails fast with a validation error instead of silently hitting a malformed GitHub URL.
8. Accessing the server
There are two ways to actually use this server, depending on your goal.
A. Through Claude Code (the real use case)
Register it once, from a normal terminal (not a sandboxed/CI one):
claude mcp add github-directory -- node "C:\Users\banda\OneDrive\Desktop\Mcp\dist\index.js"
Restart your Claude Code session (MCP servers load at session start), then just ask, naming the repo explicitly:
"List directories in Productdeveloper5192/MCP" "List my github repositories"
Claude reads the tool schemas via tools/list, decides when a request warrants calling one, and
calls it via tools/call — all of that JSON-RPC exchange happens invisibly.
B. MCP Inspector (manual/visual testing, no client needed)
npx @modelcontextprotocol/inspector node dist/index.js
This starts two things: a proxy on port 6277 (bridges the browser to your stdio process) and a UI on port 6274. It prints a URL with a session token baked in — open that exact URL.
- Click Connect.
- Tools tab → List Tools.
- Pick a tool, fill the form, Run Tool.
If you keep hitting "Error Connecting to MCP Inspector Proxy" from stale browser tabs/tokens, skip the token entirely for local testing:
$env:DANGEROUSLY_OMIT_AUTH="true"
npx @modelcontextprotocol/inspector node dist/index.js
C. Raw JSON-RPC over stdio (for scripting/debugging)
node dist/index.js
Feed it JSON-RPC lines on stdin, one per line — this is what's used internally to smoke-test the
server. Example sequence: initialize → notifications/initialized → tools/call.
9. Troubleshooting
GitHub API 404 for /repos//
owner/repo were empty when the tool was called — usually because the prompt to Claude didn't
name a specific repo. Now blocked at the schema level with a clear validation error instead (see
.min(1) in src/index.ts). Name the repo explicitly in your prompt.
"Error Connecting to MCP Inspector Proxy" The Inspector mints a new session token every time it starts. This almost always means an old browser tab is using a stale token from a previous run. Close all old Inspector tabs and open the exact URL (with token) printed by the current run.
MCP Inspector PORT IS IN USE at http://localhost:6274
A leftover node process from a prior Inspector run is still holding the port. Find and stop it:
netstat -ano | findstr 6274
Stop-Process -Id <PID> -Force
claude: command not found
You're not in a terminal where Claude Code's CLI is on PATH — use VS Code's integrated terminal or
your normal system terminal, not a restricted/sandboxed shell.
Rate limited / can't see private repos / owner omitted fails
Check GITHUB_TOKEN is actually set in .env and non-empty. Verify it directly:
curl -H "Authorization: Bearer $env:GITHUB_TOKEN" https://api.github.com/user
A 200 with your account info confirms the token is valid.
10. Advanced: extending this server
To add a new tool, follow the pattern already in src/index.ts:
server.registerTool(
"your_tool_name",
{
title: "Human-readable title",
description: "What it does — this is what the model reads to decide when to call it.",
inputSchema: {
someParam: z.string().min(1).describe("Shown to the model as field docs"),
},
},
async ({ someParam }) => {
// ... do work, call APIs, etc.
return { content: [{ type: "text", text: "result" }] };
}
);
Ideas in scope for this GitHub-focused server: list branches, list commits on a path, search code,
read a single file's content, list pull requests. Each is one more githubFetch call plus one more
registerTool block — no architectural changes needed.
If you ever need this reachable by more than one local client (e.g. a shared team server), swap
StdioServerTransport for the SDK's Streamable HTTP transport — at that point also add real auth in
front of it, since it stops being "only reachable by whoever can spawn the process" and becomes a
network service.
11. Security notes
.envholds a live GitHub token — it is git-ignored. Never commit it, never paste its contents into chat, issues, or logs.Repository_token.txtis also git-ignored as a safety net, but the token has already been moved into.env— that plaintext file is redundant and can be deleted.- Fine-grained PATs scoped to only the repos/permissions you need are safer than classic PATs with broad scopes — regenerate and re-scope if the current token was created broadly.
- This server only ever reads from GitHub (no write/delete endpoints are implemented), so the blast radius of a leaked token is limited to whatever that token itself can do on your account — treat it with the same care as a password.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.