mcp-builder

Build a working MCP server from a description of the tools you need. Produces a deployable Python server using FastMCP.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "mcp-builder" with this command: npx skills add jezweb/claude-skills/jezweb-claude-skills-mcp-builder

MCP Builder

Build a working MCP server from a description of the tools you need. Produces a deployable Python server using FastMCP.

Workflow

Step 1: Define What to Expose

Ask what the server needs to provide:

  • Tools -- Functions Claude can call (API wrappers, calculations, file operations)

  • Resources -- Data Claude can read (database records, config, documents)

  • Prompts -- Reusable prompt templates with parameters

A brief like "MCP server for querying our customer database" is enough.

Step 2: Scaffold the Server

pip install fastmcp

Create the server file. The server instance MUST be at module level:

from fastmcp import FastMCP

MUST be at module level for FastMCP Cloud

mcp = FastMCP("My Server")

@mcp.tool() async def search_customers(query: str) -> str: """Search customers by name or email.""" # Implementation here return f"Found customers matching: {query}"

@mcp.resource("customers://{customer_id}") async def get_customer(customer_id: str) -> str: """Get customer details by ID.""" return f"Customer {customer_id} details"

if name == "main": mcp.run()

Step 3: Add Companion CLI Scripts (Optional)

For Claude Code terminal use, add scripts alongside the MCP server:

my-mcp-server/ ├── src/index.ts # MCP server (for Claude.ai) ├── scripts/ │ ├── search.ts # CLI version of search tool │ └── _shared.ts # Shared auth/config ├── SCRIPTS.md # Documents available scripts └── package.json

CLI scripts provide file I/O, batch processing, and richer output that MCP can't. See assets/SCRIPTS-TEMPLATE.md and assets/script-template.ts for TypeScript templates.

Step 4: Test Locally

Quick test -- run directly:

python server.py

Dev mode with inspector UI (recommended):

fastmcp dev server.py

Opens inspector at http://localhost:5173

Hot reload, detailed logging, tool/resource inspection

HTTP mode for remote clients:

python server.py --transport http --port 8000

Automated test script using FastMCP Client:

import asyncio from fastmcp import Client

async def test_server(server_path): async with Client(server_path) as client: # List everything tools = await client.list_tools() resources = await client.list_resources() prompts = await client.list_prompts()

    print(f"Tools: {[t.name for t in tools]}")
    print(f"Resources: {[r.uri for r in resources]}")
    print(f"Prompts: {[p.name for p in prompts]}")

    # Call first tool
    if tools:
        result = await client.call_tool(tools[0].name, {})
        print(f"Tool result: {result}")

    # Read first resource
    if resources:
        data = await client.read_resource(resources[0].uri)
        print(f"Resource data: {data}")

asyncio.run(test_server("server.py"))

Step 5: Pre-Deploy Checklist

Run these checks before deploying. All required checks must pass.

Required (will cause deploy failure):

  • Server file exists

  • Python syntax valid: python3 -m py_compile server.py

  • Module-level server object (not inside a function): grep -q "^mcp = FastMCP|^server = FastMCP|^app = FastMCP" server.py

  • requirements.txt exists with PyPI packages only (no git+ , -e , .whl , .tar.gz )

  • No hardcoded secrets (check for api_key = "..." patterns excluding os.getenv /os.environ )

Advisory (warnings):

  • fastmcp listed in requirements.txt

  • .gitignore includes .env

  • No circular imports

  • Git repository initialised with remote

  • Server can load: timeout 5 fastmcp inspect server.py

Step 6: Deploy

FastMCP Cloud (simplest):

git add . && git commit -m "Ready for deployment" git push -u origin main

Visit https://fastmcp.cloud, connect repo, add env vars, deploy

URL: https://your-project.fastmcp.app/mcp

Cloud requirements:

  • Module-level server object named mcp , server , or app

  • PyPI dependencies only in requirements.txt

  • Public GitHub repository

  • Environment variables for secrets (no hardcoded values)

  • Auto-deploys on push to main, PR preview deployments

Docker (self-hosted):

FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . EXPOSE 8000 CMD ["python", "server.py", "--transport", "http", "--port", "8000"]

Cloudflare Workers (edge): See the cloudflare-worker-builder skill for Workers-based MCP servers.

Critical Patterns

Module-Level Server Instance

FastMCP Cloud requires the server instance at module level:

CORRECT

mcp = FastMCP("My Server")

@mcp.tool() def my_tool(): ...

WRONG -- Cloud can't find the server

def create_server(): mcp = FastMCP("My Server") return mcp

FIX for factory pattern -- export at module level

def create_server() -> FastMCP: mcp = FastMCP("server") return mcp mcp = create_server()

Type Annotations Required

FastMCP uses type annotations to generate tool schemas:

