Build a Model Context Protocol server that enables AI assistants to interact with GitHub.
构建模型上下文协议服务器,使AI助手能够与GitHub交互。
MCP (Model Context Protocol) is an open protocol that allows AI applications to communicate bidirectionally with external data sources and tools.
1. MCP Protocol Layer (main.py)
Tool definitions and routing / 工具定义和路由
2. Business Logic Layer (api_client.py)
GitHub API integration / GitHub API集成
3. Infrastructure Layer (config.py, exceptions.py)
Configuration and error handling / 配置和错误处理
# server/main.py
from mcp.server import Server
from server.config import settings
# Initialize server
server = Server(settings.server_name)
@server.list_tools()
async def list_tools() -> list[Tool]:
"""List available tools."""
return [
Tool(
name="get_github_issue",
description="Get details of a GitHub issue",
inputSchema={
"type": "object",
"properties": {
"owner": {"type": "string"},
"repo": {"type": "string"},
"issue_number": {"type": "integer"}
},
"required": ["owner", "repo", "issue_number"]
}
),
# ... more tools
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
"""Handle tool calls."""
try:
if name == "get_github_issue":
result = await client.get_issue(
owner=arguments["owner"],
repo=arguments["repo"],
issue_number=arguments["issue_number"]
)
return [TextContent(type="text", text=format_issue(result))]
# ... handle other tools
except Exception as e:
return [TextContent(type="text", text=f"Error: {str(e)}")]
# server/api_client.py
import httpx
from server.config import settings
class GitHubClient:
async def get_issue(self, owner: str, repo: str, issue_number: int):
"""Get issue details."""
# Validate input
if not owner or not repo:
raise ValidationError("owner/repo", "Cannot be empty")
# Make request
endpoint = f"/repos/{owner}/{repo}/issues/{issue_number}"
return await self._request("GET", endpoint)
# Run with STDIO transport
import asyncio
from mcp.server.stdio import stdio_server
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
if __name__ == "__main__":
asyncio.run(main())
# .env
GITHUB_TOKEN=ghp_xxxxxxxxxxxx # Optional, increases rate limit
Rate Limits:
# Claude Desktop config file location:
# Mac: ~/Library/Application Support/Claude/claude_desktop_config.json
# Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"github": {
"command": "python",
"args": ["-m", "server.main"],
"cwd": "C:/repos/.../week3",
"env": {
"GITHUB_TOKEN": "your_token_here"
}
}
}
}