MCP驱动的Github PR审查系统

在这篇指南中,我将引导你构建一个强大的PR审查系统,该系统使用MCP协议将Claude与GitHub和Notion连接起来,创建一个自动化的流程,从而改变你的开发过程。

MCP驱动的Github PR审查系统

代码审查在当今快节奏的开发环境中至关重要,但非常耗时。如果可以使用人工智能简化这个过程呢?介绍模型上下文协议(MCP)——Anthropic的开源标准,正在改变AI模型与外部工具交互的方式。

在这篇指南中,我将引导你构建一个强大的PR审查系统,该系统将Claude与GitHub和Notion连接起来,创建一个自动化的流程,从而改变你的开发过程。

1、什么是模型上下文协议(MCP)?

模型上下文协议是由Anthropic开发的一个开源标准,它作为AI模型与外部工具之间的通用连接器。最初是为了增强Claude的功能而构建的,Anthropic在2024年初开源了MCP,以促进行业范围内的采用。

MCP遵循客户端-服务器架构,其中:

  • MCP客户端(如Claude桌面版)请求信息并执行任务
  • MCP服务器提供对外部工具和数据源的访问
  • 主机应用程序促进模型与工具之间的通信
来源:模型上下文协议

使用MCP的好处包括:

  • 标准化集成:一种结构化的方法来连接AI与外部工具
  • 灵活性:轻松切换不同的AI模型和供应商
  • 安全性:保持敏感数据在您的基础设施内
  • 可扩展性:支持多种传输协议,包括stdio、WebSockets、HTTP SSE和UNIX套接字

2、示例项目:构建PR审查服务器

我们的示例项目使用Claude桌面版自动化代码分析,并在Notion中记录审查结果。以下是流程:

  1. 设置GitHub和Notion的环境和凭据
  2. 初始化MCP服务器以与Claude桌面版通信
  3. 从GitHub获取PR更改和元数据
  4. 使用Claude桌面版分析代码更改
  5. 在Notion中记录分析结果

让我们逐步分解实现步骤。

3、设置环境

首先,我们将安装uv包管理器,它提供了比conda更快更轻量的包管理方式:

# 对于Mac/Linux  
curl -LsSf https://astral.sh/uv/install.sh | sh  

# 对于Windows(PowerShell)  
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
  • 接下来,创建并设置项目目录:
uv init pr_reviewer  
cd pr_reviewer
  • 创建并激活虚拟环境:
# Mac/Linux  
uv venv  
source .venv/bin/activate  

# Windows  
.venv\Scripts\activate
  • 安装所需的依赖项:
uv add "mcp[cli]" requests python-dotenv notion-client

4、设置依赖项和环境变量

创建一个requirements.txt文件,内容如下:

# PR分析器的核心依赖项  
requests>=2.31.0          # 用于GitHub API调用  
python-dotenv>=1.0.0      # 用于环境变量  
mcp[cli]>=1.4.0           # 用于MCP服务器功能  
notion-client>=2.3.0      # 用于Notion集成
  • 安装这些依赖项:
uv pip install -r requirements.txt
  • 接下来,在.env文件中设置环境变量:
GITHUB_TOKEN=your_github_token  
NOTION_API_KEY=your_notion_api_key  
NOTION_PAGE_ID=your_notion_page_id

生成这些凭据的方法:

  1. GitHub令牌:登录GitHub → 设置 → 开发者设置 → 个人访问令牌 → 生成新令牌(经典)→ 启用read:orgread:repo_hookrepo权限
  2. Notion集成
  • 登录Notion的集成页面
  • 创建一个新的内部集成
  • 复制集成密钥(Notion API密钥)
  • 复制集成URL中的UUID作为Notion页面ID

5、GitHub集成

创建一个github_integration.py文件来处理PR数据检索:

import os  
import requests  
import traceback  
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) -> list:  
    """从GitHub拉取请求中获取更改。  
      
    参数:  
        repo_owner: GitHub存储库的所有者  
        repo_name: GitHub存储库的名称  
        pr_number: 要分析的拉取请求编号  
          
    返回:  
        包含每个更改详细信息的文件更改列表  
    """  
    print(f"正在为 {repo_owner}/{repo_name}#{pr_number} 获取PR更改")  
      
    # 获取PR详细信息  
    pr_url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/pulls/{pr_number}"  
    files_url = f"{pr_url}/files"  
    headers = {'Authorization': f'token {GITHUB_TOKEN}'}  
      
    try:  
        # 获取PR元数据  
        pr_response = requests.get(pr_url, headers=headers)  
        pr_response.raise_for_status()  
        pr_data = pr_response.json()  
          
        # 获取文件更改  
        files_response = requests.get(files_url, headers=headers)  
        files_response.raise_for_status()  
        files_data = files_response.json()  
          
        # 将PR元数据与文件更改组合  
        changes = []  
        for file in files_data:  
            change = {  
                'filename': file['filename'],  
                'status': file['status'],  # added, modified, removed  
                '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元数据  
        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  
        }  
          
        print(f"成功获取 {len(changes)} 次更改")  
        return pr_info  
          
    except Exception as e:  
        print(f"获取PR更改时出错: {str(e)}")  
        traceback.print_exc()  
        return None  

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

此模块发送经过身份验证的HTTP请求到GitHub API,以检索有关拉取请求的全面信息,包括元数据和文件级更改。

6、实现MCP服务器

这个MCP服务器负责主要工作:

  1. 初始化环境:设置MCP服务器和Notion客户端

2. 注册工具:向Claude公开两个工具:

  • fetch_pr:从GitHub检索PR详细信息
  • create_notion_page:在Notion中创建文档

3. 运行服务器:使用stdio作为通信的传输协议

现在,让我们创建核心PR分析器,该分析器将Claude桌面版与GitHub和Notion连接起来。创建一个pr_analyzer.py文件:

