Now that I’ve covered why remote MCP servers are such a game-changer—and what you should consider when building one—we’re ready to roll up our sleeves and write our first Remote MCP server.
In this post, I’ll show you how to build a simple Python-based MCP server using the HTTP+SSE standard (yes, the one that’s now deprecated). You might be wondering: Why use a deprecated protocol?
Good question. The reason is simple: Streamable HTTP support hasn’t been added to the Python SDK yet. But it’s coming soon. 💪
So with that context, let’s dive in.
The What
We’re going to build the same MCP server as before — but this time, using HTTP+SSE.
The server will support two capabilities: 1. Fetch the real-time stock price for a given ticker symbol. 2. Fetch the historical stock splits for a given ticker symbol.
The How
We’ll implement each feature as a tool call. Tool calling (aka function calling) is how LLMs interact with MCP servers.
Step 1: Define Tools as Python Functions
import yfinance as yf
def get_current_stock_price(ticker):
return {"currency": "USD", "value": yf.Ticker(ticker).info["open"]}
def get_historical_stock_splits(ticker):
history = []
for timestamp, ratio in yf.Ticker(ticker).splits.to_dict().items():
history.append(
{
"date": timestamp.strftime("%A, %B %d, %Y") + f", {timestamp.tzname()}",
"ratio": ratio,
}
)
return {"total": len(history), "history": history}
It’s a super simple implementation — just 17 lines of code. The function names are self-explanatory, which helps the LLM understand how to use them.
Step 2: Convert the Python Code to HTTP+SSE MCP Server
import uvicorn
import yfinance as yf
from mcp.server.fastmcp import FastMCP
from starlette.applications import Starlette
from starlette.routing import Mount
mcp = FastMCP("Stocks")
@mcp.tool()
def get_current_stock_price(ticker):
"""Get Current Stock Price for a given Ticker Symbol"""
return {"currency": "USD", "value": yf.Ticker(ticker).info["open"]}
@mcp.tool()
def get_historical_stock_splits(ticker):
"""Get list of historical stock splits"""
history = []
for timestamp, ratio in yf.Ticker(ticker).splits.to_dict().items():
history.append(
{
"date": timestamp.strftime("%A, %B %d, %Y") + f", {timestamp.tzname()}",
"ratio": ratio,
}
)
return {"total": len(history), "history": history}
app = Starlette(
routes=[
Mount("/", app=mcp.sse_app()),
]
)
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8000)
We did three key things here:
-
Decorated each function with the
@mcp.tool()
decorator. -
Added docstrings to describe each function—this helps LLMs understand what the tool does.
-
Configured the MCP server using Starlette and launched it with Uvicorn.
And that’s it — your MCP server is ready to go!
Sure, it’s a bit more complex than a stdio - based MCP server, but if you’ve ever built a web app, this should feel very familiar.
Installation
Now, Let’s install and run it.
In theory, setting up a remote MCP server should be even easier than a local one. However, Claude for Desktop doesn’t yet support remote MCP servers directly. That support will likely land once Anthropic launches its MCP Server Registry.
Until then, you’ll need a proxy/gateway to convert your HTTP+SSE MCP server into a stdio-compatible server Claude can communicate with.
Installing a Remote MCP server is a two step process:
- Install dependencies and start the server.
- Update Claude’s MCP configuration to point to the remote server via
mcp-remote
.
Step 1: Start the Remote MCP Server
If you’ve made it this far, I’ll assume you’re comfortable with the terminal.
While the MCP docs recommend using uv init
, you can use any method you like (poetry
, venv
, etc.). For this guide, I’ll stick with uv init.
- Create your project:
uv init mcp-stocks
cd mcp-stocks
- Install dependencies:
uv add yfinance
uv add 'mcp[cli]'
uv add starlette
uv add uvicorn
-
Copy the above code into the
main.py
file and save it. -
Start the server.
uv run python main.py
# INFO: Started server process [50176]
# INFO: Waiting for application startup.
# INFO: Application startup complete.
# INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
The MCP server is now running at http://localhost:8000/sse
.
Step 2: Configure Claude for Desktop
Update Claude MCP Config to include the remote MCP server::
{
"mcpServers": {
"todo": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:8080/sse"
]
}
}
}
Once you restart Claude for Desktop, the tools should be available immediately.
Here’s a quick demo:
And that’s it! 🎉
That’s it! You’ve just built and run a remote MCP server with real tools.