Sitemap

The Ultimate MCP Handbook: From Basics to Advanced LLM Integration

28 min readMay 15, 2025

Large Language Models (LLMs) like GPT or Claude are incredibly powerful at generating natural language text — but at their core, they’re just really good at predicting the next token in a sequence. Out of the box, they can’t fetch local files, run custom code, or interact with external APIs. So, how do we bridge the gap between this language intelligence and the real world?

That’s where the Model Context Protocol (MCP) comes in.

MCP is a fast-emerging standard designed to extend LLM capabilities beyond static conversations. It acts as a universal connector between AI systems and the outside world, enabling seamless interaction with tools, databases, APIs, and other services — much like how USB-C connects different devices in a plug-and-play fashion.

In this tutorial, we will explore MCP through a practical, beginner-friendly project. You will learn how to build a custom MCP server that connects an AI model to the Yahoo Finance API, empowering the model to fetch real-time stock prices, compare multiple stocks, and even perform historical trend analysis. By the end of this article, you will have a working MCP server and a solid foundation to build more advanced, real-world AI integrations.

Getting Started

Table of contents

What is MCP

Model Context Protocol (MCP) is a standardized approach for organizing, delivering, and processing context information to large language models (LLMs). It is designed to help models better understand and utilize the information provided to them in the prompt.

The key components of Model Context Protocol include:

  1. Structured formatting: Using a consistent format with clear section delineations (often XML-style tags) to organize different types of information.
  2. Information hierarchies: Arranging information by importance and relevance to help the model prioritize what matters most.
  3. Metadata tagging: Providing additional information about the context, such as source, reliability, or timestamp.
  4. Processing instructions: Explicit guidance on how the model should handle, interpret, or use specific pieces of information.

MCP is particularly useful for:

  • Complex applications where models need to process multiple types of information
  • Situations requiring specific handling of different context elements
  • Improving model performance by reducing ambiguity in how context should be used

By standardizing how context is presented to models, MCP aims to make AI interactions more reliable, consistent, and effective across different use cases and implementations.

How the MCP server works

Basically, the host handles the user interface, the MCP client routes requests, and the MCP server performs the actual tasks — acting as the operational backbone that enables LLMs to interact with real-world systems.

  • User Input: A user makes a request through the host application.
  • LLM Interpretation: The LLM processes the request and identifies if a corresponding MCP tool is available to fulfill it.
  • Client Routing: If a suitable tool is configured, the MCP client packages the request and forwards it using the MCP protocol to the MCP server.
  • Task Execution by Server:
  • The MCP server receives the request.
  • It then triggers the appropriate action — this could be:
  • Querying a local resource (e.g., a SQLite database)
  • Calling an external service (e.g., an email API, stock data API, or internal system)
  • Response Handling: The server processes the response from the tool and sends the result back to the MCP client.
  • LLM Response Generation: The LLM takes the returned result, integrates it into a natural language response, and sends it back to the user via the host application.

MCP Core functionalities

MCP servers provide three core functionalities.

  • Resources: Storing and Serving File-like Data

MCP resources function as read-only data sources that provide structured information to a Large Language Model (LLM). They are similar to REST API GET requests—exposing data without performing any computations.

These resources can be accessed by the LLM on demand.

@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"

This example defines a resource at greeting://{name} that returns a simple greeting string when accessed.

  • Tools: Functions Executed by the LLM

MCP tools allow the AI to perform specific tasks, similar to API POST requests. These functions can carry out computations, interact with databases, or call external APIs, enabling the LLM to go beyond static data and take meaningful actions.

@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers and return the result."""
return a + b

This tool calculates the BMI based on the user’s weight and height.

  • Prompts: Predefined Instruction Templates

MCP prompts are reusable templates that help the LLM carry out structured tasks consistently. These templates guide the model’s responses for common or complex request types.

@mcp.prompt()
def review_code(code: str) -> str:
return f"Please review this code:\n\n{code}"

This prompt helps the LLM respond in a structured manner when asked to perform a code review.

Building your first MCP server

Let’s build a local MCP server in Python that connects to an SQLite database to retrieve the top chatters in a community. You will interact with your LLM through tools like Cursor or Claude Desktop, while the MCP server handles all the backend database operations.

Installing uv

We will use uv, a fast and modern Python project manager, to set up and manage our environment. It simplifies tasks like handling dependencies, creating virtual environments, and running scripts.

To install uv, run this in your terminal:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

set Path=C:\Users\Codem\.local\bin;%Path%

Refer to the official website for detailed installation instructions.

Installing the dependencies

  • Initialize a uv project by executing the following command.
uv init mcp_demo
cd mcp_demo
  • Create and activate a virtual environment by executing the following command.
uv venv
source .venv/bin/activate # for linux
.venv\Scripts\activate # for windows
  • Install mcp SDK using pip. The mcp package includes both the server framework and optional CLI utilities. Installing it with the [cli] extra gives you access to helpful command-line tools.
uv add mcp[cli]
  • To confirm that the installation was successful, run:
mcp version

Example 1: Creating Your First MCP Server

Let’s begin by creating a simple calculator tool that adds two numbers.

  • Create a file named calculator.py inside the mcp_demo directory and insert the following code into it:
from mcp.server.fastmcp import FastMCP  # Import FastMCP, the quickstart server base

mcp = FastMCP("Calculator Server") # Initialize an MCP server instance with a descriptive name

@mcp.tool() # Register a function as a callable tool for the model
def add(a: int, b: int) -> int:
"""Add two numbers and return the result."""
return a + b

# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"

if __name__ == "__main__":
mcp.run(transport="stdio") # Run the server, using standard input/output for communication

This script sets up a basic MCP server with a single tool named add. The @mcp.tool() decorator registers the function with the MCP framework, making it accessible to connected LLMs.

  • You can test the mcp server using the following command.
mcp dev calculator.py

Once you run the MCP Inspector, you can access the interface in your browser at http://127.0.0.1:6274. The Inspector provides a user-friendly interface to view available tools and resources. It also allows you to interact with these tools directly using built-in UI controls.

Integrating your MCP server with Claude Desktop

To connect your MCP server to Claude, you’ll need to have Claude for Desktop installed.
You can download it from the official site: https://claude.ai/download

Follow the installation instructions provided for your operating system.

Adding Your MCP Server to Claude Desktop
Once Claude Desktop is installed, you can add your MCP server using the following command:

mcp install calculator.py

This registers your MCP server with Claude so it can be accessed from the desktop app.

Manual Configuration (Alternative Method)
If you would prefer to configure it manually, open the Claude configuration file by clicking Claude Desktop -> File -> Settings -> Developer -> Edit Config button.

  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

Then, add the following entry to the mcpServers section:

{
"mcpServers": {
"Calculator Server": {
"command": "C:\\Users\\Codem\\.local\\bin\\uv.EXE",
"args": [
"run",
" - with",
"mcp[cli]",
"mcp",
"run",
"Absolute path to calculator.py"
]
}
}
}

Replace “Absolute path to calculator.py” with the full path to your actual calculator.py MCP server script.

Testing MCP tool with Claude desktop

Restart the Claude Desktop application to see the MCP tool appear inside the IDE. Once it’s loaded, you will be able to use the tool directly within the interface.

Example 2: Interacting with SQLite database

In the previous example, we created an add tool and integrated it with Claude Desktop. However, it's important to note that such a basic arithmetic function may not be triggered by Claude, as simple calculations are already handled natively within the IDE and don’t require external processing.

Now, let’s move on to a more practical use case that demonstrates the true potential of MCP — retrieving data from a local source and making it accessible to the LLM for dynamic and context-aware interactions.

Get the Sample Database

Download the community.db file, which contains a chatters table with sample data. Once downloaded, move the database file into your project directory.

https://doimages.nyc3.cdn.digitaloceanspaces.com/006Community/MCP-server-python/community.db

Create SQLite MCP server

Create a new file called sqlite_server.py and add the following code to it.

# sqlite-server.py
from mcp.server.fastmcp import FastMCP
import sqlite3

# Initialize the MCP server with a name
mcp = FastMCP("Community Chatters")

# Define a tool to fetch the top chatters from the SQLite database
@mcp.tool()
def get_top_chatters():
"""Retrieve the top chatters sorted by number of messages."""
# Connect to the SQLite database
conn = sqlite3.connect('E:\\Experiments\\GenerativeAI\\MCP\\mcp_demo\\community.db')
cursor = conn.cursor()

# Execute the query to fetch chatters sorted by messages
cursor.execute("SELECT name, messages FROM chatters ORDER BY messages DESC")
results = cursor.fetchall()
conn.close()

# Format the results as a list of dictionaries
chatters = [{"name": name, "messages": messages} for name, messages in results]
return chatters

# Run the MCP server locally
if __name__ == '__main__':
mcp.run()

Make sure to provide the absolute path to the database in the sqlite3.connect() method. If you use a relative path, Claude Desktop may not be able to locate or access the database correctly.

  • Test the sqlite server using the following command.
mcp dev sqlite_server.py

Testing with Claude Desktop

First, integrate the SQLite MCP server with Claude by running the following command:

mcp install sqlite_server.py

Next, restart the Claude Desktop application. Once it’s running, you can begin asking questions related to the local database directly within the interface. When executing the SQLite server MCP, a prompt will appear requesting permission to run the MCP tool. Please approve the prompt to proceed.

Example 3: Using Pre-Built MCP Servers

Anthropic and its community provide a set of pre-built MCP servers that can be directly integrated with Claude Desktop or Cursor to enable this functionality in your application.

In this section, we will implement the File System and Git MCP servers.

File System

To enable filesystem functionality, we will install a pre-built Filesystem MCP server in Claude for Desktop.

  • Open the configuration file using any text editor and append the following content to the end of the file.
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/path/to/directory"
]
}
}
}

For instance, the sample configuration file look like this.

{
"mcpServers": {
"Calculator Server": {
"command": "C:\\Users\\Codem\\.local\\bin\\uv.EXE",
"args": [
"run",
"--with",
"mcp[cli]",
"mcp",
"run",
"E:\\Experiments\\GenerativeAI\\MCP\\mcp_demo\\calculator.py"
]
},
"Community Chatters": {
"command": "C:\\Users\\Codem\\.local\\bin\\uv.EXE",
"args": [
"run",
"--with",
"mcp[cli]",
"mcp",
"run",
"E:\\Experiments\\GenerativeAI\\MCP\\mcp_demo\\sqlite_server.py"
]
},
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"E:\\Experiments\\GenerativeAI\\MCP\\mcp_demo"
]
}
}
}
  • After updating the configuration file, restart Claude for Desktop to apply the changes. Once it’s running, you can begin asking questions related to the specified folder directly within the interface.

Git

Anthropic provides the mcp-server-git MCP server, which includes tools for reading, searching, and manipulating Git repositories using Large Language Models.

  • To enable git functionality, open the configuration file using any text editor and append the following content to the end of the file.
"mcpServers": {
"git": {
"command": "uvx",
"args": ["mcp-server-git", "--repository", "path/to/git/repo"]
}
}

Your application now has Git support enabled, allowing you to execute Git commands through Large Language Models (LLMs).

Example 4: Using a Python MCP Client

To perform a specific task programmatically, you can use the MCP Python SDK to create a client. In the earlier section, we created a simple tool (calculator.py) that adds two numbers. Now, let's use the MCP client to invoke the add tool and perform an addition operation.

  • Create a file named calculator_client.py and add the following code to it.
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client

# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="python", # Executable
args=["calculator.py"], # Optional command line arguments
env=None, # Optional environment variables
)

async def run():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Initialize the connection
await session.initialize()

# Call a tool
result = await session.call_tool("add", arguments={"a": 3, "b": 4})
print(f"Result of add tool: {result}")


if __name__ == "__main__":
import asyncio

asyncio.run(run())

To run the client, start the server in a terminal using the following command:

python calculator.py

Next, open another terminal and run the client using:

python calculator_client.py

Once both are running, you will see an output similar to the following:

Stock Price Comparison using MCP Server

In this section, we will build a custom MCP server using the Yahoo Finance Python API. The server will be capable of fetching real-time stock prices, performing comparisons, and providing historical data analysis.

Installing dependencies

This application is created inside the uv project (mcp_demo) which we created earlier. You can also create it as a separate project by initializing uv if required.

  • Install the YFinanace Python package using the PIP command.
pip install yfinance
  • Create a file named stock_price_server.py and add the following code to it.
from mcp.server.fastmcp import FastMCP
import yfinance as yf

# Create an MCP server with a custom name
mcp = FastMCP("Stock Price Server")

@mcp.tool()
def get_stock_price(symbol: str) -> float:
"""
Retrieve the current stock price for the given ticker symbol.
Returns the latest closing price as a float.
"""
try:
ticker = yf.Ticker(symbol)
# Get today's historical data; may return empty if market is closed or symbol is invalid.
data = ticker.history(period="1d")
if not data.empty:
# Use the last closing price from today's data
price = data['Close'].iloc[-1]
return float(price)
else:
# As a fallback, try using the regular market price from the ticker info
info = ticker.info
price = info.get("regularMarketPrice", None)
if price is not None:
return float(price)
else:
return -1.0 # Indicate failure
except Exception:
# Return -1.0 to indicate an error occurred when fetching the stock price
return -1.0

@mcp.resource("stock://{symbol}")
def stock_resource(symbol: str) -> str:
"""
Expose stock price data as a resource.
Returns a formatted string with the current stock price for the given symbol.
"""
price = get_stock_price(symbol)
if price < 0:
return f"Error: Could not retrieve price for symbol '{symbol}'."
return f"The current price of '{symbol}' is ${price:.2f}."

@mcp.tool()
def get_stock_history(symbol: str, period: str = "1mo") -> str:
"""
Retrieve historical data for a stock given a ticker symbol and a period.
Returns the historical data as a CSV formatted string.

Parameters:
symbol: The stock ticker symbol.
period: The period over which to retrieve historical data (e.g., '1mo', '3mo', '1y').
"""
try:
ticker = yf.Ticker(symbol)
data = ticker.history(period=period)
if data.empty:
return f"No historical data found for symbol '{symbol}' with period '{period}'."
# Convert the DataFrame to a CSV formatted string
csv_data = data.to_csv()
return csv_data
except Exception as e:
return f"Error fetching historical data: {str(e)}"

@mcp.tool()
def compare_stocks(symbol1: str, symbol2: str) -> str:
"""
Compare the current stock prices of two ticker symbols.
Returns a formatted message comparing the two stock prices.

Parameters:
symbol1: The first stock ticker symbol.
symbol2: The second stock ticker symbol.
"""
price1 = get_stock_price(symbol1)
price2 = get_stock_price(symbol2)
if price1 < 0 or price2 < 0:
return f"Error: Could not retrieve data for comparison of '{symbol1}' and '{symbol2}'."
if price1 > price2:
result = f"{symbol1} (${price1:.2f}) is higher than {symbol2} (${price2:.2f})."
elif price1 < price2:
result = f"{symbol1} (${price1:.2f}) is lower than {symbol2} (${price2:.2f})."
else:
result = f"Both {symbol1} and {symbol2} have the same price (${price1:.2f})."
return result

if __name__ == "__main__":
mcp.run()
  • Test the MCP server using the MCP Inspector by running the following command in your terminal.
mcp dev stock_price_server.py

You will receive an output similar to the following.

  • Integrate the stock price server with Claude for Desktop by running the following command:
mcp install stock_price_server.py --with yfinance

If your server has any dependencies that need to be installed, it is important to specify them using — with as arguments. This ensures that the necessary libraries and modules are installed before the server runs.

After the integration, restart Claude for Desktop to enable the new MCP server for stock price-related queries.

Building MCP Server for Stock Market Analysis

Manually performing stock market predictions and analysis can be a tedious and time-consuming task. Instead, imagine being able to simply ask: “What’s the RSI for MSFT right now?”

An MCP server can instantly fetch the latest stock data, calculate the RSI, and return the result — making it significantly easier to make informed trading decisions without switching between multiple apps and websites.

In this section, we will use the Alpha Vantage API (free tier) to pull real-time stock data and integrate it into an MCP server. This integration allows us to analyze stocks using custom-built AI tools.

Installing the dependencies

This application is created inside the uv project (mcp_demo) which we created earlier. You can also create it as a separate project by initializing uv if required.

  • For separate project, create a new uv project and add the dependencies using the following command.
# Create a new directory for our project
uv init finance
cd finance

# Create virtual environment and activate it
uv venv
.venv\Scripts\activate

# Install dependencies
uv add mcp[cli] requests pandas tabulate
  • For the existing project (mcp_demo), Install the MCP and httpx Python package using the PIP command.
pip install requests pandas tabulate

Fetching Stock Market Data Using the Alpha Vantage API

Alpha Vantage is a widely used service that provides both real-time and historical financial market data. It offers a range of APIs for accessing information on equities, currencies, cryptocurrencies, and more.

To begin using Alpha Vantage, you’ll need to sign up on their official website and obtain a free API key. The free tier allows up to 25 API requests per day. Once you have your API key, you can retrieve intraday stock price data using the TIME_SERIES_INTRADAY endpoint. This API returns time series data with key metrics such as open, high, low, close, and volume, updated in real time.

To make a request, you’ll need to specify:

  • The stock symbol (e.g., MSFT)
  • The interval between data points (1min, 5min, 15min, 30min, or 60min)
  • Your API key

Example API Call (5-minute interval for MSFT):

https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=5min&apikey=YOUR_API_KEY

This call returns the latest 5-minute interval data for the Microsoft stock, which you can then parse and use in your application or analysis workflow.

Implementing MCP Tools for Stock Analysis

Let's implement the MCP tool for stock analysis. This MCP server will create tools for moving averages, Relative Strength Index and Trade Recommendation.

Tool 1: Moving Averages

Moving averages are used in stock analysis to smooth price data and identify trends.

  • Short-term averages (5–10 days) react quickly and highlight recent market shifts.
  • Long-term averages (50–200 days) change slowly and reveal broader, sustained trends.

Implementing tool for calculating moving averages.

@mcp.tool()
def calculate_moving_averages(symbol: str, short_period: int = 20, long_period: int = 50) -> Dict[str, Any]:
"""
Calculate short and long moving averages for a symbol

