Skip to main content
Glama
Arnab1999india

GitHub MCP Server

README.md
# GitHub MCP Server

A project that lets an **AI assistant talk to GitHub** using safe, structured tools.

In plain words: instead of the AI guessing how GitHub works, this project gives it a clear menu of actions — like “list my repos”, “show open issues”, or “read a file”. The AI picks the right action, this server talks to GitHub, and the answer comes back in a clean format the AI can understand.

---

## What problem does this solve?

Chatbots are good at language, but they do not automatically have live access to your GitHub account.

This project builds a **bridge**:

1. You ask something in normal English (“Show open issues in microsoft/vscode”).
2. An AI model (via Groq) decides which GitHub tool to use.
3. The **MCP server** runs that tool against the real GitHub API.
4. Results are cleaned up (normalized) and returned to the AI.
5. The AI explains the result to you in simple language.

**MCP** means **Model Context Protocol**. Think of it as a standard plug: any compatible AI client can connect to this server and use its tools.

---

## Big picture (architecture)

```
You
  ↓
AI Agent (client/agent.py)  ← talks to Groq LLM
  ↓
MCP Server (notebooks/server.py)  ← menu of GitHub tools
  ↓
GitHub Client  ← HTTP calls with your token
  ↓
GitHub REST API
  ↓
GitHub
```

### Design rule (important)

Tools stay **thin**:

1. Check the input (is the repo name valid?).
2. Call the GitHub client.
3. **Normalize** the response into a stable shape.
4. Return that clean data to the agent.

All messy GitHub details stay inside the client layer — not scattered across tools.

---

## Project folders (what each part is for)

| Path | What it is |
|------|------------|
| `notebooks/server.py` | **Main MCP server** — the production entrypoint the agent starts |
| `notebooks/schemas.py` | Stable data shapes (Pydantic models) for agents |
| `notebooks/normalize.py` | Converts raw GitHub JSON → those stable shapes |
| `notebooks/safety.py` | Confirm / dry-run / allowlist for dangerous tools |
| `notebooks/pagination.py` | Page helpers for list tools (`page`, `has_next`, …) |
| `notebooks/logging_utils.py` | JSON logs to **stderr** (never prints secrets) |
| `notebooks/server_1.py` | Older/experimental copy — prefer `server.py` |
| `notebooks/01_github_mcp_server.ipynb` | Learning notebook (how the server was built step by step) |
| `client/agent.py` | Chat agent that connects to the MCP server over stdio |
| `client/test_tool_picking.py` | Checks whether the AI picks the **right tool** for sample prompts |
| `.env` | Your private keys (never commit this) |
| `.env.example` | Template showing which keys you need |
| `requirements.txt` | Python packages to install |
| `SETUP.md` | **Step-by-step setup** for non-technical users |

---

## What you can do with the tools

The server exposes many GitHub actions. Grouped simply:

### Read (safe to explore)
- List your repositories
- Get repo details
- List / get issues and pull requests
- Get PR diffs
- List branches, commits, labels
- Search code in a repo
- Read file contents
- List GitHub Actions workflow runs

### Write (changes GitHub)
- Create issues, comments, PRs, branches, labels
- Update issues, add/remove labels
- Reopen issues

### Destructive (can hurt things — protected)
These need extra confirmation by default:

- `merge_pull_request`
- `delete_file`
- `create_repository`
- `create_or_update_file`
- `close_issue`

For these, the agent should usually:

1. Call with `dry_run=true` → preview only  
2. Call again with `confirm=true` → actually do it  

You can tighten or loosen this with environment settings (see below).

---

## Normalized responses (why agents like this)

Raw GitHub responses are huge and change often. This project returns **stable** shapes.

**List tools** always look like:

```json
{
  "count": 20,
  "items": [ ... ],
  "page": 1,
  "per_page": 20,
  "has_next": true,
  "has_prev": false,
  "next_page": 2,
  "prev_page": null,
  "last_page": 5
}
```

To get the next page, call the same tool again with `page=2` (or `page=next_page`).

**Issue example:**

```json
{
  "number": 42,
  "title": "Bug in login",
  "state": "open",
  "author": "some-user",
  "labels": ["bug"],
  "comments": 3,
  "html_url": "https://github.com/...",
  "is_pull_request": false
}
```

Also: `get_issues` **filters out pull requests** (GitHub’s issues API mixes them in).

---

## Safety features

| Feature | Meaning |
|---------|---------|
| `confirm=true` | Required to run destructive tools (default mode) |
| `dry_run=true` | Shows what would happen; does **not** change GitHub |
| `destructiveHint` | MCP annotation so clients know a tool is risky |
| Allowlist | Optional list of which destructive tools are even allowed |
| Mode | `confirm` (default), `allow` (no confirm), or `deny` (block all) |

Environment variables (optional):

```env
GITHUB_MCP_DESTRUCTIVE_MODE=confirm
GITHUB_MCP_DESTRUCTIVE_ALLOWLIST=merge_pull_request,delete_file
```

---

## Logging (for debugging)

The server writes **JSON logs to stderr only**.

Why stderr? MCP uses **stdout** for the protocol. If we printed logs there, the AI connection would break.

Logs include things like:

- request method and path
- HTTP status
- duration
- rate-limit remaining

They **never** log:

- your GitHub token
- Authorization headers
- secret-looking values (PATs, bearer tokens, etc.)

