Sitemap
AI Agent Insider

AI Agent Insider is your go-to source for the latest on AI agents. Explore breakthroughs, applications, and industry impact, from virtual assistants to autonomous systems. Dive into how AI is reshaping automation and interaction in our digital world. Stay ahead with us!

Press enter or click to view image in full size
What is Model Context Protocol (MCP)?

Build a Claude-Powered PR Review System with MCP

6 min readMar 23, 2025

--

Code reviews are essential in today’s fast-paced development environments but can be very time-consuming. What if you could use AI to simplify this process? Introducing the Model Context Protocol (MCP) Anthropic’s open standard transforming the way AI models interact with external tools.

In this guide, I will guide you through building a powerful PR review system that connects Claude with GitHub and Notion, creating an automated workflow that transforms your development process.

What is Model Context Protocol (MCP)?

The Model Context Protocol is an open standard developed by Anthropic that serves as a universal connector between AI models and external tools. Initially built to enhance Claude’s capabilities, Anthropic open-sourced MCP in early 2024 to foster industry-wide adoption.

MCP follows a client-server architecture where:

  • MCP clients (like Claude Desktop) request information and execute tasks
  • MCP servers provide access to external tools and data sources
  • Host applications facilitate communication between models and tools
Press enter or click to view image in full size
Source: Model Context Protocol

The benefits of using MCP include:

  • Standardized integration: A structured approach to connect AI with external tools
  • Flexibility: Easily switch between different AI models and vendors
  • Security: Keep sensitive data within your infrastructure
  • Scalability: Support for various transport protocols including stdio, WebSockets, HTTP SSE, and UNIX sockets

The Demo Project: Building a PR Review Server

Our demo project automates code analysis using Claude Desktop and documents reviews in Notion. Here’s the pipeline:

  1. Set up environment and credentials for GitHub and Notion
  2. Initialize an MCP server for communication with Claude Desktop
  3. Fetch PR changes and metadata from GitHub
  4. Analyze code changes using Claude Desktop
  5. Document the analysis results in Notion

Let’s break down the implementation step by step.

Step 1: Setting Up the Environment

First, we’ll install the uv package manager, which offers faster and lighter package management compared to conda:

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

# For Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
  • Next, create and set up a project directory:
uv init pr_reviewer
cd pr_reviewer
  • Create and activate a virtual environment:
# Mac/Linux
uv venv
source .venv/bin/activate

# Windows
.venv\Scripts\activate
  • Install the required dependencies:
uv add "mcp[cli]" requests python-dotenv notion-client

Step 2: Set Up Dependencies and Environment Variables

Create a requirements.txt file with the following content:

# Core dependencies for PR Analyzer
requests>=2.31.0 # For GitHub API calls
python-dotenv>=1.0.0 # For environment variables
mcp[cli]>=1.4.0 # For MCP server functionality
notion-client>=2.3.0 # For Notion integration
  • Install these dependencies:
uv pip install -r requirements.txt
  • Next, set up your environment variables in a .env file:
GITHUB_TOKEN=your_github_token
NOTION_API_KEY=your_notion_api_key
NOTION_PAGE_ID=your_notion_page_id

To generate these credentials:

  1. GitHub Token: Log in to GitHub → Settings → Developer settings → Personal Access Tokens → Generate New Token (classic) → Enable read:org, read:repo_hook, and repo permissions
  2. Notion Integration:
  • Login to Notion’s integration page
  • Create a new internal integration
  • Copy the integration secret (Notion API key)
  • Copy the UUID from the integration URL for the Notion Page ID

Step 3: GitHub Integration

Create a github_integration.py file to handle PR data retrieval:

import os
import requests
import traceback
from dotenv import load_dotenv

# Load environment variables
load_dotenv()
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')

def fetch_pr_changes(repo_owner: str, repo_name: str, pr_number: int) -> list:
"""Fetch changes from a GitHub pull request.

Args:
repo_owner: The owner of the GitHub repository
repo_name: The name of the GitHub repository
pr_number: The number of the pull request to analyze

Returns:
A list of file changes with detailed information about each change
"""
print(f" Fetching PR changes for {repo_owner}/{repo_name}#{pr_number}")

# Fetch PR details
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:
# Get PR metadata
pr_response = requests.get(pr_url, headers=headers)
pr_response.raise_for_status()
pr_data = pr_response.json()

# Get file changes
files_response = requests.get(files_url, headers=headers)
files_response.raise_for_status()
files_data = files_response.json()

# Combine PR metadata with file changes
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', ''), # The actual diff
'raw_url': file.get('raw_url', ''),
'contents_url': file.get('contents_url', '')
}
changes.append(change)

# Add PR metadata
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"Successfully fetched {len(changes)} changes")
return pr_info

except Exception as e:
print(f"Error fetching PR changes: {str(e)}")
traceback.print_exc()
return None

# Example usage for debugging
# pr_data = fetch_pr_changes('owner', 'repo', 1)
# print(pr_data)

This module sends authenticated HTTP requests to the GitHub API to retrieve comprehensive information about a pull request, including metadata and file-level changes.

Step 4: Implement the MCP Server

This MCP server does the heavy lifting by:

  1. Initializing the environment: Setting up the MCP server and Notion client

2. Registering tools: Two tools are exposed to Claude:

  • fetch_pr: Retrieves PR details from GitHub
  • create_notion_page: Creates documentation in Notion

3. Running the server: Using stdio as the transport protocol for communication

Now, let’s create the core PR analyzer that will connect Claude Desktop with GitHub and Notion. Create a pr_analyzer.py file:

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 environment variables
load_dotenv()

# Initialize MCP Server
self.mcp = FastMCP("github_pr_analysis")
print("MCP Server initialized", file=sys.stderr)

# Initialize Notion client
self._init_notion()

# Register MCP tools
self._register_tools()

def _init_notion(self):
"""Initialize the Notion client with API key and page ID."""
try:
self.notion_api_key = os.getenv("NOTION_API_KEY")
self.notion_page_id = os.getenv("NOTION_PAGE_ID")

if not self.notion_api_key or not self.notion_page_id:
raise ValueError("Missing Notion API key or page ID in environment variables")

self.notion = Client(auth=self.notion_api_key)
print(f"Notion client initialized successfully", file=sys.stderr)
print(f"Using Notion page ID: {self.notion_page_id}", file=sys.stderr)
except Exception as e:
print(f"Error initializing Notion client: {str(e)}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
sys.exit(1)

def _register_tools(self):
"""Register MCP tools for PR analysis."""
@self.mcp.tool()
async def fetch_pr(repo_owner: str, repo_name: str, pr_number: int) -> Dict[str, Any]:
"""Fetch changes from a GitHub pull request."""
print(f"Fetching PR #{pr_number} from {repo_owner}/{repo_name}", file=sys.stderr)
try:
pr_info = fetch_pr_changes(repo_owner, repo_name, pr_number)
if pr_info is None:
print("No changes returned from fetch_pr_changes", file=sys.stderr)
return {}
print(f"Successfully fetched PR information", file=sys.stderr)
return pr_info
except Exception as e:
print(f"Error fetching PR: {str(e)}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
return {}

@self.mcp.tool()
async def create_notion_page(title: str, content: str) -> str:
"""Create a Notion page with PR analysis."""
print(f"Creating Notion page: {title}", file=sys.stderr)
try:
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}
}]
}
}]
)
print(f"Notion page '{title}' created successfully!", file=sys.stderr)
return f"Notion page '{title}' created successfully!"
except Exception as e:
error_msg = f"Error creating Notion page: {str(e)}"
print(error_msg, file=sys.stderr)
traceback.print_exc(file=sys.stderr)
return error_msg

def run(self):
"""Start the MCP server."""
try:
print("Running MCP Server for GitHub PR Analysis...", file=sys.stderr)
self.mcp.run(transport="stdio")
except Exception as e:
print(f"Fatal Error in MCP Server: {str(e)}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
sys.exit(1)

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

Step 5: Running the MCP Server

Now that all the pieces are in place, run the server with:

python pr_analyzer.py

When the server is running, open Claude Desktop. You’ll notice a plug icon (🔌) in the textbox, indicating the presence of an MCP server. A hammer-like icon (🔨) will display all available MCP tools.

Using the PR Review System

  1. Paste a PR link in Claude Desktop
  2. Claude will fetch the PR details using your MCP server
  3. Claude will analyze the code and provide a summary and review
  4. You can instruct Claude to upload the analysis to Notion

The completed workflow automates the entire PR review process, from fetching code changes to documenting the analysis in your Notion workspace.

Conclusion

By leveraging the Model Context Protocol, we’ve built a powerful integration that connects Claude’s intelligence with GitHub’s PR data and Notion’s documentation capabilities. This system demonstrates how MCP serves as a universal connector, allowing AI models to seamlessly interact with external tools and services.

The PR review system we’ve built offers several advantages:

  • Time savings: Automates the initial code review process
  • Consistency: Applies the same analysis patterns across all PRs
  • Documentation: Maintains a searchable history of reviews in Notion
  • Scalability: Can be extended to support additional tools and services

MCP represents a significant step forward in creating standardized, interoperable AI systems that can be easily integrated into existing workflows and tools. As more organizations adopt this open standard, we’ll likely see an explosion of innovative AI-powered applications across various domains.

References

--

--

AI Agent Insider
AI Agent Insider

Published in AI Agent Insider

AI Agent Insider is your go-to source for the latest on AI agents. Explore breakthroughs, applications, and industry impact, from virtual assistants to autonomous systems. Dive into how AI is reshaping automation and interaction in our digital world. Stay ahead with us!

Bhavik Jikadara
Bhavik Jikadara

Written by Bhavik Jikadara

🚀 AI/ML & MLOps expert 🌟 Crafting advanced solutions to speed up data retrieval 📊 and enhance ML model lifecycles. buymeacoffee.com/bhavikjikadara

No responses yet