A simple FastMCP-based server implementing a Hello World example with tools, resources, and prompts.
This is a minimal but fully representative MCP (Machine Conversation Protocol) server built using the fastmcp framework in Python. It serves as a demonstration of core MCP concepts and functionality.
The server includes:
-
Tools: Functions that can be called by agents
say_hello: Greets a user by name and logs the interactionget_greeting_log: Returns a list of previously greeted namesclear_log: Clears the greeting history
-
Resources: Shared state components
greetings://log: Resource URI that provides access to the greeting log
-
Prompts: Natural language instructions for agents
greet_user: Template for creating a prompt to greet someone
This project showcases a production-ready setup using Uvicorn as the ASGI server. Uvicorn offers several advantages:
- Performance: Uvicorn is built on uvloop (an asyncio event loop) and httptools for high performance
- Concurrency: Better handling of concurrent requests
- Production-ready: Suitable for production deployments with features like TLS support and process management
- Scaling: Can be placed behind a reverse proxy like Nginx for horizontal scaling
The integration works by:
- Creating an ASGI application from FastMCP using
mcp.sse_app() - Exposing this application to Uvicorn at
main:app - Running Uvicorn programmatically with appropriate settings
-
Create and activate a virtual environment
python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate
-
Install dependencies
pip install -r requirements.txt
-
Run the server
./setup_and_run.sh
The server will start on port 4242 with the MCP endpoint available at
/sse.
The setup script supports several options:
./setup_and_run.sh [options]Available options:
--no-uvicorn: Use the built-in FastMCP transport instead of Uvicorn--foreground: Run the server in the foreground (useful for debugging)--port=PORT: Specify a custom port (default: 4242)--host=HOST: Specify a custom host (default: 0.0.0.0)--help: Show all available options
Examples:
# Run in foreground mode for debugging
./setup_and_run.sh --foreground
# Run on a different port
./setup_and_run.sh --port=8000
# Run without Uvicorn (using built-in transport)
./setup_and_run.sh --no-uvicornThe server can run in two distinct modes:
-
Uvicorn Mode (Default)
./setup_and_run.sh
This mode uses Uvicorn as the ASGI server. You'll see log messages like:
INFO: Started server process [1234] INFO: Uvicorn running on http://0.0.0.0:4242 -
Built-in Transport Mode
./setup_and_run.sh --no-uvicorn
This mode uses FastMCP's built-in transport. You'll see log messages like:
[04/23/25 hh:mm:ss] INFO Starting server "Hello World MCP Server"...
You can quickly test the server with:
./test_server.shThis will start the server, run the test client, and then (optionally) shut down the server when testing is complete.
We provide a test client that demonstrates how to interact with the MCP server:
python test_client.pyThis will:
- Test available endpoints
- Connect to the SSE endpoint
- List available tools, resources, and prompts
- Execute each tool to demonstrate functionality
When you run the test client, you'll see output similar to this:
Testing raw endpoints:
/: 404
/tools: 404
/mcp: 404
/mcp/tools: 404
/mcp/message: 404
/sse: 200 OK
/api: 404
Created client for server at http://localhost:4242/sse
Client message path: http://localhost:4242/sse
Testing MCP Client...
1. Listing available tools:
- name='say_hello' description='Greet a person by name.' inputSchema={...}
- name='get_greeting_log' description='Get a list of all greeted names.' inputSchema={...}
- name='clear_log' description='Clear the greeting history.' inputSchema={...}
2. Testing say_hello tool:
Result: [TextContent(type='text', text='{"message": "Hello, Alice!"}', annotations=None)]
3. Testing get_greeting_log tool:
Result: [TextContent(type='text', text='{"names": ["Alice"]}', annotations=None)]
4. Testing greeting log resource:
Resource: [TextResourceContents(uri=AnyUrl('greetings://log'), mimeType='text/plain', text='{"greeted_names": ["Alice"]}')]
5. Testing clear_log tool:
Result: [TextContent(type='text', text='{"status": "cleared"}', annotations=None)]
6. Verifying log is cleared:
Result: [TextContent(type='text', text='{"names": []}', annotations=None)]
7. Listing available prompts:
- name='greet_user' description='Create a prompt for greeting someone.' arguments=[...]
8. Testing greet_user prompt:
Prompt: [PromptMessage(role='user', content=TextContent(type='text', text='\n Use the `say_hello` tool to greet Bob...')]
Key observations:
- Only the
/sseendpoint returns a 200 status code - this is normal and expected - Tool results come back as
TextContentobjects with JSON payloads - Resources are returned as
TextResourceContentsobjects with URIs and content - The greeting log stores and clears names correctly
- The prompt template generates a user message with instructions
The test client source (test_client.py) is commented and can be used as a reference for building your own MCP clients.
import asyncio
from fastmcp import Client
async def main():
async with Client("http://localhost:4242/sse") as client:
# List available tools
tools = await client.list_tools()
print(tools)
# Call a tool
result = await client.call_tool("say_hello", {"name": "Alice"})
print(result)
asyncio.run(main())Direct HTTP REST API calls are not supported. FastMCP uses a WebSocket-based protocol for client-server communication through Server-Sent Events (SSE).
This server demonstrates:
- Decorator-based API: Using decorators for tools, resources, and prompts
- Shared State: Maintaining state between requests using the GreetingLog
- SSE Transport: Using FastMCP's SSE transport for client communication
- Uvicorn Integration: Running as a production-ready ASGI server with Uvicorn
The server can run in two modes:
- Uvicorn mode (default): Uses Uvicorn's ASGI server for better performance and production readiness
- Built-in mode: Uses FastMCP's built-in server for simplicity
This project follows a modular architecture:
-
main.py: The core server definition with:
- FastMCP setup and configuration
- Tool, resource, and prompt definitions
- ASGI app initialization for Uvicorn
- Flexible runner that supports both Uvicorn and built-in modes
-
setup_and_run.sh: Deployment script with:
- Environment setup
- Port conflict detection
- Configurable runtime options
- Background/foreground process management
-
test_client.py: Client implementation that demonstrates:
- Endpoint discovery
- MCP client connection
- Tool and resource interaction
The key to the Uvicorn integration is in main.py:
# Create the ASGI app for Uvicorn to use
app = mcp.sse_app()
def run_server(use_uvicorn=True, host="0.0.0.0", port=4242):
"""Run the server using either Uvicorn or built-in transport."""
if use_uvicorn:
print(f"Starting server with Uvicorn on {host}:{port}")
uvicorn.run(
"main:app",
host=host,
port=port,
log_level="info"
)
else:
print(f"Starting server with built-in transport on port {port}")
mcp.run(transport="sse", host=host, port=port)- Server logs are saved to
server.log - Run in foreground mode for immediate feedback:
./setup_and_run.sh --foreground - The FastMCP client connects to the
/sseendpoint, not directly to tool paths - Data is exchanged via a message-based protocol, not standard REST
- You can identify which mode the server is running in by checking the logs:
- Uvicorn mode: "INFO: Uvicorn running on http://0.0.0.0:PORT"
- Built-in mode: "INFO: Starting server 'Hello World MCP Server'..."
Here's an updated section that includes both configuration options:
To configure Claude Desktop to use this MCP server, add one of the following configurations to your Claude Desktop configuration file:
- Windows:
%AppData%\Claude\claude_desktop_config.json - Mac:
~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"hello-world": {
"command": "python",
"args": [
"-m",
"main",
"--uvicorn"
],
"env": {},
"cwd": "/path/to/your/hello-world-mcp-server"
}
}
}If you've already started the server manually using ./setup_and_run.sh:
{
"mcpServers": {
"hello-world": {
"url": "http://localhost:4242/sse"
}
}
}After saving the configuration, restart Claude Desktop. You should see the hammer icon indicating MCP server availability. Click it to access the Hello World MCP tools.
For more information about MCP, see: