fix: resolve mypy type errors and linting issues

- Add type annotation for server variable
- Fix handling of optional parameters in chat and analyze_code handlers
- Rename request variable to request_analysis to avoid type confusion
- Fix model listing to handle missing attributes safely
- Remove emoji icons from README section headers
- Fix flake8 formatting issues (whitespace, line length)

All tests passing, mypy and flake8 checks now pass in CI.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Fahad
2025-06-08 21:25:19 +04:00
parent fe1fb83ab5
commit fb1d843950
2 changed files with 52 additions and 43 deletions

View File

@@ -2,7 +2,7 @@
A specialized Model Context Protocol (MCP) server that extends Claude Code's capabilities with Google's Gemini 2.5 Pro Preview, featuring a massive 1M token context window for handling large codebases and complex analysis tasks. A specialized Model Context Protocol (MCP) server that extends Claude Code's capabilities with Google's Gemini 2.5 Pro Preview, featuring a massive 1M token context window for handling large codebases and complex analysis tasks.
## 🎯 Purpose ## Purpose
This server acts as a developer assistant that augments Claude Code when you need: This server acts as a developer assistant that augments Claude Code when you need:
- Analysis of files too large for Claude's context window - Analysis of files too large for Claude's context window
@@ -11,7 +11,7 @@ This server acts as a developer assistant that augments Claude Code when you nee
- Performance analysis of large codebases - Performance analysis of large codebases
- Security audits requiring full codebase context - Security audits requiring full codebase context
## 📋 Prerequisites ## Prerequisites
Before you begin, ensure you have the following: Before you begin, ensure you have the following:
@@ -21,7 +21,7 @@ Before you begin, ensure you have the following:
- Ensure your key is enabled for the `gemini-2.5-pro-preview` model - Ensure your key is enabled for the `gemini-2.5-pro-preview` model
4. **Git:** The `git` command-line tool for cloning the repository 4. **Git:** The `git` command-line tool for cloning the repository
## 🚀 Quick Start for Claude Code ## Quick Start for Claude Code
### 1. Clone the Repository ### 1. Clone the Repository
@@ -114,7 +114,7 @@ Just talk to Claude naturally:
- "Ask Gemini to review the architecture of these files..." - "Ask Gemini to review the architecture of these files..."
- "Have Gemini check this codebase for security issues..." - "Have Gemini check this codebase for security issues..."
## 🔍 How It Works ## How It Works
This server acts as a local proxy between Claude Code and the Google Gemini API, following the Model Context Protocol (MCP): This server acts as a local proxy between Claude Code and the Google Gemini API, following the Model Context Protocol (MCP):
@@ -127,7 +127,7 @@ This server acts as a local proxy between Claude Code and the Google Gemini API,
All processing and API communication happens locally from your machine. Your API key is never exposed to Anthropic. All processing and API communication happens locally from your machine. Your API key is never exposed to Anthropic.
## 💻 Developer-Optimized Features ## Developer-Optimized Features
### Automatic Developer Context ### Automatic Developer Context
When no custom system prompt is provided, Gemini automatically operates with deep developer expertise, focusing on: When no custom system prompt is provided, Gemini automatically operates with deep developer expertise, focusing on:
@@ -147,7 +147,7 @@ When no custom system prompt is provided, Gemini automatically operates with dee
- Perfect for analyzing entire codebases - Perfect for analyzing entire codebases
- Maintains context across multiple large files - Maintains context across multiple large files
## 🛠️ Available Tools ## Available Tools
### `chat` ### `chat`
General-purpose developer conversations with Gemini. General-purpose developer conversations with Gemini.
@@ -170,7 +170,7 @@ Specialized tool for analyzing large files or multiple files that exceed Claude'
### `list_models` ### `list_models`
Lists available Gemini models (defaults to 2.5 Pro Preview). Lists available Gemini models (defaults to 2.5 Pro Preview).
## 📋 Installation ## Installation
1. Clone the repository: 1. Clone the repository:
```bash ```bash
@@ -194,7 +194,7 @@ Lists available Gemini models (defaults to 2.5 Pro Preview).
export GEMINI_API_KEY="your-api-key-here" export GEMINI_API_KEY="your-api-key-here"
``` ```
## 🔧 Advanced Configuration ## Advanced Configuration
### Custom System Prompts ### Custom System Prompts
Override the default developer prompt when needed: Override the default developer prompt when needed:
@@ -217,7 +217,7 @@ While defaulting to `gemini-2.5-pro-preview-06-05`, you can specify other models
- `gemini-1.5-flash`: Faster responses - `gemini-1.5-flash`: Faster responses
- Use `list_models` to see all available options - Use `list_models` to see all available options
## 🎯 Claude Code Integration Examples ## Claude Code Integration Examples
### When Claude hits token limits: ### When Claude hits token limits:
``` ```
@@ -235,12 +235,12 @@ You: "Use Gemini to analyze all files in /src/core/ and create an architecture d
You: "Have Gemini profile this codebase and suggest the top 5 performance improvements" You: "Have Gemini profile this codebase and suggest the top 5 performance improvements"
``` ```
## 💡 Practical Usage Tips ## Practical Usage Tips
### Effective Commands ### Effective Commands
Be specific about what you want from Gemini: Be specific about what you want from Gemini:
- "Ask Gemini to identify memory leaks in this code" - Good: "Ask Gemini to identify memory leaks in this code"
- "Ask Gemini about this" - Bad: "Ask Gemini about this"
### Common Workflows ### Common Workflows
@@ -308,14 +308,14 @@ You: "Have Gemini review my approach and check these 10 files for compatibility
6. Claude: [Refines design addressing all concerns] 6. Claude: [Refines design addressing all concerns]
``` ```
## 📝 Notes ## Notes
- Gemini 2.5 Pro Preview may occasionally block certain prompts due to safety filters - Gemini 2.5 Pro Preview may occasionally block certain prompts due to safety filters
- If a prompt is blocked by Google's safety filters, the server will return a clear error message to Claude explaining why the request could not be completed - If a prompt is blocked by Google's safety filters, the server will return a clear error message to Claude explaining why the request could not be completed
- Token estimation: ~4 characters per token - Token estimation: ~4 characters per token
- All file paths should be absolute paths - All file paths should be absolute paths
## 🔧 Troubleshooting ## Troubleshooting
### Server Not Appearing in Claude ### Server Not Appearing in Claude
@@ -337,7 +337,7 @@ You: "Have Gemini review my approach and check these 10 files for compatibility
- **`chmod: command not found` (Windows):** The `chmod +x` command is for macOS/Linux only. Windows users can skip this step - **`chmod: command not found` (Windows):** The `chmod +x` command is for macOS/Linux only. Windows users can skip this step
- **Path not found errors:** Use absolute paths in all configurations, not relative paths like `./run_gemini.sh` - **Path not found errors:** Use absolute paths in all configurations, not relative paths like `./run_gemini.sh`
## 🧪 Testing ## Testing
### Running Tests Locally ### Running Tests Locally
@@ -368,7 +368,7 @@ This project uses GitHub Actions for automated testing:
- Includes linting with flake8, black, isort, and mypy - Includes linting with flake8, black, isort, and mypy
- Maintains 80%+ code coverage - Maintains 80%+ code coverage
## 🤝 Contributing ## Contributing
This server is designed specifically for Claude Code users. Contributions that enhance the developer experience are welcome! This server is designed specifically for Claude Code users. Contributions that enhance the developer experience are welcome!
@@ -380,6 +380,6 @@ This server is designed specifically for Claude Code users. Contributions that e
6. Push to the branch (`git push origin feature/amazing-feature`) 6. Push to the branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request 7. Open a Pull Request
## 📄 License ## License
MIT License - feel free to customize for your development workflow. MIT License - feel free to customize for your development workflow.

