-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
199 lines (181 loc) · 6.14 KB
/
Copy pathserver.py
File metadata and controls
199 lines (181 loc) · 6.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import yfinance as yf
from typing import Any
from mcp.server.fastmcp import FastMCP
from datetime import datetime
mcp = FastMCP("finance")
ticker_map = {
# Cryptocurrencies (Mapping names and symbols to SYMBOL-USD format)
"bitcoin": "BTC-USD",
"btc usd": "BTC-USD",
"btc-usd": "BTC-USD",
"btc": "BTC-USD",
"ethereum": "ETH-USD",
"eth": "ETH-USD",
"ripple": "XRP-USD",
"xrp": "XRP-USD",
"cardano": "ADA-USD",
"ada": "ADA-USD",
"solana": "SOL-USD",
"sol": "SOL-USD",
"dogecoin": "DOGE-USD",
"doge": "DOGE-USD",
"polkadot": "DOT-USD",
"dot": "DOT-USD",
"litecoin": "LTC-USD",
"ltc": "LTC-USD",
"chainlink": "LINK-USD",
"link": "LINK-USD",
"bitcoin cash": "BCH-USD",
"bch": "BCH-USD",
"stellar": "XLM-USD",
"xlm": "XLM-USD",
"binance coin": "BNB-USD",
"bnb": "BNB-USD",
"shiba inu": "SHIB-USD",
"shib": "SHIB-USD",
"tron": "TRX-USD",
"trx": "TRX-USD",
"avalanche": "AVAX-USD",
"avax": "AVAX-USD",
"polygon": "MATIC-USD",
"matic": "MATIC-USD",
# Major US Stocks (Mapping common names/variations to Ticker)
"apple": "AAPL",
"apple stock": "AAPL",
"microsoft": "MSFT",
"microsoft stock": "MSFT",
"google": "GOOGL", # Often refers to Class A
"alphabet": "GOOGL",
"alphabet class a": "GOOGL",
"alphabet class c": "GOOG",
"amazon": "AMZN",
"amazon stock": "AMZN",
"meta": "META",
"meta platforms": "META",
"facebook": "META", # Common old name
"tesla": "TSLA",
"tesla stock": "TSLA",
"nvidia": "NVDA",
"nvidia stock": "NVDA",
"berkshire hathaway": "BRK-B", # Class B is more commonly traded
"berkshire hathaway class b": "BRK-B",
"berkshire hathaway class a": "BRK-A",
"jpmorgan chase": "JPM",
"jpmorgan": "JPM",
"jp morgan": "JPM",
"johnson & johnson": "JNJ",
"johnson and johnson": "JNJ",
"visa": "V",
"mastercard": "MA",
"bank of america": "BAC",
"home depot": "HD",
"procter & gamble": "PG",
"procter and gamble": "PG",
"netflix": "NFLX",
"disney": "DIS",
"walt disney": "DIS",
"intel": "INTC",
"cisco": "CSCO",
"verizon": "VZ",
"at&t": "T",
"boeing": "BA",
"ford": "F",
"general motors": "GM",
# Major Indices (Mapping names to yfinance symbol)
"s&p 500": "^GSPC",
"s&p500": "^GSPC",
"sp500": "^GSPC",
"spx": "^GSPC", # Common short name
"nasdaq": "^IXIC",
"nasdaq composite": "^IXIC",
"dow jones": "^DJI",
"dow jones industrial average": "^DJI",
"the dow": "^DJI",
"dji": "^DJI",
"russell 2000": "^RUT",
"vix": "^VIX", # Volatility Index
# Forex (Mapping common pairs to SYMBOLA-SYMBOLB=X format)
"eurusd": "EURUSD=X",
"euro dollar": "EURUSD=X",
"usdjpy": "JPY=X", # Note: yfinance uses JPY=X for USD/JPY
"dollar yen": "JPY=X",
"gbpusd": "GBPUSD=X",
"pound dollar": "GBPUSD=X",
"audusd": "AUDUSD=X",
"aussie dollar": "AUDUSD=X",
"usdcad": "CAD=X", # USD/CAD
"dollar loonie": "CAD=X",
"usdchf": "CHF=X", # USD/Swiss Franc
"dollar swiss": "CHF=X",
# Commodities/Futures (Mapping names to yfinance symbol, often =F)
"gold": "GC=F",
"gold futures": "GC=F",
"crude oil": "CL=F",
"oil": "CL=F",
"wti crude": "CL=F",
"brent crude": "BZ=F",
"silver": "SI=F",
"silver futures": "SI=F",
"natural gas": "NG=F",
"corn": "ZC=F",
"wheat": "ZW=F",
"soybeans": "ZS=F",
# Major ETFs (Mapping names/symbols)
"spy": "SPY", # S&P 500 ETF
"qqq": "QQQ", # Nasdaq 100 ETF
"dia": "DIA", # Dow Jones ETF
"gld": "GLD", # Gold ETF
"slv": "SLV", # Silver ETF
"uso": "USO", # Oil ETF
"vti": "VTI", # Vanguard Total Stock Market ETF
"agg": "AGG", # iShares Core U.S. Aggregate Bond ETF
}
def ticker_mapper(ticker: str) -> str:
"""
Validate and map the ticker symbol to its yfinance format.
"""
ticker = ticker.lower().strip()
mapped_ticker = ticker_map.get(ticker)
if mapped_ticker:
return mapped_ticker
return ticker.upper()
async def get_price(ticker: str, perdiod: str) -> Any:
return yf.Ticker(ticker).history(period=perdiod)
async def get_news(ticker: str, count: int) -> Any:
ticker = yf.Ticker(ticker)
return ticker.get_news(count=count, tab="news")
@mcp.tool(name="get_price", description="Get the price of a stock/crypto ticker.")
async def get_price_tool(ticker: str, period: str = "1d") -> str:
ticker = ticker_mapper(ticker)
try:
response = await get_price(ticker, period)
response.index = response.index.strftime("%B %d, %Y %I:%M")
text = ""
for index, row in response.iterrows():
text += f"Open: ${row['Open']:.3f}, High: ${row['High']:.3f}, Low: ${row['Low']:.3f}, Close: ${row['Close']:.3f}, Volume: ${row['Volume']:.3f}\n "
return text
except KeyError:
return f"{ticker} symbol not found"
@mcp.tool(name="get_news", description="Get the news of a stock/crypto ticker.")
async def get_news_tool(ticker: str, count: int = 5) -> str:
ticker = ticker_mapper(ticker)
try:
response = await get_news(ticker, count)
text = ""
for news in response:
publication_date = datetime.fromisoformat(
news["content"]["pubDate"].replace("Z", "+00:00")
).strftime("%Y-%m-%d %H:%M:%S")
article_link = news["content"]["provider"]["url"]
article_title = news["content"]["title"]
article_publisher = news["content"]["provider"]["displayName"]
article_summary = news["content"]["summary"]
text += f"Date: {publication_date}, Title: {article_title}, Publisher: {article_publisher}, Link: {article_link}, Summary: {article_summary}\n"
return text
except KeyError:
return f"{ticker} symbol not found"
def main() -> None:
print("Starting Finance MCP server")
mcp.run(transport="stdio")
if __name__ == "__main__":
main()