Getting Started with MCP Development
Complete tutorial for building your first Model Context Protocol server - from basic concepts to production deployment
Capabilities
Features
Available Tools (2)
Simple greeting tool for testing MCP functionality
Return current time in various formats
Getting Started
Installation
# Install FastMCP framework
pip install fastmcp
# Create new MCP server project
mkdir my-mcp-server
cd my-mcp-server
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Basic Usage
# Basic server setup
from fastmcp import FastMCP
from fastmcp.tools import tool
app = FastMCP("my-server")
@tool()
def hello_world(name: str = "World") -> str:
"""Simple greeting tool"""
return f"Hello, {name}!"
if __name__ == "__main__":
app.run()
Getting Started with MCP Development
Ready to build your first Model Context Protocol (MCP) server? This comprehensive tutorial will take you from zero to production-ready MCP server in just a few steps.
π― What Youβll Learn
By the end of this tutorial, youβll have:
- Built a working MCP server with multiple tools
- Integrated it with Claude Code for real-world testing
- Implemented error handling and logging
- Deployed to production with proper configuration
- Understanding of MCP architecture and best practices
π Quick Start (5 Minutes)
Step 1: Environment Setup
# Create project directory
mkdir my-first-mcp-server
cd my-first-mcp-server
# Set up Python environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install fastmcp
Step 2: Create Your First Server
Create server.py
:
from fastmcp import FastMCP
from fastmcp.tools import tool
from datetime import datetime
import pytz
# Initialize the MCP server
app = FastMCP("my-first-server")
@tool()
def hello_world(name: str = "World") -> str:
"""A friendly greeting tool"""
return f"Hello, {name}! Welcome to MCP development!"
@tool()
def get_current_time(timezone: str = "UTC") -> str:
"""Get current time in specified timezone"""
try:
tz = pytz.timezone(timezone)
current_time = datetime.now(tz)
return current_time.strftime("%Y-%m-%d %H:%M:%S %Z")
except Exception as e:
return f"Error: {str(e)}"
@tool()
def calculate(expression: str) -> str:
"""Simple calculator (be careful with eval!)"""
try:
# In production, use a proper expression parser
result = eval(expression)
return f"{expression} = {result}"
except Exception as e:
return f"Error calculating '{expression}': {str(e)}"
if __name__ == "__main__":
app.run()
Step 3: Test Your Server
# Run the server
python server.py
# The server will start on the default port
# You should see: "MCP Server running on port 8000"
π§ Claude Code Integration
Configuration
Add your server to Claude Codeβs configuration:
{
"mcpServers": {
"my-first-server": {
"command": "python",
"args": ["path/to/your/server.py"],
"cwd": "/path/to/your/project"
}
}
}
Testing in Claude Code
Once configured, you can test your tools:
Hey Claude, can you use the hello_world tool to greet me?
What time is it in Tokyo using the get_current_time tool?
Calculate 42 * 1337 using the calculate tool.
ποΈ Advanced Features
Adding Resources
Resources provide read-only data that Claude can access:
from fastmcp.resources import resource
@resource("server-info")
def get_server_info():
"""Information about this MCP server"""
return {
"name": "My First MCP Server",
"version": "1.0.0",
"description": "A tutorial MCP server",
"tools_count": len(app.tools),
"uptime": app.get_uptime()
}
@resource("user-manual")
def get_user_manual():
"""User manual for this server"""
return """
# My First MCP Server
## Available Tools:
- hello_world: Greet users
- get_current_time: Get time in any timezone
- calculate: Simple arithmetic
## Examples:
- hello_world(name="Alice")
- get_current_time(timezone="America/New_York")
- calculate(expression="2 + 2")
"""
Error Handling & Logging
import logging
from fastmcp.types import McpError
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@tool()
def robust_tool(input_data: str) -> str:
"""Tool with proper error handling"""
try:
logger.info(f"Processing input: {input_data}")
# Your tool logic here
result = process_data(input_data)
logger.info(f"Successfully processed: {result}")
return result
except ValueError as e:
logger.error(f"Validation error: {e}")
raise McpError(f"Invalid input: {e}")
except Exception as e:
logger.error(f"Unexpected error: {e}")
raise McpError(f"Tool failed: {e}")
Configuration Management
import os
from typing import Optional
class ServerConfig:
def __init__(self):
self.debug = os.getenv("DEBUG", "false").lower() == "true"
self.api_key = os.getenv("API_KEY")
self.rate_limit = int(os.getenv("RATE_LIMIT", "100"))
def validate(self):
if not self.api_key:
raise ValueError("API_KEY environment variable required")
config = ServerConfig()
config.validate()
# Use configuration in tools
@tool()
def api_dependent_tool(query: str) -> str:
"""Tool that requires API access"""
if not config.api_key:
return "Error: API key not configured"
# Use the API key...
return f"Query processed: {query}"
π§ͺ Testing Your Server
Unit Tests
Create test_server.py
:
import pytest
from server import hello_world, get_current_time, calculate
def test_hello_world():
result = hello_world("Alice")
assert "Alice" in result
assert "Hello" in result
def test_hello_world_default():
result = hello_world()
assert "World" in result
def test_get_current_time():
result = get_current_time("UTC")
assert "UTC" in result
# Should include year
assert "2025" in result or "2024" in result
def test_calculate():
result = calculate("2 + 2")
assert "4" in result
def test_calculate_error():
result = calculate("invalid expression")
assert "Error" in result
# Run tests: pytest test_server.py
Integration Tests
import asyncio
from fastmcp.client import McpClient
async def test_server_integration():
"""Test the actual MCP server"""
async with McpClient("http://localhost:8000") as client:
# Test tool listing
tools = await client.list_tools()
assert len(tools) > 0
# Test tool execution
result = await client.call_tool("hello_world", {"name": "Test"})
assert "Test" in result
π Production Deployment
Environment Variables
Create .env
file:
# Server configuration
DEBUG=false
PORT=8000
LOG_LEVEL=INFO
# API keys (never commit these!)
API_KEY=your_secret_key_here
DATABASE_URL=postgresql://user:pass@localhost/db
# Rate limiting
RATE_LIMIT=1000
RATE_WINDOW=3600
Docker Deployment
Create Dockerfile
:
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# Create non-root user
RUN adduser --disabled-password --gecos '' appuser
RUN chown -R appuser:appuser /app
USER appuser
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
EXPOSE 8000
CMD ["python", "server.py"]
Production Server Code
from fastmcp import FastMCP
from fastmcp.middleware import rate_limit, logging_middleware
import os
# Production configuration
app = FastMCP(
name="my-production-server",
debug=os.getenv("DEBUG", "false").lower() == "true"
)
# Add middleware
app.add_middleware(rate_limit(
calls=int(os.getenv("RATE_LIMIT", "1000")),
window=int(os.getenv("RATE_WINDOW", "3600"))
))
app.add_middleware(logging_middleware())
# Health check endpoint
@app.route("/health")
def health_check():
return {"status": "healthy", "version": "1.0.0"}
# Your tools here...
if __name__ == "__main__":
port = int(os.getenv("PORT", "8000"))
app.run(host="0.0.0.0", port=port)
π Next Steps
Explore Advanced Patterns
- Check out the MCP Server Collection - 50+ production servers
- Read about Agent MCP Server - AI-powered recommendations
- Study Real-world Examples - Recursive AI development
Join the Community
- GitHub: MCP Server Collection
- Discord: MCP Developer Community
- Documentation: Official MCP Docs
Contributing
Found a bug? Want to contribute? The MCP ecosystem thrives on community involvement:
# Fork and clone the repository
git clone https://git.supported.systems/MCP/your-fork
cd your-fork
# Create a feature branch
git checkout -b feature/amazing-improvement
# Make your changes and test
pytest tests/
# Submit a pull request
git push origin feature/amazing-improvement
π Success Stories
Developers using this tutorial have built:
- Enterprise integrations serving thousands of users
- Personal productivity tools saving hours weekly
- Research platforms accelerating scientific discovery
- Creative tools enabling new forms of AI collaboration
Your turn! What will you build with MCP?
Ready to revolutionize how Claude interacts with your systems? Start building today!