github-directory-mcp

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.

Category
Visit Server

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

  1. What is MCP
  2. How the protocol actually works
  3. Transports: stdio vs HTTP
  4. What this project does
  5. Project layout
  6. Setup from scratch
  7. Tool reference
  8. Accessing the server
  9. Troubleshooting
  10. Advanced: extending this server
  11. 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.js does.
  • 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 — calls GET /users/{owner}/repos (falling back to GET /orgs/{owner}/repos if that 404s), or GET /user/repos when owner is omitted and a token is set. Returns full_name, description, privacy/fork flags, and URL for each repo.
  • list_github_directories — calls GET /repos/{owner}/{repo}/contents/{path} for a shallow listing, or GET /repos/{owner}/{repo}/git/trees/{ref}?recursive=1 (filtered to type: "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.

  1. Click Connect.
  2. Tools tab → List Tools.
  3. 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

  • .env holds a live GitHub token — it is git-ignored. Never commit it, never paste its contents into chat, issues, or logs.
  • Repository_token.txt is 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

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured