1+ """
2+ Code Review Assistant - MCP Integration Example
3+
4+ This example demonstrates how to integrate multiple MCP providers with AI to create
5+ a practical code review assistant. It shows:
6+
7+ 1. GitHub MCP - Fetch code from repositories
8+ 2. OpenAI Integration - AI-powered code analysis
9+ 3. Browserbase MCP - Check repository documentation
10+ 4. Filesystem MCP - Save review reports
11+
12+ Usage:
13+ python code_review_assistant.py
14+
15+ Requirements:
16+ - OpenAI API key (set OPENAI_API_KEY environment variable)
17+ - GitHub token (set GITHUB_TOKEN environment variable)
18+ - Browserbase credentials (set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID)
19+ """
20+
21+ import asyncio
22+ import logging
23+ import os
24+ from python_a2a .client .llm import OpenAIA2AClient
25+ from python_a2a .mcp .providers import GitHubMCPServer , BrowserbaseMCPServer , FilesystemMCPServer
26+ from python_a2a import create_text_message
27+
28+ # Hide INFO logs for cleaner output
29+ logging .getLogger ('python_a2a' ).setLevel (logging .ERROR )
30+ logging .getLogger ('httpx' ).setLevel (logging .WARNING )
31+
32+ class CodeReviewAssistant :
33+ """AI-powered code review assistant using multiple MCP providers"""
34+
35+ def __init__ (self , openai_api_key = None , github_token = None , browserbase_api_key = None , browserbase_project_id = None ):
36+ # Get credentials from environment variables or parameters
37+ openai_key = openai_api_key or os .getenv ('OPENAI_API_KEY' )
38+ github_token = github_token or os .getenv ('GITHUB_TOKEN' )
39+ browserbase_key = browserbase_api_key or os .getenv ('BROWSERBASE_API_KEY' )
40+ browserbase_project = browserbase_project_id or os .getenv ('BROWSERBASE_PROJECT_ID' )
41+
42+ if not openai_key :
43+ raise ValueError ("OpenAI API key required. Set OPENAI_API_KEY environment variable or pass openai_api_key parameter." )
44+ if not github_token :
45+ raise ValueError ("GitHub token required. Set GITHUB_TOKEN environment variable or pass github_token parameter." )
46+ if not browserbase_key or not browserbase_project :
47+ raise ValueError ("Browserbase credentials required. Set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID environment variables." )
48+
49+ # AI reviewer
50+ self .ai = OpenAIA2AClient (api_key = openai_key )
51+
52+ # MCP providers - clean and simple
53+ self .github = GitHubMCPServer (token = github_token )
54+ self .browser = BrowserbaseMCPServer (
55+ api_key = browserbase_key ,
56+ project_id = browserbase_project
57+ )
58+ # Allow filesystem access to current directory
59+ current_dir = os .getcwd ()
60+ self .files = FilesystemMCPServer (allowed_directories = [current_dir ])
61+
62+ async def review_code (self , repo_owner , repo_name , file_path ):
63+ """Review a specific file in a repository"""
64+
65+ async with self .github , self .browser , self .files :
66+
67+ # 1. GitHub MCP: Get code from repository
68+ print (f"🐙 GitHub MCP: Fetching { file_path } from { repo_owner } /{ repo_name } " )
69+ code = await self .github .get_file_contents (repo_owner , repo_name , file_path )
70+ print (f" ✓ Retrieved { len (str (code ))} characters of code" )
71+
72+ # 2. OpenAI: AI reviews the code
73+ print ("🤖 OpenAI: Analyzing code quality..." )
74+ review_message = create_text_message (f"""
75+ Review this code for quality, bugs, and improvements:
76+
77+ { code }
78+
79+ Give me 3 key points: issues, suggestions, rating (1-10).
80+ """ )
81+ response = self .ai .send_message (review_message )
82+ review = response .content .text
83+ print (f" ✓ AI analysis completed" )
84+
85+ # 3. Browserbase MCP: Check repository documentation
86+ print ("🌐 Browserbase MCP: Checking repository documentation..." )
87+ await self .browser .navigate (f"https://github.com/{ repo_owner } /{ repo_name } " )
88+ await self .browser .wait_time (1 )
89+ readme_text = await self .browser .get_text ("article" )
90+ has_docs = "readme" in readme_text .lower ()
91+ print (f" ✓ Documentation { 'found' if has_docs else 'not found' } " )
92+
93+ # 4. Filesystem MCP: Save review report to current directory
94+ print ("📁 Filesystem MCP: Saving review report..." )
95+ report = f"""# Code Review: { repo_owner } /{ repo_name } /{ file_path }
96+
97+ ## AI Review
98+ { review }
99+
100+ ## Documentation Status
101+ { '✅ Has README documentation' if has_docs else '❌ Missing documentation' }
102+
103+ ## Summary
104+ - Repository: { repo_owner } /{ repo_name }
105+ - File reviewed: { file_path }
106+ - Code length: { len (str (code ))} characters
107+ - Documentation: { 'Present' if has_docs else 'Missing' }
108+ """
109+
110+ # Save to current directory for easy access
111+ current_dir = os .getcwd ()
112+ report_filename = f"review_{ repo_name } _{ file_path .replace ('/' , '_' )} .md"
113+ report_path = f"{ current_dir } /{ report_filename } "
114+ await self .files .write_file (report_path , report )
115+ print (f" ✓ Report saved as: { report_filename } (in current directory)" )
116+
117+ return {
118+ "repository" : f"{ repo_owner } /{ repo_name } " ,
119+ "file_reviewed" : file_path ,
120+ "code_length" : len (str (code )),
121+ "ai_rating" : "Analysis completed" ,
122+ "documentation_status" : "Present" if has_docs else "Missing" ,
123+ "report_file" : report_filename
124+ }
125+
126+ # Demo
127+ async def demo ():
128+ """Demo the code review assistant"""
129+ print ("🚀 Code Review Assistant Demo" )
130+ print ("=" * 50 )
131+
132+ try :
133+ assistant = CodeReviewAssistant ()
134+
135+ # Review a file from a public repository
136+ result = await assistant .review_code ("octocat" , "Hello-World" , "README" )
137+
138+ print ("\n 📊 Review Summary:" )
139+ print ("=" * 30 )
140+ print (f"Repository: { result ['repository' ]} " )
141+ print (f"File: { result ['file_reviewed' ]} " )
142+ print (f"Code length: { result ['code_length' ]} characters" )
143+ print (f"Documentation: { result ['documentation_status' ]} " )
144+ print (f"Report: { result ['report_file' ]} " )
145+
146+ print (f"\n ✅ Complete! All MCP providers worked together seamlessly." )
147+ print (f"📄 Check { result ['report_file' ]} for the full AI analysis." )
148+
149+ except ValueError as e :
150+ print (f"❌ Configuration error: { e } " )
151+ print ("\n 📋 Setup required:" )
152+ print ("export OPENAI_API_KEY='your-openai-key'" )
153+ print ("export GITHUB_TOKEN='your-github-token'" )
154+ print ("export BROWSERBASE_API_KEY='your-browserbase-key'" )
155+ print ("export BROWSERBASE_PROJECT_ID='your-project-id'" )
156+
157+ except Exception as e :
158+ print (f"❌ Error: { e } " )
159+
160+ if __name__ == "__main__" :
161+ asyncio .run (demo ())
0 commit comments