Skip to main content

A lightweight, easy-to-use wrapper for creating MCP (Model Context Protocol) servers in Python

Project description

MakeMCP

The fastest way to create MCP (Model Context Protocol) servers in Python. Zero boilerplate, maximum functionality.

from makemcp.quick import tool, run

@tool
def hello(name: str) -> str:
    return f"Hello, {name}! 👋"

run()  # Your MCP server is running!

MakeMCP is built on the official MCP Python SDK but removes all the complexity. Create powerful MCP servers with just decorators.

QuickstartGetting StartedExamplesDocumentation

Why MakeMCP?

  • Zero Boilerplate: Just decorators. No classes, no handlers, no setup.
  • Use Your Existing Code: Any Python file becomes an MCP server instantly
  • Async Native: Async functions work automatically alongside sync ones
  • Type Safe: Full type hints and schema generation
  • Fast: Built on the official MCP SDK for maximum performance
  • Simple: If you can write Python functions, you can build an MCP server

Installation

# Install uv if you don't have it (optional but recommended for 10-100x faster installs)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install MakeMCP
uv pip install git+https://github.com/leifmarkthaler/makemcp.git

That's it! You're ready to create MCP servers.

Alternative installation methods

Using pip (slower but works everywhere)

pip install git+https://github.com/leifmarkthaler/makemcp.git

For development

git clone https://github.com/leifmarkthaler/makemcp.git
cd makemcp
uv pip install -e ".[dev]"

For SSE/HTTP transport

uv pip install "makemcp[http] @ git+https://github.com/leifmarkthaler/makemcp.git"

Quick Start

The Simplest Example (3 lines)

from makemcp.quick import tool, run

@tool
def hello(name: str) -> str:
    return f"Hello, {name}!"

run()

Use Your Existing Code (1 line)

from makemcp.quick import from_file

# Any Python file becomes an MCP server
from_file("my_utils.py").run()

Traditional Approach (More Control)

from makemcp import MakeMCPServer

# Create a server
server = MakeMCPServer("my-server")

# Add tools with decorators
@server.tool()
def add(a: float, b: float) -> float:
    """Add two numbers."""
    return a + b

@server.tool()
def multiply(a: float, b: float) -> float:
    """Multiply two numbers."""
    return a * b

# Add resources
@server.resource("config://{key}")
def get_config(key: str) -> str:
    """Get configuration value."""
    return f"Config value for {key}"

# Add prompts
@server.prompt()
def code_review(language: str, code: str) -> str:
    """Generate a code review prompt."""
    return f"Please review this {language} code:\n\n{code}"

# Run the server
if __name__ == "__main__":
    server.run()

Usage Examples

Basic Server with Tools

from makemcp import MakeMCPServer

server = MakeMCPServer("calculator")

@server.tool()
def calculate(operation: str, x: float, y: float) -> float:
    """Perform basic calculations."""
    operations = {
        "add": lambda a, b: a + b,
        "subtract": lambda a, b: a - b,
        "multiply": lambda a, b: a * b,
        "divide": lambda a, b: a / b if b != 0 else None,
    }
    
    if operation not in operations:
        raise ValueError(f"Unknown operation: {operation}")
    
    return operations[operation](x, y)

server.run()

Async Operations

MakeMCP has full support for async functions. Async functions are automatically detected and properly wrapped while preserving their async nature.

from makemcp import MakeMCPServer
import asyncio
import aiohttp

server = MakeMCPServer("async-example")

@server.tool()
async def fetch_url(url: str) -> dict:
    """Fetch data from a URL asynchronously."""
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return {
                "url": url,
                "status": response.status,
                "content": await response.text()
            }

@server.tool()
async def parallel_process(items: list) -> list:
    """Process multiple items in parallel."""
    async def process_item(item):
        await asyncio.sleep(0.1)  # Simulate work
        return f"Processed: {item}"
    
    # Process all items concurrently
    results = await asyncio.gather(*[process_item(item) for item in items])
    return results

# Mix async and sync tools in the same server
@server.tool()
def sync_operation(x: int, y: int) -> int:
    """Synchronous operation."""
    return x + y

server.run()

Resources and Prompts

from makemcp import MakeMCPServer
import json

server = MakeMCPServer("knowledge-base")

# In-memory knowledge base
knowledge = {}

@server.tool()
def store_knowledge(topic: str, content: str) -> dict:
    """Store knowledge about a topic."""
    knowledge[topic] = content
    return {"stored": topic}

@server.resource("knowledge://{topic}")
def get_knowledge(topic: str) -> str:
    """Retrieve knowledge about a topic."""
    return knowledge.get(topic, f"No knowledge found for {topic}")

@server.prompt()
def explain_topic(topic: str, level: str = "beginner") -> str:
    """Generate a prompt to explain a topic."""
    return f"""Explain {topic} at a {level} level.
    
Include:
- Clear definition
- Real-world examples
- Common misconceptions
- Related concepts
"""

server.run()

SSE Transport for Network Access

from makemcp import MakeMCPServer

server = MakeMCPServer("network-server")

@server.tool()
def echo(message: str) -> str:
    """Echo a message back."""
    return message

# Run as SSE server on port 8080
server.run(transport="sse", port=8080)

Connect with any MCP client:

mcp-client sse http://localhost:8080/sse

MCP Factory - Auto-Generate Servers

The MCP Factory automatically creates MCP servers from existing Python code with intelligent dependency analysis, safe type conversion, and full async support. Full documentation →

Quick Examples

from makemcp.factory import create_mcp_from_module

# Create server from any Python file
server = create_mcp_from_module("my_utils.py")
server.run()

# CLI with auto-dependency detection
# mcp-factory my_utils.py --name utils-server

Smart Dependency Detection

# If dependencies are missing, get helpful errors:
$ mcp-factory my_module.py

Missing dependencies detected:
 Required: numpy, pandas
⚠️  Optional: matplotlib (in try/except block)

💡 Quick install: uv pip install numpy pandas  # Uses uv if available

Async Functions Work Automatically

# my_async_tools.py
import asyncio
import aiohttp

async def fetch_webpage(url: str) -> dict:
    """Fetch webpage content asynchronously."""
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return {
                "url": url,
                "status": response.status,
                "content": await response.text()
            }

async def parallel_requests(urls: list) -> list:
    """Fetch multiple URLs in parallel."""
    tasks = [fetch_webpage(url) for url in urls]
    return await asyncio.gather(*tasks, return_exceptions=True)

def sync_helper(text: str) -> str:
    """Synchronous helper function."""
    return text.upper()

# Generate server automatically
if __name__ == "__main__":
    from makemcp.factory import create_mcp_from_module
    server = create_mcp_from_module(__file__)
    server.run()

Generate from Classes with Async Methods

from makemcp.factory import MCPFactory

class AsyncDataProcessor:
    """Data processor with async methods."""
    
    def __init__(self):
        self.processed_count = 0
    
    async def process_batch(self, items: list) -> dict:
        """Process items asynchronously."""
        results = []
        for item in items:
            await asyncio.sleep(0.1)  # Simulate async work
            results.append(f"Processed: {item}")
        
        self.processed_count += len(items)
        return {
            "results": results,
            "total_processed": self.processed_count
        }
    
    def get_stats(self) -> dict:
        """Get processing statistics (sync method)."""
        return {"processed_count": self.processed_count}

# Generate server from class
factory = MCPFactory()
server = factory.from_class(AsyncDataProcessor)
server.run()

Use Decorators for Selective Exposure

from makemcp.factory import mcp_tool, create_mcp_from_module

@mcp_tool
async def exposed_async_function(data: str) -> str:
    """This async function will be exposed as an MCP tool."""
    await asyncio.sleep(0.1)
    return f"Processed: {data}"

@mcp_tool(name="custom_name", description="Custom async tool")
async def another_async(value: int) -> int:
    """Another async function with custom metadata."""
    await asyncio.sleep(0.1)
    return value * 2

async def not_exposed(data: str) -> str:
    """This function won't be exposed (no decorator)."""
    return data

# Only decorated functions become tools
server = create_mcp_from_module(__file__)

Advanced Features

Custom Tool Schemas

@server.tool(
    description="Advanced calculation tool",
    schema={
        "type": "object",
        "properties": {
            "operation": {"type": "string", "enum": ["add", "multiply"]},
            "values": {"type": "array", "items": {"type": "number"}}
        }
    }
)
def calculate_many(operation: str, values: list[float]) -> float:
    """Calculate with multiple values."""
    if operation == "add":
        return sum(values)
    elif operation == "multiply":
        import math
        return math.prod(values)

Server Configuration

from makemcp import MakeMCPServer

server = MakeMCPServer(
    name="my-server",
    version="2.0.0",
    description="My advanced MCP server",
    log_level="DEBUG"  # Enable debug logging
)

Standalone Decorators

You can also use decorators before creating the server:

from makemcp import tool, resource, prompt, MakeMCPServer

@tool()
def my_tool(arg: str) -> str:
    return f"Processed: {arg}"

@resource("data://{id}")
def my_resource(id: str) -> str:
    return f"Data for {id}"

# Later, create server and register
server = MakeMCPServer("my-server")
server.register_module(__main__)  # Coming soon
server.run()

Running Your Server

As stdio (default)

python your_server.py

As SSE server

python your_server.py --transport sse --port 8080

Testing with MCP Inspector

mcp-inspector stdio -- python your_server.py

Discovery and Registration

MakeMCP provides comprehensive discovery mechanisms for both local and network-based MCP servers, making it easy to integrate with Gleitzeit and other MCP clients.

Overview

MakeMCP supports two discovery approaches:

  • Registry-based discovery for stdio servers (launched as child processes)
  • Network autodiscovery for SSE/HTTP servers (running as network services)

Server Registry (for stdio servers)

The server registry allows you to register MakeMCP servers that can be launched via stdio transport.

Registering Servers

# Register a server with the CLI
makemcp register my-server "python my_server.py" \
    --description "My custom MCP server" \
    --tool-prefix "my."

# Or register programmatically
from makemcp import register_server

register_server(
    name="my-server",
    command=["python", "my_server.py"],
    description="My custom MCP server",
    tool_prefix="my."
)

Listing Registered Servers

# List all registered servers
makemcp list

# Or programmatically
from makemcp import list_servers

for server in list_servers():
    print(f"{server.name}: {server.description}")

Auto-Discovery in Filesystem

MakeMCP can automatically discover servers in your filesystem:

# Discover servers in current directory and common locations
makemcp discover --scan-filesystem

# Discover and auto-register found servers
makemcp discover --scan-filesystem --auto-register

# Specify custom search paths
makemcp discover --scan-filesystem --paths ./my-servers ~/mcp-servers

Network Autodiscovery (for SSE/HTTP servers)

Network servers automatically broadcast their presence via UDP multicast when running with SSE or HTTP transport.

Server-Side (Automatic)

from makemcp import MakeMCPServer

# Network servers automatically broadcast when running
server = MakeMCPServer("my-server")

# Add discovery metadata
server = MakeMCPServer(
    "my-server",
    discovery_metadata={
        "author": "Your Name",
        "category": "utilities",
        "tags": ["ai", "tools"]
    }
)

# Run as SSE server (autodiscovery enabled automatically)
server.run(transport="sse", port=8080)

Client-Side Discovery

# Discover network servers
makemcp discover --scan-network

# Discover with custom timeout
makemcp discover --scan-network --timeout 10

Or programmatically:

import asyncio
from makemcp import discover_servers

async def find_network_servers():
    servers = await discover_servers(timeout=5.0)
    for server in servers:
        print(f"Found: {server.name} at {server.host}:{server.port}")

asyncio.run(find_network_servers())

MakeMCP CLI

The MakeMCP CLI provides comprehensive server management:

# Register a server
makemcp register <name> <command> [options]

# Unregister a server
makemcp unregister <name>

# List registered servers
makemcp list

# Show server information
makemcp info <name>

# Discover servers (filesystem and/or network)
makemcp discover [--scan-filesystem] [--scan-network]

# Export configuration for Gleitzeit
makemcp export --format yaml > ~/.gleitzeit/mcp_servers.yaml

Server Metadata

MakeMCP servers can provide metadata via the --info flag:

# Get server information
python my_server.py --info

This returns JSON with server details:

{
  "name": "my-server",
  "version": "1.0.0",
  "description": "My custom server",
  "capabilities": {
    "tools": ["tool1", "tool2"],
    "resources": ["resource1"],
    "prompts": ["prompt1"]
  }
}

Integration with Gleitzeit

MakeMCP servers work seamlessly with Gleitzeit:

Automatic Configuration Export

MakeMCP can export your registered servers directly to Gleitzeit configuration:

# Export all registered servers to Gleitzeit config
makemcp export --format yaml > ~/.gleitzeit/mcp_servers.yaml

# The generated config will look like:
mcp:
  auto_discover: true
  servers:
    - name: "my-server"
      connection_type: "stdio"
      command: ["python", "my_server.py"]
      tool_prefix: "my."
      auto_start: true

Manual Configuration

You can also manually configure MakeMCP servers in Gleitzeit:

# ~/.gleitzeit/config.yaml
mcp:
  servers:
    # Stdio server (launched as child process)
    - name: "my-makemcp-server"
      connection_type: "stdio"
      command: ["python", "path/to/my_server.py"]
      working_dir: "${HOME}/my-servers"
      tool_prefix: "my."
      auto_start: true
    
    # SSE server (network connection)
    - name: "my-sse-server"
      connection_type: "sse"
      url: "http://localhost:8080/sse"
      tool_prefix: "sse."
      auto_start: false  # Don't launch, just connect

Discovery Workflow

  1. Register your servers with MakeMCP:

    makemcp register my-server "python my_server.py" --tool-prefix "my."
    
  2. Export to Gleitzeit:

    makemcp export > ~/.gleitzeit/mcp_servers.yaml
    
  3. Use in Gleitzeit workflows:

    tasks:
      - name: "Use MCP tool"
        type: mcp
        provider: my-server
        tool: my.some_tool
        arguments:
          param: value
    

Network Server Discovery

For SSE/HTTP servers, Gleitzeit can discover them automatically via UDP multicast:

# Your MakeMCP server broadcasts automatically
server = MakeMCPServer("my-server")
server.run(transport="sse", port=8080)  # Broadcasts on network

# Gleitzeit can discover it
# (when auto_discover: true in config)

API Reference

MakeMCPServer

Main server class for creating MCP servers.

Methods:

  • tool(name=None, description=None, schema=None) - Decorator for tools
  • resource(uri_template, name=None, description=None, mime_type="text/plain") - Decorator for resources
  • prompt(name=None, description=None, arguments=None) - Decorator for prompts
  • run(transport="stdio", host="localhost", port=8000) - Run the server
  • list_tools() - Get list of registered tools
  • list_resources() - Get list of registered resources
  • list_prompts() - Get list of registered prompts

Types

MakeMCP provides several helpful type definitions:

  • ToolResult - Standard result format for tools
  • ResourceContent - Content returned by resources
  • PromptMessage - Message in a prompt template
  • Context - Execution context for tools
  • ServerConfig - Server configuration

Testing

MakeMCP includes a comprehensive test suite. Run tests using:

# Using the test runner script (auto-detects uv)
./run_tests.sh

# Using uv directly (fastest)
uv run pytest tests/ -v

# Using standard pytest
pytest tests/ -v

# Run specific test file
uv run pytest tests/test_factory.py -v

# Run with coverage
uv run pytest tests/ --cov=src/makemcp --cov-report=html

Dependency Management

MakeMCP uses smart dependency detection and can automatically use uv for faster installations:

Automatic Detection

When the MCP Factory detects missing dependencies, it will:

  1. Check if uv is available
  2. Use uv pip install if available (10-100x faster)
  3. Fall back to pip install if not

Example with Missing Dependencies

# If numpy is not installed, MakeMCP will detect it
import numpy as np

def calculate_mean(data: list) -> float:
    """Calculate mean using numpy."""
    return np.mean(data)

When running the factory:

$ mcp-factory my_module.py

Missing dependencies detected:
❌ Required: numpy

💡 Quick install: uv pip install numpy  # or pip install if uv not available

Managing Dependencies

For projects using MakeMCP:

# Fast dependency installation with uv
uv pip sync      # Install from requirements.txt
uv pip compile   # Generate locked requirements

# Or traditional pip
pip install -r requirements.txt

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

# Clone the repository
git clone https://github.com/leifmarkthaler/makemcp.git
cd makemcp

# Use the setup script (recommended)
./setup.sh

# Or manual setup with uv
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"

# Run tests
./run_tests.sh

License

MIT License - see LICENSE file for details.

Full Feature Set

All features MakeMCP supports
  • Tools - Functions that LLMs can call
  • Resources - Data/content LLMs can access
  • Prompts - Reusable prompt templates
  • Async/Await - Full async support
  • Type Safety - Automatic schema from type hints
  • Multiple Transports - stdio, SSE, more coming
  • Auto-discovery - Network and registry based
  • Factory System - Convert existing code instantly
  • Configuration - Safe, dev, and custom configs
  • Dependency Analysis - Smart missing package detection
  • UV Integration - 10-100x faster package management
  • Error Handling - Comprehensive error messages
  • Testing - Full test suite included
  • Examples - Many examples to learn from

Links

Important Notes

Official MCP SDK Compatibility

MakeMCP is specifically designed to work with the official MCP Python SDK (mcp package). It is not compatible with:

  • FastMCP or other third-party implementations
  • Older or experimental MCP libraries

The official SDK uses a handler-based approach for registering tools, resources, and prompts. MakeMCP provides a decorator-based interface that internally manages these handlers for you.

Acknowledgments

MakeMCP is built on top of the official MCP Python SDK and aims to make MCP server development more accessible and enjoyable.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

makemcp-0.1.0.tar.gz (305.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

makemcp-0.1.0-py3-none-any.whl (51.6 kB view details)

Uploaded Python 3

File details

Details for the file makemcp-0.1.0.tar.gz.

File metadata

  • Download URL: makemcp-0.1.0.tar.gz
  • Upload date:
  • Size: 305.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.14

File hashes

Hashes for makemcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c8c53a6b196b87b2d38275cb497e8fc65e1974320fff9fe836ca0848093a928c
MD5 ffd1f5e9838d489315a9d1427a1c5d57
BLAKE2b-256 e0f35e8591c14c633280fbd99182a65d709c31eb0596548c41274337c4766515

See more details on using hashes here.

File details

Details for the file makemcp-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: makemcp-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 51.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.14

File hashes

Hashes for makemcp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d557a95c9b0bbe1b6588a5482ee51559168ff1bdb9e7494821eab81bb33fff0c
MD5 6f690c91b7c3d8b97555a0927da1a09d
BLAKE2b-256 5489a84939d063adc4898588442686082e5feae12729eaf271be39789503d30f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page