import sys  
import os  
import traceback  
from typing import Any, List, Dict  
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()  
          
        # 初始化MCP服务器  
        self.mcp = FastMCP("github_pr_analysis")  
        print("MCP服务器已初始化", file=sys.stderr)  
          
        # 初始化Notion客户端  
        self._init_notion()  
          
        # 注册MCP工具  
        self._register_tools()  
      
    def _init_notion(self):  
        """使用API密钥和页面ID初始化Notion客户端。"""  
        try:  
            self.notion_api_key = os.getenv("NOTION_API_KEY")  
            self.notion_page_id = os.getenv("NOTION_PAGE_ID")  
            self.notion_client = Client(auth=self.notion_api_key)  
            print("Notion客户端已初始化", file=sys.stderr)  
        except Exception as e:  
            print(f"初始化Notion客户端时出错: {str(e)}", file=sys.stderr)  
            traceback.print_exc()  
      
    def _register_tools(self):  
        """注册MCP工具。"""  
        try:  
            # 注册fetch_pr工具  
            self.mcp.register_tool(  
                tool_name="fetch_pr",  
                description="从GitHub检索PR详细信息。",  
                func=self.fetch_pr_changes  
            )  
            print("fetch_pr工具已注册", file=sys.stderr)  
              
            # 注册create_notion_page工具  
            self.mcp.register_tool(  
                tool_name="create_notion_page",  
                description="在Notion中创建文档。",  
                func=self.create_notion_page  
            )  
            print("create_notion_page工具已注册", file=sys.stderr)  
        except Exception as e:  
            print(f"注册MCP工具时出错: {str(e)}", file=sys.stderr)  
            traceback.print_exc()  
      
    def fetch_pr_changes(self, repo_owner: str, repo_name: str, pr_number: int) -> Dict[str, Any]:  
        """从GitHub拉取请求中获取更改。  
          
        参数:  
            repo_owner: GitHub存储库的所有者  
            repo_name: GitHub存储库的名称  
            pr_number: 要分析的拉取请求编号  
              
        返回:  
            包含PR详细信息的字典  
        """  
        try:  
            pr_info = fetch_pr_changes(repo_owner, repo_name, pr_number)  
            if pr_info:  
                print(f"成功获取PR详细信息: {pr_info}", file=sys.stderr)  
                return {"success": True, "data": pr_info}  
            else:  
                print("无法获取PR详细信息", file=sys.stderr)  
                return {"success": False, "error": "无法获取PR详细信息"}  
        except Exception as e:  
            print(f"获取PR详细信息时出错: {str(e)}", file=sys.stderr)  
            traceback.print_exc()  
            return {"success": False, "error": str(e)}  
      
    def create_notion_page(self, title: str, content: str) -> Dict[str, Any]:  
        """在Notion中创建文档。  
          
        参数:  
            title: 文档标题  
            content: 文档内容  
              
        返回:  
            包含创建状态的字典  
        """  
        try:  
            response = self.notion_client.pages.create(  
                parent={"database_id": self.notion_page_id},  
                properties={  
                    "Title": {  
                        "title": [  
                            {  
                                "text": {  
                                    "content": title  
                                }  
                            }  
                        ]  
                    }  
                },  
                children=[  
                    {  
                        "object": "block",  
                        "type": "paragraph",  
                        "paragraph": {  
                            "rich_text": [  
                                {  
                                    "type": "text",  
                                    "text": {  
                                        "content": content  
                                    }  
                                }  
                            ]  
                        }  
                    }  
                ]  
            )  
            print(f"Notion页面已创建: {response['id']}", file=sys.stderr)  
            return {"success": True, "data": response}  
        except Exception as e:  
            print(f"在Notion中创建页面时出错: {str(e)}", file=sys.stderr)  
            traceback.print_exc()  
            return {"success": False, "error": str(e)}  
      
    def run(self):  
        """运行MCP服务器。"""  
        try:  
            self.mcp.run()  
        except Exception as e:  
            print(f"MCP服务器运行时出错: {str(e)}", file=sys.stderr)  
            traceback.print_exc()  
      
if __name__ == "__main__":  
    analyzer = PRAnalyzer()  
    analyzer.run()  


7、运行MCP服务器

现在所有组件都已经就位,使用以下命令运行服务器:

python pr_analyzer.py

当服务器运行时,在Claude桌面应用程序中,你会注意到文本框旁边有一个插头图标(🔌),表示存在一个MCP服务器。一个类似锤子的图标(🔨)将显示所有可用的MCP工具。

8、使用PR审查系统

  1. 在Claude桌面中粘贴PR链接。
  2. Claude将使用你的MCP服务器获取PR详细信息。
  3. Claude将分析代码并提供摘要和审查意见。
  4. 您可以指示Claude将分析上传到Notion。

完成的工作流自动化了整个PR审查过程,从获取代码更改到在您的Notion工作区中记录分析。

9、结束语

通过利用模型上下文协议(MCP),我们构建了一个强大的集成系统,将Claude的智能与GitHub的PR数据以及Notion的文档功能连接起来。该系统展示了MCP如何作为通用连接器,使AI模型能够无缝地与外部工具和服务交互。

我们构建的PR审查系统提供了以下优势:

  • 节省时间:自动化初始代码审查过程。
  • 一致性:在整个PR中应用相同的分析模式。
  • 文档记录:在Notion中维护可搜索的审查历史记录。
  • 可扩展性:可以扩展以支持其他工具和服务。

MCP代表了创建标准化、互操作AI系统的重大进步,这些系统可以轻松集成到现有的工作流程和工具中。随着越来越多的组织采用这一开放标准,我们可能会看到各种领域中创新的AI驱动应用程序的爆炸式增长。


原文链接:Build a Claude-Powered PR Review System with MCP

汇智网翻译整理,转载请标明出处