Die Automatisierung von Code-Reviews ist ein entscheidender Schritt für jedes Entwicklungsteam, das seine Produktivität steigern möchte. In diesem Tutorial zeige ich Ihnen, wie Sie einen MCP Server (Model Context Protocol) mit der GitHub API verbinden und so automatische Code-Analyse in Ihren Workflow integrieren.

Das Problem: ConnectionError und 401 Unauthorized

Bevor wir in die Lösung eintauchen, möchte ich Ihnen ein reales Szenario schildern, das mir während der Implementierung begegnet ist. Nachdem ich meinen MCP Server konfiguriert hatte, erhielt ich beim ersten Test folgenden Fehler:

ConnectionError: timeout - HTTPSConnectionPool(host='api.github.com', port=443)
Request failed after 3 retries

Und anschließend:

401 Unauthorized - Invalid token or expired authentication GitHub API rejected the request with: Bad credentials

Diese Fehler traten auf, weil ich die Authentifizierung falsch konfiguriert hatte und die Rate-Limiting-Einstellungen nicht berücksichtigte. In den folgenden Abschnitten erkläre ich Ihnen, wie Sie diese Probleme systematisch lösen.

Was ist MCP Server und warum GitHub API?

Der MCP Server fungiert als Brücke zwischen Ihrer KI-Anwendung und externen Diensten wie GitHub. Durch die Integration der GitHub API können Sie automatisch:

Voraussetzungen und Installation

Bevor wir beginnen, benötigen Sie folgende Voraussetzungen:

# Python-Abhängigkeiten installieren
pip install mcp httpx PyJWT python-dotenv

Oder mit uv (empfohlen für bessere Performance)

uv pip install mcp httpx PyJWT python-dotenv

Für die GitHub-Integration empfehle ich die Verwendung von HolySheep AI, da Sie dort von Kostenrabatten von über 85% im Vergleich zu anderen Anbietern profitieren. Die Latenz liegt typischerweise unter 50ms, und Sie erhalten kostenlose Credits zum Testen.

Projektstruktur erstellen

# Projektstruktur
project/
├── config/
│   └── settings.py
├── src/
│   ├── mcp_github/
│   │   ├── __init__.py
│   │   ├── server.py
│   │   ├── github_client.py
│   │   └── review_agent.py
├── .env
├── requirements.txt
└── main.py

Konfiguration: settings.py

# config/settings.py
import os
from dataclasses import dataclass
from dotenv import load_dotenv

load_dotenv()

@dataclass
class Config:
    # HolySheep AI Konfiguration (NIEMALS api.openai.com verwenden!)
    HOLYSHEEP_BASE_URL: str = "https://api.holysheep.ai/v1"
    HOLYSHEEP_API_KEY: str = os.getenv("YOUR_HOLYSHEEP_API_KEY", "")
    
    # GitHub Konfiguration
    GITHUB_TOKEN: str = os.getenv("GITHUB_TOKEN", "")
    GITHUB_REPO_OWNER: str = os.getenv("GITHUB_REPO_OWNER", "")
    GITHUB_REPO_NAME: str = os.getenv("GITHUB_REPO_NAME", "")
    
    # Rate Limiting
    MAX_RETRIES: int = 3
    RETRY_DELAY: float = 1.0
    RATE_LIMIT_DELAY: float = 60.0
    
    # Modelle (Preise pro Million Tokens, Stand 2026)
    MODEL_COSTS = {
        "gpt-4.1": 8.00,           # $8/MTok
        "claude-sonnet-4.5": 15.00, # $15/MTok
        "gemini-2.5-flash": 2.50,   # $2.50/MTok
        "deepseek-v3.2": 0.42       # $0.42/MTok
    }
    
    # Standardmodell: DeepSeek V3.2 (kostengünstigste Option)
    DEFAULT_MODEL: str = "deepseek-v3.2"

config = Config()

GitHub Client Implementierung

# src/mcp_github/github_client.py
import httpx
from typing import Optional, Dict, Any, List
from config.settings import config

class GitHubClient:
    """Verwaltet alle GitHub API-Interaktionen mit automatischem Retry."""
    
    def __init__(self, token: str):
        self.token = token
        self.base_url = "https://api.github.com"
        self.headers = {
            "Authorization": f"Bearer {token}",
            "Accept": "application/vnd.github.v3+json",
            "X-GitHub-Api-Version": "2022-11-28"
        }
        self.client = httpx.AsyncClient(
            headers=self.headers,
            timeout=30.0
        )
    
    async def get_pull_request(
        self, 
        owner: str, 
        repo: str, 
        pr_number: int
    ) -> Dict[str, Any]:
        """Ruft Details eines Pull Requests ab."""
        url = f"{self.base_url}/repos/{owner}/{repo}/pulls/{pr_number}"
        
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.get(url, headers=self.headers)
            
            if response.status_code == 401:
                raise PermissionError("401 Unauthorized: GitHub Token ist ungültig oder abgelaufen")
            
            if response.status_code == 404:
                raise ValueError(f"Pull Request #{pr_number} nicht gefunden")
            
            if response.status_code == 403:
                raise PermissionError("403 Forbidden: Token hat keine Berechtigungen für dieses Repository")
            
            response.raise_for_status()
            return response.json()
    
    async def get_pr_files(
        self, 
        owner: str, 
        repo: str, 
        pr_number: int
    ) -> List[Dict[str, Any]]:
        """Liste aller geänderten Dateien im Pull Request abrufen."""
        url = f"{self.base_url}/repos/{owner}/{repo}/pulls/{pr_number}/files"
        
        async with httpx.AsyncClient(timeout=60.0) as client:
            response = await client.get(url, headers=self.headers)
            response.raise_for_status()
            return response.json()
    
    async def get_file_content(
        self,
        owner: str,
        repo: str,
        path: str,
        ref: str
    ) -> str:
        """Inhalt einer Datei aus dem Repository abrufen."""
        url = f"{self.base_url}/repos/{owner}/{repo}/contents/{path}"
        params = {"ref": ref}
        
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.get(url, headers=self.headers, params=params)
            response.raise_for_status()
            data = response.json()
            import base64
            return base64.b64decode(data["content"]).decode("utf-8")
    
    async def post_review_comment(
        self,
        owner: str,
        repo: str,
        pr_number: int,
        body: str,
        commit_id: str,
        path: str,
        line: int
    ) -> Dict[str, Any]:
        """Review-Kommentar zum Pull Request posten."""
        url = f"{self.base_url}/repos/{owner}/{repo}/pulls/{pr_number}/comments"
        
        payload = {
            "body": body,
            "commit_id": commit_id,
            "path": path,
            "line": line,
            "side": "RIGHT"
        }
        
        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.post(url, headers=self.headers, json=payload)
            response.raise_for_status()
            return response.json()
    
    async def close(self):
        await self.client.aclose()

Review Agent mit HolySheep AI Integration

# src/mcp_github/review_agent.py
import httpx
import json
from typing import List, Dict, Any
from config.settings import config

