# IoWarp MCP Server Development Guide

## Overview

This comprehensive guide documents the development standards, testing expectations, and structural requirements for MCP (Model Context Protocol) servers within the CLIO Kit repository. This guide ensures consistency, maintainability, and quality across all MCP server implementations.

## Table of Contents

1. [Project Structure Requirements](#project-structure-requirements)
2. [README Standards](#readme-standards)
3. [GitHub Workflow Requirements](#github-workflow-requirements)
4. [Testing Framework & Patterns](#testing-framework--patterns)
5. [Environment & Dependency Management](#environment--dependency-management)
6. [Code Architecture & MCP Tools](#code-architecture--mcp-tools)
7. [Examples & Best Practices](#examples--best-practices)

---

## Project Structure Requirements

### Standard Directory Structure

All MCP servers **MUST** follow this exact directory structure:

```
mcps/[ServerName]/
├── README.md                    # Required: Comprehensive documentation
├── pyproject.toml              # Required: Python project configuration
├── uv.lock                     # Required: Dependency lock file
├── pytest.ini                 # Optional: pytest configuration
├── src/                        # Required: Source code directory
│   ├── __init__.py
│   ├── server.py              # Required: Main server entry point
│   ├── mcp_handlers.py        # Optional: MCP-specific handlers
│   ├── capabilities/          # Optional: Feature-specific modules
│   │   ├── __init__.py
│   │   └── *.py
│   └── implementation/        # Optional: Core implementation modules
│       ├── __init__.py
│       └── *.py
├── tests/                     # Required: Test directory
│   ├── __init__.py
│   ├── test_server.py        # Required: Server tests
│   ├── test_*.py             # Required: Feature tests
│   └── conftest.py           # Optional: Test configuration
├── docs/                      # Optional: Extended documentation
│   ├── basic_install.md      # Optional: Installation guide
│   └── *.md
├── data/                      # Optional: Sample/test data
│   └── *
└── assets/                    # Optional: Images, examples
    └── *
```

### Key Structure Requirements

1. **pyproject.toml**: Must exist and contain valid project configuration
2. **src/server.py**: Main server implementation with FastMCP integration
3. **tests/**: Must contain comprehensive test coverage
4. **README.md**: Must follow the standardized format (see below)
5. **uv.lock**: Generated by uv package manager for reproducible builds

---

## README Standards

### Required Sections

Every MCP server README **MUST** contain these sections in this exact order:

#### 1. Header
```markdown
# [ServerName] MCP - [Brief Description]

## Description
[Detailed description with key features as bullet points]

**Key Features:**
- Feature 1 with specific benefit
- Feature 2 with specific benefit
- etc.
```

#### 2. Installation Section
```markdown
## 🛠️ Installation

### Requirements
- Python 3.10 or higher
- [uv](https://docs.astral.sh/uv/) package manager (recommended)
- Linux/macOS environment (Windows supported)
```

#### 3. IDE Integration Sections (All Required)
Must include installation instructions for **ALL** of these IDE/tools in collapsible sections:

- **Cursor** (`~/.cursor/mcp.json`)
- **VS Code** (VS Code MCP config)
- **Claude Code** (CLI command)
- **Claude Desktop** (`claude_desktop_config.json`)
- **Manual Setup** (Direct git clone and uv usage)

Example format:
```markdown
<details>
<summary><b>Install in Cursor</b></summary>

Go to: `Settings` -> `Cursor Settings` -> `MCP` -> `Add new global MCP server`

Pasting the following configuration into your Cursor `~/.cursor/mcp.json` file:

```json
{
  "mcpServers": {
    "[server-name]-mcp": {
      "command": "uvx",
      "args": ["clio-kit", "[server-name]"]
    }
  }
}
```


```

#### 4. Capabilities Section
```markdown
## Capabilities

### `tool_name`
**Description**: Detailed tool description with specific functionality

**Parameters**:
- `param1` (type): Description with constraints
- `param2` (type, optional): Optional parameter description (default: value)

**Returns**: Detailed description of return value and format
```

#### 5. Examples Section
```markdown
## Examples

### 1. Use Case Name
```
User prompt example demonstrating typical usage
```

**Tools called:**
- `tool_name` - What it does in this context

This prompt will:
- Action 1 explanation
- Action 2 explanation
- Expected outcome
```

### README Quality Standards

- **Comprehensive**: Cover all major use cases and integration methods
- **Consistent**: Follow the exact format across all servers
- **Executable**: All code examples must work as shown
- **Current**: Installation commands must match current repository structure

---

## GitHub Workflow Requirements

### Required Workflows

The repository includes several GitHub Actions workflows that **MUST** pass for all MCP servers:

#### 1. Quality Control Workflow (`quality_control.yml`)

**Discovery**: Automatically discovers all MCP directories with `pyproject.toml`

**Required Checks (All Must Pass):**
- **Ruff Linting**: `uv run ruff check --output-format=github .`
- **Ruff Formatting**: `uv run ruff format --check .`
- **MyPy Type Checking**: `uv run mypy src/ --ignore-missing-imports --show-error-codes --no-error-summary`
- **Test Coverage**: `uv run pytest tests/ -v --tb=short --cov=src --cov-report=xml --cov-report=html --cov-report=term`
- **Security Audit**: `uv run pip-audit`
- **Multi-Python Version Testing**: Python 3.10, 3.11, 3.12

#### 2. Test MCPs Workflow (`test-mcps.yml`)

**Matrix Testing**: Tests specific MCP servers individually
- Python 3.12 environment
- Special handling for system dependencies (e.g., Slurm)
- Command: `uv run pytest --tb=short -v`

#### 3. Workflow Dependencies

**Required System Dependencies:**
- **UV Package Manager**: Version "latest" via `astral-sh/setup-uv@v3`
- **Python Multi-version**: 3.10, 3.11, 3.12 support
- **System Packages**: Some servers require specific system dependencies (declared in workflow)

### Workflow Integration Points

1. **Automatic Discovery**: Servers are auto-discovered by presence of `pyproject.toml`
2. **Parallel Execution**: Up to 20 servers tested concurrently
3. **Fail-Fast Disabled**: Individual server failures don't stop other tests
4. **Coverage Reporting**: CodeCov integration with individual server flags
5. **Artifact Collection**: HTML coverage reports uploaded as artifacts

---

## Testing Framework & Patterns

### Testing Requirements

#### 1. Required Test Files

Every MCP server **MUST** have:
- `tests/test_server.py`: Main server functionality tests
- `tests/test_*.py`: Feature-specific test files
- Test coverage **MUST** be comprehensive

#### 2. Testing Framework: pytest

**Configuration** (`pytest.ini` when needed):
```ini
[pytest]
markers =
    slow: marks tests as slow (deselect with '-m "not slow"')
testpaths = tests
addopts = --tb=short
```

**Required Dependencies**:
```toml
[dependency-groups]
dev = [
    "pytest>=8.4.0",
    "pytest-asyncio>=1.0.0",
    "pytest-cov>=4.0.0",
    # Additional testing dependencies
]
```

#### 3. Test Patterns

**Server Initialization Tests**:
```python
def test_server_initialization():
    """Test FastMCP server proper initialization"""
    # Test server starts correctly
    # Test tools are registered
    # Test basic MCP protocol compliance
```

**Tool Function Tests**:
```python
@pytest.mark.asyncio
async def test_tool_functionality():
    """Test individual MCP tool functions"""
    # Test normal operation
    # Test error conditions  
    # Test parameter validation
```

**Integration Tests**:
```python
def test_mcp_protocol_compliance():
    """Test MCP protocol compliance"""
    # Test with actual MCP client
    # Test JSON-RPC protocol adherence
```

#### 4. Coverage Requirements

- **Minimum Coverage**: No specific threshold, but comprehensive testing expected
- **Coverage Reporting**: XML and HTML reports generated
- **Coverage Scope**: All `src/` directory files
- **CI Integration**: Coverage uploaded to CodeCov

### Testing Best Practices

1. **Async Support**: Use `pytest-asyncio` for async function testing
2. **Mocking**: Mock external dependencies appropriately
3. **Error Testing**: Test both success and failure cases
4. **Parameter Validation**: Test edge cases and invalid inputs
5. **Integration**: Test actual MCP client interactions where possible

---

## Environment & Dependency Management

### Python Version Requirements

**Supported Versions**: Python 3.10, 3.11, 3.12
**Primary Version**: Python 3.12 (default in workflows)

### Package Manager: UV

**Required**: All servers use UV package manager
- **Installation**: `astral-sh/setup-uv@v3` in GitHub Actions
- **Dependency Installation**: `uv sync --all-extras --dev`
- **Lock File**: `uv.lock` must be committed
- **Execution**: Tools run via `uv run <command>`

### pyproject.toml Structure

**Required Fields**:
```toml
[project]
name = "[server-name]-mcp"
version = "1.0.0"
description = "Detailed description"
readme = "README.md"
requires-python = ">=3.10"
license = "MIT"
authors = [
    { name = "IoWarp Scientific MCPs", email = "contact@iowarp.org" }
]

dependencies = [
    "fastmcp",  # Required: Core MCP framework
    # Server-specific dependencies
]

keywords = ["keyword1", "keyword2", "mcp", "llm-integration"]

[project.scripts]
[server-name]-mcp = "server:main"

[build-system]
requires = ["setuptools>=64.0", "wheel"]
build-backend = "setuptools.build_meta"
```

**Development Dependencies**:
```toml
[dependency-groups]  # or [tool.uv] for older format
dev = [
    "pytest>=8.4.0",
    "pytest-asyncio>=1.0.0", 
    "pytest-cov>=4.0.0",
    "ruff>=0.12.5",
    "mypy>=1.7.0",  # Type checking
]
```

### Core Dependencies

**Required for All Servers**:
- `fastmcp`: Core MCP protocol implementation
- `python-dotenv`: Environment variable management (recommended)

**Common Additional Dependencies**:
- `httpx`: HTTP client for API calls
- `psutil`: System information access
- Domain-specific libraries (h5py, etc.)

### Dependency Patterns

1. **Pinning**: Use minimum version constraints (`>=`) for flexibility
2. **Dev Dependencies**: Separate development tools from runtime dependencies  
3. **Optional Dependencies**: Use extras for optional features when needed
4. **Lock Files**: Always commit `uv.lock` for reproducible builds

---

## Code Architecture & MCP Tools

### Server Architecture Pattern

#### 1. Main Server File (`src/server.py`)

**Required Structure**:
```python
import os
import sys
import json
from fastmcp import FastMCP
from dotenv import load_dotenv

# Path and environment setup
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
load_dotenv()

# Initialize FastMCP server instance
mcp: FastMCP = FastMCP("[ServerName]Server")

# Tool definitions
@mcp.tool(name="tool_name", description="Tool description")
async def tool_function(param1: type, param2: type = default) -> dict:
    """
    Detailed docstring following Google/NumPy style
    
    Args:
        param1: Parameter description
        param2: Optional parameter description
        
    Returns:
        dict: Return value description
    """
    try:
        # Implementation or delegation to handler
        return await handler_function(param1, param2)
    except Exception as e:
        return {
            "content": [{"text": json.dumps({"error": str(e)})}],
            "_meta": {"tool": "tool_name", "error": type(e).__name__},
            "isError": True,
        }

# Main function
def main():
    """Main entry point with transport selection"""
    import sys
    if len(sys.argv) > 1 and sys.argv[1] == "--fastapi":
        # FastAPI mode for development/testing
        mcp.run(transport="fastapi", host="localhost", port=8000)
    else:
        # Standard stdio mode for production
        mcp.run(transport="stdio")

if __name__ == "__main__":
    main()
```

#### 2. Handler Patterns

**Option A: Direct Implementation** (Simple servers):
```python
@mcp.tool(name="simple_tool")
async def simple_tool(param: str) -> dict:
    """Direct implementation in tool function"""
    # Implementation here
    return {"result": "data"}
```

**Option B: Handler Delegation** (Complex servers):
```python
# Import handlers
import mcp_handlers

@mcp.tool(name="complex_tool") 
async def complex_tool(param: str) -> dict:
    """Delegate to handler function"""
    return await mcp_handlers.handle_complex_tool(param)
```

**Option C: Implementation Modules** (Large servers):
```python
# Import from implementation modules
from implementation.feature_handler import handle_feature

@mcp.tool(name="feature_tool")
async def feature_tool(param: str) -> dict:
    """Delegate to implementation module"""
    return await handle_feature(param)
```

### MCP Tool Standards

#### 1. Tool Registration

**Required Decorator Pattern**:
```python
@mcp.tool(
    name="descriptive_tool_name",
    description="Comprehensive description of tool functionality and use cases"
)
async def tool_function_name(parameters) -> dict:
```

#### 2. Parameter Patterns

**Type Hints**: All parameters must have explicit type hints
```python
async def tool(
    required_param: str,
    optional_param: int = 10,
    optional_with_none: str | None = None
) -> dict:
```

**Parameter Documentation**: Use comprehensive docstrings
```python
"""
Tool description.

Args:
    required_param (str): Detailed description of required parameter
    optional_param (int, optional): Optional parameter description (default: 10)
    optional_with_none (str | None, optional): Optional parameter that can be None

Returns:
    dict: Detailed description of return structure and contents
"""
```

#### 3. Return Patterns

**Success Response**:
```python
return {
    "result": "success_data",
    "metadata": {"additional": "info"},
    "_meta": {"tool": "tool_name", "status": "success"}
}
```

**Error Response**:
```python
return {
    "content": [{"text": json.dumps({"error": str(e)})}],
    "_meta": {"tool": "tool_name", "error": type(e).__name__},
    "isError": True,
}
```

#### 4. Error Handling

**Standardized Pattern**:
```python
try:
    # Tool implementation
    result = await some_operation()
    return {"result": result}
except Exception as e:
    return {
        "content": [{"text": json.dumps({"error": str(e)})}],
        "_meta": {"tool": "tool_name", "error": type(e).__name__},
        "isError": True,
    }
```

### Code Organization Patterns

#### Small Servers (< 5 tools)
- Single `server.py` with direct implementation
- Optional `mcp_handlers.py` for complex logic

#### Medium Servers (5-10 tools)  
- `server.py` with tool definitions
- `mcp_handlers.py` with implementation functions
- `capabilities/` directory for feature groupings

#### Large Servers (10+ tools)
- `server.py` with tool registration only
- `implementation/` directory with feature modules
- `capabilities/` directory for logical groupings
- Comprehensive module organization

---

## Examples & Best Practices

### Complete Server Example

Here's a minimal but complete MCP server following all standards:

**`src/server.py`**:
```python
import os
import sys
import json
from fastmcp import FastMCP
from dotenv import load_dotenv

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
load_dotenv()

mcp: FastMCP = FastMCP("ExampleServer")

@mcp.tool(
    name="example_tool",
    description="Example tool demonstrating proper MCP server patterns and best practices"
)
async def example_tool(input_text: str, max_length: int = 100) -> dict:
    """
    Example tool function with proper documentation and error handling.
    
    Args:
        input_text (str): Input text to process
        max_length (int, optional): Maximum length of processed text (default: 100)
        
    Returns:
        dict: Processed text result with metadata
    """
    try:
        # Simple processing logic
        processed = input_text.upper()[:max_length]
        
        return {
            "processed_text": processed,
            "original_length": len(input_text),
            "processed_length": len(processed),
            "_meta": {
                "tool": "example_tool", 
                "status": "success"
            }
        }
    except Exception as e:
        return {
            "content": [{"text": json.dumps({"error": str(e)})}],
            "_meta": {"tool": "example_tool", "error": type(e).__name__},
            "isError": True,
        }

def main():
    import sys
    if len(sys.argv) > 1 and sys.argv[1] == "--fastapi":
        mcp.run(transport="fastapi", host="localhost", port=8000)
    else:
        mcp.run(transport="stdio")

if __name__ == "__main__":
    main()
```

### Integration Best Practices

#### 1. Package Distribution

**Repository Structure**: All servers are part of the unified `clio-kit` package
**CLI Integration**: Servers launched via `uvx clio-kit [server-name]`
**Entry Points**: Individual servers have their own entry points

#### 2. Documentation Best Practices

- **Comprehensive Examples**: Include realistic use cases in README
- **Installation Testing**: Verify all installation methods work
- **Update Maintenance**: Keep documentation current with code changes
- **Cross-References**: Link related servers and capabilities

#### 3. Testing Best Practices

- **Automated Testing**: All code paths covered by tests
- **Integration Testing**: Test actual MCP protocol interactions
- **Performance Testing**: Mark slow tests appropriately
- **Error Testing**: Verify error handling works correctly

#### 4. Development Workflow

1. **Setup**: Use `uv` for all dependency management
2. **Testing**: Run `uv run pytest` before commits
3. **Linting**: Use `uv run ruff check` and `uv run ruff format`
4. **Type Checking**: Run `uv run mypy src/`
5. **Security**: Regular `uv run pip-audit` checks

---

## Conclusion

This guide establishes the complete development framework for IoWarp MCP servers. Following these standards ensures:

- **Consistency**: All servers follow identical patterns
- **Quality**: Comprehensive testing and code quality checks
- **Maintainability**: Clear structure and documentation standards
- **Integration**: Seamless workflow and CI/CD integration
- **User Experience**: Consistent installation and usage patterns

All new MCP servers **MUST** adhere to these standards, and existing servers should be updated to match these patterns during maintenance cycles.

For questions or clarifications, refer to existing server implementations as reference examples or consult the team for guidance on edge cases not covered in this guide.