# GitHub MCP Server - Architecture Analysis v2.5.5
**Project:** GitHub MCP Server (code-first reference implementation)
**Version:** 2.5.5
**Last Updated:** 2025-12-17
---
## Executive Summary
The GitHub MCP Server is a **code-first MCP implementation** that provides **112 tools** (111 internal + execute_code) through a single `execute_code` entrypoint, achieving **98% token reduction** compared to traditional MCP servers.
### Key Metrics
- **112 tools** across 18 categories
- **1 exposed MCP tool** (`execute_code`)
- **108 internal tools** (GitHub API + workspace operations)
- **21 tool modules** organized by domain
- **97% latency reduction** with connection pooling (~4000ms → ~108ms)
- **320 tests** with comprehensive coverage
- **Dual authentication** (GitHub App + PAT fallback)
### Core Innovations
1. **Code-First Architecture**: Single `execute_code` tool instead of 109 individual tools
2. **Connection Pooling**: Persistent Deno subprocesses with MCP connections for 35x performance improvement
3. **Dict→Model Conversion**: Automatic Pydantic model hydration from JavaScript objects
4. **Modular Structure**: Clean separation of tools, models, utilities, and authentication
---
## Project Structure
### Directory Layout
```
github-mcp-server/
├── src/github_mcp/ # Main package
│ ├── __init__.py # Package exports (server components only)
│ ├── server.py # FastMCP server + tool registration
│ ├── deno_runtime.py # TypeScript execution bridge
│ ├── cli.py # CLI utilities for diagnostics
│ ├── tools/ # 20 tool modules (105 GitHub tools)
│ │ ├── __init__.py # Tool exports
│ │ ├── repositories.py # 6 tools
│ │ ├── branches.py # 5 tools
│ │ ├── issues.py # 3 tools
│ │ ├── pull_requests.py # 7 tools
│ │ ├── files.py # 9 tools
│ │ ├── actions.py # 15 tools
│ │ ├── releases.py # 5 tools
│ │ ├── search.py # 3 tools
│ │ ├── security.py # 13 tools
│ │ ├── projects.py # 9 tools
│ │ ├── notifications.py # 6 tools
│ │ ├── collaborators.py # 3 tools
│ │ ├── gists.py # 5 tools
│ │ ├── discussions.py # 4 tools
│ │ ├── labels.py # 3 tools
│ │ ├── stargazers.py # 3 tools
│ │ ├── users.py # 3 tools
│ │ ├── commits.py # 1 tool
│ │ ├── comments.py # 1 tool
│ │ ├── misc.py # 1 tool
│ │ └── workspace.py # 3 workspace tools (not GitHub API)
│ ├── models/ # Pydantic input models
│ │ ├── __init__.py
│ │ ├── inputs.py # All input model definitions
│ │ └── enums.py # ResponseFormat, etc.
│ ├── utils/ # Shared utilities
│ │ ├── __init__.py
│ │ ├── requests.py # HTTP client + auth helpers
│ │ ├── errors.py # Error handling & mapping
│ │ ├── formatting.py # Response formatting & truncation
│ │ ├── workspace_validation.py # Workspace path validation
│ │ ├── health.py # Health check utilities
│ │ ├── deno_pool.py # Connection pooling implementation
│ │ └── pool_stats.py # Pool statistics & monitoring
│ └── auth/ # Authentication (GitHub App + PAT)
│ └── github_app.py # Dual-auth implementation
├── deno_executor/ # TypeScript runtime
│ ├── mod.ts # Unified executor (supports both pooled and single-shot modes)
│ ├── tool-definitions.ts # Tool schema catalog (112 tools)
│ ├── code-validator.ts # Code validation & sanitization
│ ├── error-codes.ts # Standardized error codes
│ └── error-handling.ts # Error handling utilities
├── servers/ # MCP client implementation
│ ├── client-deno.ts # Deno-side MCP client
│ └── client.ts # Node.js MCP client (legacy)
├── tests/ # Test suite (320 tests)
│ ├── test_individual_tools.py # Per-tool unit tests
│ ├── test_execute_code.py # execute_code integration
│ ├── test_execute_code_mcp.py # MCP bridge tests
│ ├── test_deno_runtime.py # Deno runtime tests
│ ├── test_tool_discovery.py # Tool discovery tests
│ ├── test_write_operations_integration.py # Write op tests
│ ├── test_contracts.py # TS↔Python contract tests
│ ├── test_regressions.py # Regression tests
│ └── discover_tool_issues.py # Tool schema validation
├── scripts/
│ ├── live_integration_test.py # Live API tests (15/15 passing)
│ └── benchmark_deno_pool.py # Pool performance benchmarks
└── docs/ # Documentation
├── ARCHITECTURE_ANALYSIS.md # This file
├── AUTHENTICATION.md # Auth setup guide
├── ADVANCED_GITHUB_APP.md # GitHub App setup
└── CONFIGURATION.md # Configuration guide
```
### Tool Distribution by Module
| Module | Tools | Category |
|--------|-------|----------|
| `actions.py` | 15 | GitHub Actions |
| `security.py` | 13 | Security & Dependabot |
| `files.py` | 9 | File Operations |
| `projects.py` | 9 | Projects & Boards |
| `repositories.py` | 8 | Repository Management |
| `pull_requests.py` | 7 | Pull Requests |
| `notifications.py` | 6 | Notifications |
| `branches.py` | 5 | Branch Management |
| `gists.py` | 4 | Gists |
| `discussions.py` | 4 | Discussions |
| `releases.py` | 4 | Releases |
| `search.py` | 3 | Search |
| `collaborators.py` | 3 | Collaborators |
| `issues.py` | 3 | Issues |
| `labels.py` | 3 | Labels |
| `stargazers.py` | 3 | Stargazers |
| `users.py` | 3 | Users |
| `commits.py` | 1 | Commits |
| `comments.py` | 1 | Comments |
| `misc.py` | 1 | Miscellaneous |
| `workspace.py` | 3 | Workspace (local files) |
| **Total** | **105 GitHub + 3 workspace = 108** | **+ 1 execute_code = 109** |
---
## Architecture Layers
### Layer 1: Entry Point
**Entry Point:** `python -m github_mcp` (via `src/github_mcp/__main__.py`)
Minimal entry point that delegates to the server module:
```python
from src.github_mcp.server import mcp, run
if __name__ == "__main__":
run()
```
**Purpose:**
- Provides `python -m github_mcp` entrypoint
- No backward compatibility exports (clean architecture)
---
### Layer 2: Server (FastMCP)
**File:** `src/github_mcp/server.py`
**Responsibilities:**
1. FastMCP server initialization
2. Tool registration with dict→model conversion
3. `execute_code` implementation
4. Conditional tool exposure (code-first mode)
**Key Components:**
#### Tool Registration
Tools are registered with automatic dict→Pydantic model conversion:
```python
async def wrapper(params):
# Auto-detect Pydantic model from function signature
model_cls = None
try:
sig = inspect.signature(func)
first_param = next(iter(sig.parameters.values()))
ann = first_param.annotation
if isinstance(ann, type) and issubclass(ann, BaseModel):
model_cls = ann
except Exception:
model_cls = None
# Convert dict to model if needed (for execute_code calls)
if model_cls and isinstance(params, dict):
params = model_cls(**params)
return await func(params)
```
**This enables:**
- TypeScript `callMCPTool("github_get_repo_info", { owner: "...", repo: "..." })`
- Python tools receive `RepoInfoInput(owner="...", repo="...")` automatically
#### Code-First Mode
- **Default:** `CODE_FIRST_MODE = true` (only `execute_code` exposed)
- **Internal Mode:** `CODE_FIRST_MODE = false` (all tools exposed for Deno runtime)
#### execute_code Implementation
```python
async def execute_code(code: str) -> str:
"""Execute TypeScript code with access to all GitHub MCP tools."""
runtime = get_runtime()
if hasattr(runtime, 'execute_code_async'):
result = await runtime.execute_code_async(code) # Pooled
else:
result = runtime.execute_code(code) # Single-run
# Format response (JSON for structured data, markdown for strings)
return format_result(result)
```
---
### Layer 3: Tools (Modular)
**Location:** `src/github_mcp/tools/`
**Structure:**
- Each module contains related tools (e.g., `repositories.py` has 8 repo tools)
- All tools use Pydantic input models from `models/inputs.py`
- Shared utilities from `utils/` (requests, errors, formatting)
**Example Tool Pattern:**
```python
from ..models.inputs import RepoInfoInput
from ..models.enums import ResponseFormat
from ..utils.requests import _make_github_request
from ..utils.errors import _handle_api_error
async def github_get_repo_info(params: RepoInfoInput) -> str:
"""Get repository information."""
token = _get_auth_token_fallback(params.token)
try:
response = await _make_github_request(
"GET",
f"/repos/{params.owner}/{params.repo}",
token=token
)
# Format response based on response_format
return format_repo_info(response, params.response_format)
except Exception as e:
return _handle_api_error(e, "Failed to get repository info")
```
**Key Patterns:**
1. **Pydantic Input Models**: Strict validation, type safety
2. **Dual Auth**: `_get_auth_token_fallback()` handles GitHub App + PAT
3. **Error Handling**: Centralized via `_handle_api_error()`
4. **Response Formatting**: JSON or Markdown based on `response_format` parameter
---
### Layer 4: Deno Runtime
**Files:**
- `src/github_mcp/deno_runtime.py` - Python bridge
- `src/github_mcp/utils/deno_pool.py` - Connection pooling
- `deno_executor/mod.ts` - Unified executor (supports both modes)
#### Unified Executor (`mod.ts`)
**Purpose:** Single executor supporting both pooled and single-shot execution modes
**Modes:**
1. **Pooled mode (default):** Persistent process for connection pooling
- Initialize MCP connection once (persistent)
- Loop: Read JSON lines from stdin
- Execute each line with persistent connection
- Keep process alive for reuse
2. **Single-shot mode (`--single-shot` flag):** One-time code execution
- Read code from stdin (full read until EOF)
- Initialize MCP client
- Execute user code with injected helpers
- Return JSON result
- Close MCP client and exit
**Key Features:**
- Unified codebase eliminates duplication
- Supports both execution modes via command-line flag
- Reads **all** stdin in single-shot mode (supports multiline code)
- Graceful error handling with structured errors
**Flow:**
1. Initialize MCP connection once (persistent)
2. Loop: Read JSON lines from stdin
3. Each line: `{ "code": "..." }`
4. Execute code, return JSON result
5. Keep MCP connection alive
**Key Features:**
- **Persistent MCP connection** (no re-initialization overhead)
- **JSON protocol** for multiline code support
- **Health checks** via `listTools` MCP call
- **Graceful degradation** (falls back to raw code if JSON parse fails)
#### Connection Pool (`deno_pool.py`)
**Configuration:**
- `min_size`: 1 (default)
- `max_size`: 5 (default)
- `max_idle_time`: 300s (5 minutes)
- `max_lifetime`: 3600s (1 hour)
- `max_requests_per_process`: 1000
**Lifecycle:**
1. **Initialization**: Create `min_size` processes
2. **Request Handling**:
- Find idle process or create new (up to `max_size`)
- Mark as BUSY, execute code, mark as IDLE
3. **Health Checks**: Every 30s, verify process health
4. **Cleanup**: Remove processes that are:
- Idle > `max_idle_time`
- Age > `max_lifetime`
- Request count > `max_requests_per_process`
- Unhealthy (failed health check)
**Performance:**
- **Without pooling:** ~4000ms per execution
- **With pooling:** ~108ms per execution
- **Improvement:** 97.2% (35x faster)
---
### Layer 5: GitHub API
**File:** `src/github_mcp/utils/requests.py`
**Responsibilities:**
1. HTTP client (`httpx` with async support)
2. Authentication (GitHub App + PAT)
3. Error handling & mapping
4. Rate limit awareness
**Authentication Flow:**
```
Tool Call
↓
_get_auth_token_fallback(param_token)
↓
├─ param_token provided? → Use it
└─ No param_token?
↓
get_auth_token() [auth/github_app.py]
↓
├─ GITHUB_AUTH_MODE=pat? → GITHUB_TOKEN
├─ GITHUB_AUTH_MODE=app? → GitHub App token
└─ Default?
├─ GitHub App configured? → Try App, fallback to PAT
└─ No App? → GITHUB_TOKEN
```
**Dual Authentication:**
1. **GitHub App** (Preferred)
- Rate limit: 15,000 req/hour
- Token lifetime: 60 minutes
- Cached with 55-minute TTL
- JWT generation for installation token
2. **Personal Access Token** (Fallback)
- Rate limit: 5,000 req/hour
- Required for releases (GitHub App limitation)
- Simple configuration
---
## Key Components
### Code-First Architecture
**How It Works:**
1. **MCP Client** sees only `execute_code` tool (~800 tokens)
2. **User provides TypeScript code** that calls tools dynamically
3. **Deno executor** runs code with injected helpers:
- `callMCPTool(name, params)` - Call any tool
- `listAvailableTools()` - Discover all tools
- `searchTools(keyword)` - Search tools
- `getToolInfo(name)` - Get tool details
**Example:**
```typescript
// User code (executed in Deno)
const repo = await callMCPTool("github_get_repo_info", {
owner: "crypto-ninja",
repo: "mcp-test-repo"
});
const branches = await callMCPTool("github_list_branches", {
owner: "crypto-ninja",
repo: "mcp-test-repo"
});
return { repo, branches };
```
**Benefits:**
- **98% token reduction** (70,000 → 800 tokens)
- **Multi-step workflows** in single call
- **Conditional logic** and loops
- **Error handling** with try/catch
---
### Connection Pooling
**Architecture:**
```
Python Server
↓
DenoConnectionPool
├─ PooledDenoProcess 1 (IDLE, MCP connected)
├─ PooledDenoProcess 2 (BUSY, executing)
└─ PooledDenoProcess 3 (IDLE, MCP connected)
```
**Process States:**
- `IDLE`: Ready for requests
- `BUSY`: Currently executing code
- `UNHEALTHY`: Failed health check
**Health Checks:**
- Every 30 seconds
- Calls `listTools` via MCP to verify connection
- Removes unhealthy processes
**JSON Protocol:**
Python sends:
```json
{"code": "const x = 1 + 1; return x;"}
```
Deno receives, executes, returns:
```json
{"error": false, "data": 2}
```
**Performance Benchmarks:**
| Metric | Without Pooling | With Pooling | Improvement |
|--------|----------------|--------------|-------------|
| First request | ~4000ms | ~4000ms | - |
| Subsequent requests | ~4000ms | ~108ms | **97.2%** |
| MCP connection overhead | Per request | Once per process | **Eliminated** |
| Process creation | Per request | Pooled | **Eliminated** |
---
### Authentication Flow
**File:** `src/github_mcp/auth/github_app.py`
**GitHub App Authentication:**
```python
class GitHubAppAuth:
_token: Optional[str] = None
_expires_at: Optional[float] = None
_lock: asyncio.Lock
async def get_installation_token(...):
# Check cache (55-minute TTL)
if self._token and time.time() < self._expires_at - 60:
return self._token
# Generate JWT (9-minute lifetime)
jwt = self._generate_jwt()
# Get installation token (60-minute lifetime)
token = await self._fetch_installation_token(jwt)
# Cache for 55 minutes
self._token = token
self._expires_at = time.time() + 3300
return token
```
**Dual-Auth Resolution:**
```python
def get_auth_token() -> Optional[str]:
"""Resolve authentication: App → PAT → None."""
# 1. Explicit mode: GITHUB_AUTH_MODE=pat
if os.getenv("GITHUB_AUTH_MODE") == "pat":
return os.getenv("GITHUB_TOKEN")
# 2. Explicit mode: GITHUB_AUTH_MODE=app
if os.getenv("GITHUB_AUTH_MODE") == "app":
token = get_installation_token_from_env()
if token:
return token
# Fallback to PAT
# 3. Default: Try App, fallback to PAT
if _has_app_config():
token = get_installation_token_from_env()
if token:
return token
# Fallback to PAT
return os.getenv("GITHUB_TOKEN")
```
**Token Priority:**
1. Tool `token` parameter (explicit override)
2. GitHub App (if configured)
3. Personal Access Token (`GITHUB_TOKEN`)
4. None (public repos only)
---
### Error Handling
**File:** `src/github_mcp/utils/errors.py`
**Structured Errors:**
```python
def _handle_api_error(e: Exception, context: str) -> str:
"""Map HTTP errors to user-friendly messages."""
if isinstance(e, httpx.HTTPStatusError):
status = e.response.status_code
if status == 401:
return "❌ Authentication required. Check your GITHUB_TOKEN or GitHub App configuration."
elif status == 403:
return "❌ Insufficient permissions. Check your token scopes."
elif status == 404:
return f"❌ Resource not found: {context}"
# ... more mappings
```
**Deno Error Format:**
```typescript
{
error: true,
message: "Error description",
code: "AUTHENTICATION_REQUIRED",
details: {
stack: "...",
// Additional context
}
}
```
**Error Codes:**
- `AUTHENTICATION_REQUIRED`
- `INSUFFICIENT_PERMISSIONS`
- `RESOURCE_NOT_FOUND`
- `VALIDATION_ERROR`
- `RATE_LIMIT_EXCEEDED`
- `EXECUTION_TIMEOUT`
- `CODE_VALIDATION_FAILED`
---
### Security
**Code Validation:**
**File:** `deno_executor/code-validator.ts`
**Blocked Patterns:**
- `Deno.*` (except allowed APIs)
- `import.*` (no external imports)
- `fetch.*` (no network access)
- `eval`, `Function` constructor (no dynamic code)
**Allowed APIs:**
- Standard JavaScript/TypeScript
- Injected helpers (`callMCPTool`, `listAvailableTools`, etc.)
- `JSON.parse`, `JSON.stringify`
- Array/object methods
**Sanitization:**
- Error messages sanitized before returning
- Stack traces truncated
- No sensitive data in errors
---
## Data Flow
### Read Operation Flow
```
┌─────────────┐
│ MCP Client │
│ (Cursor) │
└──────┬──────┘
│ execute_code(code)
↓
┌──────────────────────────┐
│ Python Server │
│ (server.py) │
│ - Receives code string │
│ - Gets Deno runtime │
└──────┬───────────────────┘
│ execute_code_async(code)
↓
┌──────────────────────────┐
│ Deno Pool │
│ (deno_pool.py) │
│ - Finds idle process │
│ - Sends JSON: {code} │
└──────┬───────────────────┘
│ JSON line via stdin
↓
┌──────────────────────────┐
│ Deno Executor │
│ (mod.ts) │
│ - Parses JSON │
│ - Executes user code │
│ - callMCPTool(...) │
└──────┬───────────────────┘
│ MCP tool call
↓
┌──────────────────────────┐
│ Python Tool │
│ (tools/repositories.py) │
│ - Converts dict→model │
│ - Gets auth token │
│ - Makes GitHub API call │
└──────┬───────────────────┘
│ HTTP GET
↓
┌──────────────────────────┐
│ GitHub API │
│ api.github.com │
└──────┬───────────────────┘
│ JSON response
↓
┌──────────────────────────┐
│ Python Tool │
│ - Formats response │
│ - Returns to MCP │
└──────┬───────────────────┘
│ Tool result
↓
┌──────────────────────────┐
│ Deno Executor │
│ - Collects result │
│ - Returns to pool │
└──────┬───────────────────┘
│ JSON: {error: false, data: ...}
↓
┌──────────────────────────┐
│ Python Server │
│ - Formats final result │
└──────┬───────────────────┘
│ MCP response
↓
┌─────────────┐
│ MCP Client │
│ (Result) │
└─────────────┘
```
### Write Operation Flow
Same as read flow, with additional authentication check:
```
Python Tool
↓
_get_auth_token_fallback()
↓
├─ Token provided? → Use it
└─ No token?
↓
get_auth_token()
↓
├─ GitHub App → Installation token
└─ PAT → GITHUB_TOKEN
↓
_make_github_request("POST", ...)
↓
GitHub API
↓
Response
```
**Authentication Required:**
- Create, update, delete operations
- Private repository access
- Write operations (issues, PRs, files, etc.)
**Read Operations (Public Repos):**
- Can work without authentication
- Token optional (for higher rate limits)
---
## Performance
### Benchmarks
**Connection Pooling:**
| Scenario | Latency | Notes |
|----------|---------|-------|
| First request (cold start) | ~4000ms | Process creation + MCP init |
| Subsequent requests (warm) | ~108ms | Pooled process reuse |
| **Improvement** | **97.2%** | **35x faster** |
**Token Efficiency:**
| Mode | Tokens | Savings |
|------|--------|---------|
| Traditional MCP | ~70,000 | Baseline |
| Code-First | ~800 | **98.9% reduction** |
**Rate Limits:**
| Auth Method | Rate Limit | Use Case |
|-------------|------------|----------|
| GitHub App | 15,000 req/hour | Production, CI/CD |
| Personal Access Token | 5,000 req/hour | Development, personal |
---
## Testing
### Test Coverage
**Total Tests:** 320
**Test Categories:**
1. **Unit Tests** (`test_individual_tools.py`)
- Per-tool validation
- Pydantic model validation
- Error handling
- Authentication mocks
2. **Integration Tests** (`test_execute_code.py`, `test_execute_code_mcp.py`)
- `execute_code` end-to-end
- MCP bridge functionality
- Deno runtime integration
3. **Contract Tests** (`test_contracts.py`)
- TypeScript ↔ Python schema alignment
- Tool parameter validation
- Response format consistency
4. **Live Integration Tests** (`scripts/live_integration_test.py`)
- Real GitHub API calls
- **15/15 tests passing**
- Read operations (no token)
- Write operations (with token)
- `execute_code` functionality
- Connection pooling verification
5. **Regression Tests** (`test_regressions.py`)
- Known issue prevention
- Backward compatibility
6. **Discovery Tests** (`discover_tool_issues.py`)
- Tool schema validation
- Missing tool detection
- Parameter mismatch detection
### Test Execution
```bash
# Run all tests
pytest
# Run with coverage
pytest --cov=src/github_mcp --cov-report=html
# Run live integration tests
python scripts/live_integration_test.py
```
---
## Configuration
### Environment Variables
| Variable | Required | Description | Default |
|----------|----------|-------------|---------|
| `GITHUB_TOKEN` | Yes* | Personal Access Token | - |
| `GITHUB_APP_ID` | No | GitHub App ID | - |
| `GITHUB_APP_INSTALLATION_ID` | No | Installation ID | - |
| `GITHUB_APP_PRIVATE_KEY` | No | Private key content (CI/CD) | - |
| `GITHUB_APP_PRIVATE_KEY_PATH` | No | Path to .pem file (local) | - |
| `GITHUB_AUTH_MODE` | No | `app` or `pat` | Auto-detect |
| `MCP_WORKSPACE_ROOT` | No | Workspace root directory | Current directory |
| `MCP_CODE_FIRST_MODE` | No | Code-first mode (legacy) | `true` |
| `GITHUB_MCP_DEBUG_AUTH` | No | Enable auth debug logging | `false` |
**\* Required for write operations and private repos. Read operations on public repos work without authentication.**
### Configuration Files
**`.env` file (development/local testing only):**
```bash
GITHUB_TOKEN=ghp_your_token_here
GITHUB_APP_ID=123456
GITHUB_APP_INSTALLATION_ID=12345678
GITHUB_APP_PRIVATE_KEY_PATH=/path/to/key.pem
MCP_WORKSPACE_ROOT=/path/to/workspace
```
For production and typical runtime use, environment variables should be configured via your MCP client (for example, the Claude Desktop config file) rather than a `.env` file.
**Claude Desktop Config (primary runtime configuration):**
```json
{
"mcpServers": {
"github": {
"command": "python",
"args": ["-m", "github_mcp"],
"env": {
"GITHUB_TOKEN": "ghp_your_token_here"
}
}
}
}
```
---
## Future Considerations
### Planned Improvements
1. **Automated Tool Schema Sync**
- Generate `tool-definitions.ts` from Python tool metadata
- Eliminate manual sync between TS and Python
2. **Enhanced Error Typing**
- Richer error types across Python↔TypeScript boundary
- Programmatic error handling in workflows
3. **Configurable Execution Limits**
- Max runtime per execution
- Max MCP calls per execution
- Memory limits
4. **Tool Categories in MCP Docs**
- Surface tool categories in MCP-level documentation
- Help agents discover tools before first `execute_code` call
5. **Non-Code-First Mode for Debugging**
- Optional mode exposing all tools directly
- Useful for debugging and migration
### Known Limitations
1. **Deno Runtime Required**
- Server exits early if Deno not found
- Clear error message with installation instructions
2. **Manual Schema Sync**
- TypeScript `tool-definitions.ts` must match Python tools
- Contract tests catch mismatches, but manual updates required
3. **Some Tools Don't Support `response_format=json`**
- Write operations intentionally omit `response_format`
- Some read operations may not support JSON (legacy)
---
## Architecture Diagrams
### Request Flow (ASCII)
```
┌─────────────────────────────────────────────────────────────┐
│ MCP Client │
│ (Cursor, Claude, etc.) │
└───────────────────────────┬─────────────────────────────────┘
│
│ execute_code(code: string)
↓
┌─────────────────────────────────────────────────────────────┐
│ Python MCP Server │
│ (src/github_mcp/server.py) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ FastMCP("github_mcp") │ │
│ │ - CODE_FIRST_MODE=true (default) │ │
│ │ - Tool registration with dict→model conversion │ │
│ │ - execute_code handler │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│
│ get_runtime().execute_code_async(code)
↓
┌─────────────────────────────────────────────────────────────┐
│ Deno Connection Pool │
│ (src/github_mcp/utils/deno_pool.py) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ PooledDenoProcess 1 (IDLE, MCP connected) │ │
│ │ PooledDenoProcess 2 (BUSY, executing) │ │
│ │ PooledDenoProcess 3 (IDLE, MCP connected) │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│
│ JSON: {"code": "..."}
↓
┌─────────────────────────────────────────────────────────────┐
│ Deno Executor (Pooled) │
│ (deno_executor/mod.ts) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ - Persistent MCP connection │ │
│ │ - Reads JSON lines from stdin │ │
│ │ - Executes user TypeScript code │ │
│ │ - Injected helpers: │ │
│ │ • callMCPTool(name, params) │ │
│ │ • listAvailableTools() │ │
│ │ • searchTools(keyword) │ │
│ │ • getToolInfo(name) │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│
│ MCP tool call
↓
┌─────────────────────────────────────────────────────────────┐
│ Python Tools │
│ (src/github_mcp/tools/*.py) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ - Dict→Pydantic model conversion │ │
│ │ - Authentication (GitHub App + PAT) │ │
│ │ - GitHub API calls via _make_github_request() │ │
│ │ - Error handling & formatting │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────────┬─────────────────────────────────┘
│
│ HTTP/GraphQL
↓
┌─────────────────────────────────────────────────────────────┐
│ GitHub API │
│ (api.github.com) │
└─────────────────────────────────────────────────────────────┘
```
### Authentication Flow
```
┌─────────────────────────────────────────────────────────────┐
│ Tool Call │
│ github_get_repo_info({owner, repo}) │
└───────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ _get_auth_token_fallback(param_token) │
└───────────────────────────┬─────────────────────────────────┘
│
├─ param_token provided?
│ └─→ Use param_token
│
└─ No param_token?
↓
┌─────────────────────────────────────────────────────────────┐
│ get_auth_token() │
│ (src/github_mcp/auth/github_app.py) │
└───────────────────────────┬─────────────────────────────────┘
│
├─ GITHUB_AUTH_MODE=pat?
│ └─→ Return GITHUB_TOKEN
│
├─ GITHUB_AUTH_MODE=app?
│ └─→ Try GitHub App
│ ├─ Success → Return App token
│ └─ Failure → Fallback to PAT
│
└─ Default (auto-detect)?
├─ GitHub App configured?
│ ├─ Try App → Success → Return App token
│ └─ Failure → Fallback to PAT
│
└─ Return GITHUB_TOKEN (or None)
```
### Connection Pool Lifecycle
```
┌─────────────────────────────────────────────────────────────┐
│ Pool Initialization │
│ (min_size=1, max_size=5) │
└───────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Create PooledDenoProcess 1 │
│ - Start Deno subprocess (mod.ts) │
│ - Initialize MCP connection │
│ - State: IDLE │
└───────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Request Arrives │
└───────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Find Idle Process │
│ - Check pool for IDLE process │
│ - If none, create new (up to max_size) │
│ - Mark as BUSY │
└───────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Execute Code │
│ - Send JSON: {"code": "..."} │
│ - Deno executes, calls tools via MCP │
│ - Receive JSON: {"error": false, "data": ...} │
└───────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Mark as IDLE │
│ - Update last_used timestamp │
│ - Increment request_count │
└───────────────────────────┬─────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Health Check Loop (every 30s) │
│ - Check process health (listTools MCP call) │
│ - Remove if: │
│ • Idle > max_idle_time (5 min) │
│ • Age > max_lifetime (1 hour) │
│ • Requests > max_requests_per_process (1000) │
│ • Unhealthy (failed health check) │
└─────────────────────────────────────────────────────────────┘
```
---
## Key Insights
### Design Decisions
1. **Code-First Over Traditional MCP**
- **Why:** 98% token reduction, better scalability
- **Trade-off:** Requires Deno runtime, more complex error handling
2. **Connection Pooling**
- **Why:** 97% latency reduction for subsequent requests
- **Trade-off:** More complex lifecycle management
3. **Dict→Model Conversion**
- **Why:** Seamless TypeScript→Python integration
- **Trade-off:** Runtime type checking (no compile-time safety)
4. **Dual Authentication**
- **Why:** Best of both worlds (high rate limits + full feature coverage)
- **Trade-off:** More complex configuration
5. **Modular Structure**
- **Why:** Clean separation, easier maintenance
- **Trade-off:** More files, but better organization
### Architecture Strengths
- **Highly Extensible:** Adding tools is straightforward
- **Well-Tested:** 320 tests with live integration
- **Performance-Optimized:** Connection pooling for 35x speedup
- **Token-Efficient:** 98% reduction vs traditional MCP
- **Robust Error Handling:** Structured errors with codes
- **Security-Conscious:** Code validation, sanitization
### Areas for Improvement
- **Schema Sync:** Manual sync between TS and Python (could be automated)
- **Error Typing:** Could be richer across boundaries
- **Execution Limits:** No configurable limits yet
- **Documentation:** Tool categories not surfaced in MCP docs
---
## Conclusion
The GitHub MCP Server v2.5.5 represents a **mature, production-ready code-first MCP implementation** with:
- **112 tools** across 18 categories
- **98% token reduction** through code-first architecture
- **97% latency reduction** through connection pooling
- **320 tests** with comprehensive coverage
- **Dual authentication** for flexibility and reliability
- **Modular structure** for maintainability
The architecture is **highly extensible**, **well-tested**, and **performance-optimized**, making it an excellent reference implementation for code-first MCP servers.
---
**Document Version:** 2.5.5
**Last Updated:** 2025-12-17
**Maintained By:** GitHub MCP Server Team