BasicMcpServer

BasicMcpServer

dawsonlp

Developer Tools
Visit Server

README

BasicMcpServer

A minimal, production-ready MCP (Model Context Protocol) server implementation exposed via HTTP+SSE in a Docker container.

Overview

This project implements the simplest possible Model Context Protocol (MCP) server that can be deployed in a Docker container and exposed via HTTP with Server-Sent Events (SSE). It follows best practices for environment variable management to ensure credentials are never committed to version control.

The server is designed to be:

  • Simple: Minimal boilerplate and dependencies
  • Secure: Proper credential management out of the box
  • Containerized: Ready for Docker deployment
  • Performant: Using FastMCP and Uvicorn for high-performance HTTP serving

Architecture

Python Packages

The project uses the following key packages:

  1. MCP SDK: The Python implementation of the Model Context Protocol

    • mcp: Core MCP functionality
    • mcp.server.fastmcp: High-level FastMCP framework
  2. Web Framework: FastMCP's built-in ASGI support

    • Leverages Starlette under the hood
    • Simplifies server setup and routing
    • Excellent performance characteristics
  3. ASGI Server: Uvicorn

    • High-performance ASGI server
    • Works seamlessly with FastMCP
    • Well-suited for containerized environments
  4. SSE Implementation: MCP SDK's built-in SSE transport

    • Integrated with FastMCP
    • Provides Server-Sent Events functionality
  5. Configuration Management: pydantic-settings

    • Type-safe environment variable handling
    • Validation at startup
  6. HTTP Client (if needed): httpx

    • Async-compatible HTTP client for outbound requests

Dependencies

These will be specified in pyproject.toml:

[project]
name = "basic-mcp-server"
version = "0.1.0"
description = "A minimal MCP server with HTTP+SSE in a Docker container"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
    "mcp>=1.6.0",
    "uvicorn>=0.34.1",
    "pydantic-settings>=2.8.1",
    "httpx>=0.28.1",
]

Credential Management & Security

To ensure credentials are never committed to version control:

Local Development

  1. Create a .env file locally with your credentials:

    API_KEY=your_api_key_here
    OTHER_SECRET=other_secret_here
    
  2. This file is automatically excluded from Git via the .gitignore file.

  3. Use the included .env.example as a template for required variables.

Docker Deployment

  1. Never mount your .env file directly into the container.

  2. Pass environment variables at runtime:

    docker run -e API_KEY=your_api_key_here -e OTHER_SECRET=other_secret_here basic-mcp-server
    
  3. Or use Docker Compose with environment variables:

    services:
      mcp-server:
        build: .
        environment:
          - API_KEY=${API_KEY}
          - OTHER_SECRET=${OTHER_SECRET}
    
  4. For production, consider using Docker Swarm secrets or Kubernetes secrets.

Project Structure

basic-mcp-server/
├── .gitignore            # Includes .env* patterns
├── .env.example          # Template with dummy values
├── pyproject.toml        # Dependencies and metadata
├── README.md             # This file
├── readme_fastmcp.md     # Documentation on FastMCP vs low-level Server
├── design_decisions.md   # Project design decisions log
├── docker/               # Docker containerization
│   ├── Dockerfile        # Multi-stage build with Python 3.13
│   ├── .dockerignore     # Files excluded from build context
│   ├── README.md         # Docker-specific documentation
│   └── scripts/          # Helper scripts
│       ├── entrypoint.sh # Container startup script
│       └── run.sh        # Script to replace docker-compose
└── src/
    ├── __init__.py
    ├── main.py           # Entry point
    ├── config.py         # Environment & configuration management
    ├── server.py         # MCP server implementation using FastMCP
    └── tools/            # Tool implementations (alternative organization)
        ├── __init__.py
        └── example.py    # Example tool

Implementation Details

Configuration (src/config.py)

from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    # Server settings
    host: str = "0.0.0.0"
    port: int = 7500
    
    # Add your API keys and credentials here
    api_key: str
    other_secret: str = ""  # Optional, has default empty value
    
    # Configure settings to load from .env file
    model_config = SettingsConfigDict(
        env_file=".env", 
        env_file_encoding="utf-8",
        case_sensitive=False
    )

# Create a settings instance for importing in other modules
settings = Settings()

Server Implementation (src/server.py)

from mcp.server.fastmcp import FastMCP

