Skip to main content
Glama
README.md
# my-mcp

my-mcp is a Model Context Protocol (MCP) server built with FastMCP featuring dynamic tool loading.

## Features

- **Dynamic Tool Loading**: Tools are automatically discovered and loaded from `src/tools/`
- **One Tool Per File**: Each tool is a single file with a function matching the filename
- **FastMCP Integration**: Leverages FastMCP for robust MCP protocol handling
- **Configuration Management**: Tool-specific configuration via `mcp.yaml`
- **Fail-Fast**: Server won't start if any tool fails to load
- **Auto-Generated Tests**: Automatic test generation for tool validation

## Project Structure

```
src/
├── tools/              # Tool implementations (one file per tool)
│   ├── echo.py         # Example echo tool
│   └── __init__.py     # Auto-generated tool registry
├── core/               # Dynamic loading framework
│   ├── server.py       # Dynamic MCP server
│   └── utils.py        # Shared utilities
└── main.py             # Entry point
mcp.yaml               # Configuration file
tests/                  # Generated tests
```

## Quick Start

### Option 1: Local Development (with Python/uv)

1. **Install Dependencies**:
   ```bash
   uv sync
   ```

2. **Run the Server**:
   ```bash
   # Stdio mode (default MCP transport)
   uv run python src/main.py
   
   # HTTP mode with WebSocket MCP endpoint
   uv run python src/main.py --http
   
   # HTTP mode with custom host/port
   uv run python src/main.py --http --host 0.0.0.0 --port 8080
   ```

3. **Using uv Scripts**:
   ```bash
   # Development mode (HTTP on port 3000)
   uv run dev
   
   # HTTP mode
   uv run dev-http
   
   # Stdio mode
   uv run start
   ```

4. **Add New Tools**:
   ```bash
   # Create a new tool (no tool types needed!)
   arctl mcp add-tool weather
   
   # The tool file will be created at src/tools/weather.py
   # Edit it to implement your tool logic
   ```

### Option 2: Docker-Only Development (no local Python/uv required)

1. **Build Docker Image**:
   ```bash
   arctl mcp build --verbose
   ```

2. **Run in Container**:
   ```bash
   docker run -i my-mcp:latest
   ```

3. **Add New Tools**:
   ```bash
   # Create a new tool
   arctl mcp add-tool weather
   
   # Edit the tool file, then rebuild
   arctl mcp build
   ```

## HTTP Transport Mode

The server supports running in HTTP mode for development and integration purposes.

### Starting in HTTP Mode

```bash
# Command line flag
python src/main.py --http

# Environment variable
MCP_TRANSPORT_MODE=http python src/main.py

# Custom host and port
python src/main.py --http --host localhost --port 8080
```

## Creating Tools

### Basic Tool Structure

Each tool is a Python file in `src/tools/` containing a function decorated with `@mcp.tool()`:

```python
# src/tools/weather.py
from core.server import mcp
from core.utils import get_tool_config, get_env_var

@mcp.tool()
def weather(location: str) -> str:
    """Get weather information for a location."""
    
    # Get tool configuration
    config = get_tool_config("weather")
    api_key = get_env_var(config.get("api_key_env", "WEATHER_API_KEY"))
    base_url = config.get("base_url", "https://api.openweathermap.org/data/2.5")
    
    # TODO: Implement weather API call
    return f"Weather for {location}: Sunny, 72°F"
```

### Tool Examples

The generated tool template includes commented examples for common patterns:

```python
# HTTP API calls
# async with httpx.AsyncClient() as client:
#     response = await client.get(f"{base_url}/weather?q={location}&appid={api_key}")
#     return response.json()

# Database operations  
# async with asyncpg.connect(connection_string) as conn:
#     result = await conn.fetchrow("SELECT * FROM weather WHERE location = $1", location)
#     return dict(result)

# File processing
# with open(file_path, 'r') as f:
#     content = f.read()
#     return {"content": content, "size": len(content)}
```

## Configuration

Configure tools in `mcp.yaml`:

```yaml
tools:
  weather:
    api_key_env: "WEATHER_API_KEY"
    base_url: "https://api.openweathermap.org/data/2.5"
    timeout: 30
  
  database:
    connection_string_env: "DATABASE_URL"
    max_connections: 10
```

## Testing

Run the generated tests to verify your tools load correctly:

```bash
uv run pytest tests/
```

## Development

### Adding Dependencies

Update `pyproject.toml` and run:

```bash
uv sync
```

### Code Quality

```bash
uv run black .
uv run ruff check .
uv run mypy .
```

## Deployment

### Docker

```bash
# Build image (handles lockfile automatically)
arctl mcp build

# Run container
docker run -i my-mcp:latest
```

TDQS

B3.4/5.0

Scored across 11 tools

Disambiguation4/5

Most tools have distinct purposes focused on demonstrating different MCP capabilities, with clear boundaries between them. However, 'annotatedMessage' and 'structuredContent' both demonstrate response formatting, which could cause some confusion about which to use for structured output scenarios.

Naming Consistency2/5

The naming is inconsistent with mixed conventions: 'annotatedMessage' uses camelCase while most others use snake_case. There's also inconsistency in verb usage - some start with verbs (get, list, print, start), others are nouns (echo, sum), and some are descriptive phrases (longRunningOperation).

Tool Count5/5

With 11 tools, this is well-scoped for a demonstration server covering various MCP features. Each tool serves a distinct demonstration purpose, and the count feels appropriate for showing the breadth of MCP capabilities without being overwhelming.

Completeness4/5

For a demonstration server, it covers most key MCP features well: annotations, resources, images, roots, operations, environment, LLM sampling, elicitation, structured content, and basic operations. The main gap is the lack of a tool demonstrating MCP prompts, but otherwise it's quite comprehensive for its purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues