使用 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。

相关推荐
Asthenia04123 小时前
Spring AOP 和 Aware:在Bean实例化后-调用BeanPostProcessor开始工作!在初始化方法执行之前!
后端
Asthenia04124 小时前
什么是消除直接左递归 - 编译原理解析
后端
Asthenia04124 小时前
什么是自上而下分析 - 编译原理剖析
后端
Asthenia04125 小时前
什么是语法分析 - 编译原理基础
后端
Asthenia04125 小时前
理解词法分析与LEX:编译器的守门人
后端
uhakadotcom5 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
拉不动的猪5 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪5 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
Asthenia04126 小时前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端