使用 Model Context Protocol (MCP) 构建 GitHub PR 审查服务器

什么是 Model Context Protocol (MCP)?

MCP 是由 Anthropic 开发的开放标准,用于在 AI 模型和外部工具之间建立标准化的交互接口。它允许大型语言模型通过统一的方式与 API、数据库和商业应用程序进行动态交互。MCP 遵循客户端-服务器架构,客户端(如 Claude Desktop)请求信息并执行任务,而服务器提供访问外部工具和数据源的能力。

为什么使用 MCP?

  • 标准化 AI 集成:MCP 提供了结构化的方式来连接 AI 模型与工具。
  • 灵活性:允许轻松切换不同的 AI 模型和供应商。
  • 安全性:保持数据在您的基础设施内,同时与 AI 进行交互。
  • 可扩展性:支持多种传输方式,如 stdio、WebSockets、HTTP SSE 和 UNIX sockets。

MCP Demo 项目:PR 审查服务器

项目概述

本项目使用 MCP 构建一个 GitHub PR 审查服务器,集成 Claude Desktop 和 Notion。该服务器可以:

  1. 获取 GitHub PR 详情:从 GitHub 获取 PR 的元数据和文件变更。
  2. 分析代码变更:使用 Claude Desktop 直接分析代码变更。
  3. 生成 PR 审查摘要:生成 PR 审查的摘要和建议。
  4. 保存到 Notion:将审查结果保存到 Notion 进行跟踪。

步骤概述

  1. 环境设置:安装 Python 3.10+,使用 uv 包管理器设置环境。
  2. 安装依赖 :安装必要的 Python 包,包括 mcp[cli]requestspython-dotenvnotion-client
  3. 环境变量设置 :创建 .env 文件,存储 GitHub 和 Notion 的 API 密钥。
  4. GitHub 集成:编写代码从 GitHub 获取 PR 变更。
  5. 实现 MCP 服务器:创建 MCP 服务器,注册工具以获取 PR 详情和创建 Notion 页面。
  6. 运行 MCP 服务器:启动服务器,使用 Claude Desktop 进行 PR 审查。

代码示例

GitHub 集成示例

python 复制代码
import os
import requests
from dotenv import load_dotenv

load_dotenv()
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')

def fetch_pr_changes(repo_owner: str, repo_name: str, pr_number: int) -> dict:
    """从 GitHub 获取 PR 变更"""
    pr_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/pulls/{pr_number}"
    headers = {'Authorization': f'token {GITHUB_TOKEN}'}
    
    try:
        pr_response = requests.get(pr_url, headers=headers)
        pr_response.raise_for_status()
        pr_data = pr_response.json()
        
        files_url = f"{pr_url}/files"
        files_response = requests.get(files_url, headers=headers)
        files_response.raise_for_status()
        files_data = files_response.json()
        
        changes = []
        for file in files_data:
            change = {
                'filename': file['filename'],
                'status': file['status'],
                'additions': file['additions'],
                'deletions': file['deletions'],
                'changes': file['changes'],
                'patch': file.get('patch', ''),
                'raw_url': file.get('raw_url', ''),
                'contents_url': file.get('contents_url', '')
            }
            changes.append(change)
        
        pr_info = {
            'title': pr_data['title'],
            'description': pr_data['body'],
            'author': pr_data['user']['login'],
            'created_at': pr_data['created_at'],
            'updated_at': pr_data['updated_at'],
            'state': pr_data['state'],
            'total_changes': len(changes),
            'changes': changes
        }
        
        return pr_info
        
    except Exception as e:
        print(f"Error fetching PR changes: {str(e)}")
        return None

# 示例用法
pr_data = fetch_pr_changes('owner', 'repo', 1)
print(pr_data)

MCP 服务器示例

python 复制代码
import sys
from mcp.server.fastmcp import FastMCP
from github_integration import fetch_pr_changes
from notion_client import Client
from dotenv import load_dotenv

class PRAnalyzer:
    def __init__(self):
        load_dotenv()
        
        self.mcp = FastMCP("github_pr_analysis")
        print("MCP Server initialized", file=sys.stderr)
        
        self._init_notion()
        self._register_tools()
    
    def _init_notion(self):
        self.notion_api_key = os.getenv("NOTION_API_KEY")
        self.notion_page_id = os.getenv("NOTION_PAGE_ID")
        
        self.notion = Client(auth=self.notion_api_key)
        print(f"Notion client initialized successfully", file=sys.stderr)
    
    def _register_tools(self):
        @self.mcp.tool()
        async def fetch_pr(repo_owner: str, repo_name: str, pr_number: int) -> dict:
            """获取 GitHub PR 变更"""
            pr_info = fetch_pr_changes(repo_owner, repo_name, pr_number)
            return pr_info
        
        @self.mcp.tool()
        async def create_notion_page(title: str, content: str) -> str:
            """创建 Notion 页面"""
            self.notion.pages.create(
                parent={"type": "page_id", "page_id": self.notion_page_id},
                properties={"title": {"title": [{"text": {"content": title}}]}},
                children=[{
                    "object": "block",
                    "type": "paragraph",
                    "paragraph": {
                        "rich_text": [{
                            "type": "text",
                            "text": {"content": content}
                        }]
                    }
                }]
            )
            return f"Notion page '{title}' created successfully!"
    
    def run(self):
        """启动 MCP 服务器"""
        self.mcp.run(transport="stdio")

if __name__ == "__main__":
    analyzer = PRAnalyzer()
    analyzer.run()

运行 MCP 服务器

使用以下命令启动 MCP 服务器:

bash 复制代码
python pr_analyzer.py

启动后,打开 Claude Desktop 应用程序,即可看到 MCP 的插件图标。通过 Claude Desktop,您可以分析 GitHub PR,并将结果保存到 Notion。

相关推荐
程序员cxuan27 分钟前
看了一下姚顺宇的访谈,确实太顶了。
人工智能·后端·程序员
不会写DN28 分钟前
通过白名单解决 pnpm i 报错 Ignored build scripts
javascript·面试·npm
Wy_编程34 分钟前
Go语言中的指针
开发语言·后端·golang
沪漂阿龙41 分钟前
字节跳动大模型面试题深度拆解:项目深挖、SFT 与 RLHF、Claude Code、记忆机制、并发锁与手撕题全攻略
人工智能·面试
GetcharZp44 分钟前
RabbitMQ 深度全解析,从 Docker 部署到 Go 语言高并发实战!
后端
小江的记录本1 小时前
【AI大模型选型指南】《2026年5月(最新版)国内外主流AI大模型选型指南》(企业版)
前端·人工智能·后端·ai作画·aigc·ai编程·ai写作
knight_9___2 小时前
大模型project面试3
人工智能·python·语言模型·面试·大模型·agent
晓杰'2 小时前
Balatro后端进阶(1):自定义NestJS WebSocket Adapter实现消息拦截
后端·websocket·typescript·node.js·游戏开发·nestjs·wsadapter
Makoto_Kimur2 小时前
Java 后端面试场景题:页面刷新后一直转圈,应该怎么排查?
java·开发语言·面试
芝士爱知识a2 小时前
2026 年教资面试考前急救软件推荐:基于智蛙面试app的技术评测
面试·职场和发展·智蛙面试·教资面试软件·ai模拟面试·教资考前急救·多模态大模型应用