# Directory Structure ``` ├── deploy.sh ├── Dockerfile ├── LICENSE ├── publish.sh ├── pyproject.toml ├── README.md ├── registry.json ├── smithery.yaml ├── src │ └── github_chat_mcp │ ├── __init__.py │ ├── __pycache__ │ │ ├── server.cpython-310.pyc │ │ ├── server.cpython-311.pyc │ │ └── server.cpython-312.pyc │ └── server.py └── uv.lock ``` # Files -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown 1 | # GitHub Chat MCP 2 | 3 | A Model Context Protocol (MCP) for analyzing and querying GitHub repositories using the GitHub Chat API. Official Site: https://github-chat.com 4 | 5 | ## Installation 6 | 7 | ```bash 8 | # Install with pip 9 | pip install github-chat-mcp 10 | 11 | # Or install with the newer uv package manager 12 | uv install github-chat-mcp 13 | ``` 14 | 15 | 16 | 17 | 3. Start using it with Claude! 18 | 19 | Example prompts: 20 | - "Use github-chat-mcp to analyze the React repository" 21 | - "Index the TypeScript repository with github-chat-mcp and ask about its architecture" 22 | 23 | # GitHub Chat MCP server 24 | 25 | [](https://smithery.ai/server/github-chat-mcp) 26 | 27 | ## Setup Instructions 28 | > Before anything, ensure you have a GitHub Chat API key. This is required to use the service. 29 | 30 | Install uv first. 31 | 32 | MacOS/Linux: 33 | ```bash 34 | curl -LsSf https://astral.sh/uv/install.sh | sh 35 | ``` 36 | 37 | Windows: 38 | ``` 39 | powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" 40 | ``` 41 | 42 | ### Setup with Cursor (Recommended) 43 | In mcp.json: 44 | 45 | ```json 46 | { 47 | "mcpServers": { 48 | "github-chat": { 49 | "command": "uvx", 50 | "args": [ 51 | "github-chat-mcp" 52 | ] 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | With above, no envs required since it's a freemium release. 59 | 60 | ### Setup with Claude Desktop 61 | ```json 62 | # claude_desktop_config.json 63 | # Can find location through: 64 | # Hamburger Menu -> File -> Settings -> Developer -> Edit Config 65 | # Must perform: brew install uv 66 | { 67 | "mcpServers": { 68 | "github-chat": { 69 | "command": "uvx", 70 | "args": ["github-chat-mcp"], 71 | "env": { 72 | } 73 | } 74 | } 75 | } 76 | ``` 77 | 78 | ### Installing via Smithery 79 | 80 | You can install GitHub Chat for Claude Desktop automatically via Smithery: 81 | 82 | ```bash 83 | npx -y @smithery/cli install github-chat-mcp --client claude 84 | ``` 85 | 86 | ### Using GitHub Chat with Claude 87 | 1. Index a GitHub repository first: 88 | "Index the GitHub repository at https://github.com/username/repo" 89 | 90 | 2. Then ask questions about the repository: 91 | "What is the core tech stack used in this repository?" 92 | 93 | ### Debugging 94 | Run: 95 | ```bash 96 | npx @modelcontextprotocol/inspector uvx github-chat-mcp 97 | ``` 98 | 99 | ## Local/Dev Setup Instructions 100 | 101 | ### Clone repo 102 | `git clone https://github.com/yourusername/github-chat-mcp.git` 103 | 104 | ### Install dependencies 105 | Install uv first. 106 | 107 | MacOS/Linux: 108 | ```bash 109 | curl -LsSf https://astral.sh/uv/install.sh | sh 110 | ``` 111 | 112 | Windows: 113 | ``` 114 | powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" 115 | ``` 116 | 117 | Then install MCP server dependencies: 118 | ```bash 119 | cd github-chat-mcp 120 | 121 | # Create virtual environment and activate it 122 | uv venv 123 | 124 | source .venv/bin/activate # MacOS/Linux 125 | # OR 126 | .venv/Scripts/activate # Windows 127 | 128 | # Install dependencies 129 | uv sync 130 | ``` 131 | ### Setup with Claude Desktop 132 | 133 | #### Using MCP CLI SDK 134 | ```bash 135 | # `pip install mcp[cli]` if you haven't 136 | mcp install /ABSOLUTE/PATH/TO/PARENT/FOLDER/github-chat-mcp/src/github_chat_mcp/server.py -v "GITHUB_API_KEY=API_KEY_HERE" 137 | ``` 138 | 139 | #### Manually 140 | ```json 141 | # claude_desktop_config.json 142 | # Can find location through: 143 | # Hamburger Menu -> File -> Settings -> Developer -> Edit Config 144 | { 145 | "mcpServers": { 146 | "github-chat": { 147 | "command": "uv", 148 | "args": [ 149 | "--directory", 150 | "/ABSOLUTE/PATH/TO/PARENT/FOLDER/github-chat-mcp", 151 | "run", 152 | "github-chat-mcp" 153 | ], 154 | "env": { 155 | } 156 | } 157 | } 158 | } 159 | ``` 160 | 161 | ### Using GitHub Chat with Claude 162 | 1. Index a GitHub repository first: 163 | "Index the GitHub repository at https://github.com/username/repo" 164 | 165 | 2. Then ask questions about the repository: 166 | "What is the core tech stack used in this repository?" 167 | 168 | ### Debugging 169 | Run: 170 | ```bash 171 | # If mcp cli installed (`pip install mcp[cli]`) 172 | mcp dev /ABSOLUTE/PATH/TO/PARENT/FOLDER/github-chat-mcp/src/github_chat_mcp/server.py 173 | 174 | # If not 175 | npx @modelcontextprotocol/inspector \ 176 | uv \ 177 | --directory /ABSOLUTE/PATH/TO/PARENT/FOLDER/github-chat-mcp \ 178 | run \ 179 | github-chat-mcp 180 | ``` 181 | Then access MCP Inspector at `http://localhost:5173`. You may need to add your GitHub API key in the environment variables in the inspector under `GITHUB_API_KEY`. 182 | 183 | # Notes 184 | - Level of logging is adjustable through the `FASTMCP_LOG_LEVEL` environment variable (e.g. `FASTMCP_LOG_LEVEL="ERROR"`) 185 | - This MCP server provides two main tools: 186 | 1. Repository Indexing - Index and analyze a GitHub repository 187 | 2. Repository Querying - Ask questions about the indexed repository ``` -------------------------------------------------------------------------------- /src/github_chat_mcp/__init__.py: -------------------------------------------------------------------------------- ```python 1 | from . import server 2 | 3 | 4 | def main(): 5 | """Main entry point for the package.""" 6 | server.main() 7 | 8 | 9 | # Optionally expose other important items at package level 10 | __all__ = ["main", "server"] ``` -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- ```bash 1 | #!/bin/bash 2 | set -e 3 | 4 | # Clean up any previous builds 5 | rm -rf dist/ 6 | 7 | # Build the package 8 | python -m pip install --upgrade build 9 | python -m build 10 | 11 | # Upload to PyPI 12 | python -m pip install --upgrade twine 13 | python -m twine upload dist/* 14 | 15 | echo "Package published to PyPI successfully!" ``` -------------------------------------------------------------------------------- /smithery.yaml: -------------------------------------------------------------------------------- ```yaml 1 | # Smithery configuration file: https://smithery.ai/docs/config#smitheryyaml 2 | 3 | startCommand: 4 | type: stdio 5 | configSchema: 6 | # JSON Schema defining the configuration options for the MCP. 7 | type: object 8 | required: 9 | - githubApiKey 10 | properties: 11 | githubApiKey: 12 | type: string 13 | description: The API key for the GitHub Chat MCP server. 14 | commandFunction: 15 | # A function that produces the CLI command to start the MCP on stdio. 16 | |- 17 | (config) => ({command:'uv',args:['run','github-chat-mcp'],env:{GITHUB_API_KEY:config.githubApiKey}}) 18 | ``` -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- ```toml 1 | [project] 2 | name = "github-chat-mcp" 3 | version = "0.1.0" 4 | authors = [ 5 | {name="Sheing Ng", email="[email protected]"}, 6 | ] 7 | description = "GitHub Chat MCP server for analyzing GitHub repositories" 8 | readme = "README.md" 9 | requires-python = ">=3.12" 10 | dependencies = [ 11 | "requests~=2.31.0", 12 | "mcp[cli]~=1.6.0", 13 | "pydantic~=2.10.3", 14 | ] 15 | 16 | [project.urls] 17 | Homepage = "https://github.com/AsyncFuncAI/github-chat-mcp" 18 | Issues = "https://github.com/AsyncFuncAI/github-chat-mcp/issues" 19 | 20 | [build-system] 21 | requires = ["hatchling"] 22 | build-backend = "hatchling.build" 23 | 24 | [project.scripts] 25 | github-chat-mcp = "github_chat_mcp:main" 26 | ``` -------------------------------------------------------------------------------- /registry.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "github-chat-mcp", 3 | "description": "GitHub Chat MCP server for analyzing and querying GitHub repositories", 4 | "version": "0.1.0", 5 | "repositoryUrl": "https://github.com/yourusername/github-chat-mcp", 6 | "installCommand": "pip install github-chat-mcp", 7 | "tools": [ 8 | { 9 | "name": "index_repository", 10 | "description": "Index a GitHub repository to analyze its codebase. This must be done before asking questions about the repository." 11 | }, 12 | { 13 | "name": "query_repository", 14 | "description": "Ask questions about a GitHub repository and receive detailed AI responses. The repository must be indexed first." 15 | } 16 | ], 17 | "configuration": { 18 | "githubApiKey": { 19 | "type": "string", 20 | "description": "API key for GitHub Chat API", 21 | "required": true 22 | } 23 | } 24 | } ``` -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- ```dockerfile 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile 2 | # Use a Python image with uv pre-installed 3 | FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS uv 4 | 5 | # Install the project into /app 6 | WORKDIR /app 7 | 8 | # Enable bytecode compilation 9 | ENV UV_COMPILE_BYTECODE=1 10 | 11 | # Copy the lock file and pyproject.toml for dependency management 12 | COPY uv.lock pyproject.toml /app/ 13 | 14 | # Install the project's dependencies using the lockfile and settings 15 | RUN --mount=type=cache,target=/root/.cache/uv \ 16 | uv sync --frozen --no-install-project --no-dev --no-editable 17 | 18 | # Then, add the rest of the project source code and install it 19 | ADD . /app 20 | RUN --mount=type=cache,target=/root/.cache/uv \ 21 | uv sync --frozen --no-dev --no-editable 22 | 23 | # Create the final image 24 | FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim 25 | 26 | WORKDIR /app 27 | 28 | # Copy the virtual environment directly 29 | COPY --from=uv --chown=app:app /app/.venv /app/.venv 30 | 31 | # Create app user 32 | RUN useradd -m app 33 | 34 | # Place executables in the environment at the front of the path 35 | ENV PATH="/app/.venv/bin:$PATH" 36 | 37 | # Environment variable for the GitHub API key 38 | ENV GITHUB_API_KEY=YOUR_API_KEY_HERE 39 | 40 | # Switch to non-root user 41 | USER app 42 | 43 | # Run the MCP server 44 | ENTRYPOINT ["github-chat-mcp"] 45 | ``` -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- ```bash 1 | #!/bin/bash 2 | set -e 3 | 4 | # Build the Docker image 5 | docker build -t github-chat-mcp . 6 | 7 | # Optional: Push to a container registry like Docker Hub or GitHub Container Registry 8 | # docker tag github-chat-mcp yourusername/github-chat-mcp:latest 9 | # docker push yourusername/github-chat-mcp:latest 10 | 11 | # Run locally for testing 12 | echo "Starting GitHub Chat MCP server locally for testing..." 13 | docker run -e GITHUB_API_KEY=$GITHUB_API_KEY -p 8000:8000 github-chat-mcp 14 | 15 | # Instructions for deploying to production environments 16 | cat << EOF 17 | 18 | ------------------------------------ 19 | Production Deployment Instructions: 20 | ------------------------------------ 21 | 22 | 1. Push the Docker image to a container registry: 23 | docker tag github-chat-mcp yourusername/github-chat-mcp:latest 24 | docker push yourusername/github-chat-mcp:latest 25 | 26 | 2. Deploy to your preferred hosting service: 27 | 28 | - For AWS ECS: 29 | aws ecs create-service --service-name github-chat-mcp --task-definition github-chat-mcp --desired-count 1 30 | 31 | - For Kubernetes: 32 | kubectl apply -f kubernetes-deployment.yaml 33 | 34 | - For Google Cloud Run: 35 | gcloud run deploy github-chat-mcp --image yourusername/github-chat-mcp:latest --platform managed 36 | 37 | 3. Configure the environment variable GITHUB_API_KEY in your production environment. 38 | 39 | 4. Register your MCP with the MCP registry by following the MCP documentation. 40 | 41 | EOF ``` -------------------------------------------------------------------------------- /src/github_chat_mcp/server.py: -------------------------------------------------------------------------------- ```python 1 | import json 2 | import os 3 | import requests 4 | from typing import List, Dict, Any, Optional 5 | 6 | from mcp.server.fastmcp import FastMCP 7 | from pydantic import Field 8 | 9 | 10 | GITHUB_CHAT_API_BASE = "https://api.github-chat.com" 11 | API_KEY = os.environ.get("GITHUB_API_KEY", "") 12 | 13 | mcp = FastMCP("github-chat-mcp", dependencies=["requests", "mcp[cli]"]) 14 | 15 | 16 | @mcp.tool() 17 | def index_repository( 18 | repo_url: str = Field( 19 | description="The GitHub repository URL to index (format: https://github.com/username/repo)." 20 | ), 21 | ) -> str: 22 | """Index a GitHub repository to analyze its codebase. This must be done before asking questions about the repository.""" 23 | try: 24 | if not repo_url: 25 | raise ValueError("Repository URL cannot be empty.") 26 | 27 | if not repo_url.startswith("https://github.com/"): 28 | raise ValueError("Repository URL must be in the format: https://github.com/username/repo") 29 | 30 | # Call the verify API endpoint 31 | response = requests.post( 32 | f"{GITHUB_CHAT_API_BASE}/verify", 33 | headers={"Content-Type": "application/json"}, 34 | json={"repo_url": repo_url} 35 | ) 36 | 37 | if response.status_code != 200: 38 | return f"Error indexing repository: {response.text}" 39 | 40 | return f"Successfully indexed repository: {repo_url}. You can now ask questions about this repository." 41 | 42 | except Exception as e: 43 | return f"Error: {str(e) or repr(e)}" 44 | 45 | 46 | @mcp.tool() 47 | def query_repository( 48 | repo_url: str = Field( 49 | description="The GitHub repository URL to query (format: https://github.com/username/repo)." 50 | ), 51 | question: str = Field( 52 | description="The question to ask about the repository." 53 | ), 54 | conversation_history: Optional[List[Dict[str, str]]] = Field( 55 | description="Previous conversation history for multi-turn conversations.", default=None 56 | ), 57 | ) -> str: 58 | """Ask questions about a GitHub repository and receive detailed AI responses. The repository must be indexed first.""" 59 | try: 60 | if not repo_url or not question: 61 | raise ValueError("Repository URL and question cannot be empty.") 62 | 63 | if not repo_url.startswith("https://github.com/"): 64 | raise ValueError("Repository URL must be in the format: https://github.com/username/repo") 65 | 66 | # Prepare messages array 67 | messages = conversation_history or [] 68 | messages.append({"role": "user", "content": question}) 69 | 70 | # Call the chat completions API endpoint 71 | response = requests.post( 72 | f"{GITHUB_CHAT_API_BASE}/chat/completions/sync", 73 | headers={"Content-Type": "application/json"}, 74 | json={ 75 | "repo_url": repo_url, 76 | "messages": messages 77 | } 78 | ) 79 | 80 | if response.status_code != 200: 81 | return f"Error querying repository: {response.text}" 82 | 83 | # Format the response 84 | result = response.json() 85 | formatted_response = format_chat_response(result) 86 | 87 | return formatted_response 88 | 89 | except Exception as e: 90 | return f"Error: {str(e) or repr(e)}" 91 | 92 | 93 | def format_chat_response(response: Dict[str, Any]) -> str: 94 | """Format the chat response in a readable way.""" 95 | formatted = "" 96 | 97 | if "answer" in response: 98 | formatted += response["answer"] + "\n\n" 99 | 100 | if "contexts" in response and response["contexts"]: 101 | formatted += "Sources:\n" 102 | for i, context in enumerate(response["contexts"], 1): 103 | if "meta_data" in context and "file_path" in context["meta_data"]: 104 | formatted += f"{i}. {context['meta_data']['file_path']}\n" 105 | 106 | return formatted.strip() 107 | 108 | 109 | def main(): 110 | mcp.run() 111 | 112 | 113 | if __name__ == "__main__": 114 | main() ```