Skip to content

Repository files navigation

🏆 Competitive Programming Mentor — MCP Server

A production-grade Model Context Protocol (MCP) server that decomposes competitive programming expertise into 23 modular, provider-independent tools — orchestrated by any MCP-compatible client.


📋 Table of Contents


🤔 Why MCP?

Traditional AI coding assistants force all reasoning through one massive prompt. This approach suffers from:

Problem Impact
Monolithic prompts Impossible to test, cache, or reuse individual capabilities
Provider lock-in Switching from OpenAI → Ollama requires rewriting everything
No structured output Raw text responses require fragile regex parsing
Redundant LLM calls Identical problems re-analyzed every time

This MCP server solves all four. Each capability is an independent tool with its own schema, prompt template, cache key, and validation pipeline.

┌──────────────────┐     MCP Protocol      ┌──────────────────────────┐
│  Claude Desktop  │◄─────────────────────►│   CP Mentor MCP Server   │
│  Cursor IDE      │   JSON-RPC / stdio    │                          │
│  Claude CLI      │                       │  23 Tools · 3 Resources  │
│  Any MCP Client  │                       │  3 Prompts · 2-Tier Cache│
└──────────────────┘                       └────────────┬─────────────┘
                                                        │
                                           ┌────────────▼─────────────┐
                                           │   LLM Provider Layer     │
                                           │  ┌────────┐ ┌─────────┐ │
                                           │  │ OpenAI │ │  Ollama  │ │
                                           │  │gpt-4o  │ │llama3.1 │ │
                                           │  └────────┘ └─────────┘ │
                                           └──────────────────────────┘

🏗 Architecture

graph TD
    Client["MCP Client<br/>(Cursor · Claude Desktop · CLI)"]
    Server["FastMCP Server<br/>server.py"]
    Cache{"Two-Tier Cache<br/>Memory TTL + SQLite Disk"}
    Prompt["Jinja2 Prompt Manager<br/>prompts/*.md"]
    Provider["LLM Provider Factory<br/>OpenAI | Ollama"]
    Validator{"Self-Correcting Validator<br/>Pydantic v2 Schemas"}
    Formatter["Response Formatter<br/>+ _meta tracing"]

    Client -->|"tool call (JSON-RPC)"| Server
    Server -->|"check cache"| Cache
    Cache -->|"HIT"| Formatter
    Cache -->|"MISS"| Prompt
    Prompt -->|"rendered prompt"| Provider
    Provider -->|"raw JSON"| Validator
    Validator -->|"schema fail → retry prompt"| Provider
    Validator -->|"schema pass"| Cache
    Cache -->|"store result"| Formatter
    Formatter -->|"structured response"| Client
Loading

Core Design Principles

Principle Implementation
Tool-Service Decoupling Tools contain zero business logic — they delegate to PromptManager → Provider → Validator → Cache → Formatter
Provider Independence BaseLLMProvider abstract class ensures zero OpenAI/Ollama imports in tool code
Schema-First Validation Every tool has a dedicated Pydantic BaseModel — LLM outputs are validated and auto-corrected
Two-Tier Caching In-memory TTLCache (μs latency) + persistent diskcache (survives restarts)
Fail-Safe Registration Each tool module is try/except imported — one broken tool doesn't crash the server

🔧 Tool Catalog (23 Tools)

🔍 Analysis (4 tools)

Tool Description Schema
detect_patterns Identifies algorithmic patterns (DP, Graph, Greedy, Math, etc.) from problem text PatternResponse
extract_constraints Parses numeric bounds (N, M, K, Q) and system limits (time/memory) ConstraintResponse
estimate_difficulty Approximates competitive programming difficulty rating DifficultyResponse
identify_topics Tags primary/secondary topic categories TopicsResponse

📐 Planning (4 tools)

Tool Description Schema
suggest_algorithms Recommends candidate algorithms based on constraints AlgorithmsListResponse
compare_algorithms Builds a trade-off comparison matrix across candidates AlgorithmsComparisonResponse
choose_best_algorithm Selects the optimal algorithm with justification BestAlgorithmResponse
estimate_runtime Calculates operation count vs. time budget feasibility RuntimeEstimateResponse