Args:
symbol: The ticker symbol to analyze
short_period: Short moving average period in minutes
long_period: Long moving average period in minutes

Returns:
Dictionary with moving average data and analysis
"""
cache_key = f"{symbol}_1min"

if cache_key not in market_data_cache:
df = AlphaVantageAPI.get_intraday_data(symbol, "1min", outputsize="full")
market_data_cache[cache_key] = MarketData(
symbol=symbol,
interval="1min",
data=df,
last_updated=datetime.now()
)

data = market_data_cache[cache_key].data

# Calculate moving averages
data[f'SMA{short_period}'] = data['close'].rolling(window=short_period).mean()
data[f'SMA{long_period}'] = data['close'].rolling(window=long_period).mean()

# Get latest values
latest = data.iloc[-1]
current_price = latest['close']
short_ma = latest[f'SMA{short_period}']
long_ma = latest[f'SMA{long_period}']

# Determine signal
if short_ma > long_ma:
signal = "BULLISH (Short MA above Long MA)"
elif short_ma < long_ma:
signal = "BEARISH (Short MA below Long MA)"
else:
signal = "NEUTRAL (MAs are equal)"

# Check for crossover in the last 5 periods
last_5 = data.iloc[-5:]
crossover = False
crossover_type = ""

for i in range(1, len(last_5)):
prev = last_5.iloc[i-1]
curr = last_5.iloc[i]

# Golden Cross (short crosses above long)
if prev[f'SMA{short_period}'] <= prev[f'SMA{long_period}'] and curr[f'SMA{short_period}'] > curr[f'SMA{long_period}']:
crossover = True
crossover_type = "GOLDEN CROSS (Bullish)"
break

# Death Cross (short crosses below long)
if prev[f'SMA{short_period}'] >= prev[f'SMA{long_period}'] and curr[f'SMA{short_period}'] < curr[f'SMA{long_period}']:
crossover = True
crossover_type = "DEATH CROSS (Bearish)"
break

return {
"symbol": symbol,
"current_price": current_price,
f"SMA{short_period}": short_ma,
f"SMA{long_period}": long_ma,
"signal": signal,
"crossover_detected": crossover,
"crossover_type": crossover_type if crossover else "None",
"analysis": f"""Moving Average Analysis for {symbol}:
Current Price: ${current_price:.2f}
{short_period}-period SMA: ${short_ma:.2f}
{long_period}-period SMA: ${long_ma:.2f}
Signal: {signal}
Recent Crossover: {"Yes - " + crossover_type if crossover else "No"}

Recommendation: {
"STRONG BUY" if crossover and crossover_type == "GOLDEN CROSS (Bullish)" else
"BUY" if signal == "BULLISH (Short MA above Long MA)" else
"STRONG SELL" if crossover and crossover_type == "DEATH CROSS (Bearish)" else
"SELL" if signal == "BEARISH (Short MA below Long MA)" else
"HOLD"
}"""
}

Tool 2: Relative Strength Index (RSI)

The Relative Strength Index (RSI) is a momentum indicator that helps identify overbought (RSI > 70) or oversold (RSI < 30) conditions in an asset. Calculated over a typical 14-day period, it uses the ratio of average gains to losses to assess the speed and change of price movements, aiding in better trading decisions.

Implementing tool for calculating RSI.

@mcp.tool()
def calculate_rsi(symbol: str, period: int = 14) -> Dict[str, Any]:
"""
Calculate Relative Strength Index (RSI) for a symbol

