Skip to content

Instantly share code, notes, and snippets.

@grahama1970
Created July 17, 2025 19:46
Show Gist options
  • Select an option

  • Save grahama1970/7854eb78198fe90f271136404537fefb to your computer and use it in GitHub Desktop.

Select an option

Save grahama1970/7854eb78198fe90f271136404537fefb to your computer and use it in GitHub Desktop.
claude code to kilocode code review (poc)

CC Executor Context

Project Type

MCP (Model Context Protocol) services and tools for Claude Code integration

Critical Constraints

  1. Subprocess Tool Architecture:

    • Tools in src/cc_executor/tools/*.py are CLI scripts that parse sys.argv
    • They CANNOT be converted to importable modules
    • Subprocess execution is REQUIRED, not a performance bug
  2. FastMCP Parameter Limitations:

    • FastMCP has validation bugs with Dict[str, Any] and List[str] parameters
    • All complex parameters MUST be JSON strings
    • Example: async def query(data: str) not async def query(data: Dict)
  3. Backward Compatibility:

    • Used by production Claude Code instances
    • Breaking changes are forbidden
    • Add warnings, not errors, for deprecated patterns
    • Keep default values even if insecure (with warnings)
  4. File Organization Rules:

    • Never create *_optimized.py, *_refactored.py, or similar variants
    • Modify files in place
    • Don't create new directories for refactoring
  5. Error Handling Requirements:

    • MCP tools must ALWAYS return valid JSON
    • Never let exceptions crash the MCP server
    • Defensive programming is mandatory

Intentional Design Decisions

  • Subprocess Overhead: Acceptable trade-off for reliability and isolation
  • Embedded HTML: Keeps deployment simple (single file)
  • Default Passwords: Balance between security and developer experience
  • Monolithic Classes: If it works reliably, don't split it
  • Global Variables in Tools: Required for script-style execution
  • Synchronous Operations: Some tools must remain sync for compatibility

What NOT to "Fix"

  1. Don't suggest converting subprocess tools to direct imports
  2. Don't split embedded HTML templates into separate files
  3. Don't remove defaults that would break existing deployments
  4. Don't add type hints that FastMCP can't handle (Dict, List params)
  5. Don't create "clean" abstractions that add complexity without benefit

Performance Expectations

  • Subprocess spawn time: 200-500ms is normal and acceptable
  • Memory usage: Not a constraint
  • Startup time: Not critical for MCP tools
  • Concurrency: Handled by Claude Code, not our concern

Integration Points

  • Called by Claude Code via MCP protocol
  • Must work with uv run --script execution pattern
  • WebSocket server on port 8003/8004
  • Returns JSON-RPC 2.0 formatted responses

Security Notes

  • Default credentials are for development only
  • Production deployments should set environment variables
  • All user inputs must be sanitized before subprocess execution

Testing Requirements

  • Manual testing with actual Claude Code is required
  • Unit tests may not catch MCP integration issues
  • Subprocess behavior differs in test vs production environments

Remember: This codebase prioritizes "working reliably in production" over "clean code principles".

#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.8"
# dependencies = [
# "fastmcp",
# "loguru",
# "python-dotenv"
# ]
# ///
"""
MCP Server for Kilocode Review - Provides an interface to the /review-contextual workflow.
This tool allows an AI agent to programmatically request a code review for a set of
files and then retrieve the structured results for analysis and self-correction.
"""
import asyncio
import json
import re
import sys
from pathlib import Path
from typing import List, Optional, Dict, Any
from fastmcp import FastMCP
from loguru import logger
from dotenv import load_dotenv, find_dotenv
# Add MCP logger utility
# This assumes the utils directory is in the parent of the parent directory.
# Adjust the path if your project structure is different.
sys.path.insert(0, str(Path(__file__).parent.parent))
from utils.mcp_logger import MCPLogger, debug_tool
# Configure logging
logger.remove()
logger.add(sys.stderr, level="INFO")
# Load environment variables
load_dotenv(find_dotenv())
# Initialize MCP server and logger
mcp = FastMCP("kilocode-review")
mcp_logger = MCPLogger("kilocode-review")
class KilocodeReviewTools:
"""Wraps the kilocode review CLI command for MCP."""
def __init__(self):
"""Initializes the review tools."""
# This tool is stateless, so no complex initialization is needed.
pass
async def _run_command(self, command: str) -> Dict[str, Any]:
"""
Asynchronously runs a shell command and captures its output.
Args:
command: The full shell command to execute.
Returns:
A dictionary with the command's stdout, stderr, and return code.
"""
logger.info(f"Executing command: {command}")
process = await asyncio.create_subprocess_shell(
command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
return {
"stdout": stdout.decode().strip(),
"stderr": stderr.decode().strip(),
"returncode": process.returncode
}
async def run_review(self, files: List[str], focus: Optional[str] = None, severity: Optional[str] = None) -> Dict[str, Any]:
"""
Constructs and runs the 'kilocode review-contextual' command.
Args:
files: A list of file paths to review.
focus: Optional focus area (e.g., 'security', 'performance').
severity: Optional minimum severity level (e.g., 'high').
Returns:
A dictionary containing the success status and review directory path or an error.
"""
if not files:
return {"success": False, "error": "No files provided for review."}
# Base command
command_parts = ["kilocode", "review-contextual"]
command_parts.extend(files)
# Add optional arguments
if focus:
command_parts.extend(["--focus", focus])
if severity:
command_parts.extend(["--severity", severity])
command_str = " ".join(command_parts)
result = await self._run_command(command_str)
if result["returncode"] != 0:
return {
"success": False,
"error": "Kilocode review command failed.",
"details": result["stderr"]
}
# Parse the output to find the review directory
match = re.search(r"Results saved to: (.+)", result["stdout"])
if not match:
return {
"success": False,
"error": "Could not parse review directory from Kilocode output.",
"output": result["stdout"]
}
review_directory = match.group(1).strip()
return {
"success": True,
"review_id": review_directory,
"message": "Review started successfully. Use get_review_results with the review_id to fetch the summary."
}
def parse_review_results(self, review_directory: str) -> Dict[str, Any]:
"""
Parses the output files from a completed Kilocode review.
Args:
review_directory: The path to the review output directory.
Returns:
A dictionary containing the structured review results.
"""
review_path = Path(review_directory)
if not review_path.is_dir():
return {"success": False, "error": f"Review directory not found: {review_directory}"}
results = {
"summary": None,
"actionable_fixes": None,
"incompatible_suggestions": None,
"context_applied": None
}
files_to_read = {
"summary": "review_summary.md",
"actionable_fixes": "actionable_fixes.md",
"incompatible_suggestions": "incompatible_suggestions.md",
"context_applied": "context_applied.md"
}
for key, filename in files_to_read.items():
file_path = review_path / filename
if file_path.exists():
try:
results[key] = file_path.read_text()
except Exception as e:
logger.warning(f"Could not read review file {file_path}: {e}")
results[key] = f"Error reading file: {e}"
else:
logger.warning(f"Review file not found: {file_path}")
return {"success": True, "results": results}
# Create a global instance of the tools
tools = KilocodeReviewTools()
@mcp.tool()
@debug_tool(mcp_logger)
async def start_review(files: str, focus: Optional[str] = None, severity: Optional[str] = None) -> str:
"""
Starts a context-aware code review for a given set of files.
This is a non-blocking, asynchronous call. It initiates the review process
and returns immediately with a `review_id`. Use the `get_review_results`
tool with the `review_id` to fetch the results once the review is complete.
Args:
files: A space-separated string of file paths to be reviewed.
focus: Optional. Specific areas to focus on: `security`, `performance`, `maintainability`, `architecture`.
severity: Optional. Minimum severity level: `low`, `medium`, `high`, `critical`. Default is `medium`.
Returns:
A JSON string containing the `review_id` (which is the path to the results directory)
if successful, or an error message.
"""
file_list = files.strip().split()
result = await tools.run_review(file_list, focus, severity)
return json.dumps(result, indent=2)
@mcp.tool()
@debug_tool(mcp_logger)
async def get_review_results(review_id: str) -> str:
"""
Fetches and parses the results from a completed code review.
Call this tool after `start_review` has completed. The underlying review process
can take several minutes.
Args:
review_id: The `review_id` (directory path) returned by a successful `start_review` call.
Returns:
A JSON string containing the structured review results, including the summary,
actionable fixes, and incompatible suggestions.
"""
# This tool is synchronous from the agent's perspective, but the work it does (I/O) is fast.
result = tools.parse_review_results(review_id)
return json.dumps(result, indent=2)
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "test":
print("Testing Kilocode Review MCP server...")
print(f"Tools instance: {tools}")
print("This server provides 'start_review' and 'get_review_results' tools.")
print("Server ready to start.")
else:
try:
logger.info("Starting Kilocode Review MCP server")
mcp.run()
except Exception as e:
logger.critical(f"MCP Server crashed: {e}", exc_info=True)
mcp_logger.log_error(e, {"context": "server_startup"})
sys.exit(1)

Mandatory Final Step: Self-Correction and Verification

Once you believe you have completed the primary coding task, you MUST perform a final quality check using the kilocode-review tool. This is a non-negotiable step to ensure your work adheres to all project constraints.

Follow this procedure exactly:

1. Identify Changed Files

Use your file system tools to create a list of all file paths you have created or modified during this task.

2. Initiate Review

Call the kilocode-review.start_review tool. Pass the file paths as a single space-separated string to the files argument.

  • Example Call:
    <execute_command>
      <tool_name>kilocode-review</tool_name>
      <function_name>start_review</function_name>
      <args>
        <files>src/path/to/file1.py src/path/to/another/file2.py</files>
      </args>
    </execute_command>
  • The tool will immediately return a JSON object containing a review_id. This ID is the path to the results directory. Save this review_id.

3. Wait for Completion

The review process is asynchronous and can take several minutes to run.

  • You must wait patiently. A good strategy is to wait for 2-3 minutes before proceeding to the next step.

4. Retrieve and Analyze Results

After waiting, call the kilocode-review.get_review_results tool, passing the review_id you received in step 2.

  • Example Call:
    <execute_command>
      <tool_name>kilocode-review</tool_name>
      <function_name>get_review_results</function_name>
      <args>
        <review_id>docs/code_review/20231028_120000_abcdef123</review_id>
      </args>
    </execute_command>
  • This will return a JSON object containing the full review.
  • Carefully examine the content of the results.actionable_fixes field. This contains fixes that are pre-validated and safe to apply.
  • Also, review results.incompatible_suggestions to learn what standard fixes are incorrect for this project's context.

5. Perform Self-Correction

If the results.actionable_fixes field contains any suggestions, you are REQUIRED to open the relevant files and apply the changes exactly as described.

  • If results.actionable_fixes is empty or null, no corrections are needed.

6. Conclude Task

After applying all required fixes, you may consider the task complete. In your final message, explicitly state that you have finished the work and confirm that it has passed the automated contextual review.

Slash Command

/review-contextual

Description

Context-aware two-phase code review that ensures recommendations are practical and compatible with your project's specific requirements:

  1. Phase 1: Contextual Analysis (O3) - Complete review with project constraints applied
  2. Phase 2: Validation & Synthesis (Gemini 2.5 Pro) - Independent validation with context awareness

IMPORTANT: This workflow provides analysis and recommendations only. No code changes are written to files.

Arguments

Argument Required Description
files Yes Space-separated list of file paths. If first file is .md with "context" in name, it's used as context
--context No Inline context string (max 500 chars)
--context-file No Path to context file
--focus No Specific areas: security, performance, maintainability, architecture
--severity No Minimum level: low, medium, high, critical (default: medium)

Smart Context Detection

  1. First .md file with "context", "constraints", or "readme" in name = context file
  2. Explicit context via --context or --context-file overrides auto-detection
  3. Fallback to .kilocode/CONTEXT.md if exists
  4. Auto-detection based on imports, patterns, and .mcp.json

Usage Examples

Simple - Context File First

/review-contextual .kilocode/CONTEXT.md src/servers/mcp_*.py

Inline Context - Quick Reviews

/review-contextual src/servers/mcp_*.py --context "MCP servers with subprocess tools. FastMCP needs JSON strings."

Explicit Context File

/review-contextual src/**/*.py --context-file .kilocode/contexts/cc_executor_mcp.txt