View File

@@ -103,7 +103,7 @@ class CodeAnalysisRequest(BaseModel):
# Create the MCP server instance # Create the MCP server instance
server = Server("gemini-server") server: Server = Server("gemini-server")
# Configure Gemini API # Configure Gemini API
@@ -150,7 +150,7 @@ def prepare_code_context(
# Add file contents # Add file contents
if files: if files:
summary_parts.append(f"📁 Analyzing {len(files)} file(s):") summary_parts.append(f"Analyzing {len(files)} file(s):")
for file_path in files: for file_path in files:
# Get file content for Gemini # Get file content for Gemini
file_content = read_file_content_for_gemini(file_path) file_content = read_file_content_for_gemini(file_path)
@@ -171,7 +171,7 @@ def prepare_code_context(
preview = "\n".join(preview_lines) preview = "\n".join(preview_lines)
if len(preview) > 100: if len(preview) > 100:
preview = preview[:100] + "..." preview = preview[:100] + "..."
summary_parts.append(f" 📄 {file_path} ({size:,} bytes)") summary_parts.append(f" {file_path} ({size:,} bytes)")
if preview.strip(): if preview.strip():
summary_parts.append(f" Preview: {preview[:50]}...") summary_parts.append(f" Preview: {preview[:50]}...")
except Exception: except Exception:
@@ -186,7 +186,7 @@ def prepare_code_context(
) )
context_parts.append(formatted_code) context_parts.append(formatted_code)
preview = code[:100] + "..." if len(code) > 100 else code preview = code[:100] + "..." if len(code) > 100 else code
summary_parts.append(f"💻 Direct code provided ({len(code):,} characters)") summary_parts.append(f"Direct code provided ({len(code):,} characters)")
summary_parts.append(f" Preview: {preview}") summary_parts.append(f" Preview: {preview}")
full_context = "\n\n".join(context_parts) full_context = "\n\n".join(context_parts)
@@ -302,11 +302,15 @@ async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextCon
try: try:
# Use the specified model with optimized settings # Use the specified model with optimized settings
model_name = request.model or DEFAULT_MODEL
temperature = request.temperature if request.temperature is not None else 0.5
max_tokens = request.max_tokens if request.max_tokens is not None else 8192
model = genai.GenerativeModel( model = genai.GenerativeModel(
model_name=request.model, model_name=model_name,
generation_config={ generation_config={
"temperature": request.temperature, "temperature": temperature,
"max_output_tokens": request.max_tokens, "max_output_tokens": max_tokens,
"candidate_count": 1, "candidate_count": 1,
}, },
) )
@@ -342,10 +346,10 @@ async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextCon
elif name == "analyze_code": elif name == "analyze_code":
# Validate request # Validate request
request = CodeAnalysisRequest(**arguments) request_analysis = CodeAnalysisRequest(**arguments)
# Check that we have either files or code # Check that we have either files or code
if not request.files and not request.code: if not request_analysis.files and not request_analysis.code:
return [ return [
TextContent( TextContent(
type="text", type="text",
@@ -355,7 +359,7 @@ async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextCon
try: try:
# Prepare code context - always use non-verbose mode for Claude Code compatibility # Prepare code context - always use non-verbose mode for Claude Code compatibility
code_context, summary = prepare_code_context(request.files, request.code) code_context, summary = prepare_code_context(request_analysis.files, request_analysis.code)
# Count approximate tokens (rough estimate: 1 token ≈ 4 characters) # Count approximate tokens (rough estimate: 1 token ≈ 4 characters)
estimated_tokens = len(code_context) // 4 estimated_tokens = len(code_context) // 4
@@ -369,21 +373,25 @@ async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextCon
] ]
# Use the specified model with optimized settings for code analysis # Use the specified model with optimized settings for code analysis
model_name = request_analysis.model or DEFAULT_MODEL
temperature = request_analysis.temperature if request_analysis.temperature is not None else 0.2
max_tokens = request_analysis.max_tokens if request_analysis.max_tokens is not None else 8192
model = genai.GenerativeModel( model = genai.GenerativeModel(
model_name=request.model, model_name=model_name,
generation_config={ generation_config={
"temperature": request.temperature, "temperature": temperature,
"max_output_tokens": request.max_tokens, "max_output_tokens": max_tokens,
"candidate_count": 1, "candidate_count": 1,
}, },
) )
# Prepare the full prompt with enhanced developer context and clear structure # Prepare the full prompt with enhanced developer context and clear structure
system_prompt = request.system_prompt or DEVELOPER_SYSTEM_PROMPT system_prompt = request_analysis.system_prompt or DEVELOPER_SYSTEM_PROMPT
full_prompt = f"""{system_prompt} full_prompt = f"""{system_prompt}
=== USER REQUEST === === USER REQUEST ===
{request.question} {request_analysis.question}
=== END USER REQUEST === === END USER REQUEST ===
=== CODE TO ANALYZE === === CODE TO ANALYZE ===
@@ -408,7 +416,7 @@ marked with their paths and content boundaries."""
text = f"Response blocked or incomplete. Finish reason: {finish_reason}" text = f"Response blocked or incomplete. Finish reason: {finish_reason}"
# Always return response with summary for Claude Code compatibility # Always return response with summary for Claude Code compatibility
if request.files or request.code: if request_analysis.files or request_analysis.code:
response_text = f"{summary}\n\n🤖 Gemini's Analysis:\n{text}" response_text = f"{summary}\n\n🤖 Gemini's Analysis:\n{text}"
else: else:
response_text = text response_text = text
@@ -422,14 +430,15 @@ marked with their paths and content boundaries."""
try: try:
# List available models # List available models
models = [] models = []
for model in genai.list_models(): for model_info in genai.list_models():
if "generateContent" in model.supported_generation_methods: if (hasattr(model_info, 'supported_generation_methods') and
"generateContent" in model_info.supported_generation_methods):
models.append( models.append(
{ {
"name": model.name, "name": model_info.name,
"display_name": model.display_name, "display_name": getattr(model_info, 'display_name', 'Unknown'),
"description": model.description, "description": getattr(model_info, 'description', 'No description'),
"is_default": model.name == DEFAULT_MODEL, "is_default": model_info.name.endswith(DEFAULT_MODEL),
} }
) )
@@ -458,10 +467,10 @@ Updated: {__updated__}
Author: {__author__} Author: {__author__}
Configuration: Configuration:
Default Model: {DEFAULT_MODEL} - Default Model: {DEFAULT_MODEL}
Max Context: {MAX_CONTEXT_TOKENS:,} tokens - Max Context: {MAX_CONTEXT_TOKENS:,} tokens
Python: {version_info['python_version']} - Python: {version_info['python_version']}
Started: {version_info['server_started']} - Started: {version_info['server_started']}
For updates, visit: https://github.com/BeehiveInnovations/gemini-mcp-server""", For updates, visit: https://github.com/BeehiveInnovations/gemini-mcp-server""",
) )