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

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

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.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)

# 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

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

  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

# 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

  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 file for details.

Support

  • Documentation: See 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