mcp-craft
A modern, lightweight, production-ready framework for building Model Context Protocol (MCP) servers in Python with a developer experience inspired by FastAPI.
mcp-craft wraps the official MCP Python SDK to offer tool discovery, dependency injection, middleware chains, authentication, schema validation, and framework integrations (FastAPI, Flask, Django) without reimplementing the protocol.
Features
- Declarative Tool Registration: Decorators (
@app.tool) on functions and classes with automatic Pydantic-based schema generation and validation. - FastAPI-like Dependency Injection: A lightweight, standalone DI engine supporting sync and async dependencies (
Depends). - Flexible Middleware Pipeline: Starlette-like async middleware with support for custom interceptors and built-in middlewares (
LoggingMiddleware,AuthenticationMiddleware,MetricsMiddleware,RateLimitMiddleware). - Structured Authentication Helpers: Easily secure your MCP server with API Keys, Bearer tokens, or custom callback functions.
- Rich Context Object: Expose execution context (
context.user,context.request,context.logger,context.metadata,context.storage) to all tools automatically. - Error Handling: Standard exception mapping that sanitizes tracebacks and converts Python errors to protocol-compliant MCP errors.
- Extensible Plugin System: Install reusable plugins (
app.install(plugin)) to hook into startup, shutdown, middlewares, or register dependencies and tools. - Integrations: Standalone runtime (via stdio) and first-class FastAPI, Flask, and Django integrations.
- Testing Utilities: A dedicated
TestMCPClientand mocking helpers for rapid tool testing without network layers.
Installation
pip install mcp-craft
Or install with integrations:
# For FastAPI / Starlette support
pip install "mcp-craft[fastapi]"
# For development / testing
pip install "mcp-craft[dev]"
Quick Start (Standalone / Stdio)
Creating a server is as simple as defining your application and registering your tools.
# server.py
import asyncio
from mcp_craft import MCPApplication
app = MCPApplication(
name="Math Server",
version="1.0.0",
description="Exposes basic mathematical tools"
)
@app.tool()
async def add(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
if __name__ == "__main__":
app.run()
Run it locally with:
python server.py
Dependency Injection
Inject shared components or services using Depends:
from mcp_craft import MCPApplication, Depends
app = MCPApplication(name="DI Server")
def get_db():
# Setup database connection
return {"conn": "active"}
async def get_current_user(context):
# Retrieve user from the execution context
return context.user
@app.tool()
async def fetch_profile(
user = Depends(get_current_user),
db = Depends(get_db)
):
"""Retrieve profile for the authenticated user."""
return {"username": user.get("name"), "status": "active", "db": db}
Middleware & Authentication
Add global logic like logging, metrics, rate-limiting, and authentication:
from mcp_craft import MCPApplication, APIKeyAuthentication
from mcp_craft.middleware import LoggingMiddleware, AuthenticationMiddleware, RateLimitMiddleware
app = MCPApplication(name="Secure Server")
# Configure authentication helper
auth_helper = APIKeyAuthentication(key="secret-token-123", header_name="x-api-key")
# Register middleware in order of execution
app.add_middleware(LoggingMiddleware)
app.add_middleware(AuthenticationMiddleware, auth_handler=auth_helper)
app.add_middleware(RateLimitMiddleware, limit=30, period=60.0) # 30 calls per minute
FastAPI Integration
Mount your MCP server onto a FastAPI app using the Server-Sent Events (SSE) protocol:
from fastapi import FastAPI
from mcp_craft import MCPApplication
from mcp_craft.integrations.fastapi import mount_mcp
import uvicorn
mcp_app = MCPApplication(name="Mounted Server")
@mcp_app.tool()
def hello(name: str) -> str:
"""Say hello."""
return f"Hello, {name}!"
app = FastAPI()
# This registers:
# GET /mcp/sse - SSE connection route
# POST /mcp/messages - Client message gateway
mount_mcp(app, mcp_app, path="/mcp")
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8000)
Testing Tools
Unit test your tools cleanly without running servers or network loops:
import pytest
from mcp_craft import MCPApplication
from mcp_craft.testing import TestMCPClient
app = MCPApplication(name="Test App")
@app.tool()
def square(x: int) -> int:
return x * x
@pytest.mark.asyncio
async def test_square():
client = TestMCPClient(app)
result = await client.call_tool("square", {"x": 5})
assert result.content[0].text == "25"
Development & Publishing
To package and build:
# Install packaging tool
pip install build hatch
# Build source distribution and wheel
python3 -m build
License
This project is licensed under the MIT License - see the LICENSE file for details.
Metadata
Release files for mcp-craft 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_craft-0.1.3.tar.gz | 74.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_craft-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 92.2 kB
Release files / mcp_craft-0.1.3.tar.gz
| Download URL | mcp_craft-0.1.3.tar.gz |
|---|---|
| Size | 74.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a9ceb10df69ed71d2b0f1bf26f88dda35ebb9a1785539b937fc4de58ff73416e
|
|
BLAKE2b-256 checksum How to use checksums |
2227a3f3289f87d93c14874f53295009013b3a8e1f04890a87a0f0d789b5b92e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|
Release files / mcp_craft-0.1.3-py3-none-any.whl
| Download URL | mcp_craft-0.1.3-py3-none-any.whl |
|---|---|
| Size | 17.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
762c9f8b986b168a084811d47e420c0bab7206768560ddc423f237a3fdd7e946
|
|
BLAKE2b-256 checksum How to use checksums |
a1b97707882d5483a60ab4c429901d707e310bd0afb3377c8aeed7b667c317a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.3
|