enhanced-mcp-tools/examples/fastmcp_server_patterns.py
Ryan Malloy 8ff3775562 🚀 Major FastMCP 2.12.3 upgrade with ComponentService and BulkToolCaller integration
This massive update transforms Enhanced MCP Tools into a comprehensive workflow orchestration platform:

**Core Upgrades:**
- Updated FastMCP from 2.8.1 to 2.12.3 (latest release)
- Updated MCP SDK from 1.9.4 to 1.14.1
- Updated 29+ dependencies for compatibility

**New Features:**
- ComponentService integration with progressive tool disclosure
- SecurityManager with SACRED TRUST safety framework enhancement
- BulkToolCaller for workflow orchestration and batch operations
- Enhanced CLI with stdio default and explicit HTTP mode (--http flag)

**Security Enhancements:**
- Progressive tool disclosure (SAFE/CAUTION/DESTRUCTIVE levels)
- Safe mode enabled by default
- Destructive tools require explicit confirmation
- Mandatory dry-run validation for bulk operations
- Centralized security management across all modules

**Architecture Improvements:**
- Enhanced MCPBase with ComponentService integration
- Tool executor registry for bulk operations
- Backward compatibility with legacy modules
- Graceful fallback for missing ComponentService features

**Tool Count Expansion:**
- Total tools: 64+ (up from 50+)
- Categories: 16 (up from 14)
- New SecurityManager: 5 tools
- New BulkOperations: 8 tools

**Files Added:**
- src/enhanced_mcp/security_manager.py - Comprehensive security management
- src/enhanced_mcp/bulk_operations.py - Workflow orchestration system
- examples/ - Comprehensive integration guides and examples

**Files Modified:**
- pyproject.toml - FastMCP 2.12.3 dependency update
- src/enhanced_mcp/mcp_server.py - ComponentService integration
- src/enhanced_mcp/base.py - Enhanced MCPBase with security framework
- Multiple modules updated for ComponentService compatibility

All features tested and verified working. Server maintains stdio default behavior
for MCP clients while providing powerful workflow orchestration capabilities.
2025-09-22 17:15:02 -06:00

279 lines
8.6 KiB
Python

#!/usr/bin/env python3
"""
FastMCP Server Startup Patterns - Complete Reference Implementation
This example demonstrates the correct patterns for starting FastMCP servers
in both stdio and HTTP modes, with proper error handling and CLI integration.
🛡️ FastMCP Expert Architecture Pattern:
- Intelligent Transport Selection: Auto-detect transport based on arguments
- Progressive Disclosure: Security-first server initialization
- Mixin Composition: Modular tool registration with proper prefixes
- Production Ready: Comprehensive error handling and logging
"""
import argparse
import sys
from typing import Optional
from fastmcp import FastMCP
class ServerManager:
"""FastMCP Server Manager with intelligent transport selection"""
def __init__(self, name: str = "FastMCP Server"):
self.name = name
self.app: Optional[FastMCP] = None
def create_server(self) -> FastMCP:
"""Create and configure FastMCP server"""
if self.app is None:
self.app = FastMCP(self.name)
self._register_tools()
return self.app
def _register_tools(self):
"""Register example tools - replace with your actual tools"""
@self.app.tool
def hello_world(name: str = "World") -> str:
"""Say hello to someone"""
return f"Hello, {name}!"
@self.app.tool
def get_status() -> dict:
"""Get server status"""
return {
"name": self.name,
"status": "running",
"transport": "active"
}
def run_stdio(self) -> None:
"""Run server in stdio mode (for MCP clients like Claude Desktop)"""
try:
print(f"🚀 {self.name} - stdio mode", file=sys.stderr)
print("📋 Ready for MCP client communication", file=sys.stderr)
app = self.create_server()
app.run(transport="stdio")
except Exception as e:
print(f"❌ Stdio mode error: {e}", file=sys.stderr)
sys.exit(1)
def run_http(self,
host: str = "localhost",
port: int = 8000,
transport: str = "sse") -> None:
"""Run server in HTTP mode with specified transport
Args:
host: Host to bind to
port: Port to bind to
transport: HTTP transport type ("sse" or "streamable-http")
"""
try:
transport_name = {
"sse": "SSE (Server-Sent Events)",
"streamable-http": "Streamable HTTP"
}.get(transport, transport)
print(f"🚀 {self.name} - HTTP server", file=sys.stderr)
print(f"🌐 Server: http://{host}:{port}", file=sys.stderr)
print(f"📡 Transport: {transport_name}", file=sys.stderr)
app = self.create_server()
app.run(transport=transport, host=host, port=port)
except Exception as e:
print(f"❌ HTTP server error: {e}", file=sys.stderr)
sys.exit(1)
def get_package_version(self) -> str:
"""Get package version for startup banner"""
try:
from importlib.metadata import version
return version("enhanced-mcp-tools")
except:
return "1.0.0"
def create_cli_parser() -> argparse.ArgumentParser:
"""Create comprehensive CLI argument parser for FastMCP server"""
parser = argparse.ArgumentParser(
prog="fastmcp-server",
description="FastMCP Server with intelligent transport selection",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
FastMCP Transport Modes:
STDIO Mode (for MCP clients):
--stdio # Direct MCP protocol communication
HTTP Modes (for web/API access):
--transport sse # Server-Sent Events (recommended)
--transport streamable-http # Streamable HTTP responses
Examples:
%(prog)s --stdio # MCP client mode
%(prog)s --transport sse # HTTP with SSE (default)
%(prog)s --transport streamable-http # HTTP with streaming
%(prog)s --host 0.0.0.0 --port 8080 # Custom host/port
For uvx usage:
uvx my-fastmcp-server --stdio # Direct execution
"""
)
# Transport selection
transport_group = parser.add_mutually_exclusive_group()
transport_group.add_argument(
"--stdio",
action="store_true",
help="Run in stdio mode (for MCP clients like Claude Desktop)"
)
transport_group.add_argument(
"--transport",
choices=["sse", "streamable-http"],
default="sse",
help="HTTP transport type (default: sse)"
)
# Server configuration
parser.add_argument(
"--host",
default="localhost",
help="Host to bind to (default: localhost)"
)
parser.add_argument(
"--port",
type=int,
default=8000,
help="Port to bind to (default: 8000)"
)
parser.add_argument(
"--name",
default="FastMCP Server",
help="Server name (default: FastMCP Server)"
)
# Utility options
parser.add_argument(
"--version",
action="version",
version="FastMCP Server Patterns 1.0.0"
)
parser.add_argument(
"--list-tools",
action="store_true",
help="List available tools and exit"
)
return parser
async def list_tools_async(server_manager: ServerManager):
"""List all available tools asynchronously"""
try:
app = server_manager.create_server()
tools = await app.get_tools()
print(f"📋 {server_manager.name} - Available Tools:")
print("=" * 60)
for i, tool_name in enumerate(sorted(tools), 1):
print(f" {i:2d}. {tool_name}")
print(f"\n🎯 Total: {len(tools)} tools available")
print("\n💡 Usage:")
print(" --stdio # For MCP clients")
print(" --transport sse # HTTP with SSE")
except Exception as e:
print(f"❌ Failed to list tools: {e}", file=sys.stderr)
sys.exit(1)
def main():
"""Main entry point demonstrating FastMCP server patterns"""
parser = create_cli_parser()
args = parser.parse_args()
# Create server manager
server_manager = ServerManager(args.name)
# Handle list-tools option
if args.list_tools:
import asyncio
asyncio.run(list_tools_async(server_manager))
return
# Intelligent transport selection
try:
if args.stdio:
# stdio mode for MCP clients
server_manager.run_stdio()
else:
# HTTP mode with selected transport
server_manager.run_http(
host=args.host,
port=args.port,
transport=args.transport
)
except KeyboardInterrupt:
print(f"\n👋 Shutting down {server_manager.name}", file=sys.stderr)
sys.exit(0)
except Exception as e:
print(f"❌ Server startup failed: {e}", file=sys.stderr)
sys.exit(1)
# FastMCP Server Startup Pattern Reference
# =====================================
def demo_all_startup_patterns():
"""Demonstrate all FastMCP server startup patterns"""
# Pattern 1: Basic stdio mode
def pattern_stdio():
app = FastMCP("Demo Server")
app.run(transport="stdio")
# Pattern 2: HTTP with SSE transport (recommended)
def pattern_http_sse():
app = FastMCP("Demo Server")
app.run(transport="sse", host="localhost", port=8000)
# Pattern 3: HTTP with streamable transport
def pattern_http_streamable():
app = FastMCP("Demo Server")
app.run(transport="streamable-http", host="localhost", port=8000)
# Pattern 4: Async startup (for advanced use cases)
async def pattern_async():
app = FastMCP("Demo Server")
await app.run_async(transport="sse", host="localhost", port=8000)
# Pattern 5: Conditional transport selection
def pattern_intelligent_selection(use_stdio: bool = False):
app = FastMCP("Demo Server")
if use_stdio:
# For MCP clients
app.run(transport="stdio")
else:
# For HTTP clients
app.run(transport="sse", host="localhost", port=8000)
print("🛡️ FastMCP Expert Patterns:")
print("1. stdio: app.run(transport='stdio')")
print("2. HTTP SSE: app.run(transport='sse', host='host', port=port)")
print("3. HTTP Streamable: app.run(transport='streamable-http', host='host', port=port)")
print("4. Async: await app.run_async(transport='sse', ...)")
print("5. Intelligent Selection: Conditional based on args")
if __name__ == "__main__":
main()