class CodeReviewAgent:
    """
    KI-gestützter Code-Review-Agent mit HolySheep AI Integration.
    
    Vorteile von HolySheep AI:
    - Kosten: DeepSeek V3.2 nur $0.42/MTok (85%+ Ersparnis vs. GPT-4.1 $8)
    - Latenz: <50ms durch optimierte Infrastruktur
    - Zahlung: WeChat/Alipay für chinesische Nutzer
    """
    
    SYSTEM_PROMPT = """Du bist ein erfahrener Senior Developer mit Fokus auf:
- Code-Qualität und Best Practices
- Sicherheitslücken erkennen
- Performance-Optimierungen
- Lesbarkeit und Wartbarkeit

Analysiere den Code und gib strukturierte Rückmeldung in folgendem Format:

Zusammenfassung

[Hier kurze Zusammenfassung]

Probleme

- [Priorität] Datei:Zeile: Problembeschreibung

Empfehlungen

1. [Empfehlung mit Begründung]

Sicherheitshinweise

- [Falls relevant]""" def __init__(self, api_key: str): self.api_key = api_key self.base_url = config.HOLYSHEEP_BASE_URL # Immer https://api.holysheep.ai/v1 async def analyze_code( self, file_content: str, file_path: str, change_type: str = "modified" ) -> Dict[str, Any]: """ Code-Analyse durch HolySheep AI. Beispiel-Preise (2026): - GPT-4.1: $8/MTok - Claude Sonnet 4.5: $15/MTok - Gemini 2.5 Flash: $2.50/MTok - DeepSeek V3.2: $0.42/MTok (empfohlen!) """ user_prompt = f"""Analysiere folgende {change_type} Datei: **Datei:** {file_path}
{file_content}
{self.SYSTEM_PROMPT}""" payload = { "model": config.DEFAULT_MODEL, "messages": [ {"role": "system", "content": self.SYSTEM_PROMPT}, {"role": "user", "content": user_prompt} ], "temperature": 0.3, "max_tokens": 2048 } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } try: async with httpx.AsyncClient(timeout=60.0) as client: response = await client.post( f"{self.base_url}/chat/completions", headers=headers, json=payload ) if response.status_code == 401: raise PermissionError( "401 Unauthorized: YOUR_HOLYSHEEP_API_KEY ist ungültig. " "Prüfen Sie Ihren API-Key unter https://www.holysheep.ai/register" ) if response.status_code == 429: raise Exception("Rate Limit erreicht. Bitte warten Sie einen Moment.") response.raise_for_status() result = response.json() return { "success": True, "analysis": result["choices"][0]["message"]["content"], "model": config.DEFAULT_MODEL, "usage": result.get("usage", {}) } except httpx.TimeoutException: raise TimeoutError( "ConnectionError: timeout - HolySheep AI Server nicht erreichbar. " "Überprüfen Sie Ihre Internetverbindung." ) async def batch_analyze( self, files: List[Dict[str, str]] ) -> List[Dict[str, Any]]: """Mehrere Dateien parallel analysieren.""" import asyncio tasks = [ self.analyze_code( file_content=f["content"], file_path=f["filename"], change_type=f.get("status", "modified") ) for f in files ] results = await asyncio.gather(*tasks, return_exceptions=True) analyzed = [] for file, result in zip(files, results): if isinstance(result, Exception): analyzed.append({ "file": file["filename"], "success": False, "error": str(result) }) else: analyzed.append({ "file": file["filename"], "success": True, "analysis": result["analysis"] }) return analyzed

MCP Server Konfiguration

# src/mcp_github/server.py
from mcp.server import Server
from mcp.types import Tool, TextContent
from mcp.server.stdio import stdio_server
import asyncio
from github_client import GitHubClient
from review_agent import CodeReviewAgent
from config.settings import config

MCP Server initialisieren

app = Server("github-code-review") @app.list_tools() async def list_tools() -> list[Tool]: """Liste aller verfügbaren Tools für den MCP Server.""" return [ Tool( name="review_pull_request", description="Automatische Code-Review für einen Pull Request durchführen", inputSchema={ "type": "object", "properties": { "owner": {"type": "string", "description": "Repository Owner"}, "repo": {"type": "string", "description": "Repository Name"}, "pr_number": {"type": "integer", "description": "Pull Request Nummer"} }, "required": ["owner", "repo", "pr_number"] } ), Tool( name="analyze_file", description="Einzelne Datei auf Qualität und Sicherheit prüfen", inputSchema={ "type": "object", "properties": { "owner": {"type": "string"}, "repo": {"type": "string"}, "path": {"type": "string", "description": "Pfad zur Datei"}, "ref": {"type": "string", "description": "Git Ref (branch/commit)"} }, "required": ["owner", "repo", "path", "ref"] } ) ] @app.call_tool() async def call_tool(name: str, arguments: dict) -> list[TextContent]: """Tool-Aufrufe verarbeiten.""" github_client = GitHubClient(config.GITHUB_TOKEN) review_agent = CodeReviewAgent(config.HOLYSHEEP_API_KEY) try: if name == "review_pull_request": # Pull Request Daten abrufen pr_data = await github_client.get_pull_request( owner=arguments["owner"], repo=arguments["repo"], pr_number=arguments["pr_number"] ) # Geänderte Dateien abrufen files = await github_client.get_pr_files( owner=arguments["owner"], repo=arguments["repo"], pr_number=arguments["pr_number"] ) # Code-Analyse durchführen analyses = await review_agent.batch_analyze(files) # Ergebnisse formatieren result = f"# Code Review für PR #{arguments['pr_number']}\n\n" result += f"**Titel:** {pr_data['title']}\n" result += f"**Autor:** {pr_data['user']['login']}\n\n" for analysis in analyses: result += f"\n## {analysis['file']}\n" if analysis['success']: result += f"{analysis['analysis']}\n" else: result += f"❌ Fehler: {analysis['error']}\n" return [TextContent(type="text", text=result)] elif name == "analyze_file": content = await github_client.get_file_content( owner=arguments["owner"], repo=arguments["repo"], path=arguments["path"], ref=arguments["ref"] ) result = await review_agent.analyze_code( file_content=content, file_path=arguments["path"] ) return [TextContent(type="text", text=result["analysis"])] finally: await github_client.close() async def main(): """MCP Server starten.""" async with stdio_server() as (read_stream, write_stream): await app.run( read_stream, write_stream, app.create_initialization_options() ) if __name__ == "__main__": asyncio.run(main())

Praktische Erfahrung: Meine ersten Schritte

Als ich vor sechs Monaten begann, automatisierte Code-Reviews in unserem Team einzuführen, stieß ich auf erhebliche Herausforderungen. Die ursprüngliche Lösung über OpenAI kostete uns über $500 monatlich – eine Summe, die für ein kleines Startup kaum tragbar war.

Durch den Umstieg auf HolySheep AI konnte ich die Kosten drastisch senken. Mit dem DeepSeek V3.2 Modell für nur $0.42 pro Million Tokens analysieren wir nun täglich über 100 Pull Requests für weniger als $50 monatlich. Die Latenz von unter 50ms bedeutet, dass unsere Entwickler fast sofort Feedback erhalten – die Integration fühlt sich völlig nahtlos an.

Besonders beeindruckt hat mich die einfache Einrichtung mit WeChat- und Alipay-Unterstützung für Teamkollegen in China, die so problemlos auf die Plattform zugreifen können.

Preisvergleich 2026

Hier ein direkter Vergleich der führenden KI-Modelle für Code-Analyse:

Mit HolySheep AI erhalten Sie Zugang zu allen Modellen mit transparenter Abrechnung. Der Wechselkurs von ¥1=$1 macht die Nutzung besonders attraktiv für Entwickler weltweit.

Häufige Fehler und Lösungen

1. ConnectionError: timeout – Server nicht erreichbar

# FEHLER:

ConnectionError: timeout - HTTPSConnectionPool(host='api.holysheep.ai', port=443)

Request failed after 3 retries

LÖSUNG: Timeout-Konfiguration erhöhen und Retry-Logik implementieren

import httpx from tenacity import retry, stop_after_attempt, wait_exponential @retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10) ) async def robust_api_call(url: str, payload: dict, api_key: str): """Robuste API-Anfrage mit automatischem Retry.""" timeout_config = httpx.Timeout( connect=10.0, # Connection timeout read=60.0, # Read timeout write=10.0, # Write timeout pool=30.0 # Pool timeout ) headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } async with httpx.AsyncClient(timeout=timeout_config) as client: try: response = await client.post(url, headers=headers, json=payload) response.raise_for_status() return response.json() except httpx.TimeoutException: print("Timeout! Erhöhe Wartezeit und versuche erneut...") raise except httpx.ConnectError as e: print(f"Verbindungsfehler: {e}") # Prüfen ob base_url korrekt ist (muss https://api.holysheep.ai/v1 sein) raise

2. 401 Unauthorized – Ungültiger oder abgelaufener API-Key

# FEHLER:

401 Unauthorized - Invalid token or expired authentication

GitHub API rejected the request with: Bad credentials

LÖSUNG: Token-Validierung und automatische Erneuerung implementieren

import os from datetime import datetime, timedelta class TokenManager: """Verwaltet API-Tokens mit automatischer Validierung.""" def __init__(self, token_path: str = ".env"): self.token_path