def create_mcp_server():
    """
    Create and configure an MCP server instance using FastMCP.
    
    Returns:
        FastMCP: A configured FastMCP server instance
    """
    # Create a FastMCP server instance with a unique name
    mcp = FastMCP("basic-mcp-server")
    
    # Add an example tool using the simpler decorator syntax
    @mcp.tool()
    def example(input: str) -> str:
        """An example tool that processes input text"""
        return f"Processed: {input}"
    
    # You can add more tools, resources, and prompts here
    
    return mcp

Main Entry Point (src/main.py)

import logging
import sys

from .config import settings
from .server import create_mcp_server

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger(__name__)

def start():
    """Start the MCP server using FastMCP's built-in functionality."""
    logger.info(f"Starting MCP server on {settings.host}:{settings.port}")
    
    # Create the MCP server
    mcp_server = create_mcp_server()
    
    # Configure server settings
    mcp_server.settings.host = settings.host
    mcp_server.settings.port = settings.port
    mcp_server.settings.debug = True
    mcp_server.settings.log_level = "INFO"
    
    # Run the server with SSE transport
    mcp_server.run("sse")

# Alternative approach using the FastMCP ASGI application
def create_app():
    """Create an ASGI application for use with an external ASGI server."""
    mcp_server = create_mcp_server()
    mcp_server.settings.debug = True
    return mcp_server.sse_app()

if __name__ == "__main__":
    start()

Docker Implementation

We've separated Docker containerization concerns from application functionality to improve maintainability and follow best practices:

Directory Structure

docker/
├── Dockerfile         # Optimized multi-stage Dockerfile
├── .dockerignore      # Files excluded from build context
└── scripts/           # Container helper scripts
    ├── entrypoint.sh  # Container startup script
    └── run.sh         # Script to replace docker-compose functionality

Multi-stage Dockerfile

The Docker implementation uses a multi-stage build approach with Python 3.13:

# Stage 1: Builder
FROM python:3.13-slim AS builder

# Set build-time environment variables
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

# Create app directory
WORKDIR /build

# Copy only what's needed for installation
COPY pyproject.toml README.md ./

# Install build dependencies
RUN apt-get update \
    && apt-get install -y --no-install-recommends gcc python3-dev \
    && pip install --upgrade pip \
    && pip install build wheel \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Build wheel package
RUN pip wheel --no-deps --wheel-dir /wheels -e .

# Stage 2: Runtime
FROM python:3.13-slim AS runtime

# Set runtime environment variables
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1

# Set working directory
WORKDIR /app

# Copy wheel from builder stage
COPY --from=builder /wheels /wheels

# Copy application code
COPY ./src ./src

# Install dependencies and app
RUN pip install --no-cache-dir --upgrade pip \
    && pip install --no-cache-dir /wheels/* \
    && rm -rf /wheels

# Create non-root user for security
RUN adduser --disabled-password --gecos "" appuser \
    && chown -R appuser:appuser /app
USER appuser

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD python -c "import http.client; conn = http.client.HTTPConnection('localhost:7501'); conn.request('GET', '/health'); response = conn.getresponse(); exit(0 if response.status == 200 else 1)"

# Expose the port
EXPOSE 7501

# Command to run the application
CMD ["python", "-m", "src.main"]

Helper Scripts Instead of Docker Compose

For a single-container application, we've replaced Docker Compose with helper scripts that provide similar functionality with less complexity:

# Build the Docker image
./docker/scripts/run.sh build

# Run the server
./docker/scripts/run.sh run

# Run with hot reload for development
./docker/scripts/run.sh dev

# Run tests in container
./docker/scripts/run.sh test

# Clean up resources
./docker/scripts/run.sh clean

For more details, see docker/README.md.

Getting Started

Setup

  1. Clone this repository
  2. Copy .env.example to .env and update with your credentials
  3. Install dependencies:
    pip install uv
    uv pip install -e .
    

Run Locally

python -m src.main

Build and Run with Docker

# Build the Docker image
./docker/scripts/run.sh build

# Run the server
./docker/scripts/run.sh run

For development with hot-reloading:

./docker/scripts/run.sh dev

Other useful commands:

# Run tests in container
./docker/scripts/run.sh test

# Clean up resources
./docker/scripts/run.sh clean

Testing Your MCP Server

Manual Testing

Using the MCP SDK CLI

If you have the MCP SDK CLI installed, you can use it to test your server:

mcp dev http://localhost:7500/sse

Using Claude

To test with Claude:

  1. Update Claude's MCP settings file with:

    {
      "mcpServers": {
        "basic-mcp-server": {
          "url": "http://localhost:7500/sse",
          "disabled": false,
          "autoApprove": ["example"]
        }
      }
    }
    
  2. In Claude, use the tool:

    <use_mcp_tool>
    <server_name>basic-mcp-server</server_name>
    <tool_name>example</tool_name>
    <arguments>
    {
      "input": "Hello MCP World!"
    }
    </arguments>
    </use_mcp_tool>
    
  3. You should receive: "Processed: Hello MCP World!"

Using HTTP Requests

You can also test your server with HTTP requests:

  1. Connect to the SSE endpoint:

    curl -N http://localhost:7500/sse
    
  2. In another terminal, send a message to the server:

    curl -X POST -H "Content-Type: application/json" -d '{"type":"initialize","requestId":"test-123","content":{"clientInfo":{"clientType":"test","clientVersion":"1.0.0"},"capabilities":{"receiveText":true,"receiveImage":false}}}' http://localhost:7500/messages/?session_id=test-session-id
    

Automated End-to-End Testing

We provide automated tests that verify the MCP server works correctly when deployed as a container:

  1. Install test dependencies:

    cd tests/e2e
    pip install -r requirements.txt
    
  2. Run the test:

    python mcp_container_test.py
    

The test script will:

  • Build and start a Docker container with the MCP server
  • Test HTTP connectivity to the server
  • Test the MCP protocol (initialization, tool listing)
  • Test the example tool functionality
  • Clean up all resources when done

See tests/e2e/README.md for more details on the end-to-end tests.

Troubleshooting

If you encounter issues:

  1. Connection refused:

    • Ensure the container is running: docker ps | grep mcp-server
    • Verify port mapping: docker port [container-id]
  2. "Not connected" error in Claude:

    • Ensure the URL includes the /sse path: http://localhost:7500/sse
    • Check container logs: docker logs [container-id]
    • Try restarting the VSCode window
  3. Timeout or no response:

    • Examine server logs for errors
    • Check if another service is using port 7500

Reference Implementation

This project is based on the Model Context Protocol (MCP) Python SDK. For more details on the MCP specification and SDK, refer to the original project README.

FastMCP vs Low-Level Server

This project has been migrated from using the low-level Server class to using the more ergonomic FastMCP approach. For details on the differences and benefits, see readme_fastmcp.md.

Next Steps

  1. Add more tools to make your MCP server useful
  2. Implement authentication for the HTTP endpoints
  3. Add monitoring and logging
  4. Deploy to your preferred cloud provider

This implementation provides a minimal but production-ready MCP server. You can extend it by adding more tools, resources, or custom functionality as needed.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
MCP Package Docs Server

MCP Package Docs Server

Facilitates LLMs to efficiently access and fetch structured documentation for packages in Go, Python, and NPM, enhancing software development with multi-language support and performance optimization.

Featured
Local
TypeScript
Claude Code MCP

Claude Code MCP

An implementation of Claude Code as a Model Context Protocol server that enables using Claude's software engineering capabilities (code generation, editing, reviewing, and file operations) through the standardized MCP interface.

Featured
Local
JavaScript
@kazuph/mcp-taskmanager

@kazuph/mcp-taskmanager

Model Context Protocol server for Task Management. This allows Claude Desktop (or any MCP client) to manage and execute tasks in a queue-based system.

Featured
Local
JavaScript
Linear MCP Server

Linear MCP Server

Enables interaction with Linear's API for managing issues, teams, and projects programmatically through the Model Context Protocol.

Featured
JavaScript
mermaid-mcp-server

mermaid-mcp-server

A Model Context Protocol (MCP) server that converts Mermaid diagrams to PNG images.

Featured
JavaScript
Jira-Context-MCP

Jira-Context-MCP

MCP server to provide Jira Tickets information to AI coding agents like Cursor

Featured
TypeScript
Linear MCP Server

Linear MCP Server

A Model Context Protocol server that integrates with Linear's issue tracking system, allowing LLMs to create, update, search, and comment on Linear issues through natural language interactions.

Featured
JavaScript
Sequential Thinking MCP Server

Sequential Thinking MCP Server

This server facilitates structured problem-solving by breaking down complex issues into sequential steps, supporting revisions, and enabling multiple solution paths through full MCP integration.

Featured
Python