Auto-Detection (Simplest)

# If .kilocode/CONTEXT.md exists
/review-contextual src/servers/mcp_*.py

Context File Format

# Project Context

## Type
MCP Server for Claude Code

## Critical Constraints
1. Tools are subprocess scripts using sys.argv - NOT importable modules
2. FastMCP doesn't support Dict/List parameters - use JSON strings
3. Backward compatibility is mandatory
4. No duplicate files with similar names (e.g., tool_optimized.py)

## Design Decisions
- Subprocess execution is REQUIRED, not inefficient
- Embedded HTML templates are intentional (single-file deployment)
- Default passwords with warnings are acceptable for dev experience

## What NOT to "Fix"
- Don't convert subprocess tools to imports
- Don't split embedded templates into separate files
- Don't remove defaults that would break existing deployments

Workflow & Output

  1. Context Processing

    • Loads and validates context
    • Merges with auto-detected patterns
    • Creates context digest for both phases
  2. Phase 1: Contextual O3 Review

    • Applies context constraints upfront
    • Flags incompatible suggestions
    • Generates phase1_contextual_report.json
  3. Phase 2: Contextual Validation

    • Gemini independently reviews with same context
    • Validates context was properly applied
    • Creates final consolidated review
  4. Final Output Structure

πŸ“ docs/code_review/{timestamp}_{context_hash}/
β”œβ”€β”€ πŸ“„ context_applied.md           # Exact context used
β”œβ”€β”€ πŸ“„ phase1_contextual_report.json
β”œβ”€β”€ πŸ“„ phase2_validation.json
β”œβ”€β”€ πŸ“„ actionable_fixes.md          # Only context-compatible fixes
β”œβ”€β”€ πŸ“„ incompatible_suggestions.md  # What was rejected and why
└── πŸ“„ review_summary.md           # Executive summary