Args:
symbol: The ticker symbol to analyze
period: RSI calculation period in minutes

Returns:
Dictionary with RSI data and analysis
"""
cache_key = f"{symbol}_1min"

if cache_key not in market_data_cache:
df = AlphaVantageAPI.get_intraday_data(symbol, "1min", outputsize="full")
market_data_cache[cache_key] = MarketData(
symbol=symbol,
interval="1min",
data=df,
last_updated=datetime.now()
)

data = market_data_cache[cache_key].data.copy()

# Calculate price changes
delta = data['close'].diff()

# Create gain and loss series
gain = delta.copy()
loss = delta.copy()
gain[gain < 0] = 0
loss[loss > 0] = 0
loss = abs(loss)

# Calculate average gain and loss
avg_gain = gain.rolling(window=period).mean()
avg_loss = loss.rolling(window=period).mean()

# Calculate RS and RSI
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))

# Get latest RSI
latest_rsi = rsi.iloc[-1]

# Determine signal
if latest_rsi < 30:
signal = "OVERSOLD (Potential buy opportunity)"
elif latest_rsi > 70:
signal = "OVERBOUGHT (Potential sell opportunity)"
else:
signal = "NEUTRAL"

return {
"symbol": symbol,
"period": period,
"rsi": latest_rsi,
"signal": signal,
"analysis": f"""RSI Analysis for {symbol}:
{period}-period RSI: {latest_rsi:.2f}
Signal: {signal}

Recommendation: {
"BUY" if latest_rsi < 30 else
"SELL" if latest_rsi > 70 else
"HOLD"
}"""
}

Tool 3: Trade Recommendation

This tool aggregates insights from both the moving average and RSI indicators to provide a clear recommendation on whether to buy, hold, or sell an asset.

@mcp.tool()
def trade_recommendation(symbol: str) -> Dict[str, Any]:
"""
Provide a comprehensive trade recommendation based on multiple indicators

Args:
symbol: The ticker symbol to analyze

Returns:
Dictionary with trading recommendation and supporting data
"""
# Calculate individual indicators
ma_data = calculate_moving_averages(symbol)
rsi_data = calculate_rsi(symbol)

# Extract signals
ma_signal = ma_data["signal"]
ma_crossover = ma_data["crossover_detected"]
ma_crossover_type = ma_data["crossover_type"]
rsi_value = rsi_data["rsi"]
rsi_signal = rsi_data["signal"]

# Determine overall signal strength
signal_strength = 0

# MA contribution
if "BULLISH" in ma_signal:
signal_strength += 1
elif "BEARISH" in ma_signal:
signal_strength -= 1

# Crossover contribution
if ma_crossover:
if "GOLDEN" in ma_crossover_type:
signal_strength += 2
elif "DEATH" in ma_crossover_type:
signal_strength -= 2

# RSI contribution
if "OVERSOLD" in rsi_signal:
signal_strength += 1.5
elif "OVERBOUGHT" in rsi_signal:
signal_strength -= 1.5

# Determine final recommendation
if signal_strength >= 2:
recommendation = "STRONG BUY"
elif signal_strength > 0:
recommendation = "BUY"
elif signal_strength <= -2:
recommendation = "STRONG SELL"
elif signal_strength < 0:
recommendation = "SELL"
else:
recommendation = "HOLD"

# Calculate risk level (simple version)
risk_level = "MEDIUM"
if abs(signal_strength) > 3:
risk_level = "LOW" # Strong signal, lower risk
elif abs(signal_strength) < 1:
risk_level = "HIGH" # Weak signal, higher risk

analysis = f"""# Trading Recommendation for {symbol}

## Summary
Recommendation: {recommendation}
Risk Level: {risk_level}
Signal Strength: {signal_strength:.1f} / 4.5

## Technical Indicators
Moving Averages: {ma_signal}
Recent Crossover: {"Yes - " + ma_crossover_type if ma_crossover else "No"}
RSI ({rsi_data["period"]}): {rsi_value:.2f} - {rsi_signal}

## Reasoning
This recommendation is based on a combination of Moving Average analysis and RSI indicators.
{
f"The {ma_crossover_type} provides a strong directional signal. " if ma_crossover else ""
}{
f"The RSI indicates the stock is {rsi_signal.split(' ')[0].lower()}. " if "NEUTRAL" not in rsi_signal else ""
}

## Action Plan
{
"Consider immediate entry with a stop loss at the recent low. Target the next resistance level." if recommendation == "STRONG BUY" else
"Look for a good entry point on small dips. Set reasonable stop loss." if recommendation == "BUY" else
"Consider immediate exit or setting tight stop losses to protect gains." if recommendation == "STRONG SELL" else
"Start reducing position on strength or set trailing stop losses." if recommendation == "SELL" else
"Monitor the position but no immediate action needed."
}
"""

return {
"symbol": symbol,
"recommendation": recommendation,
"risk_level": risk_level,
"signal_strength": signal_strength,
"ma_signal": ma_signal,
"rsi_signal": rsi_signal,
"current_price": ma_data["current_price"],
"analysis": analysis
}

Prompt 1: Analyze a Single Ticker

@mcp.prompt()
def analyze_ticker(symbol: str) -> str:
"""
Analyze a ticker symbol for trading opportunities
"""
return f"""You are a professional stock market analyst. I would like you to analyze the stock {symbol} and provide trading insights.

