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:

  1. Decorated each function with the @mcp.tool() decorator.

  2. Added docstrings to describe each function—this helps LLMs understand what the tool does.

  3. Configured the MCP server using Starlette and launched it with Uvicorn.

    • Starlette is a lightweight ASGI framework — great for async Python web services.
    • Uvicorn is an ASGI web server implementation that runs the app.

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:

  1. Install dependencies and start the server.
  2. 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.

  1. Create your project:
uv init mcp-stocks
cd mcp-stocks
  1. Install dependencies:
uv add yfinance
uv add 'mcp[cli]'
uv add starlette
uv add uvicorn
  1. Copy the above code into the main.py file and save it.

  2. 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.