💻 Code Generation (3 tools)

Tool Description Schema
generate_solution Produces optimized, contest-ready code in the target language SolutionResponse
generate_pseudocode Outputs language-agnostic structural pseudocode PseudocodeResponse
generate_multi_language Generates C++, Java, and Rust implementations simultaneously MultiLangResponse

✅ Verification (3 tools)

Tool Description Schema
dry_run Traces variable states step-by-step through sample inputs DryRunResponse
prove_correctness Provides formal correctness proofs (loop invariants, induction) CorrectnessProofResponse
analyze_complexity Computes asymptotic time/space complexity with justification ComplexityResponse

🧪 Testing (3 tools)

Tool Description Schema
generate_testcases Creates input/output test pairs covering standard scenarios TestcasesResponse
generate_edge_cases Targets boundary conditions, zero-cases, and overflow scenarios EdgeCasesResponse
stress_testing Generates randomized brute-force stress test configurations StressTestResponse

🔎 Code Review (3 tools)

Tool Description Schema
review_solution Full code review with correctness, efficiency, and style feedback ReviewResponse
find_bug Pinpoints logical, runtime, or compile-time bugs BugResponse
optimize_solution Suggests constant-factor and algorithmic optimizations OptimizationResponse

📚 Learning (3 tools)

Tool Description Schema
get_hint Progressive hint system (nudge → approach → partial solution) HintResponse
explain_algorithm Educational breakdown with examples, when-to-use heuristics ExplanationResponse
recommend_next_problem Suggests follow-up problems to reinforce learned concepts RecommendationResponse

📁 Project Structure

Competitive Programming Mentor MCP Server/
│
├── app.py                     # Entry point — mcp.run()
├── server.py                  # FastMCP app, tool/resource/prompt registration
├── config.py                  # Pydantic-settings configuration from .env
├── pyproject.toml             # Dependencies & build config
├── .env.example               # Environment template
│
├── services/                  # Core business logic layer
│   ├── llm/
│   │   ├── base_provider.py       # Abstract LLM interface
│   │   ├── openai_provider.py     # OpenAI gpt-4o-mini adapter
│   │   ├── ollama_provider.py     # Ollama local LLM adapter
│   │   └── provider_factory.py    # Factory: .env → Provider instance
│   ├── prompt_manager.py          # Jinja2 template renderer
│   ├── validator.py               # Pydantic validation + self-correcting retry
│   ├── cache.py                   # Two-tier cache (TTLCache + diskcache)
│   ├── problem_parser.py          # Regex constraint extractor (N, M, K, Q)
│   └── formatter.py               # Response normalization + _meta tags
│
├── tools/                     # MCP tool implementations (23 tools)
│   ├── analysis/                  # detect_patterns, extract_constraints, ...
│   ├── planning/                  # suggest_algorithms, compare_algorithms, ...
│   ├── generation/                # generate_solution, generate_pseudocode, ...
│   ├── verification/              # dry_run, prove_correctness, ...
│   ├── testing/                   # generate_testcases, generate_edge_cases, ...
│   ├── review/                    # review_solution, find_bug, optimize_solution
│   └── learning/                  # get_hint, explain_algorithm, recommend_problem
│
├── schemas/                   # Pydantic response models (one per tool)
├── prompts/                   # Jinja2 markdown templates (one per tool + personas)
├── resources/                 # Static knowledge base (Markdown files)
│   ├── algorithms/graphs/         # dijkstra.md
│   ├── data_structures/           # segment_tree.md
│   └── patterns/                  # sliding_window.md
│
├── tests/                     # Pytest test suite
│   ├── test_parser.py             # Constraint parsing tests
│   ├── test_cache.py              # Two-tier cache tests
│   └── test_validator.py          # Schema validation + retry tests
│
└── docs/
    ├── ARCHITECTURE.md            # System design documentation
    └── TOOLS.md                   # Tool reference catalog

🚀 Getting Started

Prerequisites

  • Python 3.11+
  • uv (recommended) or pip
  • OpenAI API key or Ollama installed locally

Installation

# Clone the repository
git clone https://github.com/your-username/competitive-programming-mcp.git
cd competitive-programming-mcp

