Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ GITHUB_TOKEN=ghp_your_token_here
GITHUB_API_BASE_URL=https://api.github.com

# Server Configuration
MCP_SERVER_PORT=8000
MCP_SERVER_PORT=7860
LOG_LEVEL=INFO

# Docker BuildKit (enable for faster builds with cache mounts)
Expand Down
148 changes: 148 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

GitHub MCP Server is a Model Context Protocol (MCP) server that provides access to GitHub documentation via the GitHub API. It's built with FastMCP and runs as a stdio-based MCP server, designed to be integrated with Claude Desktop or other MCP clients.

## Development Commands

### Environment Setup

```bash
# Create and activate virtual environment
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

# Configure environment
cp .env.example .env
# Edit .env and add your GITHUB_TOKEN
```

### Running the Server

```bash
# Run directly with Python (stdio mode for MCP)
python main.py

# Run with Docker
docker build -t github-mcp-server:local .
docker run -i --rm -e GITHUB_TOKEN='your_token' github-mcp-server:local

# Run with docker-compose
docker-compose build
docker-compose up
```

### Docker Build Performance

The Dockerfile is optimized for fast rebuilds (10-20x faster):
- Uses BuildKit for layer caching
- Separates dependency installation from code copying
- Enable BuildKit: `export DOCKER_BUILDKIT=1`

## Architecture

### Single-File Architecture

The entire server is implemented in `main.py` (~650 lines) with a clear functional organization:

1. **Configuration & Setup** (lines 1-37): Environment loading, logging, MCP initialization
2. **Helper Functions** (lines 39-114): GitHub API headers, /doc folder detection, content type determination
3. **Business Logic Functions** (lines 116-442): Core async functions that implement GitHub API interactions
4. **MCP Tools Registration** (lines 444-569): Decorated wrappers that expose business logic as MCP tools
5. **MCP Resources** (lines 571-638): URI-based resource handlers for documentation access
6. **Main Entry Point** (lines 640-652): Server startup

### Key Design Patterns

**Separation of Concerns**: Business logic functions (e.g., `get_org_repos()`) are separate from MCP tool decorators (e.g., `get_org_repos_tool()`). This allows the core logic to be testable independently of MCP.

**Async/Await Throughout**: All GitHub API interactions use `aiohttp` for async HTTP requests. Functions reuse `ClientSession` objects for connection pooling.

**Two-Strategy Approach**: `get_org_repos()` tries GitHub Search API first (efficient, one request), then falls back to listing all repos individually if search fails.

**Base64 Decoding**: GitHub API returns file content as base64-encoded strings. The `get_file_content()` function automatically decodes this to UTF-8 text.

## MCP Integration

### Tools (4 total)

- `get_org_repos_tool(org)` - Lists repositories with /doc folder detection
- `get_repo_docs_tool(org, repo)` - Lists documentation files in a repo's /doc folder
- `get_file_content_tool(org, repo, path)` - Fetches and decodes file content
- `search_documentation_tool(org, query)` - Searches docs across repos using GitHub Code Search API

### Resources (2 patterns)

- `documentation://{org}/{repo}` - Lists documentation files in formatted text
- `content://{org}/{repo}/{path}` - Returns raw file content

### Environment Variables

Required:
- `GITHUB_TOKEN` - GitHub personal access token (scopes: `repo`, `read:org`, `read:user`)

Optional:
- `GITHUB_API_BASE_URL` - Default: `https://api.github.com`
- `LOG_LEVEL` - Default: `INFO`
- `MCP_SERVER_PORT` - Default: `8000` (note: not used in stdio mode)

## Supported File Types

The server filters for specific documentation file types in /doc folders:
- Markdown: `.md`
- Mermaid diagrams: `.mmd`, `.mermaid`
- SVG images: `.svg`
- OpenAPI specs: `.yml`, `.yaml`, `.json`
- Postman collections: `.json` (filename must start with "postman")

## Error Handling

- 404 responses return empty lists or specific error messages
- Rate limiting (403 from Search API) returns user-facing error message
- All GitHub API errors include status code and response text
- Missing GITHUB_TOKEN triggers warning but allows unauthenticated requests (with rate limits)

## Claude Desktop Configuration

Add to `claude_desktop_config.json`:

**Docker deployment:**
```json
{
"mcpServers": {
"github-docs": {
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_TOKEN", "ghcr.io/sperekrestova/github-mcp-server:latest"],
"env": {"GITHUB_TOKEN": "ghp_your_token_here"}
}
}
}
```

**Python deployment:**
```json
{
"mcpServers": {
"github-docs": {
"command": "python3",
"args": ["/absolute/path/to/main.py"],
"env": {"GITHUB_TOKEN": "ghp_your_token_here"}
}
}
}
```

## Testing Approach

Currently no test suite exists. When adding tests:
- Test business logic functions separately from MCP tool wrappers
- Mock `aiohttp.ClientSession` for GitHub API interactions
- Test base64 decoding edge cases in `get_file_content()`
- Test /doc folder detection logic
- Test file type filtering against supported extensions
38 changes: 10 additions & 28 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,35 +1,17 @@
# Optimized for fast builds using Debian slim with pre-compiled wheels
# Build time: ~30 seconds (cached) vs 5-10 minutes (Alpine compilation)
# Image size: ~150MB (acceptable trade-off for 10-20x faster builds)
FROM python:3.10

FROM python:3.10-slim AS builder
RUN useradd -m -u 1000 user
USER user
ENV PATH="/home/user/.local/bin:$PATH"

WORKDIR /app

# Copy requirements first (better layer caching)
COPY requirements.txt .
COPY --chown=user ./requirements.txt requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt

# Use BuildKit cache mount for pip - dramatically speeds up rebuilds
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --user -r requirements.txt
COPY --chown=user . /app

# Runtime stage - minimal final image
FROM python:3.10-slim
# Expose port 7860 for Hugging Face Spaces
EXPOSE 7860

# Create non-root user
RUN useradd -m -u 1000 app

WORKDIR /app

# Copy Python packages from builder
COPY --from=builder --chown=app:app /root/.local /home/app/.local

# Copy application code (changes frequently, so last)
COPY --chown=app:app main.py .

USER app

ENV PATH="/home/app/.local/bin:$PATH" \
PYTHONUNBUFFERED=1

ENTRYPOINT ["python", "main.py"]
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
---
title: GitHub MCP Server
emoji: 🐙
colorFrom: blue
colorTo: purple
sdk: docker
app_port: 7860
---

# GitHub MCP Server

Model Context Protocol server for accessing GitHub documentation via API.
Expand Down
Loading