# MCP Template Server & LLM Client A comprehensive Python implementation of the **Model Context Protocol (MCP)** with multi-provider LLM support, featuring modular tools, prompts, and resources. This project provides a production-ready MCP server and flexible client that supports OpenAI, Claude, and Grok models. ## Table of Contents - [Quick Start](#quick-start) - [Introduction](#introduction) - [Architecture & Code Structure](#architecture--code-structure) - [Tools](#tools) - [Prompts](#prompts) - [Resources](#resources) - [Test Cases](#test-cases) - [Configuration](#configuration) - [Running the System](#running-the-system) - [Development](#development) - [API Reference](#api-reference) - [Contributing](#contributing) ## Quick Start ### Basic Usage (5 minutes) ```bash # 1. Install dependencies pip install -r requirements.txt # 2. Set your API key (choose your provider) export OPENAI_API_KEY="your-openai-key" # OR export ANTHROPIC_API_KEY="your-claude-key" # OR export GROK_API_KEY="your-grok-key" # 3. Start the MCP server python run_mcp_server.py --transport sse # 4. Run the client (in another terminal) python mcp_llm_client.py --provider openai --query "Calculate 25 squared" ``` ### Output ``` Connected to MCP server using SSE transport Processing query: 'Calculate 25 squared' Calling openai/gpt-4o with 24 available tools... Assistant wants to use 1 tool(s) 1. Calling tool: power Arguments: {'kwargs': '{"base": 25, "exponent": 2}'} Result: 625 Getting final response from openai/gpt-4o... Final answer: 25 squared is 625. ``` ## Introduction ### What is MCP? **MCP (Model Context Protocol)** is an open standard for connecting AI applications to external systems and data sources. It enables AI models to: - **Execute tools** (calculations, API calls, system commands) - **Access resources** (files, databases, configurations) - **Use prompts** (reusable conversation templates) ### Getting Started with MCP For a basic introduction to MCP concepts, see the [`intro_test/`](./intro_test/) directory, which contains: - **[Complete MCP Guide](./intro_test/INTRO_README.md)** - Comprehensive introduction to MCP concepts - **Basic Server & Client Examples** - Simple implementations using FastMCP - **Transport Protocol Examples** - SSE and STDIO transport implementations - **OpenAI Integration** - Basic MCP-OpenAI client example > **New to MCP?** Start with [`intro_test/INTRO_README.md`](./intro_test/INTRO_README.md) for a complete beginner's guide. ## Architecture & Code Structure ``` mcp_template/ ├── src/mcp_template/ │ ├── core/ # Core MCP types and interfaces │ ├── llm_client/ # Multi-provider LLM client factory │ │ ├── base_client.py # Abstract base client │ │ ├── openai_client.py # OpenAI implementation │ │ ├── claude_client.py # Claude implementation │ │ ├── grok_client.py # Grok implementation │ │ └── client_factory.py # Factory for creating clients │ ├── server/ │ │ ├── modular_server.py # Main MCP server │ │ ├── tools/ # Tool registration system │ │ ├── prompts/ # Prompt management │ │ └── resources/ # Resource management │ └── tools/ # Tool implementations │ ├── math_tools.py # Mathematical operations │ ├── text_tools.py # Text processing │ ├── system_tools.py # System utilities │ └── web_tools.py # Web utilities ├── intro_test/ # Basic MCP examples ├── mcp_llm_client.py # Multi-provider MCP client ├── run_mcp_server.py # Server launcher └── config.py # Configuration management ``` ### Key Components - **`modular_server.py`** - Main MCP server with auto-discovery - **`mcp_llm_client.py`** - Client supporting multiple AI providers - **`client_factory.py`** - Factory pattern for LLM client creation - **Tool Registry** - Automatic tool discovery and registration - **Transport Layer** - SSE and STDIO transport implementations ## Tools Tools are executable functions that AI models can invoke to perform actions. The system includes **24 built-in tools** across multiple categories. ### Available Tool Categories #### Mathematical Tools (`math_tools.py`) ```python # Available functions: add, subtract, multiply, divide, power, square_root, calculate_bmi result = await add(a=10, b=5) # Returns: 15 result = await power(base=5, exponent=3) # Returns: 125 result = await square_root(number=144) # Returns: 12.0 ``` #### Text Processing Tools (`text_tools.py`) ```python # Available functions: count_words, search_text, replace_text, to_uppercase, to_lowercase, text_length word_count = await count_words(text="Hello world") # Returns: 2 uppercase = await to_uppercase(text="hello") # Returns: "HELLO" ``` #### System Tools (`system_tools.py`) ```python # Available functions: get_system_info, get_current_time, list_directory, get_file_info, get_environment_variable sys_info = await get_system_info() # Returns system information current_time = await get_current_time() # Returns: "2024-01-15 14:30:25" ``` #### Web Tools (`web_tools.py`) ```python # Available functions: url_encode, url_decode, parse_url, validate_email, extract_domain encoded = await url_encode(text="hello world") # Returns: "hello%20world" is_valid = await validate_email(email="user@example.com") # Returns: True ``` ### Creating Custom Tools #### Method 1: Using MCPTool Class ```python from mcp_template.core.types import MCPTool async def custom_calculator(x: float, operation: str) -> float: """Perform custom calculation""" if operation == "double": return x * 2 elif operation == "half": return x / 2 return x tool = MCPTool( name="custom_calculator", description="Perform custom calculations", input_schema={ "type": "object", "properties": { "x": {"type": "number", "description": "Input number"}, "operation": { "type": "string", "enum": ["double", "half"], "description": "Operation to perform" } }, "required": ["x", "operation"] }, handler=custom_calculator ) ``` #### Method 2: Using Tool Classes ```python from mcp_template.tools.tool_registry import ServerToolRegistry class CustomTools: @staticmethod def get_tools(): return [ CustomTools._create_custom_tool(), ] @staticmethod def _create_custom_tool(): async def my_tool(param1: str, param2: int = 0) -> str: """Description of my tool""" return f"Processed {param1} with {param2}" return MCPTool( name="my_custom_tool", description="Custom tool description", input_schema={ "type": "object", "properties": { "param1": {"type": "string", "description": "First parameter"}, "param2": {"type": "integer", "description": "Second parameter", "default": 0} }, "required": ["param1"] }, handler=my_tool ) ``` #### Method 3: FastMCP Integration ```python from mcp.server.fastmcp import FastMCP mcp = FastMCP("MyServer") @mcp.tool() async def my_fastmcp_tool(input: str) -> str: """FastMCP tool with automatic schema generation""" return f"Processed: {input}" # Tool is automatically registered with proper schema ``` ### Tool Registration Tools are automatically discovered and registered: ```python # Automatic registration (recommended) from mcp_template.server.modular_server import create_default_server server = create_default_server() await server.initialize() # Automatically discovers and registers all tools # Manual registration from mcp_template.server.tools.tool_registry import ServerToolRegistry registry = ServerToolRegistry() registry.register_tools(your_custom_tools) ``` ## Prompts Prompts are reusable conversation templates that help AI models perform specific tasks. ### Available Prompts #### Greeting Prompt ```python from mcp_template.server.prompts.greeting_prompt import GreetingPrompt prompt = GreetingPrompt() result = await prompt.generate( name="Alice", style="friendly", tone="warm", element="compliment" ) # Returns: Template with substituted variables ``` ### Creating Custom Prompts ```python from mcp_template.server.prompts.base_prompt import BaseServerPrompt class CodeReviewPrompt(BaseServerPrompt): def __init__(self): super().__init__( name="code_review", description="Generate code review feedback", template=""" Please review the following {language} code for: - Code quality and best practices - Potential bugs or security issues - Performance optimizations - Readability improvements Code to review: {code} Focus on: {focus_areas} """, arguments={ "language": { "type": "string", "enum": ["python", "javascript", "java", "cpp"], "description": "Programming language" }, "focus_areas": { "type": "string", "description": "Areas to focus the review on" } } ) async def generate(self, code: str, language: str, focus_areas: str = "all") -> str: return self._substitute_template( code=code, language=language, focus_areas=focus_areas ) ``` ## Resources Resources represent data sources that AI models can access and read. ### Available Resources #### Configuration Resource ```python # URI: config://settings # Returns: Server configuration in JSON format { "server_name": "MCP Template Server", "version": "1.0.0", "features": ["tools", "prompts", "resources"], "transport": {"supported": ["stdio", "sse"], "default": "stdio"}, "tools_count": 24, "prompts_count": 1, "resources_count": 2 } ``` #### Dynamic Greeting Resource ```python # URI: dynamic://greeting # Returns: Personalized greeting with current timestamp ``` ### Creating Custom Resources ```python from mcp_template.server.resources.base_resource import BaseServerResource class DatabaseResource(BaseServerResource): def __init__(self, db_path: str): super().__init__( uri=f"db://{db_path}", name="Database Connection", description=f"Access to database: {db_path}", mime_type="application/json" ) self.db_path = db_path async def read(self, query: str = None, **kwargs) -> str: """Execute database query and return results""" # Implement database logic here import json if query: # Execute specific query result = {"query": query, "result": "mock_data"} else: # Return database info result = {"database": self.db_path, "status": "connected"} return json.dumps(result, indent=2) ``` ## Test Cases Test cases should be written for each tool category to ensure proper functionality: ### Mathematical Tools Tests Should test basic arithmetic, power functions, square root calculations, and BMI calculations. ### Text Tools Tests Should test word counting, case conversion, text search, and text replacement functionality. ### System Tools Tests Should test system information retrieval, current time, and environment variable access. ### Web Tools Tests Should test URL encoding/decoding, email validation, and domain extraction. ## Configuration ### Environment Variables Create a `.env` file in the project root: ```bash # OpenAI (default provider) OPENAI_API_KEY=sk-your-openai-key-here # Claude (alternative provider) ANTHROPIC_API_KEY=sk-ant-your-claude-key-here # Grok (alternative provider) GROK_API_KEY=xai-your-grok-key-here ``` ### Server Configuration The server automatically discovers and registers: - **Tools**: All classes in `src/mcp_template/tools/` - **Prompts**: All classes in `src/mcp_template/server/prompts/` - **Resources**: All classes in `src/mcp_template/server/resources/` ## Running the System ### Transport Methods #### 1. Server-Sent Events (SSE) - Recommended **Start Server:** ```bash python run_mcp_server.py --transport sse --port 8050 ``` **Run Client:** ```bash # Interactive mode python mcp_llm_client.py --provider openai --model gpt-4o # Single query python mcp_llm_client.py --provider openai --query "Calculate 25 + 30" # With custom parameters python mcp_llm_client.py --provider openai --model gpt-4o --temperature 0.7 --max-tokens 1000 ``` #### 2. Standard Input/Output (STDIO) **Note:** STDIO transport doesn't require starting a separate server. The client automatically launches the server process. ```bash # The client will automatically start the server python mcp_llm_client.py --transport stdio --provider openai --query "Calculate 10 * 5" ``` ### Advanced Usage #### Multiple Providers ```bash # OpenAI (default) python mcp_llm_client.py --provider openai --model gpt-4o # Claude python mcp_llm_client.py --provider claude --model claude-3-opus-20240229 # Grok python mcp_llm_client.py --provider grok --model grok-1 ``` #### Custom Parameters ```bash python mcp_llm_client.py \ --provider openai \ --model gpt-4o \ --temperature 0.01 \ --max-tokens 500 \ --top-p 0.9 \ --query "Explain quantum computing" ``` #### Interactive Mode ```bash python mcp_llm_client.py --provider openai --temperature 0.7 # Now you can have natural conversations: # Your query: Calculate 15 + 27 # Response: 15 + 27 equals 42. # # Your query: What's the square root of 144? # Response: The square root of 144 is 12. # # Your query: Count words in "Hello beautiful world" # Response: The text contains 3 words. ``` ### Docker Usage (Future) ```bash # Build the image docker build -t mcp-template . # Run with environment variables docker run -e OPENAI_API_KEY=your-key -p 8050:8050 mcp-template ``` ## Development ### Adding New Tools 1. **Create tool file** in `src/mcp_template/tools/` 2. **Implement tool class** with `get_tools()` method 3. **Return MCPTool objects** with proper schemas 4. **Tools are auto-discovered** - no registration needed ### Adding New Prompts 1. **Create prompt class** in `src/mcp_template/server/prompts/` 2. **Extend BaseServerPrompt** 3. **Implement template and arguments** 4. **Prompts are auto-discovered** ### Adding New Resources 1. **Create resource class** in `src/mcp_template/server/resources/` 2. **Extend BaseServerResource** 3. **Implement read() method** 4. **Resources are auto-discovered** ### Testing ```bash # Run all tests python -m pytest tests/ # Run specific test file python -m pytest tests/unit/test_tools.py # Run with coverage python -m pytest --cov=src tests/ ``` ## API Reference ### MCPAIClient ```python class MCPAIClient: def __init__( self, model: str = "gpt-4o", transport: TransportType = TransportType.SSE, provider: str = "openai", temperature: float = 0.7, max_tokens: int = 1000, **kwargs ) async def process_query(self, query: str) -> str async def get_mcp_tools(self) -> List[Dict[str, Any]] async def interactive_session(self) ``` ### AIClientFactory ```python class AIClientFactory: @staticmethod def create_client(provider: str, model_name: str, **kwargs) -> BaseAIClient @staticmethod def create_openai_client(model_name: str = "gpt-4o", **kwargs) -> OpenAIClient @staticmethod def create_claude_client(model_name: str = "claude-3-opus-20240229", **kwargs) -> ClaudeClient @staticmethod def create_grok_client(model_name: str = "grok-1", **kwargs) -> GrokClient ``` ## Contributing 1. **Fork the repository** 2. **Create feature branch**: `git checkout -b feature/your-feature` 3. **Add tests** for new functionality 4. **Ensure tests pass**: `python -m pytest` 5. **Submit pull request** ### Code Standards - Use type hints for all function parameters and return values - Follow PEP 8 style guidelines - Add docstrings to all classes and methods - Include unit tests for new features - Update documentation for API changes ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Support - **Documentation**: See [`intro_test/INTRO_README.md`](./intro_test/INTRO_README.md) for MCP basics - **Issues**: Report bugs on GitHub Issues - **Discussions**: Join discussions on GitHub Discussions - **Email**: Contact maintainers for support --- **Built with using the Model Context Protocol (MCP)** *Transforming AI applications with standardized tool integration*