refactor: rename review tools for clarity and consistency

- Renamed `review_code` tool to `codereview` for better naming convention
- Renamed `review_changes` tool to `precommit` to better reflect its purpose
- Updated all tool descriptions to remove "Triggers:" sections and improve clarity
- Updated all imports and references throughout the codebase
- Renamed test files to match new tool names
- Updated server.py tool registrations
- All existing functionality preserved with improved naming

This refactoring improves code organization and makes tool purposes clearer.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Fahad
2025-06-10 12:30:06 +04:00
parent 67f18ef3c9
commit 5f8ed3aae8
18 changed files with 119 additions and 122 deletions

View File

@@ -19,8 +19,8 @@ The ultimate development partner for Claude - a Model Context Protocol server th
- **Tools Reference** - **Tools Reference**
- [`chat`](#1-chat---general-development-chat--collaborative-thinking) - Collaborative thinking - [`chat`](#1-chat---general-development-chat--collaborative-thinking) - Collaborative thinking
- [`think_deeper`](#2-think_deeper---extended-reasoning-partner) - Extended reasoning - [`think_deeper`](#2-think_deeper---extended-reasoning-partner) - Extended reasoning
- [`review_code`](#3-review_code---professional-code-review) - Code review - [`codereview`](#3-codereview---professional-code-review) - Code review
- [`review_changes`](#4-review_changes---pre-commit-validation) - Pre-commit validation - [`precommit`](#4-precommit---pre-commit-validation) - Pre-commit validation
- [`debug`](#5-debug---expert-debugging-assistant) - Debugging help - [`debug`](#5-debug---expert-debugging-assistant) - Debugging help
- [`analyze`](#6-analyze---smart-file-analysis) - File analysis - [`analyze`](#6-analyze---smart-file-analysis) - File analysis
@@ -42,8 +42,8 @@ The ultimate development partner for Claude - a Model Context Protocol server th
Claude is brilliant, but sometimes you need: Claude is brilliant, but sometimes you need:
- **A senior developer partner** to validate and extend ideas ([`chat`](#1-chat---general-development-chat--collaborative-thinking)) - **A senior developer partner** to validate and extend ideas ([`chat`](#1-chat---general-development-chat--collaborative-thinking))
- **A second opinion** on complex architectural decisions - augment Claude's extended thinking with Gemini's perspective ([`think_deeper`](#2-think_deeper---extended-reasoning-partner)) - **A second opinion** on complex architectural decisions - augment Claude's extended thinking with Gemini's perspective ([`think_deeper`](#2-think_deeper---extended-reasoning-partner))
- **Professional code reviews** with actionable feedback across entire repositories ([`review_code`](#3-review_code---professional-code-review)) - **Professional code reviews** with actionable feedback across entire repositories ([`codereview`](#3-codereview---professional-code-review))
- **Pre-commit validation** with deep analysis that finds edge cases, validates your implementation against original requirements, and catches subtle bugs Claude might miss ([`review_changes`](#4-review_changes---pre-commit-validation)) - **Pre-commit validation** with deep analysis that finds edge cases, validates your implementation against original requirements, and catches subtle bugs Claude might miss ([`precommit`](#4-precommit---pre-commit-validation))
- **Expert debugging** for tricky issues with full system context ([`debug`](#5-debug---expert-debugging-assistant)) - **Expert debugging** for tricky issues with full system context ([`debug`](#5-debug---expert-debugging-assistant))
- **Massive context window** (1M tokens) - Gemini 2.5 Pro can analyze entire codebases, read hundreds of files at once, and provide comprehensive insights ([`analyze`](#6-analyze---smart-file-analysis)) - **Massive context window** (1M tokens) - Gemini 2.5 Pro can analyze entire codebases, read hundreds of files at once, and provide comprehensive insights ([`analyze`](#6-analyze---smart-file-analysis))
- **Deep code analysis** across massive codebases that exceed Claude's context limits ([`analyze`](#6-analyze---smart-file-analysis)) - **Deep code analysis** across massive codebases that exceed Claude's context limits ([`analyze`](#6-analyze---smart-file-analysis))
@@ -562,7 +562,7 @@ about event ordering and failure scenarios. Then integrate gemini's insights and
**Triggers:** think deeper, ultrathink, extend my analysis, validate my approach **Triggers:** think deeper, ultrathink, extend my analysis, validate my approach
### 3. `review_code` - Professional Code Review ### 3. `codereview` - Professional Code Review
**Comprehensive code analysis with prioritized feedback** **Comprehensive code analysis with prioritized feedback**
**Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` for security-critical code (worth the extra tokens) or `low` for quick style checks (saves ~6k tokens). **Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` for security-critical code (worth the extra tokens) or `low` for quick style checks (saves ~6k tokens).
@@ -607,7 +607,7 @@ make any necessary adjustments and show me the final secure implementation."
**Triggers:** review code, check for issues, find bugs, security check **Triggers:** review code, check for issues, find bugs, security check
### 4. `review_changes` - Pre-Commit Validation ### 4. `precommit` - Pre-Commit Validation
**Comprehensive review of staged/unstaged git changes across multiple repositories** **Comprehensive review of staged/unstaged git changes across multiple repositories**
**Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` or `max` for critical releases when thorough validation justifies the token cost. **Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` or `max` for critical releases when thorough validation justifies the token cost.

View File

@@ -5,14 +5,14 @@ System prompts for Gemini tools
from .tool_prompts import ( from .tool_prompts import (
ANALYZE_PROMPT, ANALYZE_PROMPT,
CHAT_PROMPT, CHAT_PROMPT,
CODEREVIEW_PROMPT,
DEBUG_ISSUE_PROMPT, DEBUG_ISSUE_PROMPT,
REVIEW_CODE_PROMPT,
THINK_DEEPER_PROMPT, THINK_DEEPER_PROMPT,
) )
__all__ = [ __all__ = [
"THINK_DEEPER_PROMPT", "THINK_DEEPER_PROMPT",
"REVIEW_CODE_PROMPT", "CODEREVIEW_PROMPT",
"DEBUG_ISSUE_PROMPT", "DEBUG_ISSUE_PROMPT",
"ANALYZE_PROMPT", "ANALYZE_PROMPT",
"CHAT_PROMPT", "CHAT_PROMPT",

View File

@@ -38,7 +38,7 @@ Be direct and technical. Assume Claude and the user are experienced developers w
deep, nuanced analysis rather than basic explanations. Your goal is to be the perfect deep, nuanced analysis rather than basic explanations. Your goal is to be the perfect
development partner that extends Claude's capabilities.""" development partner that extends Claude's capabilities."""
REVIEW_CODE_PROMPT = """You are an expert code reviewer with deep knowledge of software engineering best practices. CODEREVIEW_PROMPT = """You are an expert code reviewer with deep knowledge of software engineering best practices.
Your expertise spans security, performance, maintainability, and architectural patterns. Your expertise spans security, performance, maintainability, and architectural patterns.
IMPORTANT: If you need additional context (e.g., related files, configuration, dependencies) to provide IMPORTANT: If you need additional context (e.g., related files, configuration, dependencies) to provide
@@ -171,7 +171,7 @@ the ideal thinking partner who helps explore ideas deeply, validates approaches,
insights that might be missed in solo analysis. Think step by step through complex problems insights that might be missed in solo analysis. Think step by step through complex problems
and don't hesitate to explore tangential but relevant considerations.""" and don't hesitate to explore tangential but relevant considerations."""
REVIEW_CHANGES_PROMPT = """You are an expert code change analyst specializing in pre-commit review of git diffs. PRECOMMIT_PROMPT = """You are an expert code change analyst specializing in pre-commit review of git diffs.
Your role is to act as a seasoned senior developer performing a final review before code is committed. Your role is to act as a seasoned senior developer performing a final review before code is committed.
IMPORTANT: If you need additional context (e.g., related files not in the diff, test files, configuration) IMPORTANT: If you need additional context (e.g., related files not in the diff, test files, configuration)

View File

@@ -40,9 +40,9 @@ from config import (
from tools import ( from tools import (
AnalyzeTool, AnalyzeTool,
ChatTool, ChatTool,
CodeReviewTool,
DebugIssueTool, DebugIssueTool,
ReviewChanges, Precommit,
ReviewCodeTool,
ThinkDeeperTool, ThinkDeeperTool,
) )
@@ -60,11 +60,11 @@ server: Server = Server("gemini-server")
# Tools are instantiated once and reused across requests (stateless design) # Tools are instantiated once and reused across requests (stateless design)
TOOLS = { TOOLS = {
"think_deeper": ThinkDeeperTool(), # Extended reasoning for complex problems "think_deeper": ThinkDeeperTool(), # Extended reasoning for complex problems
"review_code": ReviewCodeTool(), # Comprehensive code review and quality analysis "codereview": CodeReviewTool(), # Comprehensive code review and quality analysis
"debug": DebugIssueTool(), # Root cause analysis and debugging assistance "debug": DebugIssueTool(), # Root cause analysis and debugging assistance
"analyze": AnalyzeTool(), # General-purpose file and code analysis "analyze": AnalyzeTool(), # General-purpose file and code analysis
"chat": ChatTool(), # Interactive development chat and brainstorming "chat": ChatTool(), # Interactive development chat and brainstorming
"review_changes": ReviewChanges(), # Pre-commit review of git changes "precommit": Precommit(), # Pre-commit validation of git changes
} }

View File

@@ -156,10 +156,10 @@ def test_review_changes_docker_path_translation():
utils.file_utils.CONTAINER_WORKSPACE = container_workspace utils.file_utils.CONTAINER_WORKSPACE = container_workspace
# Import after reloading to get updated environment # Import after reloading to get updated environment
from tools.review_changes import ReviewChanges from tools.precommit import Precommit
# Create tool instance # Create tool instance
tool = ReviewChanges() tool = Precommit()
# Test path translation in prepare_prompt # Test path translation in prepare_prompt
request = tool.get_request_model()( request = tool.get_request_model()(
@@ -209,10 +209,10 @@ def test_review_changes_docker_path_error():
utils.file_utils.CONTAINER_WORKSPACE = container_workspace utils.file_utils.CONTAINER_WORKSPACE = container_workspace
# Import after reloading to get updated environment # Import after reloading to get updated environment
from tools.review_changes import ReviewChanges from tools.precommit import Precommit
# Create tool instance # Create tool instance
tool = ReviewChanges() tool = Precommit()
# Test path translation with an inaccessible path # Test path translation with an inaccessible path
request = tool.get_request_model()( request = tool.get_request_model()(

View File

@@ -18,9 +18,9 @@ from mcp.types import TextContent
from config import MCP_PROMPT_SIZE_LIMIT from config import MCP_PROMPT_SIZE_LIMIT
from tools.analyze import AnalyzeTool from tools.analyze import AnalyzeTool
from tools.chat import ChatTool from tools.chat import ChatTool
from tools.codereview import CodeReviewTool
from tools.debug import DebugIssueTool from tools.debug import DebugIssueTool
from tools.review_changes import ReviewChanges from tools.precommit import Precommit
from tools.review_code import ReviewCodeTool
from tools.think_deeper import ThinkDeeperTool from tools.think_deeper import ThinkDeeperTool
@@ -141,9 +141,9 @@ class TestLargePromptHandling:
assert output["status"] == "requires_file_prompt" assert output["status"] == "requires_file_prompt"
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_review_code_large_focus(self, large_prompt): async def test_codereview_large_focus(self, large_prompt):
"""Test that review_code tool detects large focus_on field.""" """Test that codereview tool detects large focus_on field."""
tool = ReviewCodeTool() tool = CodeReviewTool()
result = await tool.execute( result = await tool.execute(
{ {
"files": ["/some/file.py"], "files": ["/some/file.py"],
@@ -159,7 +159,7 @@ class TestLargePromptHandling:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_review_changes_large_original_request(self, large_prompt): async def test_review_changes_large_original_request(self, large_prompt):
"""Test that review_changes tool detects large original_request.""" """Test that review_changes tool detects large original_request."""
tool = ReviewChanges() tool = Precommit()
result = await tool.execute({"path": "/some/path", "original_request": large_prompt}) result = await tool.execute({"path": "/some/path", "original_request": large_prompt})
assert len(result) == 1 assert len(result) == 1

View File

@@ -1,5 +1,5 @@
""" """
Tests for the review_changes tool Tests for the precommit tool
""" """
import json import json
@@ -7,22 +7,22 @@ from unittest.mock import Mock, patch
import pytest import pytest
from tools.review_changes import ReviewChanges, ReviewChangesRequest from tools.precommit import Precommit, PrecommitRequest
class TestReviewChangesTool: class TestPrecommitTool:
"""Test the review_changes tool""" """Test the precommit tool"""
@pytest.fixture @pytest.fixture
def tool(self): def tool(self):
"""Create tool instance""" """Create tool instance"""
return ReviewChanges() return Precommit()
def test_tool_metadata(self, tool): def test_tool_metadata(self, tool):
"""Test tool metadata""" """Test tool metadata"""
assert tool.get_name() == "review_changes" assert tool.get_name() == "precommit"
assert "REVIEW PENDING GIT CHANGES" in tool.get_description() assert "PRECOMMIT VALIDATION" in tool.get_description()
assert "pre-commit review" in tool.get_description() assert "pre-commit" in tool.get_description()
# Check schema # Check schema
schema = tool.get_input_schema() schema = tool.get_input_schema()
@@ -34,7 +34,7 @@ class TestReviewChangesTool:
def test_request_model_defaults(self): def test_request_model_defaults(self):
"""Test request model default values""" """Test request model default values"""
request = ReviewChangesRequest(path="/some/absolute/path") request = PrecommitRequest(path="/some/absolute/path")
assert request.path == "/some/absolute/path" assert request.path == "/some/absolute/path"
assert request.original_request is None assert request.original_request is None
assert request.compare_to is None assert request.compare_to is None
@@ -56,21 +56,21 @@ class TestReviewChangesTool:
assert "./relative/path" in response["content"] assert "./relative/path" in response["content"]
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.review_changes.find_git_repositories") @patch("tools.precommit.find_git_repositories")
async def test_no_repositories_found(self, mock_find_repos, tool): async def test_no_repositories_found(self, mock_find_repos, tool):
"""Test when no git repositories are found""" """Test when no git repositories are found"""
mock_find_repos.return_value = [] mock_find_repos.return_value = []
request = ReviewChangesRequest(path="/absolute/path/no-git") request = PrecommitRequest(path="/absolute/path/no-git")
result = await tool.prepare_prompt(request) result = await tool.prepare_prompt(request)
assert result == "No git repositories found in the specified path." assert result == "No git repositories found in the specified path."
mock_find_repos.assert_called_once_with("/absolute/path/no-git", 5) mock_find_repos.assert_called_once_with("/absolute/path/no-git", 5)
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.review_changes.find_git_repositories") @patch("tools.precommit.find_git_repositories")
@patch("tools.review_changes.get_git_status") @patch("tools.precommit.get_git_status")
@patch("tools.review_changes.run_git_command") @patch("tools.precommit.run_git_command")
async def test_no_changes_found(self, mock_run_git, mock_status, mock_find_repos, tool): async def test_no_changes_found(self, mock_run_git, mock_status, mock_find_repos, tool):
"""Test when repositories have no changes""" """Test when repositories have no changes"""
mock_find_repos.return_value = ["/test/repo"] mock_find_repos.return_value = ["/test/repo"]
@@ -89,15 +89,15 @@ class TestReviewChangesTool:
(True, ""), # unstaged files (empty) (True, ""), # unstaged files (empty)
] ]
request = ReviewChangesRequest(path="/absolute/repo/path") request = PrecommitRequest(path="/absolute/repo/path")
result = await tool.prepare_prompt(request) result = await tool.prepare_prompt(request)
assert result == "No pending changes found in any of the git repositories." assert result == "No pending changes found in any of the git repositories."
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.review_changes.find_git_repositories") @patch("tools.precommit.find_git_repositories")
@patch("tools.review_changes.get_git_status") @patch("tools.precommit.get_git_status")
@patch("tools.review_changes.run_git_command") @patch("tools.precommit.run_git_command")
async def test_staged_changes_review( async def test_staged_changes_review(
self, self,
mock_run_git, mock_run_git,
@@ -126,7 +126,7 @@ class TestReviewChangesTool:
(True, ""), # unstaged files (empty) (True, ""), # unstaged files (empty)
] ]
request = ReviewChangesRequest( request = PrecommitRequest(
path="/absolute/repo/path", path="/absolute/repo/path",
original_request="Add hello message", original_request="Add hello message",
review_type="security", review_type="security",
@@ -143,9 +143,9 @@ class TestReviewChangesTool:
assert "## Git Diffs" in result assert "## Git Diffs" in result
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.review_changes.find_git_repositories") @patch("tools.precommit.find_git_repositories")
@patch("tools.review_changes.get_git_status") @patch("tools.precommit.get_git_status")
@patch("tools.review_changes.run_git_command") @patch("tools.precommit.run_git_command")
async def test_compare_to_invalid_ref(self, mock_run_git, mock_status, mock_find_repos, tool): async def test_compare_to_invalid_ref(self, mock_run_git, mock_status, mock_find_repos, tool):
"""Test comparing to an invalid git ref""" """Test comparing to an invalid git ref"""
mock_find_repos.return_value = ["/test/repo"] mock_find_repos.return_value = ["/test/repo"]
@@ -156,14 +156,14 @@ class TestReviewChangesTool:
(False, "fatal: not a valid ref"), # rev-parse fails (False, "fatal: not a valid ref"), # rev-parse fails
] ]
request = ReviewChangesRequest(path="/absolute/repo/path", compare_to="invalid-branch") request = PrecommitRequest(path="/absolute/repo/path", compare_to="invalid-branch")
result = await tool.prepare_prompt(request) result = await tool.prepare_prompt(request)
# When all repos have errors and no changes, we get this message # When all repos have errors and no changes, we get this message
assert "No pending changes found in any of the git repositories." in result assert "No pending changes found in any of the git repositories." in result
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.review_changes.ReviewChanges.execute") @patch("tools.precommit.Precommit.execute")
async def test_execute_integration(self, mock_execute, tool): async def test_execute_integration(self, mock_execute, tool):
"""Test execute method integration""" """Test execute method integration"""
# Mock the execute to return a standardized response # Mock the execute to return a standardized response
@@ -183,9 +183,9 @@ class TestReviewChangesTool:
assert tool.get_default_temperature() == TEMPERATURE_ANALYTICAL assert tool.get_default_temperature() == TEMPERATURE_ANALYTICAL
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.review_changes.find_git_repositories") @patch("tools.precommit.find_git_repositories")
@patch("tools.review_changes.get_git_status") @patch("tools.precommit.get_git_status")
@patch("tools.review_changes.run_git_command") @patch("tools.precommit.run_git_command")
async def test_mixed_staged_unstaged_changes( async def test_mixed_staged_unstaged_changes(
self, self,
mock_run_git, mock_run_git,
@@ -211,7 +211,7 @@ class TestReviewChangesTool:
(True, "diff --git a/file2.py..."), # diff for file2.py (True, "diff --git a/file2.py..."), # diff for file2.py
] ]
request = ReviewChangesRequest( request = PrecommitRequest(
path="/absolute/repo/path", path="/absolute/repo/path",
focus_on="error handling", focus_on="error handling",
severity_filter="high", severity_filter="high",
@@ -225,10 +225,10 @@ class TestReviewChangesTool:
assert "Reviewing: staged and unstaged changes" in result assert "Reviewing: staged and unstaged changes" in result
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.review_changes.find_git_repositories") @patch("tools.precommit.find_git_repositories")
@patch("tools.review_changes.get_git_status") @patch("tools.precommit.get_git_status")
@patch("tools.review_changes.run_git_command") @patch("tools.precommit.run_git_command")
@patch("tools.review_changes.read_files") @patch("tools.precommit.read_files")
async def test_files_parameter_with_context( async def test_files_parameter_with_context(
self, self,
mock_read_files, mock_read_files,
@@ -257,7 +257,7 @@ class TestReviewChangesTool:
# Mock read_files # Mock read_files
mock_read_files.return_value = "=== FILE: config.py ===\nCONFIG_VALUE = 42\n=== END FILE ===" mock_read_files.return_value = "=== FILE: config.py ===\nCONFIG_VALUE = 42\n=== END FILE ==="
request = ReviewChangesRequest( request = PrecommitRequest(
path="/absolute/repo/path", path="/absolute/repo/path",
files=["/absolute/repo/path/config.py"], files=["/absolute/repo/path/config.py"],
) )
@@ -271,9 +271,9 @@ class TestReviewChangesTool:
assert "CONFIG_VALUE = 42" in result assert "CONFIG_VALUE = 42" in result
@pytest.mark.asyncio @pytest.mark.asyncio
@patch("tools.review_changes.find_git_repositories") @patch("tools.precommit.find_git_repositories")
@patch("tools.review_changes.get_git_status") @patch("tools.precommit.get_git_status")
@patch("tools.review_changes.run_git_command") @patch("tools.precommit.run_git_command")
async def test_files_request_instruction( async def test_files_request_instruction(
self, self,
mock_run_git, mock_run_git,
@@ -298,7 +298,7 @@ class TestReviewChangesTool:
] ]
# Request without files # Request without files
request = ReviewChangesRequest(path="/absolute/repo/path") request = PrecommitRequest(path="/absolute/repo/path")
result = await tool.prepare_prompt(request) result = await tool.prepare_prompt(request)
# Should include instruction for requesting files # Should include instruction for requesting files
@@ -306,7 +306,7 @@ class TestReviewChangesTool:
assert "standardized JSON response format" in result assert "standardized JSON response format" in result
# Request with files - should not include instruction # Request with files - should not include instruction
request_with_files = ReviewChangesRequest(path="/absolute/repo/path", files=["/some/file.py"]) request_with_files = PrecommitRequest(path="/absolute/repo/path", files=["/some/file.py"])
# Need to reset mocks for second call # Need to reset mocks for second call
mock_find_repos.return_value = ["/test/repo"] mock_find_repos.return_value = ["/test/repo"]
@@ -317,7 +317,7 @@ class TestReviewChangesTool:
] ]
# Mock read_files to return empty (file not found) # Mock read_files to return empty (file not found)
with patch("tools.review_changes.read_files") as mock_read: with patch("tools.precommit.read_files") as mock_read:
mock_read.return_value = "" mock_read.return_value = ""
result_with_files = await tool.prepare_prompt(request_with_files) result_with_files = await tool.prepare_prompt(request_with_files)

View File

@@ -12,9 +12,9 @@ import pytest
from tools.analyze import AnalyzeTool from tools.analyze import AnalyzeTool
from tools.chat import ChatTool from tools.chat import ChatTool
from tools.codereview import CodeReviewTool
from tools.debug import DebugIssueTool from tools.debug import DebugIssueTool
from tools.review_changes import ReviewChanges from tools.precommit import Precommit
from tools.review_code import ReviewCodeTool
from tools.think_deeper import ThinkDeeperTool from tools.think_deeper import ThinkDeeperTool
@@ -105,9 +105,9 @@ class TestPromptRegression:
assert "deeper analysis" in output["content"] assert "deeper analysis" in output["content"]
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_review_code_normal_review(self, mock_model_response): async def test_codereview_normal_review(self, mock_model_response):
"""Test review_code tool with normal inputs.""" """Test codereview tool with normal inputs."""
tool = ReviewCodeTool() tool = CodeReviewTool()
with patch.object(tool, "create_model") as mock_create_model: with patch.object(tool, "create_model") as mock_create_model:
mock_model = MagicMock() mock_model = MagicMock()
@@ -117,7 +117,7 @@ class TestPromptRegression:
mock_create_model.return_value = mock_model mock_create_model.return_value = mock_model
# Mock file reading # Mock file reading
with patch("tools.review_code.read_files") as mock_read_files: with patch("tools.codereview.read_files") as mock_read_files:
mock_read_files.return_value = "def main(): pass" mock_read_files.return_value = "def main(): pass"
result = await tool.execute( result = await tool.execute(
@@ -137,7 +137,7 @@ class TestPromptRegression:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_review_changes_normal_request(self, mock_model_response): async def test_review_changes_normal_request(self, mock_model_response):
"""Test review_changes tool with normal original_request.""" """Test review_changes tool with normal original_request."""
tool = ReviewChanges() tool = Precommit()
with patch.object(tool, "create_model") as mock_create_model: with patch.object(tool, "create_model") as mock_create_model:
mock_model = MagicMock() mock_model = MagicMock()
@@ -147,8 +147,8 @@ class TestPromptRegression:
mock_create_model.return_value = mock_model mock_create_model.return_value = mock_model
# Mock git operations # Mock git operations
with patch("tools.review_changes.find_git_repositories") as mock_find_repos: with patch("tools.precommit.find_git_repositories") as mock_find_repos:
with patch("tools.review_changes.get_git_status") as mock_git_status: with patch("tools.precommit.get_git_status") as mock_git_status:
mock_find_repos.return_value = ["/path/to/repo"] mock_find_repos.return_value = ["/path/to/repo"]
mock_git_status.return_value = { mock_git_status.return_value = {
"modified": ["file.py"], "modified": ["file.py"],

View File

@@ -20,11 +20,11 @@ class TestServerTools:
# Check all core tools are present # Check all core tools are present
assert "think_deeper" in tool_names assert "think_deeper" in tool_names
assert "review_code" in tool_names assert "codereview" in tool_names
assert "debug" in tool_names assert "debug" in tool_names
assert "analyze" in tool_names assert "analyze" in tool_names
assert "chat" in tool_names assert "chat" in tool_names
assert "review_changes" in tool_names assert "precommit" in tool_names
assert "get_version" in tool_names assert "get_version" in tool_names
# Should have exactly 7 tools # Should have exactly 7 tools

View File

@@ -7,8 +7,8 @@ from unittest.mock import Mock, patch
import pytest import pytest
from tools.analyze import AnalyzeTool from tools.analyze import AnalyzeTool
from tools.codereview import CodeReviewTool
from tools.debug import DebugIssueTool from tools.debug import DebugIssueTool
from tools.review_code import ReviewCodeTool
from tools.think_deeper import ThinkDeeperTool from tools.think_deeper import ThinkDeeperTool
@@ -27,7 +27,7 @@ class TestThinkingModes:
tools = [ tools = [
(ThinkDeeperTool(), "high"), (ThinkDeeperTool(), "high"),
(AnalyzeTool(), "medium"), (AnalyzeTool(), "medium"),
(ReviewCodeTool(), "medium"), (CodeReviewTool(), "medium"),
(DebugIssueTool(), "medium"), (DebugIssueTool(), "medium"),
] ]
@@ -77,7 +77,7 @@ class TestThinkingModes:
) )
mock_create_model.return_value = mock_model mock_create_model.return_value = mock_model
tool = ReviewCodeTool() tool = CodeReviewTool()
result = await tool.execute( result = await tool.execute(
{ {
"files": ["/absolute/path/test.py"], "files": ["/absolute/path/test.py"],

View File

@@ -7,7 +7,7 @@ from unittest.mock import Mock, patch
import pytest import pytest
from tools import AnalyzeTool, ChatTool, DebugIssueTool, ReviewCodeTool, ThinkDeeperTool from tools import AnalyzeTool, ChatTool, CodeReviewTool, DebugIssueTool, ThinkDeeperTool
class TestThinkDeeperTool: class TestThinkDeeperTool:
@@ -54,16 +54,16 @@ class TestThinkDeeperTool:
assert "Extended analysis" in output["content"] assert "Extended analysis" in output["content"]
class TestReviewCodeTool: class TestCodeReviewTool:
"""Test the review_code tool""" """Test the codereview tool"""
@pytest.fixture @pytest.fixture
def tool(self): def tool(self):
return ReviewCodeTool() return CodeReviewTool()
def test_tool_metadata(self, tool): def test_tool_metadata(self, tool):
"""Test tool metadata""" """Test tool metadata"""
assert tool.get_name() == "review_code" assert tool.get_name() == "codereview"
assert "PROFESSIONAL CODE REVIEW" in tool.get_description() assert "PROFESSIONAL CODE REVIEW" in tool.get_description()
assert tool.get_default_temperature() == 0.2 assert tool.get_default_temperature() == 0.2
@@ -214,9 +214,9 @@ class TestAbsolutePathValidation:
assert "./relative/path.py" in response["content"] assert "./relative/path.py" in response["content"]
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_review_code_tool_relative_path_rejected(self): async def test_codereview_tool_relative_path_rejected(self):
"""Test that review_code tool rejects relative paths""" """Test that codereview tool rejects relative paths"""
tool = ReviewCodeTool() tool = CodeReviewTool()
result = await tool.execute( result = await tool.execute(
{ {
"files": ["../parent/file.py"], "files": ["../parent/file.py"],

View File

@@ -4,16 +4,16 @@ Tool implementations for Gemini MCP Server
from .analyze import AnalyzeTool from .analyze import AnalyzeTool
from .chat import ChatTool from .chat import ChatTool
from .codereview import CodeReviewTool
from .debug import DebugIssueTool from .debug import DebugIssueTool
from .review_changes import ReviewChanges from .precommit import Precommit
from .review_code import ReviewCodeTool
from .think_deeper import ThinkDeeperTool from .think_deeper import ThinkDeeperTool
__all__ = [ __all__ = [
"ThinkDeeperTool", "ThinkDeeperTool",
"ReviewCodeTool", "CodeReviewTool",
"DebugIssueTool", "DebugIssueTool",
"AnalyzeTool", "AnalyzeTool",
"ChatTool", "ChatTool",
"ReviewChanges", "Precommit",
] ]

View File

@@ -37,8 +37,7 @@ class AnalyzeTool(BaseTool):
return ( return (
"ANALYZE FILES & CODE - General-purpose analysis for understanding code. " "ANALYZE FILES & CODE - General-purpose analysis for understanding code. "
"Supports both individual files and entire directories. " "Supports both individual files and entire directories. "
"Use this for examining files, understanding architecture, or investigating specific aspects. " "Use this when you need to analyze files, examine code, or understand specific aspects of a codebase. "
"Triggers: 'analyze these files', 'examine this code', 'understand this'. "
"Perfect for: codebase exploration, dependency analysis, pattern detection. " "Perfect for: codebase exploration, dependency analysis, pattern detection. "
"Always uses file paths for clean terminal output." "Always uses file paths for clean terminal output."
) )

View File

@@ -40,8 +40,8 @@ class ChatTool(BaseTool):
"Perfect for: bouncing ideas during your own analysis, getting second opinions on your plans, " "Perfect for: bouncing ideas during your own analysis, getting second opinions on your plans, "
"collaborative brainstorming, validating your checklists and approaches, exploring alternatives. " "collaborative brainstorming, validating your checklists and approaches, exploring alternatives. "
"Also great for: explanations, comparisons, general development questions. " "Also great for: explanations, comparisons, general development questions. "
"Triggers: 'ask gemini', 'brainstorm with gemini', 'get gemini's opinion', 'discuss with gemini', " "Use this when you want to ask Gemini questions, brainstorm ideas, get opinions, discuss topics, "
"'share my thinking with gemini', 'explain', 'what is', 'how do I'." "share your thinking, or need explanations about concepts and approaches."
) )
def get_input_schema(self) -> dict[str, Any]: def get_input_schema(self) -> dict[str, Any]:

View File

@@ -20,14 +20,14 @@ from mcp.types import TextContent
from pydantic import Field from pydantic import Field
from config import TEMPERATURE_ANALYTICAL from config import TEMPERATURE_ANALYTICAL
from prompts import REVIEW_CODE_PROMPT from prompts import CODEREVIEW_PROMPT
from utils import read_files from utils import read_files
from .base import BaseTool, ToolRequest from .base import BaseTool, ToolRequest
from .models import ToolOutput from .models import ToolOutput
class ReviewCodeRequest(ToolRequest): class CodeReviewRequest(ToolRequest):
""" """
Request model for the code review tool. Request model for the code review tool.
@@ -53,7 +53,7 @@ class ReviewCodeRequest(ToolRequest):
) )
class ReviewCodeTool(BaseTool): class CodeReviewTool(BaseTool):
""" """
Professional code review tool implementation. Professional code review tool implementation.
@@ -63,14 +63,13 @@ class ReviewCodeTool(BaseTool):
""" """
def get_name(self) -> str: def get_name(self) -> str:
return "review_code" return "codereview"
def get_description(self) -> str: def get_description(self) -> str:
return ( return (
"PROFESSIONAL CODE REVIEW - Comprehensive analysis for bugs, security, and quality. " "PROFESSIONAL CODE REVIEW - Comprehensive analysis for bugs, security, and quality. "
"Supports both individual files and entire directories/projects. " "Supports both individual files and entire directories/projects. "
"Use this for thorough code review with actionable feedback. " "Use this when you need to review code, check for issues, find bugs, or perform security audits. "
"Triggers: 'review this code', 'check for issues', 'find bugs', 'security audit'. "
"I'll identify issues by severity (Critical→High→Medium→Low) with specific fixes. " "I'll identify issues by severity (Critical→High→Medium→Low) with specific fixes. "
"Supports focused reviews: security, performance, or quick checks. " "Supports focused reviews: security, performance, or quick checks. "
"Choose thinking_mode based on review scope: 'low' for small code snippets, " "Choose thinking_mode based on review scope: 'low' for small code snippets, "
@@ -132,13 +131,13 @@ class ReviewCodeTool(BaseTool):
} }
def get_system_prompt(self) -> str: def get_system_prompt(self) -> str:
return REVIEW_CODE_PROMPT return CODEREVIEW_PROMPT
def get_default_temperature(self) -> float: def get_default_temperature(self) -> float:
return TEMPERATURE_ANALYTICAL return TEMPERATURE_ANALYTICAL
def get_request_model(self): def get_request_model(self):
return ReviewCodeRequest return CodeReviewRequest
async def execute(self, arguments: dict[str, Any]) -> list[TextContent]: async def execute(self, arguments: dict[str, Any]) -> list[TextContent]:
"""Override execute to check focus_on size before processing""" """Override execute to check focus_on size before processing"""
@@ -155,7 +154,7 @@ class ReviewCodeTool(BaseTool):
# Continue with normal execution # Continue with normal execution
return await super().execute(arguments) return await super().execute(arguments)
async def prepare_prompt(self, request: ReviewCodeRequest) -> str: async def prepare_prompt(self, request: CodeReviewRequest) -> str:
""" """
Prepare the code review prompt with customized instructions. Prepare the code review prompt with customized instructions.
@@ -239,7 +238,7 @@ Please provide a code review aligned with the user's context and expectations, f
return full_prompt return full_prompt
def format_response(self, response: str, request: ReviewCodeRequest) -> str: def format_response(self, response: str, request: CodeReviewRequest) -> str:
""" """
Format the review response with appropriate headers. Format the review response with appropriate headers.

View File

@@ -37,8 +37,8 @@ class DebugIssueTool(BaseTool):
def get_description(self) -> str: def get_description(self) -> str:
return ( return (
"DEBUG & ROOT CAUSE ANALYSIS - Expert debugging for complex issues with 1M token capacity. " "DEBUG & ROOT CAUSE ANALYSIS - Expert debugging for complex issues with 1M token capacity. "
"Use this when you need help tracking down bugs or understanding errors. " "Use this when you need to debug code, find out why something is failing, identify root causes, "
"Triggers: 'debug this', 'why is this failing', 'root cause', 'trace error', 'diagnose issue'. " "trace errors, or diagnose issues. "
"IMPORTANT: Share diagnostic files liberally! Gemini can handle up to 1M tokens, so include: " "IMPORTANT: Share diagnostic files liberally! Gemini can handle up to 1M tokens, so include: "
"large log files, full stack traces, memory dumps, diagnostic outputs, multiple related files, " "large log files, full stack traces, memory dumps, diagnostic outputs, multiple related files, "
"entire modules, test results, configuration files - anything that might help debug the issue. " "entire modules, test results, configuration files - anything that might help debug the issue. "

View File

@@ -1,5 +1,5 @@
""" """
Tool for reviewing pending git changes across multiple repositories. Tool for pre-commit validation of git changes across multiple repositories.
""" """
import os import os
@@ -9,7 +9,7 @@ from mcp.types import TextContent
from pydantic import Field from pydantic import Field
from config import MAX_CONTEXT_TOKENS from config import MAX_CONTEXT_TOKENS
from prompts.tool_prompts import REVIEW_CHANGES_PROMPT from prompts.tool_prompts import PRECOMMIT_PROMPT
from utils.file_utils import read_files, translate_file_paths, translate_path_for_environment from utils.file_utils import read_files, translate_file_paths, translate_path_for_environment
from utils.git_utils import find_git_repositories, get_git_status, run_git_command from utils.git_utils import find_git_repositories, get_git_status, run_git_command
from utils.token_utils import estimate_tokens from utils.token_utils import estimate_tokens
@@ -18,8 +18,8 @@ from .base import BaseTool, ToolRequest
from .models import ToolOutput from .models import ToolOutput
class ReviewChangesRequest(ToolRequest): class PrecommitRequest(ToolRequest):
"""Request model for review_changes tool""" """Request model for precommit tool"""
path: str = Field( path: str = Field(
..., ...,
@@ -71,21 +71,21 @@ class ReviewChangesRequest(ToolRequest):
) )
class ReviewChanges(BaseTool): class Precommit(BaseTool):
"""Tool for reviewing git changes across multiple repositories.""" """Tool for pre-commit validation of git changes across multiple repositories."""
def get_name(self) -> str: def get_name(self) -> str:
return "review_changes" return "precommit"
def get_description(self) -> str: def get_description(self) -> str:
return ( return (
"REVIEW PENDING GIT CHANGES BEFORE COMMITTING - ALWAYS use this tool before creating any git commit! " "PRECOMMIT VALIDATION FOR GIT CHANGES - ALWAYS use this tool before creating any git commit! "
"Comprehensive pre-commit validation that catches bugs, security issues, incomplete implementations, " "Comprehensive pre-commit validation that catches bugs, security issues, incomplete implementations, "
"and ensures changes match the original requirements. Searches all git repositories recursively and " "and ensures changes match the original requirements. Searches all git repositories recursively and "
"provides deep analysis of staged/unstaged changes. Essential for code quality and preventing bugs. " "provides deep analysis of staged/unstaged changes. Essential for code quality and preventing bugs. "
"Triggers: 'before commit', 'review changes', 'check my changes', 'validate changes', 'pre-commit review', " "Use this before committing, when reviewing changes, checking your changes, validating changes, "
"'about to commit', 'ready to commit'. Claude should proactively suggest using this tool whenever " "or when you're about to commit or ready to commit. Claude should proactively suggest using this tool "
"the user mentions committing or when changes are complete. " "whenever the user mentions committing or when changes are complete. "
"Choose thinking_mode based on changeset size: 'low' for small focused changes, " "Choose thinking_mode based on changeset size: 'low' for small focused changes, "
"'medium' for standard commits (default), 'high' for large feature branches or complex refactoring, " "'medium' for standard commits (default), 'high' for large feature branches or complex refactoring, "
"'max' for critical releases or when reviewing extensive changes across multiple systems." "'max' for critical releases or when reviewing extensive changes across multiple systems."
@@ -103,10 +103,10 @@ class ReviewChanges(BaseTool):
return schema return schema
def get_system_prompt(self) -> str: def get_system_prompt(self) -> str:
return REVIEW_CHANGES_PROMPT return PRECOMMIT_PROMPT
def get_request_model(self): def get_request_model(self):
return ReviewChangesRequest return PrecommitRequest
def get_default_temperature(self) -> float: def get_default_temperature(self) -> float:
"""Use analytical temperature for code review.""" """Use analytical temperature for code review."""
@@ -129,7 +129,7 @@ class ReviewChanges(BaseTool):
# Continue with normal execution # Continue with normal execution
return await super().execute(arguments) return await super().execute(arguments)
async def prepare_prompt(self, request: ReviewChangesRequest) -> str: async def prepare_prompt(self, request: PrecommitRequest) -> str:
"""Prepare the prompt with git diff information.""" """Prepare the prompt with git diff information."""
# Check for prompt.txt in files # Check for prompt.txt in files
prompt_content, updated_files = self.handle_prompt_file(request.files) prompt_content, updated_files = self.handle_prompt_file(request.files)
@@ -409,6 +409,6 @@ class ReviewChanges(BaseTool):
return full_prompt return full_prompt
def format_response(self, response: str, request: ReviewChangesRequest) -> str: def format_response(self, response: str, request: PrecommitRequest) -> str:
"""Format the response with commit guidance""" """Format the response with commit guidance"""
return f"{response}\n\n---\n\n**Commit Status:** If no critical issues found, changes are ready for commit. Otherwise, address issues first and re-run review. Check with user before proceeding with any commit." return f"{response}\n\n---\n\n**Commit Status:** If no critical issues found, changes are ready for commit. Otherwise, address issues first and re-run review. Check with user before proceeding with any commit."

View File

@@ -39,9 +39,8 @@ class ThinkDeeperTool(BaseTool):
def get_description(self) -> str: def get_description(self) -> str:
return ( return (
"EXTENDED THINKING & REASONING - Your deep thinking partner for complex problems. " "EXTENDED THINKING & REASONING - Your deep thinking partner for complex problems. "
"Use this when you need to extend your analysis, explore alternatives, or validate approaches. " "Use this when you need to think deeper about a problem, extend your analysis, explore alternatives, or validate approaches. "
"Perfect for: architecture decisions, complex bugs, performance challenges, security analysis. " "Perfect for: architecture decisions, complex bugs, performance challenges, security analysis. "
"Triggers: 'think deeper', 'ultrathink', 'extend my analysis', 'explore alternatives'. "
"I'll challenge assumptions, find edge cases, and provide alternative solutions. " "I'll challenge assumptions, find edge cases, and provide alternative solutions. "
"IMPORTANT: Choose the appropriate thinking_mode based on task complexity - " "IMPORTANT: Choose the appropriate thinking_mode based on task complexity - "
"'low' for quick analysis, 'medium' for standard problems, 'high' for complex issues (default), " "'low' for quick analysis, 'medium' for standard problems, 'high' for complex issues (default), "