Start by examining the current market data and technical indicators. Here are the specific tasks:

1. First, check the current market data for {symbol}
2. Calculate the moving averages using the calculate_moving_averages tool
3. Calculate the RSI using the calculate_rsi tool
4. Generate a comprehensive trade recommendation using the trade_recommendation tool
5. Based on all this information, provide your professional analysis, highlighting:
- The current market position
- Key technical indicators and what they suggest
- Potential trading opportunities and risks
- Your recommended action (buy, sell, or hold) with a brief explanation

Please organize your response in a clear, structured format suitable for a professional trader.
"""

Prompt 2: Compare Multiple Tickers

@mcp.prompt()
def compare_tickers(symbols: str) -> str:
"""
Compare multiple ticker symbols for the best trading opportunity

Args:
symbols: Comma-separated list of ticker symbols
"""
symbol_list = [s.strip() for s in symbols.split(",")]
symbol_section = "\n".join([f"- {s}" for s in symbol_list])

return f"""You are a professional stock market analyst. I would like you to compare these stocks and identify the best trading opportunity:

{symbol_section}

For each stock in the list, please:

1. Check the current market data using the appropriate resource
2. Generate a comprehensive trade recommendation using the trade_recommendation tool
3. Compare all stocks based on:
- Current trend direction and strength
- Technical indicator signals
- Risk/reward profile
- Trading recommendation strength

After analyzing each stock, rank them from most promising to least promising trading opportunity. Explain your ranking criteria and why you believe the top-ranked stock represents the best current trading opportunity.

Conclude with a specific recommendation on which stock to trade and what action to take (buy, sell, or hold).
"""

Prompt 3: Build an Intraday Trading Strategy

@mcp.prompt()
def intraday_strategy_builder(symbol: str) -> str:
"""
Build a custom intraday trading strategy for a specific ticker
"""
return f"""You are an expert algorithmic trader specializing in intraday strategies. I want you to develop a custom intraday trading strategy for {symbol}.

Please follow these steps:

1. First, analyze the current market data for {symbol} using the market-data resource
2. Calculate relevant technical indicators:
- Moving averages (short and long periods)
- RSI
3. Based on your analysis, design an intraday trading strategy that includes:
- Specific entry conditions (technical setups that would trigger a buy/sell)
- Exit conditions (both take-profit and stop-loss levels)
- Position sizing recommendations
- Optimal trading times during the day
- Risk management rules

Make your strategy specific to the current market conditions for {symbol}, not just generic advice. Include exact indicator values and price levels where possible.

Conclude with a summary of the strategy and how a trader should implement it for today's trading session.
"""

Complete Code for Stock Market Analysis

  • Create a file named stock_analysis_server.py to implement the MCP server. Add the following code to it.
# stock_analysis_server.py
from mcp.server.fastmcp import FastMCP
import requests
import pandas as pd
from dataclasses import dataclass
from datetime import datetime
from typing import Dict, Any

# Create the MCP server
mcp = FastMCP("Stock Analysis Server", dependencies=["requests", "pandas", "tabulate"])

# Constants and configurations
API_KEY = "6BZ33KPJPJ09AQAP" # Replace with your actual AlphaVantage API key

@dataclass
class MarketData:
symbol: str
interval: str
data: pd.DataFrame
last_updated: datetime

class AlphaVantageAPI:
@staticmethod
def get_intraday_data(symbol: str, interval: str = "1min", outputsize: str = "compact") -> pd.DataFrame:
"""Fetch intraday data from AlphaVantage API"""
url = f"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol={symbol}&interval={interval}&outputsize={outputsize}&apikey={API_KEY}"

response = requests.get(url)
data = response.json()

# Check for error responses
if "Error Message" in data:
raise ValueError(f"API Error: {data['Error Message']}")
if "Note" in data:
print(f"API Note: {data['Note']}")

# Extract time series data
time_series_key = f"Time Series ({interval})"
if time_series_key not in data:
raise ValueError(f"No time series data found for {symbol} with interval {interval}")

time_series = data[time_series_key]

# Convert to DataFrame
df = pd.DataFrame.from_dict(time_series, orient="index")
df.index = pd.to_datetime(df.index)
df = df.sort_index()

# Rename columns and convert to numeric
df.columns = [col.split(". ")[1] for col in df.columns]
for col in df.columns:
df[col] = pd.to_numeric(df[col])

return df

# In-memory cache for market data
market_data_cache: Dict[str, MarketData] = {}

# Resources
@mcp.resource("config://app")
def get_config() -> str:
"""Static configuration data"""
return "App configuration here"

# Technical Analysis Tools
@mcp.tool()
def calculate_moving_averages(symbol: str, short_period: int = 20, long_period: int = 50) -> Dict[str, Any]:
"""
Calculate short and long moving averages for a symbol

Args:
symbol: The ticker symbol to analyze
short_period: Short moving average period in minutes
long_period: Long moving average period in minutes

Returns:
Dictionary with moving average data and analysis
"""
cache_key = f"{symbol}_1min"

if cache_key not in market_data_cache:
df = AlphaVantageAPI.get_intraday_data(symbol, "1min", outputsize="full")
market_data_cache[cache_key] = MarketData(
symbol=symbol,
interval="1min",
data=df,
last_updated=datetime.now()
)

data = market_data_cache[cache_key].data

# Calculate moving averages
data[f'SMA{short_period}'] = data['close'].rolling(window=short_period).mean()
data[f'SMA{long_period}'] = data['close'].rolling(window=long_period).mean()

# Get latest values
latest = data.iloc[-1]
current_price = latest['close']
short_ma = latest[f'SMA{short_period}']
long_ma = latest[f'SMA{long_period}']

# Determine signal
if short_ma > long_ma:
signal = "BULLISH (Short MA above Long MA)"
elif short_ma < long_ma:
signal = "BEARISH (Short MA below Long MA)"
else:
signal = "NEUTRAL (MAs are equal)"

# Check for crossover in the last 5 periods
last_5 = data.iloc[-5:]
crossover = False
crossover_type = ""

for i in range(1, len(last_5)):
prev = last_5.iloc[i-1]
curr = last_5.iloc[i]

# Golden Cross (short crosses above long)
if prev[f'SMA{short_period}'] <= prev[f'SMA{long_period}'] and curr[f'SMA{short_period}'] > curr[f'SMA{long_period}']:
crossover = True
crossover_type = "GOLDEN CROSS (Bullish)"
break

# Death Cross (short crosses below long)
if prev[f'SMA{short_period}'] >= prev[f'SMA{long_period}'] and curr[f'SMA{short_period}'] < curr[f'SMA{long_period}']:
crossover = True
crossover_type = "DEATH CROSS (Bearish)"
break

return {
"symbol": symbol,
"current_price": current_price,
f"SMA{short_period}": short_ma,
f"SMA{long_period}": long_ma,
"signal": signal,
"crossover_detected": crossover,
"crossover_type": crossover_type if crossover else "None",
"analysis": f"""Moving Average Analysis for {symbol}:
Current Price: ${current_price:.2f}
{short_period}-period SMA: ${short_ma:.2f}
{long_period}-period SMA: ${long_ma:.2f}
Signal: {signal}
Recent Crossover: {"Yes - " + crossover_type if crossover else "No"}

Recommendation: {
"STRONG BUY" if crossover and crossover_type == "GOLDEN CROSS (Bullish)" else
"BUY" if signal == "BULLISH (Short MA above Long MA)" else
"STRONG SELL" if crossover and crossover_type == "DEATH CROSS (Bearish)" else
"SELL" if signal == "BEARISH (Short MA below Long MA)" else
"HOLD"
}"""
}

@mcp.tool()
def calculate_rsi(symbol: str, period: int = 14) -> Dict[str, Any]:
"""
Calculate Relative Strength Index (RSI) for a symbol

Args:
symbol: The ticker symbol to analyze
period: RSI calculation period in minutes

Returns:
Dictionary with RSI data and analysis
"""
cache_key = f"{symbol}_1min"

if cache_key not in market_data_cache:
df = AlphaVantageAPI.get_intraday_data(symbol, "1min", outputsize="full")
market_data_cache[cache_key] = MarketData(
symbol=symbol,
interval="1min",
data=df,
last_updated=datetime.now()
)

data = market_data_cache[cache_key].data.copy()

# Calculate price changes
delta = data['close'].diff()

# Create gain and loss series
gain = delta.copy()
loss = delta.copy()
gain[gain < 0] = 0
loss[loss > 0] = 0
loss = abs(loss)

# Calculate average gain and loss
avg_gain = gain.rolling(window=period).mean()
avg_loss = loss.rolling(window=period).mean()

# Calculate RS and RSI
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))

# Get latest RSI
latest_rsi = rsi.iloc[-1]

# Determine signal
if latest_rsi < 30:
signal = "OVERSOLD (Potential buy opportunity)"
elif latest_rsi > 70:
signal = "OVERBOUGHT (Potential sell opportunity)"
else:
signal = "NEUTRAL"

return {
"symbol": symbol,
"period": period,
"rsi": latest_rsi,
"signal": signal,
"analysis": f"""RSI Analysis for {symbol}:
{period}-period RSI: {latest_rsi:.2f}
Signal: {signal}

Recommendation: {
"BUY" if latest_rsi < 30 else
"SELL" if latest_rsi > 70 else
"HOLD"
}"""
}

@mcp.tool()
def trade_recommendation(symbol: str) -> Dict[str, Any]:
"""
Provide a comprehensive trade recommendation based on multiple indicators

Args:
symbol: The ticker symbol to analyze

Returns:
Dictionary with trading recommendation and supporting data
"""
# Calculate individual indicators
ma_data = calculate_moving_averages(symbol)
rsi_data = calculate_rsi(symbol)

# Extract signals
ma_signal = ma_data["signal"]
ma_crossover = ma_data["crossover_detected"]
ma_crossover_type = ma_data["crossover_type"]
rsi_value = rsi_data["rsi"]
rsi_signal = rsi_data["signal"]

# Determine overall signal strength
signal_strength = 0

# MA contribution
if "BULLISH" in ma_signal:
signal_strength += 1
elif "BEARISH" in ma_signal:
signal_strength -= 1

# Crossover contribution
if ma_crossover:
if "GOLDEN" in ma_crossover_type:
signal_strength += 2
elif "DEATH" in ma_crossover_type:
signal_strength -= 2

# RSI contribution
if "OVERSOLD" in rsi_signal:
signal_strength += 1.5
elif "OVERBOUGHT" in rsi_signal:
signal_strength -= 1.5

# Determine final recommendation
if signal_strength >= 2:
recommendation = "STRONG BUY"
elif signal_strength > 0:
recommendation = "BUY"
elif signal_strength <= -2:
recommendation = "STRONG SELL"
elif signal_strength < 0:
recommendation = "SELL"
else:
recommendation = "HOLD"

# Calculate risk level (simple version)
risk_level = "MEDIUM"
if abs(signal_strength) > 3:
risk_level = "LOW" # Strong signal, lower risk
elif abs(signal_strength) < 1:
risk_level = "HIGH" # Weak signal, higher risk

analysis = f"""# Trading Recommendation for {symbol}

