17 KiB
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
- Introduction
- Architecture & Code Structure
- Tools
- Prompts
- Resources
- Test Cases
- Configuration
- Running the System
- Development
- API Reference
- Contributing
Quick Start
Basic Usage (5 minutes)
# 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/ directory, which contains:
- Complete MCP Guide - 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.mdfor 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-discoverymcp_llm_client.py- Client supporting multiple AI providersclient_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)
# 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)
# 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)
# 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)
# 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
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
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
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:
# 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
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
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
# 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
# URI: dynamic://greeting
# Returns: Personalized greeting with current timestamp
Creating Custom Resources
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:
# 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:
python run_mcp_server.py --transport sse --port 8050
Run Client:
# 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.
# The client will automatically start the server
python mcp_llm_client.py --transport stdio --provider openai --query "Calculate 10 * 5"
Advanced Usage
Multiple Providers
# 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
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
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)
# 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
- Create tool file in
src/mcp_template/tools/ - Implement tool class with
get_tools()method - Return MCPTool objects with proper schemas
- Tools are auto-discovered - no registration needed
Adding New Prompts
- Create prompt class in
src/mcp_template/server/prompts/ - Extend BaseServerPrompt
- Implement template and arguments
- Prompts are auto-discovered
Adding New Resources
- Create resource class in
src/mcp_template/server/resources/ - Extend BaseServerResource
- Implement read() method
- Resources are auto-discovered
Testing
# 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
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
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
- Fork the repository
- Create feature branch:
git checkout -b feature/your-feature - Add tests for new functionality
- Ensure tests pass:
python -m pytest - 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 file for details.
Support
- Documentation: See
intro_test/INTRO_README.mdfor 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