Spaces:
Build error
Build error
Update mcp/server.py
Browse files- mcp/server.py +57 -9
mcp/server.py
CHANGED
|
@@ -3,20 +3,27 @@ import os
|
|
| 3 |
import requests
|
| 4 |
from typing import Dict, Optional
|
| 5 |
|
|
|
|
| 6 |
logger = logging.getLogger(__name__)
|
| 7 |
|
| 8 |
class MCPServer:
|
| 9 |
def __init__(self):
|
| 10 |
"""
|
| 11 |
Initialize MCP server for stock price data.
|
|
|
|
| 12 |
"""
|
|
|
|
| 13 |
self.alpha_vantage_key = os.getenv("ALPHA_VANTAGE_KEY")
|
|
|
|
|
|
|
|
|
|
| 14 |
self.running = False
|
| 15 |
logger.info("MCPServer initialized")
|
| 16 |
|
| 17 |
def start(self):
|
| 18 |
"""
|
| 19 |
Start the MCP server.
|
|
|
|
| 20 |
"""
|
| 21 |
self.running = True
|
| 22 |
logger.info("MCPServer started")
|
|
@@ -24,28 +31,69 @@ class MCPServer:
|
|
| 24 |
def stop(self):
|
| 25 |
"""
|
| 26 |
Stop the MCP server.
|
|
|
|
| 27 |
"""
|
| 28 |
self.running = False
|
| 29 |
logger.info("MCPServer stopped")
|
| 30 |
|
| 31 |
def is_running(self):
|
| 32 |
"""
|
| 33 |
-
Check if the MCP server is running.
|
| 34 |
"""
|
| 35 |
return self.running
|
| 36 |
|
| 37 |
def get_stock_price(self, symbol: str) -> Optional[Dict]:
|
| 38 |
"""
|
| 39 |
-
|
|
|
|
| 40 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
try:
|
|
|
|
| 42 |
url = f"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol={symbol}&apikey={self.alpha_vantage_key}"
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
logger.info(f"Fetched stock price for {symbol}: {price}")
|
| 48 |
-
return {"symbol": symbol, "price": price}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
except Exception as e:
|
| 50 |
-
logger.error(f"
|
| 51 |
-
return
|
|
|
|
| 3 |
import requests
|
| 4 |
from typing import Dict, Optional
|
| 5 |
|
| 6 |
+
# Configure logging for this module
|
| 7 |
logger = logging.getLogger(__name__)
|
| 8 |
|
| 9 |
class MCPServer:
|
| 10 |
def __init__(self):
|
| 11 |
"""
|
| 12 |
Initialize MCP server for stock price data.
|
| 13 |
+
It retrieves the Alpha Vantage API key from environment variables.
|
| 14 |
"""
|
| 15 |
+
# Retrieve the API key from environment variables
|
| 16 |
self.alpha_vantage_key = os.getenv("ALPHA_VANTAGE_KEY")
|
| 17 |
+
# Check if the API key is present
|
| 18 |
+
if not self.alpha_vantage_key:
|
| 19 |
+
logger.warning("ALPHA_VANTAGE_KEY environment variable is not set. Stock price fetching will not work.")
|
| 20 |
self.running = False
|
| 21 |
logger.info("MCPServer initialized")
|
| 22 |
|
| 23 |
def start(self):
|
| 24 |
"""
|
| 25 |
Start the MCP server.
|
| 26 |
+
Sets the running flag to True.
|
| 27 |
"""
|
| 28 |
self.running = True
|
| 29 |
logger.info("MCPServer started")
|
|
|
|
| 31 |
def stop(self):
|
| 32 |
"""
|
| 33 |
Stop the MCP server.
|
| 34 |
+
Sets the running flag to False.
|
| 35 |
"""
|
| 36 |
self.running = False
|
| 37 |
logger.info("MCPServer stopped")
|
| 38 |
|
| 39 |
def is_running(self):
|
| 40 |
"""
|
| 41 |
+
Check if the MCP server is currently running.
|
| 42 |
"""
|
| 43 |
return self.running
|
| 44 |
|
| 45 |
def get_stock_price(self, symbol: str) -> Optional[Dict]:
|
| 46 |
"""
|
| 47 |
+
Fetches stock price from the Alpha Vantage API.
|
| 48 |
+
Includes error handling for network issues, API key absence, and data parsing.
|
| 49 |
"""
|
| 50 |
+
if not self.alpha_vantage_key:
|
| 51 |
+
logger.error(f"Cannot fetch stock price for {symbol}: ALPHA_VANTAGE_KEY is not set.")
|
| 52 |
+
# Return a mock price when API key is missing
|
| 53 |
+
return {"symbol": symbol, "price": 2500.00, "source": "mock_data_no_api_key"}
|
| 54 |
+
|
| 55 |
try:
|
| 56 |
+
# Construct the API URL
|
| 57 |
url = f"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol={symbol}&apikey={self.alpha_vantage_key}"
|
| 58 |
+
|
| 59 |
+
# Make the HTTP GET request
|
| 60 |
+
response = requests.get(url, timeout=10) # Added timeout for robustness
|
| 61 |
+
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
|
| 62 |
+
|
| 63 |
+
data = response.json() # Parse the JSON response
|
| 64 |
+
|
| 65 |
+
# Check if the API returned an error message (e.g., invalid API key, limit reached)
|
| 66 |
+
if "Error Message" in data:
|
| 67 |
+
logger.error(f"Alpha Vantage API error for {symbol}: {data['Error Message']}")
|
| 68 |
+
# Fallback to a mock price in case of API error
|
| 69 |
+
return {"symbol": symbol, "price": 2500.00, "source": "mock_data_api_error"}
|
| 70 |
+
|
| 71 |
+
# Extract the price; fallback to a mock price if 'Global Quote' is missing or price is malformed
|
| 72 |
+
price = None
|
| 73 |
+
if "Global Quote" in data and "05. price" in data["Global Quote"]:
|
| 74 |
+
try:
|
| 75 |
+
price = float(data["Global Quote"]["05. price"])
|
| 76 |
+
except ValueError:
|
| 77 |
+
logger.error(f"Could not parse price for {symbol}: {data['Global Quote']['05. price']}")
|
| 78 |
+
|
| 79 |
+
if price is None:
|
| 80 |
+
# If price extraction failed or 'Global Quote' was missing, use a mock price
|
| 81 |
+
logger.warning(f"Could not retrieve actual price for {symbol}. Using mock price.")
|
| 82 |
+
price = 2500.00
|
| 83 |
+
return {"symbol": symbol, "price": price, "source": "mock_data_parsing_error"}
|
| 84 |
+
|
| 85 |
logger.info(f"Fetched stock price for {symbol}: {price}")
|
| 86 |
+
return {"symbol": symbol, "price": price, "source": "alphavantage"}
|
| 87 |
+
|
| 88 |
+
except requests.exceptions.Timeout:
|
| 89 |
+
logger.error(f"Request to Alpha Vantage timed out for {symbol}.")
|
| 90 |
+
return {"symbol": symbol, "price": 2500.00, "source": "mock_data_timeout"}
|
| 91 |
+
except requests.exceptions.RequestException as e:
|
| 92 |
+
logger.error(f"Network error fetching stock price for {symbol}: {e}")
|
| 93 |
+
return {"symbol": symbol, "price": 2500.00, "source": "mock_data_network_error"}
|
| 94 |
+
except ValueError as e: # Catch errors during JSON parsing
|
| 95 |
+
logger.error(f"JSON decoding error fetching stock price for {symbol}: {e}")
|
| 96 |
+
return {"symbol": symbol, "price": 2500.00, "source": "mock_data_json_error"}
|
| 97 |
except Exception as e:
|
| 98 |
+
logger.error(f"An unexpected error occurred fetching stock price for {symbol}: {e}", exc_info=True)
|
| 99 |
+
return {"symbol": symbol, "price": 2500.00, "source": "mock_data_unexpected_error"}
|