## Summary
Recommendation: {recommendation}
Risk Level: {risk_level}
Signal Strength: {signal_strength:.1f} / 4.5

## Technical Indicators
Moving Averages: {ma_signal}
Recent Crossover: {"Yes - " + ma_crossover_type if ma_crossover else "No"}
RSI ({rsi_data["period"]}): {rsi_value:.2f} - {rsi_signal}

## Reasoning
This recommendation is based on a combination of Moving Average analysis and RSI indicators.
{
f"The {ma_crossover_type} provides a strong directional signal. " if ma_crossover else ""
}{
f"The RSI indicates the stock is {rsi_signal.split(' ')[0].lower()}. " if "NEUTRAL" not in rsi_signal else ""
}

## Action Plan
{
"Consider immediate entry with a stop loss at the recent low. Target the next resistance level." if recommendation == "STRONG BUY" else
"Look for a good entry point on small dips. Set reasonable stop loss." if recommendation == "BUY" else
"Consider immediate exit or setting tight stop losses to protect gains." if recommendation == "STRONG SELL" else
"Start reducing position on strength or set trailing stop losses." if recommendation == "SELL" else
"Monitor the position but no immediate action needed."
}
"""

return {
"symbol": symbol,
"recommendation": recommendation,
"risk_level": risk_level,
"signal_strength": signal_strength,
"ma_signal": ma_signal,
"rsi_signal": rsi_signal,
"current_price": ma_data["current_price"],
"analysis": analysis
}

# Prompts
@mcp.prompt()
def analyze_ticker(symbol: str) -> str:
"""
Analyze a ticker symbol for trading opportunities
"""
return f"""You are a professional stock market analyst. I would like you to analyze the stock {symbol} and provide trading insights.

Start by examining the current market data and technical indicators. Here are the specific tasks:

1. First, check the current market data for {symbol}
2. Calculate the moving averages using the calculate_moving_averages tool
3. Calculate the RSI using the calculate_rsi tool
4. Generate a comprehensive trade recommendation using the trade_recommendation tool
5. Based on all this information, provide your professional analysis, highlighting:
- The current market position
- Key technical indicators and what they suggest
- Potential trading opportunities and risks
- Your recommended action (buy, sell, or hold) with a brief explanation

Please organize your response in a clear, structured format suitable for a professional trader.
"""

@mcp.prompt()
def compare_tickers(symbols: str) -> str:
"""
Compare multiple ticker symbols for the best trading opportunity

Args:
symbols: Comma-separated list of ticker symbols
"""
symbol_list = [s.strip() for s in symbols.split(",")]
symbol_section = "\n".join([f"- {s}" for s in symbol_list])

return f"""You are a professional stock market analyst. I would like you to compare these stocks and identify the best trading opportunity:

{symbol_section}

For each stock in the list, please:

1. Check the current market data using the appropriate resource
2. Generate a comprehensive trade recommendation using the trade_recommendation tool
3. Compare all stocks based on:
- Current trend direction and strength
- Technical indicator signals
- Risk/reward profile
- Trading recommendation strength

After analyzing each stock, rank them from most promising to least promising trading opportunity. Explain your ranking criteria and why you believe the top-ranked stock represents the best current trading opportunity.

Conclude with a specific recommendation on which stock to trade and what action to take (buy, sell, or hold).
"""

@mcp.prompt()
def intraday_strategy_builder(symbol: str) -> str:
"""
Build a custom intraday trading strategy for a specific ticker
"""
return f"""You are an expert algorithmic trader specializing in intraday strategies. I want you to develop a custom intraday trading strategy for {symbol}.

Please follow these steps:

1. First, analyze the current market data for {symbol} using the market-data resource
2. Calculate relevant technical indicators:
- Moving averages (short and long periods)
- RSI
3. Based on your analysis, design an intraday trading strategy that includes:
- Specific entry conditions (technical setups that would trigger a buy/sell)
- Exit conditions (both take-profit and stop-loss levels)
- Position sizing recommendations
- Optimal trading times during the day
- Risk management rules

Make your strategy specific to the current market conditions for {symbol}, not just generic advice. Include exact indicator values and price levels where possible.

Conclude with a summary of the strategy and how a trader should implement it for today's trading session.
"""

Integrating the MCP server with Claude Desktop

  • Integrate the stock price server with Claude for Desktop by running the following command:
mcp install stock_analysis_server.py --with requests --with pandas --with tabulate

After the integration, restart Claude for Desktop to enable the new MCP server for stock analysis related queries.

--

--

Vishnu Sivan
Vishnu Sivan

Written by Vishnu Sivan

Try not to become a man of SUCCESS but rather try to become a man of VALUE