Key Deliverables

actionable_fixes.md

# Actionable Fixes (Context-Compatible)

## Critical Issues (0)
*No critical issues that are compatible with context*

## High Priority (1)
### 1. Add Environment Variable Warning
**File:** src/servers/mcp_arango_tools.py:45
**Current:**
```python
password = os.getenv("ARANGO_PASSWORD", "openSesame")

Fixed:

password = os.getenv("ARANGO_PASSWORD", "")
if not password:
    logger.warning("⚠️ ARANGO_PASSWORD not set - using insecure default")
    password = "openSesame"

Rationale: Maintains backward compatibility while alerting users Context: βœ… Compatible - adds warning without breaking changes


#### **incompatible_suggestions.md**
```markdown
# Incompatible Suggestions (Rejected)

## Would Break MCP Compatibility
### 1. ❌ Convert subprocess tools to direct imports
**Why Rejected:** Tools in src/cc_executor/tools/*.py are CLI scripts that parse sys.argv. Direct import would break MCP protocol.

### 2. ❌ Use Dict parameters in FastMCP
**Why Rejected:** FastMCP has validation bugs with Dict/List types. Must use JSON strings.

### 3. ❌ Remove default password entirely
**Why Rejected:** Would break existing deployments. Context requires backward compatibility.

MCP Auto-Detection Rules

When these patterns are found, MCP constraints are automatically applied:

  • from fastmcp import FastMCP
  • .mcp.json in directory
  • Files matching mcp_*.py
  • #!/usr/bin/env -S uv run --script

Context Validation

The system validates context for:

  • Relevance: Warns if context seems unrelated to files
  • Completeness: Suggests missing constraints based on code patterns
  • Conflicts: Identifies contradictory requirements

Best Practices

  1. Project-Wide Context

    # Create once
    cat > .kilocode/CONTEXT.md << 'EOF'
    # CC Executor Context
    MCP services with subprocess tools. FastMCP limitations. No breaking changes.
    EOF
    
    # Use everywhere
    /review-contextual src/**/*.py
  2. Component-Specific Context

    /review-contextual src/api/API_CONTEXT.md src/api/**/*.py
  3. CI Integration

    - name: Contextual Code Review
      run: /review-contextual src/**/*.py --context-file .kilocode/CONTEXT.md

Pro Tips

  1. Quick Context for One-Off Reviews

    /review-contextual file.py --context "Legacy code. Minimal changes only."
  2. Combine Multiple Contexts

    /review-contextual CONTEXT.md MCP_CONSTRAINTS.md src/**/*.py
    # Both .md files are merged as context
  3. Override Auto-Detection

    /review-contextual src/api/*.py --context "Not an MCP server despite imports"

Error Handling

  • Missing context: Proceeds with auto-detection + warning
  • Invalid context file: Shows error and halts
  • Conflicting contexts: Shows conflicts and asks for clarification

Runtime: Up to 5 minutes per phase Quality Gates:

  • Phase 1: Rejects suggestions violating explicit context
  • Phase 2: Validates context was properly applied
  • Both phases: Flag but include "general best practice" items for awareness
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment