The Model Context Protocol (MCP) enables seamless integration of contextual data into AI tools like Claude Desktop, enhancing their capabilities. In this guide, we'll walk through creating an MCP server using the fastapi-mcp package, integrated with FastAPI, to serve stock analysis endpoints. We'll use code from a stock analysis project, set up Claude Desktop on Windows, and demonstrate how to use the server with an example using the stock ACB

Table of Contents

Introduction

MCP servers provide structured data to AI models, making them more context-aware. The fastapi-mcp package extends FastAPI to support MCP, simplifying server creation. We'll build an MCP server based on the provided code from the Stock Price for Fun repository, expose stock analysis endpoints, and connect it to Claude Desktop on Windows.

Setting Up the Environment

Prepare your development environment with these steps:

  1. Install Python: Ensure Python 3.7+ is installed. Download from python.org.

  2. Install uv: The provided README uses uv for package management. Install it with:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
   set Path=%USERPROFILE%\.local\bin;%Path%
   uv tool install mcp-proxy

This installs uv and mcp-proxy, which proxies MCP requests.

  1. Install Dependencies: Install required packages using uv or pip:
uv pip install fastapi uvicorn fastapi-mcp pydantic pyyaml

Or with pip:

pip install fastapi uvicorn fastapi-mcp pydantic pyyaml
  • fastapi: Web framework for the API.
  • uvicorn: ASGI server to run the app.
  • fastapi-mcp: MCP integration for FastAPI.
  • pydantic, pyyaml: For data validation and config parsing.

Note: The stock analysis code requires additional dependencies (e.g., for PayBackTime, Stock). Refer to the Stock Price for Fun repo for a full list or setup a requirements.txt.

  1. Project Structure: Organize your project as follows:
project_root/
   ├── config/
   │   ├── config.yaml
   ├── src/
   │   ├── api.py
   │   ├── apis/
   │   │   ├── stock_apis.py
   │   ├── Utils/
   │   │   ├── utils.py

Ensure config.yaml exists with settings like:

api_host: 0.0.0.0
   api_port: 8668
   asset_data_path: path/to/asset/data
   pbt_params: [5, 20]  # Example: report_range, window_size
   motif_data_path: path/to/motif/data
   buy_sell_df_path: path/to/buy_sell/data
   win_loss_df_path: path/to/win_loss/data

Installing and Configuring Claude Desktop on Windows

To use the MCP server with Claude Desktop:

  1. Download Claude Desktop:
  • Visit Anthropic’s website or the official Claude Desktop download page.
  • Download the Windows installer (.exe or .msi).
  • Run the installer, follow prompts, and accept the license agreement.
  1. Launch Claude Desktop:
  • Open Claude Desktop from the Start menu or desktop shortcut.
  • Sign in with your Anthropic account. If you don’t have one, create an account at Anthropic.
  1. Configure MCP Settings:
  • Locate the configuration file at C:\Users\\AppData\Roaming\Claude\claude_desktop_config.json.

  • If it doesn’t exist, create it.

  • Add the MCP server configuration as per the README:

     {
         "mcpServers": {
           "filesystem": {
             "command": "npx",
             "args": [
               "-y",
               "@modelcontextprotocol/server-filesystem",
               "C:\\Users\\\\Desktop",
               "C:\\Users\\\\Downloads",
               "D:\\"
             ]
           }
     }
    
  • Save the file.

  • Ensure mcp-proxy is installed (via uv tool install mcp-proxy or equivalent).

  1. Verify Claude Desktop:
  • Restart Claude Desktop to load the new configuration.
  • Check if Claude recognizes the MCP server (this may depend on Claude’s UI; consult Anthropic’s documentation for details).

Building the FastAPI Application

Use the provided src/api.py to create the FastAPI application:

import sys
sys.path.append("")

from fastapi import FastAPI
import uvicorn
from fastapi_mcp import FastApiMCP
from src.apis.stock_apis import router as stocks_router
from src.apis.mcp_apis import router as mcp_router
from src.Utils.utils import config_parser

app = FastAPI(title="Stock Bot API", description="API for stock analysis and control panel operations")

# Include routers
app.include_router(stocks_router)
app.include_router(mcp_router)

# Read configuration
data = config_parser(data_config_path='config/config.yaml')

# Add MCP server to the FastAPI app
mcp = FastApiMCP(
    app,
    name="Item API MCP",
    description="MCP server for the Item API",
    base_url="http://localhost:8668",
)

mcp.mount()

mcp.setup_server()

if __name__ == "__main__":
    host = data.get('api_host', '0.0.0.0')
    port = data.get('api_port', 8000)
    uvicorn.run(app, host=host, port=port)

And src/apis/stock_apis.py for stock analysis endpoints (abridged for brevity, full code as provided):

import sys
sys.path.append("")

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from typing import List, Dict, Any
import os
from src.PayBackTime import PayBackTime, find_PBT_stocks
from src.stock_class import Stock
from src.motif import MotifMatching, BestMarketMotifSearch
from src.support_resist import SupportResistFinding
from src.trading_record import BuySellAnalyzer, WinLossAnalyzer, AssetAnalyzer
from src.summarize_text import NewsSummarizer, NewsScraper
from src.Utils.utils import filter_stocks, general_rating, config_parser, validate_symbol
from functools import wraps

router = APIRouter(prefix="/stocks", tags=["Stock Operations"])

data = config_parser(data_config_path='config/config.yaml')

class SymbolRequest(BaseModel):
    symbol: str

class PatternRequest(BaseModel):
    symbol: str
    start_date: str  # Format: YYYY-mm-dd

class NewsSummaryRequest(BaseModel):
    url: str

def validate_symbol_decorator(func):
    @wraps(func)
    async def wrapper(request: SymbolRequest | PatternRequest, *args, **kwargs):
        if not validate_symbol(request.symbol.upper()):
            raise HTTPException(status_code=400, detail=f"Invalid symbol: {request.symbol}")
        return await func(request, *args, **kwargs)
    return wrapper

@router.post(
    "/paybacktime",
    operation_id="calculate_payback_time",
)
@validate_symbol_decorator
async def get_paybacktime(request: SymbolRequest):
    """Calculates the payback-time price for a given stock symbol"""
    try:
        pbt_params = data.get('pbt_params')
        pbt_generator = PayBackTime(symbol=request.symbol.upper(), report_range=pbt_params[0], window_size=pbt_params[1])
        report = pbt_generator.get_report()
        return {"report": report}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error calculating payback time: {str(e)}")

@router.post(
    "/support-resistance",
    operation_id="find_support_resistance",
)
@validate_symbol_decorator
async def get_support_resistance(request: SymbolRequest):
    """Finds the closest support and resistance levels for a given stock symbol"""
    try:
        sr_finding = SupportResistFinding(symbol=request.symbol.upper())
        result = sr_finding.find_closest_support_resist(current_price=sr_finding.get_current_price())
        report = (
            f"The current price for {request.symbol.upper()} is {sr_finding.get_current_price()}\n"
            f"- The closest support is {round(result[0], 2)}\n"
            f"- The closest resistance is {round(result[1], 2)}\n"
        )
        return {"report": report}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error calculating support/resistance: {str(e)}")

# ... (other endpoints)

This code:

  • Sets up a FastAPI app with stock and MCP routers.
  • Loads configuration from config.yaml.
  • Defines endpoints like /stocks/paybacktime and /stocks/support-resistance for stock analysis.
  • Note: mcp_apis.py is assumed to exist for MCP-specific routes, as referenced in api.py.

Integrating fastapi-mcp

The src/api.py already integrates fastapi-mcp:

  • Initializes FastApiMCP with the app, name, description, and base_url="http://localhost:8668".
  • Calls mcp.mount() to add MCP routes (likely /mcp).
  • Calls mcp.setup_server() to configure the MCP server.
  • Runs on the host and port from config.yaml (defaults to 0.0.0.0:8000, but we’ll use 8668 to match the README).

Ensure the base_url and port align with the client configuration (http://localhost:8668/mcp).

Configuring the Client

Configure Claude Desktop to connect to the MCP server by editing C:\Users\\AppData\Roaming\Claude\claude_desktop_config.json:

{
    "mcpServers": {
      "filesystem": {
        "command": "npx",
        "args": [
          "-y",
          "@modelcontextprotocol/server-filesystem",
          "C:\\Users\\\\Desktop",
          "C:\\Users\\\\Downloads",
          "D:\\"
        ]
      },
      "paybacktime": {
        "command": "mcp-proxy",
        "args": ["http://127.0.0.1:8668/mcp"]
      }
    }
}
  • "paybacktime": Name of the MCP server entry.
  • "command": "mcp-proxy": Uses mcp-proxy to connect.
  • "args": Points to the MCP endpoint.

Restart Claude Desktop to apply changes.

Running the Server

Run the server from the project root:

python src/mcp_server.py

Note: The README mentions running mcp_server.py, but based on the provided code, it’s likely meant to be src/api.py. Update the command if your file is named differently:

python src/api.py

This starts the server on http://localhost:8668 (per config.yaml). Access:

  • API docs at http://localhost:8668/docs.
  • Stock endpoints at http://localhost:8668/stocks/*.
  • MCP endpoint at http://localhost:8668/mcp.

Example Usage and Results

Test the API using curl, Postman, or the FastAPI docs at http://localhost:8668/docs.

Key Endpoints

  1. POST /stocks/paybacktime:
  • Input: JSON with symbol (e.g., {"symbol": "ACB"}).
  • Output: Payback time analysis report.
  • Purpose: Analyzes the stock’s payback time based on financial metrics.
  1. POST /stocks/support-resistance:
  • Input: JSON with symbol.
  • Output: Current price, closest support, and resistance levels.
  • Purpose: Identifies key price levels for trading.
  1. GET /stocks/find-paybacktime-stocks:
  • Input: None.
  • Output: List of stocks meeting payback time criteria.
  • Purpose: Screens stocks with favorable payback times.

Testing the Paybacktime Endpoint

Test the /stocks/paybacktime endpoint for ACB:

curl -X POST "http://localhost:8668/stocks/paybacktime" -H "Content-Type: application/json" -d '{"symbol": "ACB"}'

Example Response (simplified, as actual output depends on PayBackTime.get_report()):

{
    "report": "Payback time for ACB: 3.5 years based on current financials."
}

The actual report will include detailed financial metrics, as implemented in the PayBackTime class.

Using with Claude Desktop

With Claude Desktop configured, it can query the MCP server via http://127.0.0.1:8668/mcp. For example, asking Claude to analyze ACB’s payback time would invoke /stocks/paybacktime, returning the report to enhance Claude’s response. The exact interaction depends on Claude’s UI (check Anthropic’s docs).

Here are the available tools for MCP:

MCP Tools

Example 1: ACB Stock Report

I asked Claude to generate a report for ACB stock using the MCP server to support its analysis.

ACB Stock Question

And the result

ACB Stock Report

Example 2: Payback Time Stocks Analysis

I requested Claude to identify and analyze all payback time stocks for today.

Payback Time Stocks

Conclusion

You’ve built an MCP server with fastapi-mcp, integrated stock analysis endpoints, and connected it to Claude Desktop on Windows. The server provides powerful stock analysis tools, like payback time and support/resistance, accessible via HTTP or MCP. Expand it with more endpoints from stock_apis.py or explore the Stock Price for Fun repo for advanced features.

References