# Install dependencies with uv
uv sync --all-extras

# Copy and configure environment
cp .env.example .env
# Edit .env with your API keys / Ollama settings

Quick Start

# Start the MCP server (stdio transport)
uv run app.py

# Or run in development mode with auto-reload
fastmcp dev app.py

# Run tests
uv run pytest

⚙ Configuration

All settings are managed via .env and loaded through Pydantic Settings:

# ─── LLM Provider ────────────────────────────────────
LLM_PROVIDER=openai              # "openai" or "ollama"

# ─── OpenAI (when LLM_PROVIDER=openai) ───────────────
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-4o-mini         # ~$0.15/1M input tokens
OPENAI_MAX_TOKENS=4096
OPENAI_TEMPERATURE=0.2           # Low = deterministic code

# ─── Ollama (when LLM_PROVIDER=ollama) ────────────────
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.1:8b         # Run: ollama pull llama3.1:8b

# ─── Cache ────────────────────────────────────────────
CACHE_ENABLED=true
CACHE_TTL_SECONDS=3600           # 1-hour TTL
CACHE_DISK_DIR=.cache            # SQLite-backed persistent cache

# ─── Server ──────────────────────────────────────────
LOG_LEVEL=INFO                   # DEBUG | INFO | WARNING | ERROR

📖 Workflows

Workflow 1: Claude Desktop Integration

Add the following to your claude_desktop_config.json:

{
  "mcpServers": {
    "cp-mentor": {
      "command": "uv",
      "args": [
        "--directory",
        "YOUR_ABSOLUTE_PATH\\Competitive Programming Mentor MCP Server",
        "run",
        "app.py"
      ]
    }
  }
}

Note on Config Locations:

  • Standard Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Windows Store App: C:\Users\YOUR_NAME\AppData\Local\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\claude_desktop_config.json

Restart Claude Desktop completely. Note: In the latest versions of Claude Desktop, the plug (🔌) icon has been removed from the UI. MCP tools are simply loaded silently in the background. Just ask Claude to "Use your cp-mentor tools to solve X" and you will see an approval pop-up!

Workflow 2: Claude CLI Integration

If you use the claude terminal tool, run:

claude mcp add cp-mentor uv --directory "/path/to/project" run app.py
claude   # Start a session

Important for local models: If you are using ollama with the Claude CLI, make sure you launch it with a large enough model (e.g., 9B+ parameters) that supports tool calling. Small models (like 4B or 1B) will crash or fail to invoke MCP tools properly. Example: ollama launch claude --model qwen2.5:14b

Workflow 3: Cursor IDE Integration

  1. Open Cursor → Settings → Features → MCP
  2. Click + Add New MCP Server
  3. Set Name: cp-mentor
  4. Set Type: command
  5. Set Command: uv --directory "/path/to/project" run app.py

Workflow 4: Full Problem-Solving Pipeline

User provides a problem (e.g., LeetCode / Codeforces)
        │
        ▼
  ┌─────────────┐
  │ Step 1       │  detect_patterns(problem)
  │ Analyze      │  extract_constraints(problem)
  │              │  identify_topics(problem)
  └──────┬──────┘
         │
         ▼
  ┌─────────────┐
  │ Step 2       │  suggest_algorithms(problem)
  │ Plan         │  compare_algorithms(problem, candidates)
  │              │  choose_best_algorithm(problem, candidates)
  └──────┬──────┘
         │
         ▼
  ┌─────────────┐
  │ Step 3       │  generate_solution(problem, approach, language)
  │ Generate     │  generate_pseudocode(problem)
  └──────┬──────┘
         │
         ▼
  ┌─────────────┐
  │ Step 4       │  dry_run(problem, code)
  │ Verify       │  prove_correctness(problem)
  │              │  analyze_complexity(problem, code)
  └──────┬──────┘
         │
         ▼
  ┌─────────────┐
  │ Step 5       │  generate_testcases(problem)
  │ Test         │  generate_edge_cases(problem)
  │              │  stress_testing(problem)
  └──────┬──────┘
         │
         ▼
  ┌─────────────┐
  │ Step 6       │  review_solution(problem, code)
  │ Review       │  optimize_solution(problem, code)
  └─────────────┘

