Files
ds_mcp_template/README.md
T
2025-09-11 23:13:58 +01:00

592 lines
17 KiB
Markdown

# 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*