@mcp.tool() async def search( query: str, # Required parameter limit: int = 10, # Optional with default tags: list[str] = [] # Complex types supported ) -> str: """Docstring becomes the tool description.""" ...

Error Handling

Return errors as strings, don't raise exceptions:

@mcp.tool() async def get_data(id: str) -> str: try: result = await fetch_data(id) return json.dumps(result) except NotFoundError: return f"Error: No data found for ID {id}"

Cloud-Ready Server Pattern

import os from fastmcp import FastMCP

mcp = FastMCP("production-server") API_KEY = os.getenv("API_KEY")

@mcp.tool() async def production_tool(data: str) -> dict: if not API_KEY: return {"error": "API_KEY not configured"} return {"status": "success", "data": data}

if name == "main": mcp.run()

Common Errors and Fixes

These are the errors you will hit. Fix them before deploying.

Error Cause Fix

RuntimeError: No server object found at module level

Server inside a function Export mcp = FastMCP(...) at module level

RuntimeError: no running event loop

Missing async/await Use async def for async operations

TypeError: missing required argument 'context'

Context not type-hinted Add context: Context with type hint

ValueError: Invalid resource URI

Missing URI scheme Use data:// , file:// , info:// , api://

Resource template parameter mismatch Name mismatch user://{user_id} needs def get_user(user_id: str)

Pydantic validation error Wrong type hints Ensure hints match actual data types

Transport mismatch Client/server protocol differ Match both to stdio or both to http

Import errors with editable package Package not installed pip install -e . or add to PYTHONPATH

DeprecationWarning: mcp.settings

Old API Use os.getenv() instead

Port already in use Stale process lsof -ti:8000 | xargs kill -9

Schema generation failure Non-JSON types Use JSON-compatible types (no NumPy arrays)

JSON serialization error datetime/bytes in response Convert to .isoformat() or string

Circular import Factory in init.py

Use direct imports, avoid factory pattern

Python 3.12+ datetime warning datetime.utcnow() deprecated Use datetime.now(timezone.utc)

Import-time execution Async resource at module level Use lazy init pattern

Production Patterns

Self-Contained Server

Keep all utilities in one file to avoid circular imports:

from fastmcp import FastMCP import os

mcp = FastMCP("my-server")

Config

class Config: API_KEY = os.getenv("API_KEY", "") BASE_URL = os.getenv("BASE_URL", "https://api.example.com")

Helpers

def format_success(data): return {"status": "success", "data": data} def format_error(msg): return {"status": "error", "message": msg}

@mcp.tool() async def my_tool(query: str) -> dict: if not Config.API_KEY: return format_error("API_KEY not configured") return format_success({"query": query})

Lazy Initialisation

Don't create async resources at module level. Initialise on first use:

_db = None

async def get_db(): global _db if _db is None: _db = await create_connection(Config.DB_URL) return _db

Health Check Resource

@mcp.resource("health://status") async def health_check() -> dict: return { "status": "healthy", "version": "1.0.0", "checks": { "api": "connected", "database": "connected" } }

Connection Pooling

import httpx

_client = None

def get_client() -> httpx.AsyncClient: global _client if _client is None: _client = httpx.AsyncClient( base_url=Config.BASE_URL, headers={"Authorization": f"Bearer {Config.API_KEY}"}, limits=httpx.Limits(max_connections=20, max_keepalive_connections=5), timeout=30.0 ) return _client

Retry with Backoff

async def retry_with_backoff(func, max_retries=3, initial_delay=1.0): for attempt in range(max_retries): try: return await func() except Exception as e: if attempt == max_retries - 1: raise delay = initial_delay * (2 ** attempt) await asyncio.sleep(delay)

Context Features (Advanced)

Context Injection

from fastmcp import Context

@mcp.tool() async def tool_with_context(param: str, context: Context) -> dict: # Context parameter MUST have type hint pass

Progress Tracking

@mcp.tool() async def long_task(items: list[str], context: Context) -> str: for i, item in enumerate(items): await context.report_progress(i + 1, len(items), f"Processing {item}") await process(item) return "Done"

Sampling (LLM from within tools)

@mcp.tool() async def summarise(text: str, context: Context) -> str: result = await context.request_sampling( messages=[{"role": "user", "content": f"Summarise: {text}"}], max_tokens=200 ) return result

CLI Quick Reference

fastmcp dev server.py # Dev mode with inspector UI fastmcp run server.py # Run (stdio) fastmcp run server.py --transport http --port 8000 # Run (HTTP) fastmcp inspect server.py # Inspect without running fastmcp install server.py # Install to Claude Desktop fastmcp deploy server.py --name my-server # Deploy to Cloud

Environment variables: FASTMCP_LOG_LEVEL (DEBUG/INFO/WARNING/ERROR), FASTMCP_ENV (development/staging/production).

Integration Patterns (Optional)

For specific integration approaches, see references/integration-patterns.md :

  • Manual API -- httpx.AsyncClient with reusable client

  • OpenAPI auto-generation -- FastMCP.from_openapi(spec, client, route_maps=[...])

  • FastAPI conversion -- FastMCP.from_fastapi(app)

Asset Files

  • assets/basic-server.py -- Minimal FastMCP server template

  • assets/self-contained-server.py -- Server with storage and middleware

  • assets/tools-examples.py -- Tool patterns and type annotations

  • assets/resources-examples.py -- Resource URI patterns

  • assets/prompts-examples.py -- Prompt template patterns

  • assets/client-example.py -- MCP client usage

  • assets/SCRIPTS-TEMPLATE.md -- CLI companion docs template

  • assets/script-template.ts -- TypeScript CLI script template

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

github-release

No summary provided by upstream source.

Repository SourceNeeds Review
712-jezweb
Coding

agent-development

No summary provided by upstream source.

Repository SourceNeeds Review
361-jezweb
Coding

developer-toolbox

No summary provided by upstream source.

Repository SourceNeeds Review
360-jezweb
Coding

dev-session

No summary provided by upstream source.

Repository SourceNeeds Review
357-jezweb