Now that I’ve shared why I love MCP and explored some of its fundamental building blocks, it’s time to roll up our sleeves and build a simple MCP server from scratch.

The goal here is to provide a gentle introduction to building MCP servers and demonstrate how powerful it is — without writing a lot of code.

For this post, I’ll focus on just one type of MCP server feature: Tools. I believe tool calling is the most exciting part of MCP.

Also, I’ll be writing the MCP server in Python.

So with that context, let’s dive right in.

The What

We’re going to build an MCP server that can:

  1. Fetch the real-time stock price for a given ticker symbol.
  2. Fetch historical stock splits for a given ticker symbol.

The How

We’ll implement each requirement as a tool call. Tool calling (also known as function calling) is how LLMs interact with MCP.

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}

This is a super simple implementation — just 17 lines of Python code. Notice how the function names are straightforward and self-explanatory. That’s one way to help the LLM understand how to interact with the MCP.

Step 2: Convert the Python Code to MCP Server

import yfinance as yf
from mcp.server.fastmcp import FastMCP

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}


if __name__ == "__main__":
    mcp.run(transport="stdio")

We did three key things here:

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

  2. Added docstrings to each function to provide clear descriptions. These help the LLM understand how to use the tool.

  3. Started the MCP server in stdio mode.

And that’s it — your MCP server is ready!

As you can see, developing an MCP server is incredibly straightforward.

Installation

Now, let’s install and run this.

Funny enough, installing this MCP server is more involved than building it. That’s because you need to package it in a way that Claude can load both the server and the required libraries: yfinance and mcp (the MCP Python SDK). I hope, and believe this will get easier in the coming months.

Step 1: Project Setup

If you’ve made it this far, I’ll assume you’re a programmer — or at least comfortable running commands in a terminal.

MCP documentation recommends using uv init to set up your MCP server. This isn’t mandatory — you can use poetry, or any other method — as long as you can provide Claude a command to launch the MCP server with its dependencies.

I’ll use uv init for this guide.

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

  2. Grab the venv Python path and use it to run main.py.

This is necessary so that the correct virtual environment (with all dependencies) is used:

echo "command: \"`pwd`/.venv/bin/python\""
echo "args: [\"`pwd`/main.py\"]"

Step 2: Configure Claude for Desktop

  1. Use the output in your Claude MCP Config.
{
    "mcpServers": {
      "stocks": {
        "command": "<replace-with-actual-python-path>",
        "args": [
            "<replace-with-actual-main-path>"
        ]
      }
    }
}

Once you restart Claude, you should be able to use both tools immediately.

Here’s a quick demo:

That’s it! You’ve built and deployed a working MCP server with real tools.