mcp hosted on a server and client app
In this post, we are going to host our mcp tool on a remote server and let it called by a client.
First ensure we have initialize the directory and added the right packages here
uv add fastmcp uvicorn
Then we will have our server.py where we will use uvicorn to host it and then expose /sse endpoint for client to call.
server.py
# server.py
import os
from fastmcp import FastMCP
# 1. Initialize FastMCP
mcp = FastMCP("Remote Centralized Tooling")
# 2. Define your tool(s)
@mcp.tool()
def calculate_server_metrics(cpu_load: float, memory_load: float) -> str:
"""Performs complex analysis on system performance metrics."""
# Since this lives entirely on your remote server, you can update this logic
# at any time, and local clients will get the updated behavior instantly.
score = (cpu_load * 0.7) + (memory_load * 0.3)
if score > 80:
return f"Warning: Server health score is critical ({score:.1f}%). Optimize immediately."
return f"Server health score is stable ({score:.1f}%)."
# 3. Expose the underlying ASGI app for Uvicorn
#app = mcp.streamable_http_app()
#app = mcp.http_app()
app = mcp.http_app(transport="sse")
# If run directly via `python server.py`, it boots via uvicorn
if __name__ == "__main__":
import uvicorn
# In production, change host to "0.0.0.0" and protect it behind a proxy/VPN
uvicorn.run("server.py:app", host="0.0.0.0", port=8000, reload=True)
And then here, client.py
import asyncio
from mcp import ClientSession
# Use the standard SSE client, no streamable dependencies
from mcp.client.sse import sse_client
async def run_remote_tool_locally():
# FastMCP's http_app() defaults to exposing the SSE stream at the /sse path
remote_url = "http://127.0.0.1:8000/sse"
print(f"Connecting to standard SSE server at {remote_url}...")
# sse_client yields a tuple of (read_stream, write_stream)
async with sse_client(remote_url) as (read_stream, write_stream):
# Initialize the session using the standard streams
async with ClientSession(read_stream, write_stream) as session:
# 1. Complete the handshake
await session.initialize()
print("Connection established!\n")
# 2. Dynamically fetch available tools over the network
tools_response = await session.list_tools()
print("--- Available Remote Tools ---")
for tool in tools_response.tools:
print(f"Tool Name: {tool.name} | Description: {tool.description}")
# 3. Call the tool execution remotely
print("\nExecuting remote tool...")
result = await session.call_tool(
name="calculate_server_metrics",
arguments={"cpu_load": 85.5, "memory_load": 72.0}
)
print(f"Result from remote server:\n{result.content[0].text}")
if __name__ == "__main__":
asyncio.run(run_remote_tool_locally())
To start the server run the following
uvicorn main:app --host 0.0.0.0 --port 8000
And then we initiate a client request by running
python client.py
Comments