Skip to main content
Glama
Red5d

Beszel MCP Server

by Red5d
WHY_FASTMCP.md6.93 kB
# Why FastMCP? This document explains why we use FastMCP and how it simplifies MCP server development. ## The Problem with Raw MCP SDK The raw MCP SDK is powerful but requires significant boilerplate: ```python # OLD WAY: Low-level MCP SDK (verbose) from mcp.server import Server from mcp.types import Tool, TextContent app = Server("beszel-mcp") @app.list_tools() async def list_tools() -> list[Tool]: return [ Tool( name="list_systems", description="List all monitored systems in Beszel...", inputSchema={ "type": "object", "properties": { "page": { "type": "number", "description": "Page number", "default": 1, }, "per_page": { "type": "number", "description": "Results per page", "default": 50, }, # ... more properties }, }, ), # ... more tools ] @app.call_tool() async def call_tool(name: str, arguments: Any) -> list[TextContent]: if name == "list_systems": result = await client.get_list( collection="systems", page=arguments.get("page", 1), per_page=arguments.get("per_page", 50), # ... ) return [TextContent(type="text", text=json.dumps(result, indent=2))] elif name == "list_containers": # ... more elif branches ``` **Problems:** - 🔴 Lots of boilerplate for tool definitions - 🔴 Manual JSON schema writing - 🔴 Complex if/elif chains for routing - 🔴 Manual response formatting - 🔴 Verbose type definitions - 🔴 Error-prone string matching ## The FastMCP Solution FastMCP provides a high-level, decorator-based API: ```python # NEW WAY: FastMCP (clean and simple) from fastmcp import FastMCP mcp = FastMCP("beszel-mcp") @mcp.tool() async def list_systems( page: int = 1, per_page: int = 50, filter: Optional[str] = None, sort: Optional[str] = None, ) -> dict: """List all monitored systems in Beszel. Args: page: Page number (default: 1) per_page: Number of results per page (default: 50) filter: PocketBase filter string sort: Sort order Returns: Dictionary containing paginated list of systems """ client = get_client() await ensure_authenticated(client) return await client.get_list( collection="systems", page=page, per_page=per_page, filter=filter, sort=sort, ) # That's it! No manual schema, no routing, no response formatting! ``` **Benefits:** - ✅ Clean decorator-based API - ✅ Automatic JSON schema generation from type hints - ✅ Direct return values (no manual TextContent wrapping) - ✅ Docstrings become tool descriptions - ✅ Type safety with Python types - ✅ Less code = fewer bugs ## Feature Comparison | Feature | Raw MCP SDK | FastMCP | |---------|-------------|---------| | Lines of code (for 6 tools) | ~300 | ~120 | | Tool definition | Manual JSON Schema | Type hints + decorators | | Routing | Manual if/elif | Automatic | | Response formatting | Manual TextContent | Automatic | | Documentation | Separate strings | From docstrings | | Type safety | Limited | Full Python typing | | Learning curve | Steep | Gentle | ## Code Reduction **Before (Raw MCP SDK):** - `server.py`: ~280 lines - Boilerplate: ~60% - Business logic: ~40% **After (FastMCP):** - `server.py`: ~180 lines - Boilerplate: ~20% - Business logic: ~80% **Result: 35% less code, much more readable!** ## What FastMCP Does For You ### 1. Automatic Schema Generation ```python # You write: async def query_system_stats( system_id: str, start_time: Optional[str] = None, page: int = 1, ) -> dict: """Query statistics for a system.""" pass # FastMCP generates: # { # "type": "object", # "properties": { # "system_id": {"type": "string"}, # "start_time": {"type": "string"}, # "page": {"type": "integer", "default": 1} # }, # "required": ["system_id"] # } ``` ### 2. Automatic Routing ```python # You write: @mcp.tool() async def list_systems(): pass @mcp.tool() async def list_containers(): pass # FastMCP automatically routes: # - Call to "list_systems" → list_systems() # - Call to "list_containers" → list_containers() ``` ### 3. Automatic Response Handling ```python # You write: return {"items": [...], "total": 42} # FastMCP converts to: # [TextContent(type="text", text='{"items": [...], "total": 42}')] ``` ### 4. Error Handling ```python # You write: raise ValueError("System not found") # FastMCP converts to proper MCP error response automatically ``` ## Developer Experience ### Raw MCP SDK ```python # Define tool (verbose) Tool(name="...", description="...", inputSchema={...}) # Implement handler (string matching) if name == "my_tool": # Extract args arg1 = arguments.get("arg1") arg2 = arguments.get("arg2", default) # Call logic result = await do_something(arg1, arg2) # Format response return [TextContent(type="text", text=json.dumps(result))] ``` ### FastMCP ```python # Everything in one place! @mcp.tool() async def my_tool(arg1: str, arg2: int = 42) -> dict: """Does something cool.""" return await do_something(arg1, arg2) ``` ## Running the Server ### Raw MCP SDK ```python async def main(): from mcp.server.stdio import stdio_server async with stdio_server() as (read_stream, write_stream): await app.run(read_stream, write_stream, app.create_initialization_options()) if __name__ == "__main__": import asyncio asyncio.run(main()) ``` ### FastMCP ```python if __name__ == "__main__": mcp.run() # That's it! ``` ## Additional FastMCP Features ### Development Mode ```bash # Interactive testing fastmcp dev src/beszel_mcp/server.py ``` ### Built-in CLI ```bash # Run production fastmcp run src/beszel_mcp/server.py # Install as tool fastmcp install src/beszel_mcp/server.py ``` ### Hot Reloading ```bash # Auto-restart on code changes fastmcp dev --reload src/beszel_mcp/server.py ``` ## Conclusion FastMCP is to MCP what Flask is to WSGI - a high-level framework that handles the boring parts so you can focus on your application logic. **Use FastMCP when:** - ✅ You want to build MCP servers quickly - ✅ You prefer clean, readable code - ✅ You want automatic schema generation - ✅ You value developer experience - ✅ You're building a new MCP server **Use raw MCP SDK when:** - ⚠️ You need fine-grained control over every detail - ⚠️ You're extending an existing low-level implementation - ⚠️ You need features not yet in FastMCP For 99% of use cases, **FastMCP is the better choice**.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Red5d/beszel-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server