Example log line:

```json
{"ts":"2026-08-23T12:00:00+00:00","level":"INFO","event":"github_request","method":"GET","path":"/repos/microsoft/vscode/issues","status_code":200,"duration_ms":120.5}
```

---

## The AI agent (`client/agent.py`)

The agent:

1. Starts the MCP server as a subprocess (`notebooks/server.py`).
2. Asks the server for the tool list.
3. Sends your question + tools to Groq.
4. If Groq wants a tool, the agent calls it through MCP.
5. Sends the tool result back to Groq for a final answer.

Useful commands (from the project folder, with the virtual environment active):

```powershell
# See all registered tools
python client/agent.py --list-tools

# Only show which tool the AI would pick (no GitHub write)
python client/agent.py --dry-run "list my github repos"

# One real question, then exit
python client/agent.py --once "show open issues for microsoft/vscode"

# Interactive chat
python client/agent.py

# Check tool-picking quality on many sample prompts
python client/test_tool_picking.py
```

Loop limits (optional):

```powershell
python client/agent.py --max-rounds 5 --once "..."
```

Or in `.env`:

```env
AGENT_MAX_TOOL_ROUNDS=8
AGENT_MAX_TOOL_CALLS=16
AGENT_MAX_CONSECUTIVE_ERRORS=3
```

---

## Environment variables

### Required for the MCP server

| Variable | Purpose |
|----------|---------|
| `GITHUB_TOKEN` | Personal access token so the server can call GitHub |
| `GITHUB_USERNAME` | Your GitHub username (used at startup validation) |
| `GITHUB_REPO` | A default repo name (used at startup validation) |

### Required for the agent (chat / tool picking)

| Variable | Purpose |
|----------|---------|
| `GROQ_API_KEY` | API key for Groq (LLM) |

### Optional

| Variable | Purpose |
|----------|---------|
| `GROQ_MODEL` | Default: `openai/gpt-oss-20b` |
| `GITHUB_MCP_DESTRUCTIVE_MODE` | `confirm` / `allow` / `deny` |
| `GITHUB_MCP_DESTRUCTIVE_ALLOWLIST` | Comma-separated destructive tool names |
| `AGENT_MAX_TOOL_ROUNDS` | Max tool rounds per user message |
| `AGENT_MAX_TOOL_CALLS` | Max tool executions per user message |
| `AGENT_MAX_CONSECUTIVE_ERRORS` | Stop after N tool failures in a row |

Copy `.env.example` → `.env` and fill in real values. See **SETUP.md** for the full walkthrough.

---

## Tech stack (for the curious)

- **Python 3.13+** (project was developed on 3.13)
- **MCP** (`mcp` Python package) — tool server protocol
- **httpx** — HTTP client for GitHub
- **Pydantic** — schemas / validation
- **python-dotenv** — load `.env`
- **OpenAI-compatible client** → Groq for the agent
- **Jupyter** (optional) — the learning notebook

---

## How to set up and run

Follow the friendly guide:

👉 **[SETUP.md](SETUP.md)** — install Python, create keys, configure `.env`, and run your first commands.

Short version (if you already know Python):

```powershell
cd "path\to\Github-MCP-server"
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
copy .env.example .env
# edit .env with your tokens
python client/agent.py --list-tools
python client/agent.py --once "list my github repos"
```

---

## Learning path (recommended)

1. Read this README (you are here).
2. Complete **SETUP.md** until `--list-tools` works.
3. Read **[docs/ARCHITECTURE_HLD_LLD.md](docs/ARCHITECTURE_HLD_LLD.md)** for HLD + LLD flows.
4. Try `--dry-run` and `--once` with simple read-only questions.
5. Run the **50-scenario manual test plan**: [tests/MANUAL_TESTING_50_SCENARIOS.md](tests/MANUAL_TESTING_50_SCENARIOS.md)
   - Auto picking: `python client/run_manual_scenarios.py`
6. Open `notebooks/01_github_mcp_server.ipynb` to see how each layer was built.
7. Only then try write/destructive tools with `dry_run` + `confirm`.

---

## Troubleshooting (quick)

| Problem | Likely fix |
|---------|------------|
| `No module named 'mcp'` | Activate `.venv` or use `.\.venv\Scripts\python.exe` |
| Groq model 404 | Set `GROQ_MODEL=openai/gpt-oss-20b` (or another model from your Groq account) |
| Missing env vars | Fill `GITHUB_TOKEN`, `GITHUB_USERNAME`, `GITHUB_REPO` in `.env` |
| Destructive tool blocked | Expected — use `dry_run=true` then `confirm=true`, or set mode in `.env` |
| Agent hangs on exit (Windows) | Known stdio quirk; one-shot commands force-exit after finishing |

---

## Security reminders

- Never commit `.env`.
- Never paste your GitHub or Groq tokens into chat, screenshots, or GitHub issues.
- Prefer a GitHub token with **only the scopes you need**.
- Keep `GITHUB_MCP_DESTRUCTIVE_MODE=confirm` (or `deny`) unless you fully trust the environment.
- Do not share `server_1.py` debug output if it ever printed tokens in older experiments — use `server.py`.

---

## License / ownership

This is a personal / learning Gen-AI project for a GitHub MCP server and agent. Adjust ownership and license as needed before publishing publicly.