🔬 How It Works (Deep Dive)

1. Request Flow

When a client invokes detect_patterns(problem="..."), the following pipeline executes:

1. FastMCP receives JSON-RPC call via stdio transport
2. Tool function in tools/analysis/detect_patterns.py is invoked
3. CacheService.get("detect_patterns", {problem: "..."}) → checks memory, then disk
4. On MISS: PromptManager renders prompts/detect_patterns.md with Jinja2
5. ProviderFactory returns OpenAIProvider or OllamaProvider
6. Provider.structured_output(prompt, PatternResponse) calls the LLM API
7. Validator checks response against PatternResponse Pydantic schema
8. On validation failure: auto-correcting retry with error feedback prompt
9. CacheService.set() stores result in both memory and disk tiers
10. Formatter wraps response with _meta (tool name, model, cache status, latency)
11. Structured JSON returned to client

2. Self-Correcting Validator

The validator implements a retry loop that feeds Pydantic validation errors back to the LLM:

# Simplified flow
for attempt in range(max_retries):
    raw_json = await provider.structured_output(prompt, schema)
    try:
        return schema.model_validate_json(raw_json)  # Success
    except ValidationError as e:
        prompt = f"Fix these errors: {e.errors()}\nOriginal: {raw_json}"
        # Retry with corrective context

3. Two-Tier Cache

                    ┌─────────────────┐
  get(key) ────────►│  Memory (TTL)   │──── HIT ────► return value
                    │  ~256 entries   │
                    │  μs latency     │
                    └───────┬─────────┘
                            │ MISS
                    ┌───────▼─────────┐
                    │  Disk (SQLite)  │──── HIT ────► promote to memory
                    │  Persistent     │               + return value
                    │  ms latency     │
                    └───────┬─────────┘
                            │ MISS
                            ▼
                    Call LLM Provider

Cache keys are deterministic: f"{tool_name}:{sha256(sorted_json(inputs))[:16]}"

4. Provider Abstraction

class BaseLLMProvider(ABC):
    @abstractmethod
    async def generate(self, prompt: str, system: str = "") -> str: ...

    @abstractmethod
    async def structured_output(self, prompt: str, response_model: type[T], system: str = "") -> T: ...

    @property
    @abstractmethod
    def model_name(self) -> str: ...
  • OpenAIProvider: Uses client.beta.chat.completions.parse() for native JSON schema generation
  • OllamaProvider: Uses openai-compatible endpoint with regex JSON extraction fallback

🧪 Testing

# Run all tests
$env:PYTHONPATH="."    # PowerShell
uv run pytest

# Run with verbose output
uv run pytest -v

# Test specific module
uv run pytest tests/test_parser.py
uv run pytest tests/test_cache.py
uv run pytest tests/test_validator.py

Test Coverage

Module Tests What's Verified
problem_parser 2 Constraint regex parsing (including 2 * 10^5 notation), default handling
cache 2 Memory/disk hit/miss, tier promotion, Windows file lock cleanup
validator 2 Schema compliance on first try, self-correcting retry on malformed JSON

🛠 Tech Stack

Component Technology Purpose
MCP Framework fastmcp >= 2.0 Server SDK, tool registration, stdio transport
LLM Client openai >= 1.30 OpenAI + Ollama-compatible API calls
Validation pydantic >= 2.7 Typed schemas for all 23 tool outputs
Configuration pydantic-settings >= 2.3 .env → typed config singleton
Templating jinja2 >= 3.1 Prompt template rendering
Memory Cache cachetools >= 5.3 In-memory TTL cache
Disk Cache diskcache >= 5.6 SQLite-backed persistent cache
Retry Logic tenacity >= 8.3 Exponential backoff for LLM API calls
Testing pytest + pytest-asyncio Async-compatible test framework

📄 License

This project is provided as-is for educational and competitive programming purposes.


Built with 🧠 by sami_codeai — Turning competitive programming into composable AI tools.

About

A Model Context Protocol (MCP) server providing modular tools for analyzing, generating, and reviewing competitive programming algorithms.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages