This is page 3 of 4. Use http://codebase.md/calvernaz/alphavantage?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .bumpversion.cfg ├── .github │ ├── FUNDING.yml │ └── workflows │ └── publish.yml ├── .gitignore ├── .python-version ├── CONTRIBUTING.md ├── deploy │ └── aws-stateless-mcp-lambda │ ├── .aws-sam │ │ └── build.toml │ ├── deploy.sh │ ├── lambda_function.py │ ├── README.md │ ├── requirements.txt │ └── template.yaml ├── DEVELOPMENT.md ├── Dockerfile ├── LICENSE ├── pyproject.toml ├── pytest.ini ├── README.md ├── scripts │ └── publish.py ├── smithery.yaml ├── src │ ├── alphavantage_mcp_client │ │ └── client.py │ └── alphavantage_mcp_server │ ├── __init__.py │ ├── api.py │ ├── oauth.py │ ├── prompts.py │ ├── response_utils.py │ ├── server.py │ ├── telemetry_bootstrap.py │ ├── telemetry_instrument.py │ └── tools.py ├── tests │ ├── test_api.py │ ├── test_http_mcp_client.py │ ├── test_http_transport.py │ ├── test_integration.py │ ├── test_stdio_transport.py │ └── test_telemetry.py └── uv.lock ``` # Files -------------------------------------------------------------------------------- /src/alphavantage_mcp_server/server.py: -------------------------------------------------------------------------------- ```python 1 | import asyncio 2 | import json 3 | import logging 4 | 5 | import mcp.server.stdio 6 | import mcp.types as types 7 | import toml 8 | import uvicorn 9 | from mcp.server import NotificationOptions, Server 10 | from mcp.server.models import InitializationOptions 11 | from mcp.server.streamable_http import StreamableHTTPServerTransport 12 | from starlette.requests import Request 13 | from starlette.responses import Response 14 | 15 | from .oauth import OAuthResourceServer, create_oauth_config_from_env 16 | from .prompts import prompts_definitions 17 | from .tools import AlphavantageTools, tools_definitions 18 | from .telemetry_bootstrap import init_telemetry 19 | from .api import ( 20 | fetch_quote, 21 | fetch_intraday, 22 | fetch_time_series_daily, 23 | fetch_time_series_daily_adjusted, 24 | fetch_time_series_weekly, 25 | fetch_time_series_weekly_adjusted, 26 | fetch_time_series_monthly, 27 | fetch_time_series_monthly_adjusted, 28 | fetch_realtime_bulk_quotes, 29 | search_endpoint, 30 | fetch_market_status, 31 | fetch_realtime_options, 32 | fetch_historical_options, 33 | fetch_news_sentiment, 34 | fetch_top_gainer_losers, 35 | fetch_insider_transactions, 36 | fetch_analytics_fixed_window, 37 | fetch_analytics_sliding_window, 38 | fetch_company_overview, 39 | company_dividends, 40 | fetch_etf_profile, 41 | fetch_company_splits, 42 | fetch_income_statement, 43 | fetch_balance_sheet, 44 | fetch_cash_flow, 45 | fetch_listing_status, 46 | fetch_earnings_calendar, 47 | fetch_ipo_calendar, 48 | fetch_exchange_rate, 49 | fetch_fx_intraday, 50 | fetch_fx_daily, 51 | fetch_fx_weekly, 52 | fetch_fx_monthly, 53 | fetch_digital_currency_intraday, 54 | fetch_digital_currency_daily, 55 | fetch_digital_currency_monthly, 56 | fetch_wti_crude, 57 | fetch_brent_crude, 58 | fetch_natural_gas, 59 | fetch_copper, 60 | fetch_aluminum, 61 | fetch_wheat, 62 | fetch_corn, 63 | fetch_cotton, 64 | fetch_sugar, 65 | fetch_coffee, 66 | fetch_all_commodities, 67 | fetch_real_gdp, 68 | fetch_real_gdp_per_capita, 69 | fetch_treasury_yield, 70 | fetch_federal_funds_rate, 71 | fetch_cpi, 72 | fetch_inflation, 73 | fetch_retail_sales, 74 | fetch_durables, 75 | fetch_unemployment, 76 | fetch_nonfarm_payrolls, 77 | fetch_sma, 78 | fetch_ema, 79 | fetch_wma, 80 | fetch_dema, 81 | fetch_tema, 82 | fetch_trima, 83 | fetch_kama, 84 | fetch_mama, 85 | fetch_t3, 86 | fetch_macd, 87 | fetch_macdext, 88 | fetch_stoch, 89 | fetch_stochf, 90 | fetch_rsi, 91 | fetch_stochrsi, 92 | fetch_willr, 93 | fetch_adx, 94 | fetch_adxr, 95 | fetch_apo, 96 | fetch_ppo, 97 | fetch_mom, 98 | fetch_bop, 99 | fetch_cci, 100 | fetch_cmo, 101 | fetch_roc, 102 | fetch_rocr, 103 | fetch_aroon, 104 | fetch_aroonosc, 105 | fetch_mfi, 106 | fetch_trix, 107 | fetch_ultosc, 108 | fetch_dx, 109 | fetch_minus_di, 110 | fetch_plus_di, 111 | fetch_minus_dm, 112 | fetch_plus_dm, 113 | fetch_bbands, 114 | fetch_midpoint, 115 | fetch_midprice, 116 | fetch_sar, 117 | fetch_trange, 118 | fetch_atr, 119 | fetch_natr, 120 | fetch_ad, 121 | fetch_adosc, 122 | fetch_obv, 123 | fetch_ht_trendline, 124 | fetch_ht_sine, 125 | fetch_ht_trendmode, 126 | fetch_ht_dcperiod, 127 | fetch_ht_dcphase, 128 | fetch_ht_phasor, 129 | fetch_vwap, 130 | fetch_earnings, 131 | fetch_earnings_call_transcript, 132 | ) 133 | 134 | logger = logging.getLogger(__name__) 135 | 136 | 137 | server = Server("alphavantage") 138 | 139 | 140 | @server.list_prompts() 141 | async def list_prompts() -> list[types.Prompt]: 142 | return prompts_definitions() 143 | 144 | 145 | @server.get_prompt() 146 | async def get_prompt( 147 | name: str, arguments: dict[str, str] | None = None 148 | ) -> types.GetPromptResult: 149 | if name == AlphavantageTools.STOCK_QUOTE.value: 150 | symbol = arguments.get("symbol") if arguments else "" 151 | return types.GetPromptResult( 152 | messages=[ 153 | types.PromptMessage( 154 | role="user", 155 | content=types.TextContent( 156 | type="text", 157 | text=f"Fetch the stock quote for the symbol {symbol}", 158 | ), 159 | ) 160 | ], 161 | ) 162 | if name == AlphavantageTools.TIME_SERIES_INTRADAY.value: 163 | symbol = arguments.get("symbol") if arguments else "" 164 | interval = arguments.get("interval") if arguments else "" 165 | return types.GetPromptResult( 166 | messages=[ 167 | types.PromptMessage( 168 | role="user", 169 | content=types.TextContent( 170 | type="text", 171 | text=f"Fetch the time series intraday for the symbol {symbol} with interval {interval}", 172 | ), 173 | ) 174 | ], 175 | ) 176 | if name == AlphavantageTools.TIME_SERIES_DAILY.value: 177 | symbol = arguments.get("symbol") if arguments else "" 178 | return types.GetPromptResult( 179 | messages=[ 180 | types.PromptMessage( 181 | role="user", 182 | content=types.TextContent( 183 | type="text", 184 | text=f"Fetch the time series daily for the symbol {symbol}", 185 | ), 186 | ) 187 | ], 188 | ) 189 | if name == AlphavantageTools.TIME_SERIES_DAILY_ADJUSTED.value: 190 | symbol = arguments.get("symbol") if arguments else "" 191 | return types.GetPromptResult( 192 | messages=[ 193 | types.PromptMessage( 194 | role="user", 195 | content=types.TextContent( 196 | type="text", 197 | text=f"Fetch the time series daily adjusted for the symbol {symbol}", 198 | ), 199 | ) 200 | ], 201 | ) 202 | if name == AlphavantageTools.TIME_SERIES_WEEKLY.value: 203 | symbol = arguments.get("symbol") if arguments else "" 204 | return types.GetPromptResult( 205 | messages=[ 206 | types.PromptMessage( 207 | role="user", 208 | content=types.TextContent( 209 | type="text", 210 | text=f"Fetch the time series weekly for the symbol {symbol}", 211 | ), 212 | ) 213 | ], 214 | ) 215 | if name == AlphavantageTools.TIME_SERIES_WEEKLY_ADJUSTED.value: 216 | symbol = arguments.get("symbol") if arguments else "" 217 | return types.GetPromptResult( 218 | messages=[ 219 | types.PromptMessage( 220 | role="user", 221 | content=types.TextContent( 222 | type="text", 223 | text=f"Fetch the time series weekly adjusted for the symbol {symbol}", 224 | ), 225 | ) 226 | ], 227 | ) 228 | if name == AlphavantageTools.TIME_SERIES_MONTHLY.value: 229 | symbol = arguments.get("symbol") if arguments else "" 230 | return types.GetPromptResult( 231 | messages=[ 232 | types.PromptMessage( 233 | role="user", 234 | content=types.TextContent( 235 | type="text", 236 | text=f"Fetch the time series monthly for the symbol {symbol}", 237 | ), 238 | ) 239 | ], 240 | ) 241 | if name == AlphavantageTools.TIME_SERIES_MONTHLY_ADJUSTED.value: 242 | symbol = arguments.get("symbol") if arguments else "" 243 | return types.GetPromptResult( 244 | messages=[ 245 | types.PromptMessage( 246 | role="user", 247 | content=types.TextContent( 248 | type="text", 249 | text=f"Fetch the time series monthly adjusted for the symbol {symbol}", 250 | ), 251 | ) 252 | ], 253 | ) 254 | if name == AlphavantageTools.REALTIME_BULK_QUOTES.value: 255 | symbol = arguments.get("symbol") if arguments else "" 256 | return types.GetPromptResult( 257 | messages=[ 258 | types.PromptMessage( 259 | role="user", 260 | content=types.TextContent( 261 | type="text", 262 | text=f"Fetch real time bulk quotes for the symbols {symbol}", 263 | ), 264 | ) 265 | ], 266 | ) 267 | if name == AlphavantageTools.SYMBOL_SEARCH.value: 268 | keywords = arguments.get("keywords") if arguments else "" 269 | return types.GetPromptResult( 270 | messages=[ 271 | types.PromptMessage( 272 | role="user", 273 | content=types.TextContent( 274 | type="text", 275 | text=f"Search for symbols with keywords {keywords}", 276 | ), 277 | ) 278 | ], 279 | ) 280 | if name == AlphavantageTools.MARKET_STATUS.value: 281 | return types.GetPromptResult( 282 | messages=[ 283 | types.PromptMessage( 284 | role="user", 285 | content=types.TextContent( 286 | type="text", text="Fetch the market status" 287 | ), 288 | ) 289 | ], 290 | ) 291 | if name == AlphavantageTools.REALTIME_OPTIONS.value: 292 | symbol = arguments.get("symbol") if arguments else "" 293 | contract = arguments.get("contract") if arguments else "" 294 | return types.GetPromptResult( 295 | messages=[ 296 | types.PromptMessage( 297 | role="user", 298 | content=types.TextContent( 299 | type="text", 300 | text=f"Fetch real time options for the symbol {symbol} with contract {contract}", 301 | ), 302 | ) 303 | ], 304 | ) 305 | if name == AlphavantageTools.HISTORICAL_OPTIONS.value: 306 | symbol = arguments.get("symbol") if arguments else "" 307 | contract = arguments.get("contract") if arguments else "" 308 | return types.GetPromptResult( 309 | messages=[ 310 | types.PromptMessage( 311 | role="user", 312 | content=types.TextContent( 313 | type="text", 314 | text=f"Fetch historical options for the symbol {symbol} with contract {contract}", 315 | ), 316 | ) 317 | ], 318 | ) 319 | if name == AlphavantageTools.NEWS_SENTIMENT.value: 320 | tickers = arguments.get("tickers") if arguments else "" 321 | topics = arguments.get("topics") if arguments else "" 322 | return types.GetPromptResult( 323 | messages=[ 324 | types.PromptMessage( 325 | role="user", 326 | content=types.TextContent( 327 | type="text", 328 | text=f"Fetch news sentiment for the tickers {tickers} with topics {topics}", 329 | ), 330 | ) 331 | ], 332 | ) 333 | if name == AlphavantageTools.TOP_GAINERS_LOSERS.value: 334 | return types.GetPromptResult( 335 | messages=[ 336 | types.PromptMessage( 337 | role="user", 338 | content=types.TextContent( 339 | type="text", text="Fetch the top gainers and losers" 340 | ), 341 | ) 342 | ], 343 | ) 344 | if name == AlphavantageTools.INSIDER_TRANSACTIONS.value: 345 | symbol = arguments.get("symbol") if arguments else "" 346 | return types.GetPromptResult( 347 | messages=[ 348 | types.PromptMessage( 349 | role="user", 350 | content=types.TextContent( 351 | type="text", 352 | text=f"Fetch insider transactions for the symbol {symbol}", 353 | ), 354 | ) 355 | ], 356 | ) 357 | if name == AlphavantageTools.ANALYTICS_FIXED_WINDOW.value: 358 | symbol = arguments.get("symbol") if arguments else "" 359 | window = arguments.get("window") if arguments else "" 360 | return types.GetPromptResult( 361 | messages=[ 362 | types.PromptMessage( 363 | role="user", 364 | content=types.TextContent( 365 | type="text", 366 | text=f"Fetch analytics with fixed window for the symbol {symbol} with window {window}", 367 | ), 368 | ) 369 | ], 370 | ) 371 | if name == AlphavantageTools.ANALYTICS_SLIDING_WINDOW.value: 372 | symbol = arguments.get("symbol") if arguments else "" 373 | window = arguments.get("window") if arguments else "" 374 | return types.GetPromptResult( 375 | messages=[ 376 | types.PromptMessage( 377 | role="user", 378 | content=types.TextContent( 379 | type="text", 380 | text=f"Fetch analytics with sliding window for the symbol {symbol} with window {window}", 381 | ), 382 | ) 383 | ], 384 | ) 385 | if name == AlphavantageTools.COMPANY_OVERVIEW.value: 386 | symbol = arguments.get("symbol") if arguments else "" 387 | datatype = arguments.get("datatype") if arguments else "" 388 | return types.GetPromptResult( 389 | messages=[ 390 | types.PromptMessage( 391 | role="user", 392 | content=types.TextContent( 393 | type="text", 394 | text=f"Fetch the company overview for the symbol {symbol} with datatype {datatype}", 395 | ), 396 | ) 397 | ], 398 | ) 399 | if name == AlphavantageTools.ETF_PROFILE.value: 400 | symbol = arguments.get("symbol") if arguments else "" 401 | datatype = arguments.get("datatype") if arguments else "" 402 | return types.GetPromptResult( 403 | messages=[ 404 | types.PromptMessage( 405 | role="user", 406 | content=types.TextContent( 407 | type="text", 408 | text=f"Fetch the ETF profile for the symbol {symbol} with datatype {datatype}", 409 | ), 410 | ) 411 | ], 412 | ) 413 | if name == AlphavantageTools.COMPANY_DIVIDENDS.value: 414 | symbol = arguments.get("symbol") if arguments else "" 415 | return types.GetPromptResult( 416 | messages=[ 417 | types.PromptMessage( 418 | role="user", 419 | content=types.TextContent( 420 | type="text", 421 | text=f"Fetch the company dividends for the symbol {symbol}", 422 | ), 423 | ) 424 | ], 425 | ) 426 | if name == AlphavantageTools.COMPANY_SPLITS.value: 427 | symbol = arguments.get("symbol") if arguments else "" 428 | return types.GetPromptResult( 429 | messages=[ 430 | types.PromptMessage( 431 | role="user", 432 | content=types.TextContent( 433 | type="text", 434 | text=f"Fetch the company split events for the symbol {symbol}", 435 | ), 436 | ) 437 | ], 438 | ) 439 | if name == AlphavantageTools.INCOME_STATEMENT.value: 440 | symbol = arguments.get("symbol") if arguments else "" 441 | return types.GetPromptResult( 442 | messages=[ 443 | types.PromptMessage( 444 | role="user", 445 | content=types.TextContent( 446 | type="text", 447 | text=f"Fetch the annual and quarterly income statements for the company {symbol}", 448 | ), 449 | ) 450 | ], 451 | ) 452 | if name == AlphavantageTools.BALANCE_SHEET.value: 453 | symbol = arguments.get("symbol") if arguments else "" 454 | return types.GetPromptResult( 455 | messages=[ 456 | types.PromptMessage( 457 | role="user", 458 | content=types.TextContent( 459 | type="text", 460 | text=f"Fetch the annual and quarterly balance sheet for the company {symbol}", 461 | ), 462 | ) 463 | ], 464 | ) 465 | if name == AlphavantageTools.CASH_FLOW.value: 466 | symbol = arguments.get("symbol") if arguments else "" 467 | return types.GetPromptResult( 468 | messages=[ 469 | types.PromptMessage( 470 | role="user", 471 | content=types.TextContent( 472 | type="text", 473 | text=f"Fetch the annual and quarterly cash flow for the company {symbol}", 474 | ), 475 | ) 476 | ], 477 | ) 478 | if name == AlphavantageTools.COMPANY_EARNINGS.value: 479 | symbol = arguments.get("symbol") if arguments else "" 480 | return types.GetPromptResult( 481 | messages=[ 482 | types.PromptMessage( 483 | role="user", 484 | content=types.TextContent( 485 | type="text", 486 | text=f"Fetch the annual and quarterly earnings (EPS) for the company {symbol}", 487 | ), 488 | ) 489 | ], 490 | ) 491 | if name == AlphavantageTools.LISTING_STATUS.value: 492 | return types.GetPromptResult( 493 | messages=[ 494 | types.PromptMessage( 495 | role="user", 496 | content=types.TextContent( 497 | type="text", 498 | text="Fetch the list of active or delisted US stocks and ETFs", 499 | ), 500 | ) 501 | ] 502 | ) 503 | if name == AlphavantageTools.EARNINGS_CALENDAR.value: 504 | symbol = arguments.get("symbol") if arguments else "" 505 | return types.GetPromptResult( 506 | messages=[ 507 | types.PromptMessage( 508 | role="user", 509 | content=types.TextContent( 510 | type="text", 511 | text=f"Fetch the earnings expected in the next 3, 6, or 12 months for the {symbol}", 512 | ), 513 | ) 514 | ], 515 | ) 516 | if name == AlphavantageTools.EARNINGS_CALL_TRANSCRIPT.value: 517 | symbol = arguments.get("symbol") if arguments else "" 518 | quarter = arguments.get("quarter") if arguments else "2024Q1" 519 | return types.GetPromptResult( 520 | messages=[ 521 | types.PromptMessage( 522 | role="user", 523 | content=types.TextContent( 524 | type="text", 525 | text=f"Fetch the earnings call transcript for the {symbol} for the quarter {quarter}", 526 | ), 527 | ) 528 | ], 529 | ) 530 | 531 | if name == AlphavantageTools.IPO_CALENDAR.value: 532 | return types.GetPromptResult( 533 | messages=[ 534 | types.PromptMessage( 535 | role="user", 536 | content=types.TextContent( 537 | type="text", 538 | text="Fetch list of IPOs expected in the next 3 months", 539 | ), 540 | ) 541 | ], 542 | ) 543 | if name == AlphavantageTools.EXCHANGE_RATE.value: 544 | from_currency = arguments.get("from_currency") if arguments else "" 545 | to_currency = arguments.get("to_currency") if arguments else "" 546 | return types.GetPromptResult( 547 | messages=[ 548 | types.PromptMessage( 549 | role="user", 550 | content=types.TextContent( 551 | type="text", 552 | text=f"Fetch the exchange rate from {from_currency} to {to_currency}", 553 | ), 554 | ) 555 | ], 556 | ) 557 | if name == AlphavantageTools.FX_INTRADAY.value: 558 | from_symbol = arguments.get("from_symbol") if arguments else "" 559 | to_symbol = arguments.get("to_symbol") if arguments else "" 560 | interval = arguments.get("interval") if arguments else "" 561 | return types.GetPromptResult( 562 | messages=[ 563 | types.PromptMessage( 564 | role="user", 565 | content=types.TextContent( 566 | type="text", 567 | text=f"Fetch the intraday exchange rate from {from_symbol} to {to_symbol} with interval {interval}", 568 | ), 569 | ) 570 | ], 571 | ) 572 | if name == AlphavantageTools.FX_DAILY.value: 573 | from_symbol = arguments.get("from_symbol") if arguments else "" 574 | to_symbol = arguments.get("to_symbol") if arguments else "" 575 | return types.GetPromptResult( 576 | messages=[ 577 | types.PromptMessage( 578 | role="user", 579 | content=types.TextContent( 580 | type="text", 581 | text=f"Fetch the daily exchange rate from {from_symbol} to {to_symbol}", 582 | ), 583 | ) 584 | ], 585 | ) 586 | if name == AlphavantageTools.FX_WEEKLY.value: 587 | from_symbol = arguments.get("from_symbol") if arguments else "" 588 | to_symbol = arguments.get("to_symbol") if arguments else "" 589 | return types.GetPromptResult( 590 | messages=[ 591 | types.PromptMessage( 592 | role="user", 593 | content=types.TextContent( 594 | type="text", 595 | text=f"Fetch the weekly exchange rate from {from_symbol} to {to_symbol}", 596 | ), 597 | ) 598 | ], 599 | ) 600 | if name == AlphavantageTools.FX_MONTHLY.value: 601 | from_symbol = arguments.get("from_symbol") if arguments else "" 602 | to_symbol = arguments.get("to_symbol") if arguments else "" 603 | return types.GetPromptResult( 604 | messages=[ 605 | types.PromptMessage( 606 | role="user", 607 | content=types.TextContent( 608 | type="text", 609 | text=f"Fetch the monthly exchange rate from {from_symbol} to {to_symbol}", 610 | ), 611 | ) 612 | ], 613 | ) 614 | if name == AlphavantageTools.CRYPTO_INTRADAY.value: 615 | symbol = arguments.get("symbol") if arguments else "" 616 | market = arguments.get("market") if arguments else "" 617 | interval = arguments.get("interval") if arguments else "" 618 | 619 | return types.GetPromptResult( 620 | messages=[ 621 | types.PromptMessage( 622 | role="user", 623 | content=types.TextContent( 624 | type="text", 625 | text=f"Fetch the intraday crypto data for {symbol} in {market} with interval {interval}", 626 | ), 627 | ) 628 | ], 629 | ) 630 | if name == AlphavantageTools.DIGITAL_CURRENCY_DAILY.value: 631 | symbol = arguments.get("symbol") if arguments else "" 632 | market = arguments.get("market") if arguments else "" 633 | 634 | return types.GetPromptResult( 635 | messages=[ 636 | types.PromptMessage( 637 | role="user", 638 | content=types.TextContent( 639 | type="text", 640 | text=f"Fetch the daily historical time series for a digital currency (e.g., {symbol}) traded on a specific market (e.g., {market})", 641 | ), 642 | ) 643 | ], 644 | ) 645 | if name == AlphavantageTools.DIGITAL_CURRENCY_WEEKLY.value: 646 | symbol = arguments.get("symbol") if arguments else "" 647 | market = arguments.get("market") if arguments else "" 648 | 649 | return types.GetPromptResult( 650 | messages=[ 651 | types.PromptMessage( 652 | role="user", 653 | content=types.TextContent( 654 | type="text", 655 | text=f"Fetch the weekly historical time series for a digital currency (e.g., {symbol}) traded on a specific market, e.g., {market}", 656 | ), 657 | ) 658 | ], 659 | ) 660 | if name == AlphavantageTools.DIGITAL_CURRENCY_MONTHLY.value: 661 | symbol = arguments.get("symbol") if arguments else "" 662 | market = arguments.get("market") if arguments else "" 663 | 664 | return types.GetPromptResult( 665 | messages=[ 666 | types.PromptMessage( 667 | role="user", 668 | content=types.TextContent( 669 | type="text", 670 | text=f"Fetch the monthly historical time series for a digital currency (e.g., {symbol}) traded on a specific market, e.g., {market}", 671 | ), 672 | ) 673 | ], 674 | ) 675 | if name == AlphavantageTools.WTI_CRUDE_OIL.value: 676 | function = arguments.get("function") if arguments else "WTI" 677 | interval = arguments.get("interval") if arguments else "monthly" 678 | datatype = arguments.get("datatype") if arguments else "json" 679 | 680 | return types.GetPromptResult( 681 | messages=[ 682 | types.PromptMessage( 683 | role="user", 684 | content=types.TextContent( 685 | type="text", 686 | text=f"Fetch the West Texas Intermediate ({function}) crude oil prices in daily, weekly, and monthly horizons", 687 | ), 688 | ) 689 | ], 690 | ) 691 | 692 | if name == AlphavantageTools.BRENT_CRUDE_OIL.value: 693 | function = arguments.get("function") if arguments else "Brent" 694 | interval = arguments.get("interval") if arguments else "monthly" 695 | datatype = arguments.get("datatype") if arguments else "json" 696 | 697 | return types.GetPromptResult( 698 | messages=[ 699 | types.PromptMessage( 700 | role="user", 701 | content=types.TextContent( 702 | type="text", 703 | text=f"Fetch the {function} crude oil prices in daily, weekly, and monthly horizons", 704 | ), 705 | ) 706 | ], 707 | ) 708 | if name == AlphavantageTools.NATURAL_GAS.value: 709 | function = arguments.get("function") if arguments else "NATURAL_GAS" 710 | interval = arguments.get("interval") if arguments else "monthly" 711 | datatype = arguments.get("datatype") if arguments else "json" 712 | 713 | return types.GetPromptResult( 714 | messages=[ 715 | types.PromptMessage( 716 | role="user", 717 | content=types.TextContent( 718 | type="text", 719 | text="Fetch the Henry Hub natural gas spot prices in daily, weekly, and monthly horizons.", 720 | ), 721 | ) 722 | ], 723 | ) 724 | 725 | raise ValueError("Prompt implementation not found") 726 | 727 | 728 | @server.list_tools() 729 | async def handle_list_tools() -> list[types.Tool]: 730 | """ 731 | Get all available tool definitions with their schemas. 732 | 733 | Returns: 734 | List of MCP Tool objects with input schemas 735 | """ 736 | return tools_definitions() 737 | 738 | 739 | @server.call_tool() 740 | async def handle_call_tool( 741 | name: str, arguments: dict | None 742 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]: 743 | """ 744 | Handle tool execution requests. 745 | Tools can modify server state and notify clients of changes. 746 | """ 747 | try: 748 | match name: 749 | case AlphavantageTools.STOCK_QUOTE.value: 750 | symbol = arguments.get("symbol") 751 | if not symbol: 752 | raise ValueError("Missing required argument: symbol") 753 | 754 | datatype = arguments.get("datatype", "json") 755 | result = await fetch_quote(symbol, datatype) 756 | 757 | case AlphavantageTools.TIME_SERIES_INTRADAY.value: 758 | symbol = arguments.get("symbol") 759 | interval = arguments.get("interval") 760 | if not symbol or not interval: 761 | raise ValueError("Missing required arguments: symbol, interval") 762 | 763 | datatype = arguments.get("datatype", "json") 764 | adjusted = arguments.get("adjusted", True) 765 | extended_hours = arguments.get("extended_hours", True) 766 | outputsize = arguments.get("outputsize", "compact") 767 | month = arguments.get("month", None) 768 | 769 | result = await fetch_intraday( 770 | symbol, 771 | interval, 772 | datatype, 773 | extended_hours, 774 | adjusted, 775 | outputsize, 776 | month, 777 | ) 778 | case AlphavantageTools.TIME_SERIES_DAILY.value: 779 | symbol = arguments.get("symbol") 780 | if not symbol: 781 | raise ValueError("Missing required argument: symbol") 782 | 783 | datatype = arguments.get("datatype", "json") 784 | outputsize = arguments.get("outputsize", "compact") 785 | 786 | result = await fetch_time_series_daily(symbol, datatype, outputsize) 787 | case AlphavantageTools.TIME_SERIES_DAILY_ADJUSTED.value: 788 | symbol = arguments.get("symbol") 789 | if not symbol: 790 | raise ValueError("Missing required argument: symbol") 791 | 792 | datatype = arguments.get("datatype", "json") 793 | outputsize = arguments.get("outputsize", "compact") 794 | 795 | result = await fetch_time_series_daily_adjusted( 796 | symbol, datatype, outputsize 797 | ) 798 | case AlphavantageTools.TIME_SERIES_WEEKLY.value: 799 | symbol = arguments.get("symbol") 800 | if not symbol: 801 | raise ValueError("Missing required argument: symbol") 802 | 803 | datatype = arguments.get("datatype", "json") 804 | 805 | result = await fetch_time_series_weekly(symbol, datatype) 806 | case AlphavantageTools.TIME_SERIES_WEEKLY_ADJUSTED.value: 807 | symbol = arguments.get("symbol") 808 | if not symbol: 809 | raise ValueError("Missing required argument: symbol") 810 | 811 | datatype = arguments.get("datatype", "json") 812 | 813 | result = await fetch_time_series_weekly_adjusted(symbol, datatype) 814 | case AlphavantageTools.TIME_SERIES_MONTHLY.value: 815 | symbol = arguments.get("symbol") 816 | if not symbol: 817 | raise ValueError("Missing required argument: symbol") 818 | 819 | datatype = arguments.get("datatype", "json") 820 | 821 | result = await fetch_time_series_monthly(symbol, datatype) 822 | case AlphavantageTools.TIME_SERIES_MONTHLY_ADJUSTED.value: 823 | symbol = arguments.get("symbol") 824 | if not symbol: 825 | raise ValueError("Missing required argument: symbol") 826 | 827 | datatype = arguments.get("datatype", "json") 828 | 829 | result = await fetch_time_series_monthly_adjusted(symbol, datatype) 830 | 831 | case AlphavantageTools.REALTIME_BULK_QUOTES.value: 832 | symbols = arguments.get("symbols") 833 | if not symbols: 834 | raise ValueError("Missing required argument: symbols") 835 | 836 | datatype = arguments.get("datatype", "json") 837 | result = await fetch_realtime_bulk_quotes(symbols, datatype) 838 | 839 | case AlphavantageTools.SYMBOL_SEARCH.value: 840 | keywords = arguments.get("keywords") 841 | if not keywords: 842 | raise ValueError("Missing required argument: keywords") 843 | 844 | datatype = arguments.get("datatype", "json") 845 | result = await search_endpoint(keywords, datatype) 846 | 847 | case AlphavantageTools.MARKET_STATUS.value: 848 | result = await fetch_market_status() 849 | 850 | case AlphavantageTools.REALTIME_OPTIONS.value: 851 | symbol = arguments.get("symbol") 852 | if not symbol: 853 | raise ValueError("Missing required argument: symbol") 854 | 855 | datatype = arguments.get("datatype", "json") 856 | contract = arguments.get("contract", "all") 857 | result = await fetch_realtime_options(symbol, datatype, contract) 858 | 859 | case AlphavantageTools.HISTORICAL_OPTIONS.value: 860 | symbol = arguments.get("symbol") 861 | if not symbol: 862 | raise ValueError("Missing required argument: symbol") 863 | 864 | datatype = arguments.get("datatype", "json") 865 | contract = arguments.get("contract", "all") 866 | result = await fetch_historical_options(symbol, datatype, contract) 867 | 868 | case AlphavantageTools.NEWS_SENTIMENT.value: 869 | tickers = arguments.get("tickers", []) 870 | datatype = arguments.get("datatype", "json") 871 | topics = arguments.get("topics", None) 872 | time_from = arguments.get("time_from", None) 873 | time_to = arguments.get("time_to", None) 874 | sort = arguments.get("sort", "LATEST") 875 | limit = arguments.get("limit", 50) 876 | 877 | result = await fetch_news_sentiment( 878 | tickers, datatype, topics, time_from, time_to, sort, limit 879 | ) 880 | 881 | case AlphavantageTools.TOP_GAINERS_LOSERS.value: 882 | result = await fetch_top_gainer_losers() 883 | 884 | case AlphavantageTools.INSIDER_TRANSACTIONS.value: 885 | symbol = arguments.get("symbol") 886 | if not symbol: 887 | raise ValueError("Missing required argument: symbol") 888 | 889 | result = await fetch_insider_transactions(symbol) 890 | 891 | case AlphavantageTools.ANALYTICS_FIXED_WINDOW.value: 892 | symbols = arguments.get("symbols") 893 | interval = arguments.get("interval") 894 | series_range = arguments.get("series_range") 895 | ohlc = arguments.get("ohlc", "close") 896 | calculations = arguments.get("calculations") 897 | 898 | if not symbols or not interval or not series_range or not calculations: 899 | raise ValueError( 900 | "Missing required arguments: symbols, interval, series_range, calculations" 901 | ) 902 | result = await fetch_analytics_fixed_window( 903 | symbols, interval, series_range, ohlc, calculations 904 | ) 905 | 906 | case AlphavantageTools.ANALYTICS_SLIDING_WINDOW.value: 907 | symbols = arguments.get("symbols") 908 | interval = arguments.get("interval") 909 | series_range = arguments.get("series_range") 910 | ohlc = arguments.get("ohlc", "close") 911 | window_size = arguments.get("window_size") 912 | calculations = arguments.get("calculations", []) 913 | 914 | if ( 915 | not symbols 916 | or not interval 917 | or not series_range 918 | or not calculations 919 | or not window_size 920 | ): 921 | raise ValueError( 922 | "Missing required arguments: symbols, interval, series_range, calculations, window_size" 923 | ) 924 | result = await fetch_analytics_sliding_window( 925 | symbols, series_range, ohlc, interval, interval, calculations 926 | ) 927 | 928 | case AlphavantageTools.COMPANY_OVERVIEW.value: 929 | symbol = arguments.get("symbol") 930 | if not symbol: 931 | raise ValueError("Missing required argument: symbol") 932 | 933 | result = await fetch_company_overview(symbol) 934 | 935 | case AlphavantageTools.ETF_PROFILE.value: 936 | symbol = arguments.get("symbol") 937 | if not symbol: 938 | raise ValueError("Missing required argument: symbol") 939 | 940 | result = await fetch_etf_profile(symbol) 941 | 942 | case AlphavantageTools.COMPANY_DIVIDENDS.value: 943 | symbol = arguments.get("symbol") 944 | if not symbol: 945 | raise ValueError("Missing required argument: symbol") 946 | 947 | result = await company_dividends(symbol) 948 | 949 | case AlphavantageTools.COMPANY_SPLITS.value: 950 | symbol = arguments.get("symbol") 951 | if not symbol: 952 | raise ValueError("Missing required argument: symbol") 953 | 954 | result = await fetch_company_splits(symbol) 955 | 956 | case AlphavantageTools.INCOME_STATEMENT.value: 957 | symbol = arguments.get("symbol") 958 | if not symbol: 959 | raise ValueError("Missing required argument: symbol") 960 | 961 | result = await fetch_income_statement(symbol) 962 | case AlphavantageTools.BALANCE_SHEET.value: 963 | symbol = arguments.get("symbol") 964 | if not symbol: 965 | raise ValueError("Missing required argument: symbol") 966 | 967 | result = await fetch_balance_sheet(symbol) 968 | 969 | case AlphavantageTools.CASH_FLOW.value: 970 | symbol = arguments.get("symbol") 971 | if not symbol: 972 | raise ValueError("Missing required argument: symbol") 973 | 974 | result = await fetch_cash_flow(symbol) 975 | 976 | case AlphavantageTools.COMPANY_EARNINGS.value: 977 | symbol = arguments.get("symbol") 978 | if not symbol: 979 | raise ValueError("Missing required argument: symbol") 980 | result = await fetch_earnings(symbol) 981 | 982 | case AlphavantageTools.LISTING_STATUS.value: 983 | date = arguments.get("date") 984 | state = arguments.get("state") 985 | result = await fetch_listing_status(date, state) 986 | 987 | case AlphavantageTools.EARNINGS_CALENDAR.value: 988 | symbol = arguments.get("symbol") 989 | horizon = arguments.get("horizon") 990 | 991 | result = await fetch_earnings_calendar(symbol, horizon) 992 | 993 | case AlphavantageTools.EARNINGS_CALL_TRANSCRIPT.value: 994 | symbol = arguments.get("symbol") 995 | quarter = arguments.get("quarter") 996 | 997 | result = await fetch_earnings_call_transcript(symbol, quarter) 998 | 999 | case AlphavantageTools.IPO_CALENDAR.value: 1000 | result = await fetch_ipo_calendar() 1001 | 1002 | case AlphavantageTools.EXCHANGE_RATE.value: 1003 | from_currency = arguments.get("from_currency") 1004 | to_currency = arguments.get("to_currency") 1005 | 1006 | if not from_currency or not to_currency: 1007 | raise ValueError( 1008 | "Missing required arguments: from_currency, to_currency" 1009 | ) 1010 | 1011 | result = await fetch_exchange_rate(from_currency, to_currency) 1012 | 1013 | case AlphavantageTools.FX_INTRADAY.value: 1014 | from_symbol = arguments.get("from_symbol") 1015 | to_symbol = arguments.get("to_symbol") 1016 | interval = arguments.get("interval") 1017 | outputsize = arguments.get("outputsize", "compact") 1018 | datatype = arguments.get("datatype", "json") 1019 | 1020 | if not from_symbol or not to_symbol or not interval: 1021 | raise ValueError( 1022 | "Missing required arguments: from_symbol, to_symbol, interval" 1023 | ) 1024 | 1025 | result = await fetch_fx_intraday( 1026 | from_symbol, to_symbol, interval, outputsize, datatype 1027 | ) 1028 | 1029 | case AlphavantageTools.FX_DAILY.value: 1030 | from_symbol = arguments.get("from_symbol") 1031 | to_symbol = arguments.get("to_symbol") 1032 | datatype = arguments.get("datatype", "json") 1033 | outputsize = arguments.get("outputsize", "compact") 1034 | 1035 | if not from_symbol or not to_symbol: 1036 | raise ValueError( 1037 | "Missing required arguments: from_symbol, to_symbol" 1038 | ) 1039 | 1040 | result = await fetch_fx_daily( 1041 | from_symbol, to_symbol, datatype, outputsize 1042 | ) 1043 | 1044 | case AlphavantageTools.FX_WEEKLY.value: 1045 | from_symbol = arguments.get("from_symbol") 1046 | to_symbol = arguments.get("to_symbol") 1047 | datatype = arguments.get("datatype", "json") 1048 | 1049 | if not from_symbol or not to_symbol: 1050 | raise ValueError( 1051 | "Missing required arguments: from_symbol, to_symbol" 1052 | ) 1053 | 1054 | result = await fetch_fx_weekly(from_symbol, to_symbol, datatype) 1055 | 1056 | case AlphavantageTools.FX_MONTHLY.value: 1057 | from_symbol = arguments.get("from_symbol") 1058 | to_symbol = arguments.get("to_symbol") 1059 | datatype = arguments.get("datatype", "json") 1060 | 1061 | if not from_symbol or not to_symbol: 1062 | raise ValueError( 1063 | "Missing required arguments: from_symbol, to_symbol" 1064 | ) 1065 | 1066 | result = await fetch_fx_monthly(from_symbol, to_symbol, datatype) 1067 | 1068 | case AlphavantageTools.CRYPTO_INTRADAY.value: 1069 | symbol = arguments.get("symbol") 1070 | market = arguments.get("market") 1071 | interval = arguments.get("interval") 1072 | outputsize = arguments.get("outputsize", "compact") 1073 | datatype = arguments.get("datatype", "json") 1074 | 1075 | if not symbol or not market or not interval: 1076 | raise ValueError( 1077 | "Missing required arguments: symbol, market, interval" 1078 | ) 1079 | 1080 | result = await fetch_digital_currency_intraday( 1081 | symbol, market, interval, datatype, outputsize 1082 | ) 1083 | 1084 | case AlphavantageTools.DIGITAL_CURRENCY_DAILY.value: 1085 | symbol = arguments.get("symbol") 1086 | market = arguments.get("market") 1087 | 1088 | if not symbol or not market: 1089 | raise ValueError("Missing required arguments: symbol, market") 1090 | 1091 | result = await fetch_digital_currency_daily(symbol, market) 1092 | 1093 | case AlphavantageTools.DIGITAL_CURRENCY_WEEKLY.value: 1094 | symbol = arguments.get("symbol") 1095 | market = arguments.get("market") 1096 | 1097 | if not symbol or not market: 1098 | raise ValueError("Missing required arguments: symbol, market") 1099 | 1100 | result = await fetch_digital_currency_daily(symbol, market) 1101 | 1102 | case AlphavantageTools.DIGITAL_CURRENCY_MONTHLY.value: 1103 | symbol = arguments.get("symbol") 1104 | market = arguments.get("market") 1105 | 1106 | if not symbol or not market: 1107 | raise ValueError("Missing required arguments: symbol, market") 1108 | 1109 | result = await fetch_digital_currency_monthly(symbol, market) 1110 | 1111 | case AlphavantageTools.WTI_CRUDE_OIL.value: 1112 | interval = arguments.get("interval", "montHly") 1113 | datatype = arguments.get("datatype", "json") 1114 | 1115 | result = await fetch_wti_crude(interval, datatype) 1116 | 1117 | case AlphavantageTools.BRENT_CRUDE_OIL.value: 1118 | interval = arguments.get("interval", "monthly") 1119 | datatype = arguments.get("datatype", "json") 1120 | 1121 | result = await fetch_brent_crude(interval, datatype) 1122 | 1123 | case AlphavantageTools.NATURAL_GAS.value: 1124 | interval = arguments.get("interval", "monthly") 1125 | datatype = arguments.get("datatype", "json") 1126 | 1127 | result = await fetch_natural_gas(interval, datatype) 1128 | 1129 | case AlphavantageTools.COPPER.value: 1130 | interval = arguments.get("interval", "monthly") 1131 | datatype = arguments.get("datatype", "json") 1132 | 1133 | result = await fetch_copper(interval, datatype) 1134 | 1135 | case AlphavantageTools.ALUMINUM.value: 1136 | interval = arguments.get("interval", "monthly") 1137 | datatype = arguments.get("datatype", "json") 1138 | 1139 | result = await fetch_aluminum(interval, datatype) 1140 | 1141 | case AlphavantageTools.WHEAT.value: 1142 | interval = arguments.get("interval", "monthly") 1143 | datatype = arguments.get("datatype", "json") 1144 | 1145 | result = await fetch_wheat(interval, datatype) 1146 | 1147 | case AlphavantageTools.CORN.value: 1148 | interval = arguments.get("interval", "monthly") 1149 | datatype = arguments.get("datatype", "json") 1150 | 1151 | result = await fetch_corn(interval, datatype) 1152 | 1153 | case AlphavantageTools.COTTON.value: 1154 | interval = arguments.get("interval", "monthly") 1155 | datatype = arguments.get("datatype", "json") 1156 | 1157 | result = await fetch_cotton(interval, datatype) 1158 | 1159 | case AlphavantageTools.SUGAR.value: 1160 | interval = arguments.get("interval", "monthly") 1161 | datatype = arguments.get("datatype", "json") 1162 | 1163 | result = await fetch_sugar(interval, datatype) 1164 | 1165 | case AlphavantageTools.COFFEE.value: 1166 | interval = arguments.get("interval", "monthly") 1167 | datatype = arguments.get("datatype", "json") 1168 | 1169 | result = await fetch_coffee(interval, datatype) 1170 | 1171 | case AlphavantageTools.ALL_COMMODITIES.value: 1172 | interval = arguments.get("interval", "monthly") 1173 | datatype = arguments.get("datatype", "json") 1174 | 1175 | result = await fetch_all_commodities(interval, datatype) 1176 | 1177 | case AlphavantageTools.REAL_GDP.value: 1178 | interval = arguments.get("interval", "monthly") 1179 | datatype = arguments.get("datatype", "json") 1180 | 1181 | result = await fetch_real_gdp(interval, datatype) 1182 | 1183 | case AlphavantageTools.REAL_GDP_PER_CAPITA.value: 1184 | datatype = arguments.get("datatype", "json") 1185 | 1186 | result = await fetch_real_gdp_per_capita(datatype) 1187 | 1188 | case AlphavantageTools.TREASURY_YIELD.value: 1189 | interval = arguments.get("interval", "monthly") 1190 | maturity = arguments.get("maturity", "10year") 1191 | datatype = arguments.get("datatype", "json") 1192 | 1193 | result = await fetch_treasury_yield(interval, maturity, datatype) 1194 | 1195 | case AlphavantageTools.FEDERAL_FUNDS_RATE.value: 1196 | interval = arguments.get("interval", "monthly") 1197 | datatype = arguments.get("datatype", "json") 1198 | 1199 | result = await fetch_federal_funds_rate(interval, datatype) 1200 | 1201 | case AlphavantageTools.CPI.value: 1202 | interval = arguments.get("interval", "monthly") 1203 | datatype = arguments.get("datatype", "json") 1204 | 1205 | result = await fetch_cpi(interval, datatype) 1206 | 1207 | case AlphavantageTools.INFLATION.value: 1208 | datatype = arguments.get("datatype", "json") 1209 | 1210 | result = await fetch_inflation(datatype) 1211 | 1212 | case AlphavantageTools.RETAIL_SALES.value: 1213 | datatype = arguments.get("datatype", "json") 1214 | 1215 | result = await fetch_retail_sales(datatype) 1216 | 1217 | case AlphavantageTools.DURABLES.value: 1218 | datatype = arguments.get("datatype", "json") 1219 | 1220 | result = await fetch_durables(datatype) 1221 | 1222 | case AlphavantageTools.UNEMPLOYMENT.value: 1223 | datatype = arguments.get("datatype", "json") 1224 | 1225 | result = await fetch_unemployment(datatype) 1226 | 1227 | case AlphavantageTools.NONFARM_PAYROLL.value: 1228 | datatype = arguments.get("datatype", "json") 1229 | 1230 | result = await fetch_nonfarm_payrolls(datatype) 1231 | 1232 | case AlphavantageTools.SMA.value: 1233 | symbol = arguments.get("symbol") 1234 | interval = arguments.get("interval") 1235 | month = arguments.get("month") 1236 | time_period = arguments.get("time_period") 1237 | series_type = arguments.get("series_type") 1238 | datatype = arguments.get("datatype", "json") 1239 | max_data_points = arguments.get("max_data_points", 100) 1240 | 1241 | if not symbol or not interval or not time_period or not series_type: 1242 | raise ValueError( 1243 | "Missing required arguments: symbol, interval, time_period, series_type" 1244 | ) 1245 | 1246 | result = await fetch_sma( 1247 | symbol, 1248 | interval, 1249 | month, 1250 | time_period, 1251 | series_type, 1252 | datatype, 1253 | max_data_points, 1254 | ) 1255 | 1256 | case AlphavantageTools.EMA.value: 1257 | symbol = arguments.get("symbol") 1258 | interval = arguments.get("interval") 1259 | month = arguments.get("month") 1260 | time_period = arguments.get("time_period") 1261 | series_type = arguments.get("series_type") 1262 | datatype = arguments.get("datatype", "json") 1263 | 1264 | if not symbol or not interval or not time_period or not series_type: 1265 | raise ValueError( 1266 | "Missing required arguments: symbol, interval, time_period, series_type" 1267 | ) 1268 | 1269 | result = await fetch_ema( 1270 | symbol, interval, month, time_period, series_type, datatype 1271 | ) 1272 | 1273 | case AlphavantageTools.WMA.value: 1274 | symbol = arguments.get("symbol") 1275 | interval = arguments.get("interval") 1276 | month = arguments.get("month") 1277 | time_period = arguments.get("time_period") 1278 | series_type = arguments.get("series_type") 1279 | datatype = arguments.get("datatype", "json") 1280 | 1281 | if not symbol or not interval or not time_period or not series_type: 1282 | raise ValueError( 1283 | "Missing required arguments: symbol, interval, time_period, series_type" 1284 | ) 1285 | 1286 | result = await fetch_wma( 1287 | symbol, interval, month, time_period, series_type, datatype 1288 | ) 1289 | 1290 | case AlphavantageTools.DEMA.value: 1291 | symbol = arguments.get("symbol") 1292 | interval = arguments.get("interval") 1293 | month = arguments.get("month") 1294 | time_period = arguments.get("time_period") 1295 | series_type = arguments.get("series_type") 1296 | datatype = arguments.get("datatype", "json") 1297 | 1298 | if not symbol or not interval or not time_period or not series_type: 1299 | raise ValueError( 1300 | "Missing required arguments: symbol, interval, time_period, series_type" 1301 | ) 1302 | 1303 | result = await fetch_dema( 1304 | symbol, interval, month, time_period, series_type, datatype 1305 | ) 1306 | 1307 | case AlphavantageTools.TEMA.value: 1308 | symbol = arguments.get("symbol") 1309 | interval = arguments.get("interval") 1310 | month = arguments.get("month") 1311 | time_period = arguments.get("time_period") 1312 | series_type = arguments.get("series_type") 1313 | datatype = arguments.get("datatype", "json") 1314 | 1315 | if not symbol or not interval or not time_period or not series_type: 1316 | raise ValueError( 1317 | "Missing required arguments: symbol, interval, time_period, series_type" 1318 | ) 1319 | 1320 | result = await fetch_tema( 1321 | symbol, interval, month, time_period, series_type, datatype 1322 | ) 1323 | 1324 | case AlphavantageTools.TRIMA.value: 1325 | symbol = arguments.get("symbol") 1326 | interval = arguments.get("interval") 1327 | month = arguments.get("month") 1328 | time_period = arguments.get("time_period") 1329 | series_type = arguments.get("series_type") 1330 | datatype = arguments.get("datatype", "json") 1331 | 1332 | if not symbol or not interval or not time_period or not series_type: 1333 | raise ValueError( 1334 | "Missing required arguments: symbol, interval, time_period, series_type" 1335 | ) 1336 | 1337 | result = await fetch_trima( 1338 | symbol, interval, month, time_period, series_type, datatype 1339 | ) 1340 | 1341 | case AlphavantageTools.KAMA.value: 1342 | symbol = arguments.get("symbol") 1343 | interval = arguments.get("interval") 1344 | month = arguments.get("month") 1345 | time_period = arguments.get("time_period") 1346 | series_type = arguments.get("series_type") 1347 | datatype = arguments.get("datatype", "json") 1348 | 1349 | if not symbol or not interval or not time_period or not series_type: 1350 | raise ValueError( 1351 | "Missing required arguments: symbol, interval, time_period, series_type" 1352 | ) 1353 | 1354 | result = await fetch_kama( 1355 | symbol, interval, month, time_period, series_type, datatype 1356 | ) 1357 | 1358 | case AlphavantageTools.MAMA.value: 1359 | symbol = arguments.get("symbol") 1360 | interval = arguments.get("interval") 1361 | month = arguments.get("month") 1362 | series_type = arguments.get("series_type") 1363 | fastlimit = arguments.get("fastlimit") 1364 | slowlimit = arguments.get("slowlimit") 1365 | datatype = arguments.get("datatype", "json") 1366 | 1367 | if ( 1368 | not symbol 1369 | or not interval 1370 | or not series_type 1371 | or not fastlimit 1372 | or not slowlimit 1373 | ): 1374 | raise ValueError( 1375 | "Missing required arguments: symbol, interval, series_type, fastlimit, slowlimit" 1376 | ) 1377 | 1378 | result = await fetch_mama( 1379 | symbol, interval, month, series_type, fastlimit, slowlimit, datatype 1380 | ) 1381 | 1382 | case AlphavantageTools.VWAP.value: 1383 | symbol = arguments.get("symbol") 1384 | interval = arguments.get("interval") 1385 | month = arguments.get("month") 1386 | datatype = arguments.get("datatype", "json") 1387 | 1388 | if not symbol or not interval: 1389 | raise ValueError("Missing required arguments: symbol, interval") 1390 | 1391 | result = await fetch_vwap(symbol, interval, month, datatype) 1392 | 1393 | case AlphavantageTools.T3.value: 1394 | symbol = arguments.get("symbol") 1395 | interval = arguments.get("interval") 1396 | month = arguments.get("month") 1397 | time_period = arguments.get("time_period") 1398 | series_type = arguments.get("series_type") 1399 | datatype = arguments.get("datatype", "json") 1400 | 1401 | if not symbol or not interval or not time_period or not series_type: 1402 | raise ValueError( 1403 | "Missing required arguments: symbol, interval, time_period, series_type" 1404 | ) 1405 | 1406 | result = await fetch_t3( 1407 | symbol, interval, month, time_period, series_type, datatype 1408 | ) 1409 | 1410 | case AlphavantageTools.MACD.value: 1411 | symbol = arguments.get("symbol") 1412 | interval = arguments.get("interval") 1413 | month = arguments.get("month") 1414 | series_type = arguments.get("series_type") 1415 | fastperiod = arguments.get("fastperiod", 12) 1416 | slowperiod = arguments.get("slowperiod", 26) 1417 | signalperiod = arguments.get("signalperiod", 9) 1418 | datatype = arguments.get("datatype", "json") 1419 | 1420 | if not symbol or not interval or not series_type: 1421 | raise ValueError( 1422 | "Missing required arguments: symbol, interval, series_type" 1423 | ) 1424 | 1425 | result = await fetch_macd( 1426 | symbol, 1427 | interval, 1428 | month, 1429 | series_type, 1430 | fastperiod, 1431 | slowperiod, 1432 | signalperiod, 1433 | datatype, 1434 | ) 1435 | case AlphavantageTools.MACDEXT.value: 1436 | symbol = arguments.get("symbol") 1437 | interval = arguments.get("interval") 1438 | month = arguments.get("month") 1439 | series_type = arguments.get("series_type") 1440 | fastperiod = arguments.get("fastperiod", 12) 1441 | slowperiod = arguments.get("slowperiod", 26) 1442 | signalperiod = arguments.get("signalperiod", 9) 1443 | fastmatype = arguments.get("fastmatype", 0) 1444 | slowmatype = arguments.get("slowmatype", 0) 1445 | signalmatype = arguments.get("signalmatype", 0) 1446 | datatype = arguments.get("datatype", "json") 1447 | 1448 | if not symbol or not interval or not series_type: 1449 | raise ValueError( 1450 | "Missing required arguments: symbol, interval, series_type" 1451 | ) 1452 | 1453 | result = await fetch_macdext( 1454 | symbol, 1455 | interval, 1456 | month, 1457 | series_type, 1458 | fastperiod, 1459 | slowperiod, 1460 | signalperiod, 1461 | fastmatype, 1462 | slowmatype, 1463 | signalmatype, 1464 | datatype, 1465 | ) 1466 | 1467 | case AlphavantageTools.STOCH.value: 1468 | symbol = arguments.get("symbol") 1469 | interval = arguments.get("interval") 1470 | month = arguments.get("month") 1471 | fastkperiod = arguments.get("fastkperiod", 5) 1472 | slowkperiod = arguments.get("slowkperiod", 3) 1473 | slowdperiod = arguments.get("slowdperiod", 3) 1474 | slowkmatype = arguments.get("slowkmatype", 0) 1475 | slowdmatype = arguments.get("slowdmatype", 0) 1476 | datatype = arguments.get("datatype", "json") 1477 | 1478 | if not symbol or not interval: 1479 | raise ValueError("Missing required arguments: symbol, interval") 1480 | 1481 | result = await fetch_stoch( 1482 | symbol, 1483 | interval, 1484 | month, 1485 | fastkperiod, 1486 | slowkperiod, 1487 | slowdperiod, 1488 | slowkmatype, 1489 | slowdmatype, 1490 | datatype, 1491 | ) 1492 | 1493 | case AlphavantageTools.STOCHF.value: 1494 | symbol = arguments.get("symbol") 1495 | interval = arguments.get("interval") 1496 | month = arguments.get("month") 1497 | fastkperiod = arguments.get("fastkperiod", 5) 1498 | fastdperiod = arguments.get("fastdperiod", 3) 1499 | fastdmatype = arguments.get("fastdmatype", 0) 1500 | datatype = arguments.get("datatype", "json") 1501 | 1502 | if not symbol or not interval: 1503 | raise ValueError("Missing required arguments: symbol, interval") 1504 | 1505 | result = await fetch_stochf( 1506 | symbol, 1507 | interval, 1508 | month, 1509 | fastkperiod, 1510 | fastdperiod, 1511 | fastdmatype, 1512 | datatype, 1513 | ) 1514 | 1515 | case AlphavantageTools.RSI.value: 1516 | symbol = arguments.get("symbol") 1517 | interval = arguments.get("interval") 1518 | month = arguments.get("month") 1519 | time_period = arguments.get("time_period", 14) 1520 | series_type = arguments.get("series_type") 1521 | datatype = arguments.get("datatype", "json") 1522 | 1523 | if not symbol or not interval or not series_type: 1524 | raise ValueError( 1525 | "Missing required arguments: symbol, interval, series_type" 1526 | ) 1527 | 1528 | result = await fetch_rsi( 1529 | symbol, interval, month, time_period, series_type, datatype 1530 | ) 1531 | 1532 | case AlphavantageTools.STOCHRSI.value: 1533 | symbol = arguments.get("symbol") 1534 | interval = arguments.get("interval") 1535 | month = arguments.get("month") 1536 | time_period = arguments.get("time_period", 14) 1537 | series_type = arguments.get("series_type") 1538 | fastkperiod = arguments.get("fastkperiod", 5) 1539 | fastdperiod = arguments.get("fastdperiod", 3) 1540 | fastdmatype = arguments.get("fastdmatype", 0) 1541 | datatype = arguments.get("datatype", "json") 1542 | 1543 | if not symbol or not interval or not time_period or not series_type: 1544 | raise ValueError( 1545 | "Missing required arguments: symbol, interval, time_period, series_type" 1546 | ) 1547 | 1548 | result = await fetch_stochrsi( 1549 | symbol, 1550 | interval, 1551 | month, 1552 | time_period, 1553 | series_type, 1554 | fastkperiod, 1555 | fastdperiod, 1556 | fastdmatype, 1557 | datatype, 1558 | ) 1559 | 1560 | case AlphavantageTools.WILLR.value: 1561 | symbol = arguments.get("symbol") 1562 | interval = arguments.get("interval") 1563 | month = arguments.get("month") 1564 | time_period = arguments.get("time_period", 14) 1565 | datatype = arguments.get("datatype", "json") 1566 | 1567 | if not symbol or not interval: 1568 | raise ValueError( 1569 | "Missing required arguments: symbol, interval, time_period" 1570 | ) 1571 | 1572 | result = await fetch_willr( 1573 | symbol, interval, month, time_period, datatype 1574 | ) 1575 | 1576 | case AlphavantageTools.ADX.value: 1577 | symbol = arguments.get("symbol") 1578 | interval = arguments.get("interval") 1579 | month = arguments.get("month") 1580 | time_period = arguments.get("time_period", 14) 1581 | datatype = arguments.get("datatype", "json") 1582 | 1583 | if not symbol or not interval: 1584 | raise ValueError( 1585 | "Missing required arguments: symbol, interval, time_period" 1586 | ) 1587 | 1588 | result = await fetch_adx(symbol, interval, month, time_period, datatype) 1589 | 1590 | case AlphavantageTools.ADXR.value: 1591 | symbol = arguments.get("symbol") 1592 | interval = arguments.get("interval") 1593 | month = arguments.get("month") 1594 | time_period = arguments.get("time_period", 14) 1595 | datatype = arguments.get("datatype", "json") 1596 | 1597 | if not symbol or not interval: 1598 | raise ValueError( 1599 | "Missing required arguments: symbol, interval, time_period" 1600 | ) 1601 | 1602 | result = await fetch_adxr( 1603 | symbol, interval, month, time_period, datatype 1604 | ) 1605 | 1606 | case AlphavantageTools.APO.value: 1607 | symbol = arguments.get("symbol") 1608 | interval = arguments.get("interval") 1609 | month = arguments.get("month") 1610 | series_type = arguments.get("series_type") 1611 | fastperiod = arguments.get("fastperiod", 12) 1612 | slowperiod = arguments.get("slowperiod", 26) 1613 | matype = arguments.get("matype", 0) 1614 | datatype = arguments.get("datatype", "json") 1615 | 1616 | if not symbol or not interval or not series_type: 1617 | raise ValueError( 1618 | "Missing required arguments: symbol, interval, series_type" 1619 | ) 1620 | 1621 | result = await fetch_apo( 1622 | symbol, 1623 | interval, 1624 | month, 1625 | series_type, 1626 | fastperiod, 1627 | slowperiod, 1628 | matype, 1629 | datatype, 1630 | ) 1631 | 1632 | case AlphavantageTools.PPO.value: 1633 | symbol = arguments.get("symbol") 1634 | interval = arguments.get("interval") 1635 | month = arguments.get("month") 1636 | series_type = arguments.get("series_type") 1637 | fastperiod = arguments.get("fastperiod", 12) 1638 | slowperiod = arguments.get("slowperiod", 26) 1639 | matype = arguments.get("matype", 0) 1640 | datatype = arguments.get("datatype", "json") 1641 | 1642 | if not symbol or not interval or not series_type: 1643 | raise ValueError( 1644 | "Missing required arguments: symbol, interval, series_type" 1645 | ) 1646 | 1647 | result = await fetch_ppo( 1648 | symbol, 1649 | interval, 1650 | month, 1651 | series_type, 1652 | fastperiod, 1653 | slowperiod, 1654 | matype, 1655 | datatype, 1656 | ) 1657 | 1658 | case AlphavantageTools.MOM.value: 1659 | symbol = arguments.get("symbol") 1660 | interval = arguments.get("interval") 1661 | month = arguments.get("month") 1662 | time_period = arguments.get("time_period", 10) 1663 | series_type = arguments.get("series_type") 1664 | datatype = arguments.get("datatype", "json") 1665 | 1666 | if not symbol or not interval or not series_type: 1667 | raise ValueError( 1668 | "Missing required arguments: symbol, interval, series_type" 1669 | ) 1670 | 1671 | result = await fetch_mom( 1672 | symbol, interval, month, time_period, series_type, datatype 1673 | ) 1674 | 1675 | case AlphavantageTools.BOP.value: 1676 | symbol = arguments.get("symbol") 1677 | interval = arguments.get("interval") 1678 | month = arguments.get("month") 1679 | datatype = arguments.get("datatype", "json") 1680 | 1681 | if not symbol or not interval: 1682 | raise ValueError("Missing required arguments: symbol, interval") 1683 | 1684 | result = await fetch_bop(symbol, interval, month, datatype) 1685 | 1686 | case AlphavantageTools.CCI.value: 1687 | symbol = arguments.get("symbol") 1688 | interval = arguments.get("interval") 1689 | month = arguments.get("month") 1690 | time_period = arguments.get("time_period", 20) 1691 | datatype = arguments.get("datatype", "json") 1692 | 1693 | if not symbol or not interval: 1694 | raise ValueError("Missing required arguments: symbol, interval") 1695 | 1696 | result = await fetch_cci(symbol, interval, month, time_period, datatype) 1697 | 1698 | case AlphavantageTools.CMO.value: 1699 | symbol = arguments.get("symbol") 1700 | interval = arguments.get("interval") 1701 | month = arguments.get("month") 1702 | time_period = arguments.get("time_period", 14) 1703 | datatype = arguments.get("datatype", "json") 1704 | 1705 | if not symbol or not interval: 1706 | raise ValueError("Missing required arguments: symbol, interval") 1707 | 1708 | result = await fetch_cmo(symbol, interval, month, time_period, datatype) 1709 | 1710 | case AlphavantageTools.ROC.value: 1711 | symbol = arguments.get("symbol") 1712 | interval = arguments.get("interval") 1713 | month = arguments.get("month") 1714 | time_period = arguments.get("time_period", 10) 1715 | series_type = arguments.get("series_type") 1716 | datatype = arguments.get("datatype", "json") 1717 | 1718 | if not symbol or not interval or not series_type: 1719 | raise ValueError( 1720 | "Missing required arguments: symbol, interval, series_type" 1721 | ) 1722 | 1723 | result = await fetch_roc( 1724 | symbol, interval, month, time_period, series_type, datatype 1725 | ) 1726 | 1727 | case AlphavantageTools.ROCR.value: 1728 | symbol = arguments.get("symbol") 1729 | interval = arguments.get("interval") 1730 | month = arguments.get("month") 1731 | time_period = arguments.get("time_period", 10) 1732 | series_type = arguments.get("series_type") 1733 | datatype = arguments.get("datatype", "json") 1734 | 1735 | if not symbol or not interval or not series_type: 1736 | raise ValueError( 1737 | "Missing required arguments: symbol, interval, series_type" 1738 | ) 1739 | 1740 | result = await fetch_rocr( 1741 | symbol, interval, month, time_period, series_type, datatype 1742 | ) 1743 | 1744 | case AlphavantageTools.AROON.value: 1745 | symbol = arguments.get("symbol") 1746 | interval = arguments.get("interval") 1747 | month = arguments.get("month") 1748 | time_period = arguments.get("time_period", 14) 1749 | datatype = arguments.get("datatype", "json") 1750 | 1751 | if not symbol or not interval: 1752 | raise ValueError("Missing required arguments: symbol, interval") 1753 | 1754 | result = await fetch_aroon( 1755 | symbol, interval, month, time_period, datatype 1756 | ) 1757 | 1758 | case AlphavantageTools.AROONOSC.value: 1759 | symbol = arguments.get("symbol") 1760 | interval = arguments.get("interval") 1761 | month = arguments.get("month") 1762 | time_period = arguments.get("time_period", 14) 1763 | datatype = arguments.get("datatype", "json") 1764 | 1765 | if not symbol or not interval: 1766 | raise ValueError("Missing required arguments: symbol, interval") 1767 | 1768 | result = await fetch_aroonosc( 1769 | symbol, interval, month, time_period, datatype 1770 | ) 1771 | 1772 | case AlphavantageTools.MFI.value: 1773 | symbol = arguments.get("symbol") 1774 | interval = arguments.get("interval") 1775 | month = arguments.get("month") 1776 | time_period = arguments.get("time_period", 14) 1777 | datatype = arguments.get("datatype", "json") 1778 | 1779 | if not symbol or not interval: 1780 | raise ValueError("Missing required arguments: symbol, interval") 1781 | 1782 | result = await fetch_mfi(symbol, interval, month, time_period, datatype) 1783 | 1784 | case AlphavantageTools.TRIX.value: 1785 | symbol = arguments.get("symbol") 1786 | interval = arguments.get("interval") 1787 | month = arguments.get("month") 1788 | time_period = arguments.get("time_period", 30) 1789 | series_type = arguments.get("series_type") 1790 | datatype = arguments.get("datatype", "json") 1791 | 1792 | if not symbol or not interval or not series_type: 1793 | raise ValueError( 1794 | "Missing required arguments: symbol, interval, series_type" 1795 | ) 1796 | 1797 | result = await fetch_trix( 1798 | symbol, interval, month, time_period, series_type, datatype 1799 | ) 1800 | 1801 | case AlphavantageTools.ULTOSC.value: 1802 | symbol = arguments.get("symbol") 1803 | interval = arguments.get("interval") 1804 | month = arguments.get("month") 1805 | time_period1 = arguments.get("time_period1", 7) 1806 | time_period2 = arguments.get("time_period2", 14) 1807 | time_period3 = arguments.get("time_period3", 28) 1808 | datatype = arguments.get("datatype", "json") 1809 | 1810 | if not symbol or not interval: 1811 | raise ValueError("Missing required arguments: symbol, interval") 1812 | 1813 | result = await fetch_ultosc( 1814 | symbol, 1815 | interval, 1816 | month, 1817 | time_period1, 1818 | time_period2, 1819 | time_period3, 1820 | datatype, 1821 | ) 1822 | 1823 | case AlphavantageTools.DX.value: 1824 | symbol = arguments.get("symbol") 1825 | interval = arguments.get("interval") 1826 | month = arguments.get("month") 1827 | time_period = arguments.get("time_period", 14) 1828 | datatype = arguments.get("datatype", "json") 1829 | 1830 | if not symbol or not interval or not time_period: 1831 | raise ValueError( 1832 | "Missing required arguments: symbol, interval, time_period" 1833 | ) 1834 | 1835 | result = await fetch_dx(symbol, interval, month, time_period, datatype) 1836 | 1837 | case AlphavantageTools.MINUS_DI.value: 1838 | symbol = arguments.get("symbol") 1839 | interval = arguments.get("interval") 1840 | month = arguments.get("month") 1841 | time_period = arguments.get("time_period", 14) 1842 | datatype = arguments.get("datatype", "json") 1843 | 1844 | if not symbol or not interval or not time_period: 1845 | raise ValueError( 1846 | "Missing required arguments: symbol, interval, time_period" 1847 | ) 1848 | 1849 | result = await fetch_minus_di( 1850 | symbol, interval, month, time_period, datatype 1851 | ) 1852 | 1853 | case AlphavantageTools.PLUS_DI.value: 1854 | symbol = arguments.get("symbol") 1855 | interval = arguments.get("interval") 1856 | month = arguments.get("month") 1857 | time_period = arguments.get("time_period", 14) 1858 | datatype = arguments.get("datatype", "json") 1859 | 1860 | if not symbol or not interval or not time_period: 1861 | raise ValueError( 1862 | "Missing required arguments: symbol, interval, time_period" 1863 | ) 1864 | 1865 | result = await fetch_plus_di( 1866 | symbol, interval, month, time_period, datatype 1867 | ) 1868 | case AlphavantageTools.MINUS_DM.value: 1869 | symbol = arguments.get("symbol") 1870 | interval = arguments.get("interval") 1871 | month = arguments.get("month") 1872 | time_period = arguments.get("time_period", 14) 1873 | datatype = arguments.get("datatype", "json") 1874 | 1875 | if not symbol or not interval or not time_period: 1876 | raise ValueError( 1877 | "Missing required arguments: symbol, interval, time_period" 1878 | ) 1879 | 1880 | result = await fetch_minus_dm( 1881 | symbol, interval, month, time_period, datatype 1882 | ) 1883 | 1884 | case AlphavantageTools.PLUS_DM.value: 1885 | symbol = arguments.get("symbol") 1886 | interval = arguments.get("interval") 1887 | month = arguments.get("month") 1888 | time_period = arguments.get("time_period", 14) 1889 | datatype = arguments.get("datatype", "json") 1890 | 1891 | if not symbol or not interval or not time_period: 1892 | raise ValueError( 1893 | "Missing required arguments: symbol, interval, time_period" 1894 | ) 1895 | 1896 | result = await fetch_plus_dm( 1897 | symbol, interval, month, time_period, datatype 1898 | ) 1899 | 1900 | case AlphavantageTools.BBANDS.value: 1901 | symbol = arguments.get("symbol") 1902 | interval = arguments.get("interval") 1903 | month = arguments.get("month") 1904 | time_period = arguments.get("time_period", 20) 1905 | series_type = arguments.get("series_type") 1906 | nbdevup = arguments.get("nbdevup", 2) 1907 | nbdevdn = arguments.get("nbdevdn", 2) 1908 | matype = arguments.get("matype", 0) 1909 | datatype = arguments.get("datatype", "json") 1910 | 1911 | if not symbol or not interval or not series_type: 1912 | raise ValueError( 1913 | "Missing required arguments: symbol, interval, series_type" 1914 | ) 1915 | 1916 | result = await fetch_bbands( 1917 | symbol, 1918 | interval, 1919 | month, 1920 | time_period, 1921 | series_type, 1922 | nbdevup, 1923 | nbdevdn, 1924 | matype, 1925 | datatype, 1926 | ) 1927 | 1928 | case AlphavantageTools.MIDPOINT.value: 1929 | symbol = arguments.get("symbol") 1930 | interval = arguments.get("interval") 1931 | month = arguments.get("month") 1932 | time_period = arguments.get("time_period", 14) 1933 | series_type = arguments.get("series_type") 1934 | datatype = arguments.get("datatype", "json") 1935 | 1936 | if not symbol or not interval or not time_period or not series_type: 1937 | raise ValueError( 1938 | "Missing required arguments: symbol, interval, time_period, series_type" 1939 | ) 1940 | 1941 | result = await fetch_midpoint( 1942 | symbol, interval, month, time_period, series_type, datatype 1943 | ) 1944 | 1945 | case AlphavantageTools.MIDPRICE.value: 1946 | symbol = arguments.get("symbol") 1947 | interval = arguments.get("interval") 1948 | month = arguments.get("month") 1949 | time_period = arguments.get("time_period", 14) 1950 | datatype = arguments.get("datatype", "json") 1951 | 1952 | if not symbol or not interval or not time_period: 1953 | raise ValueError( 1954 | "Missing required arguments: symbol, interval, time_period" 1955 | ) 1956 | 1957 | result = await fetch_midprice( 1958 | symbol, interval, month, time_period, datatype 1959 | ) 1960 | 1961 | case AlphavantageTools.SAR.value: 1962 | symbol = arguments.get("symbol") 1963 | interval = arguments.get("interval") 1964 | month = arguments.get("month") 1965 | acceleration = arguments.get("acceleration", 0.02) 1966 | maximum = arguments.get("maximum", 0.2) 1967 | datatype = arguments.get("datatype", "json") 1968 | 1969 | if not symbol or not interval: 1970 | raise ValueError("Missing required arguments: symbol, interval") 1971 | 1972 | result = await fetch_sar( 1973 | symbol, interval, month, acceleration, maximum, datatype 1974 | ) 1975 | 1976 | case AlphavantageTools.TRANGE.value: 1977 | symbol = arguments.get("symbol") 1978 | interval = arguments.get("interval") 1979 | month = arguments.get("month") 1980 | datatype = arguments.get("datatype", "json") 1981 | 1982 | if not symbol or not interval: 1983 | raise ValueError("Missing required arguments: symbol, interval") 1984 | 1985 | result = await fetch_trange(symbol, interval, month, datatype) 1986 | 1987 | case AlphavantageTools.ATR.value: 1988 | symbol = arguments.get("symbol") 1989 | interval = arguments.get("interval") 1990 | month = arguments.get("month") 1991 | time_period = arguments.get("time_period", 14) 1992 | datatype = arguments.get("datatype", "json") 1993 | 1994 | if not symbol or not interval or not time_period: 1995 | raise ValueError( 1996 | "Missing required arguments: symbol, interval, time_period" 1997 | ) 1998 | 1999 | result = await fetch_atr(symbol, interval, month, time_period, datatype) 2000 | 2001 | case AlphavantageTools.NATR.value: 2002 | symbol = arguments.get("symbol") 2003 | interval = arguments.get("interval") 2004 | month = arguments.get("month") 2005 | time_period = arguments.get("time_period", 14) 2006 | datatype = arguments.get("datatype", "json") 2007 | 2008 | if not symbol or not interval or not time_period: 2009 | raise ValueError( 2010 | "Missing required arguments: symbol, interval, time_period" 2011 | ) 2012 | 2013 | result = await fetch_natr( 2014 | symbol, interval, month, time_period, datatype 2015 | ) 2016 | 2017 | case AlphavantageTools.AD.value: 2018 | symbol = arguments.get("symbol") 2019 | interval = arguments.get("interval") 2020 | month = arguments.get("month") 2021 | datatype = arguments.get("datatype", "json") 2022 | 2023 | if not symbol or not interval: 2024 | raise ValueError("Missing required arguments: symbol, interval") 2025 | 2026 | result = await fetch_ad(symbol, interval, month, datatype) 2027 | 2028 | case AlphavantageTools.ADOSC.value: 2029 | symbol = arguments.get("symbol") 2030 | interval = arguments.get("interval") 2031 | month = arguments.get("month") 2032 | fastperiod = arguments.get("fastperiod", 3) 2033 | slowperiod = arguments.get("slowperiod", 10) 2034 | datatype = arguments.get("datatype", "json") 2035 | 2036 | if not symbol or not interval: 2037 | raise ValueError("Missing required arguments: symbol, interval") 2038 | 2039 | result = await fetch_adosc( 2040 | symbol, interval, month, fastperiod, slowperiod, datatype 2041 | ) 2042 | 2043 | case AlphavantageTools.OBV.value: 2044 | symbol = arguments.get("symbol") 2045 | interval = arguments.get("interval") 2046 | month = arguments.get("month") 2047 | datatype = arguments.get("datatype", "json") 2048 | 2049 | if not symbol or not interval: 2050 | raise ValueError("Missing required arguments: symbol, interval") 2051 | 2052 | result = await fetch_obv(symbol, interval, month, datatype) 2053 | 2054 | case AlphavantageTools.HT_TRENDLINE.value: 2055 | symbol = arguments.get("symbol") 2056 | interval = arguments.get("interval") 2057 | month = arguments.get("month") 2058 | series_type = arguments.get("series_type") 2059 | datatype = arguments.get("datatype", "json") 2060 | 2061 | if not symbol or not interval or not series_type: 2062 | raise ValueError( 2063 | "Missing required arguments: symbol, interval, series_type" 2064 | ) 2065 | 2066 | result = await fetch_ht_trendline( 2067 | symbol, interval, month, series_type, datatype 2068 | ) 2069 | 2070 | case AlphavantageTools.HT_SINE.value: 2071 | symbol = arguments.get("symbol") 2072 | interval = arguments.get("interval") 2073 | month = arguments.get("month") 2074 | series_type = arguments.get("series_type") 2075 | datatype = arguments.get("datatype", "json") 2076 | 2077 | if not symbol or not interval or not series_type: 2078 | raise ValueError( 2079 | "Missing required arguments: symbol, interval, series_type" 2080 | ) 2081 | 2082 | result = await fetch_ht_sine( 2083 | symbol, interval, month, series_type, datatype 2084 | ) 2085 | 2086 | case AlphavantageTools.HT_TRENDMODE.value: 2087 | symbol = arguments.get("symbol") 2088 | interval = arguments.get("interval") 2089 | month = arguments.get("month") 2090 | datatype = arguments.get("datatype", "json") 2091 | 2092 | if not symbol or not interval: 2093 | raise ValueError("Missing required arguments: symbol, interval") 2094 | 2095 | result = await fetch_ht_trendmode(symbol, interval, month, datatype) 2096 | 2097 | case AlphavantageTools.HT_DCPERIOD.value: 2098 | symbol = arguments.get("symbol") 2099 | interval = arguments.get("interval") 2100 | month = arguments.get("month") 2101 | series_types = arguments.get("series_types") 2102 | datatype = arguments.get("datatype", "json") 2103 | 2104 | if not symbol or not interval or not series_types: 2105 | raise ValueError( 2106 | "Missing required arguments: symbol, interval, series_types" 2107 | ) 2108 | 2109 | result = await fetch_ht_dcperiod( 2110 | symbol, interval, month, series_types, datatype 2111 | ) 2112 | 2113 | case AlphavantageTools.HT_DCPHASE.value: 2114 | symbol = arguments.get("symbol") 2115 | interval = arguments.get("interval") 2116 | month = arguments.get("month") 2117 | series_types = arguments.get("series_types") 2118 | datatype = arguments.get("datatype", "json") 2119 | 2120 | if not symbol or not interval or not series_types: 2121 | raise ValueError( 2122 | "Missing required arguments: symbol, interval, series_types" 2123 | ) 2124 | 2125 | result = await fetch_ht_dcphase( 2126 | symbol, interval, month, series_types, datatype 2127 | ) 2128 | 2129 | case AlphavantageTools.HT_PHASOR.value: 2130 | symbol = arguments.get("symbol") 2131 | interval = arguments.get("interval") 2132 | month = arguments.get("month") 2133 | series_types = arguments.get("series_types") 2134 | datatype = arguments.get("datatype", "json") 2135 | 2136 | if not symbol or not interval or not series_types: 2137 | raise ValueError( 2138 | "Missing required arguments: symbol, interval, series_types" 2139 | ) 2140 | 2141 | result = await fetch_ht_phasor( 2142 | symbol, interval, month, series_types, datatype 2143 | ) 2144 | case _: 2145 | raise ValueError(f"Unknown tool: {name}") 2146 | 2147 | return [types.TextContent(type="text", text=json.dumps(result, indent=2))] 2148 | 2149 | except Exception as e: 2150 | raise ValueError(f"Error processing alphavantage query: {str(e)}") from e 2151 | 2152 | 2153 | def get_version(): 2154 | with open("pyproject.toml", "r") as f: 2155 | pyproject = toml.load(f) 2156 | return pyproject["project"]["version"] 2157 | 2158 | 2159 | async def run_stdio_server(): 2160 | """Run the MCP stdio server""" 2161 | # Initialize telemetry for stdio transport 2162 | init_telemetry(start_metrics=True) 2163 | 2164 | async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): 2165 | await server.run( 2166 | read_stream, 2167 | write_stream, 2168 | InitializationOptions( 2169 | server_name="alphavantage", 2170 | server_version=get_version(), 2171 | capabilities=server.get_capabilities( 2172 | notification_options=NotificationOptions(), 2173 | experimental_capabilities={}, 2174 | ), 2175 | ), 2176 | ) 2177 | 2178 | 2179 | async def run_streamable_http_server(port=8080, oauth_enabled=False): 2180 | """Run the Streamable HTTP server on the specified port""" 2181 | 2182 | # Initialize telemetry for HTTP transport 2183 | init_telemetry(start_metrics=True) 2184 | 2185 | transport = StreamableHTTPServerTransport( 2186 | mcp_session_id=None, is_json_response_enabled=True 2187 | ) 2188 | 2189 | # Setup OAuth if enabled 2190 | oauth_server = None 2191 | if oauth_enabled: 2192 | oauth_config = create_oauth_config_from_env() 2193 | if oauth_config: 2194 | oauth_server = OAuthResourceServer(oauth_config) 2195 | logger.info( 2196 | f"OAuth enabled for resource server: {oauth_config.resource_server_uri}" 2197 | ) 2198 | else: 2199 | logger.warning( 2200 | "OAuth requested but no configuration found. Running without OAuth." 2201 | ) 2202 | 2203 | async with transport.connect() as (read_stream, write_stream): 2204 | server_task = asyncio.create_task( 2205 | server.run( 2206 | read_stream, 2207 | write_stream, 2208 | InitializationOptions( 2209 | server_name="alphavantage", 2210 | server_version=get_version(), 2211 | capabilities=server.get_capabilities( 2212 | notification_options=NotificationOptions(), 2213 | experimental_capabilities={}, 2214 | ), 2215 | ), 2216 | ) 2217 | ) 2218 | 2219 | # Create OAuth-enhanced ASGI app wrapper for the transport 2220 | async def asgi_app(scope, receive, send): 2221 | if scope["type"] != "http": 2222 | return await send_404(send) 2223 | 2224 | path = scope["path"] 2225 | request = Request(scope, receive) 2226 | 2227 | # Handle OAuth metadata endpoint if OAuth is enabled 2228 | if oauth_server and path == oauth_server.config.resource_metadata_path: 2229 | response = await oauth_server.handle_resource_metadata_request(request) 2230 | return await send_starlette_response(response, send) 2231 | 2232 | # Handle MCP requests 2233 | elif path.startswith("/mcp"): 2234 | # OAuth authentication if enabled 2235 | if oauth_server: 2236 | # Extract session ID from request if present 2237 | session_id = request.headers.get("X-Session-ID") 2238 | 2239 | ( 2240 | is_authenticated, 2241 | validation_result, 2242 | ) = await oauth_server.authenticate_request(request, session_id) 2243 | 2244 | if not is_authenticated: 2245 | # Return appropriate error response 2246 | if ( 2247 | validation_result 2248 | and validation_result.error == "Insufficient scopes" 2249 | ): 2250 | response = await oauth_server.create_forbidden_response( 2251 | error="insufficient_scope", 2252 | description="Required scopes not present in token", 2253 | ) 2254 | else: 2255 | error_desc = ( 2256 | validation_result.error 2257 | if validation_result 2258 | else "No valid token provided" 2259 | ) 2260 | response = await oauth_server.create_unauthorized_response( 2261 | error="invalid_token", description=error_desc 2262 | ) 2263 | return await send_starlette_response(response, send) 2264 | 2265 | # Log successful authentication 2266 | logger.info( 2267 | f"Authenticated MCP request for user: {validation_result.subject}" 2268 | ) 2269 | 2270 | # Process MCP request 2271 | try: 2272 | await transport.handle_request(scope, receive, send) 2273 | except Exception as e: 2274 | logger.error(f"Error handling MCP request: {e}") 2275 | await send_error_response(send, 500, "Internal Server Error") 2276 | 2277 | else: 2278 | # Return 404 for unknown paths 2279 | await send_404(send) 2280 | 2281 | config = uvicorn.Config(asgi_app, host="localhost", port=port) 2282 | uvicorn_server = uvicorn.Server(config) 2283 | http_task = asyncio.create_task(uvicorn_server.serve()) 2284 | 2285 | try: 2286 | await asyncio.gather(server_task, http_task) 2287 | finally: 2288 | # Cleanup OAuth resources 2289 | if oauth_server: 2290 | await oauth_server.cleanup() 2291 | 2292 | 2293 | async def send_starlette_response(response: Response, send): 2294 | """Send a Starlette Response through ASGI send callable.""" 2295 | await send( 2296 | { 2297 | "type": "http.response.start", 2298 | "status": response.status_code, 2299 | "headers": [ 2300 | [key.encode(), value.encode()] 2301 | for key, value in response.headers.items() 2302 | ], 2303 | } 2304 | ) 2305 | 2306 | # Handle different response types 2307 | if hasattr(response, "body"): 2308 | body = response.body 2309 | elif hasattr(response, "content"): 2310 | body = response.content 2311 | else: 2312 | body = b"" 2313 | 2314 | await send( 2315 | { 2316 | "type": "http.response.body", 2317 | "body": body, 2318 | } 2319 | ) 2320 | 2321 | 2322 | async def send_404(send): 2323 | """Send a 404 Not Found response.""" 2324 | await send( 2325 | { 2326 | "type": "http.response.start", 2327 | "status": 404, 2328 | "headers": [[b"content-type", b"text/plain"]], 2329 | } 2330 | ) 2331 | await send( 2332 | { 2333 | "type": "http.response.body", 2334 | "body": b"Not Found", 2335 | } 2336 | ) 2337 | 2338 | 2339 | async def send_error_response(send, status_code: int, message: str): 2340 | """Send an error response.""" 2341 | await send( 2342 | { 2343 | "type": "http.response.start", 2344 | "status": status_code, 2345 | "headers": [[b"content-type", b"text/plain"]], 2346 | } 2347 | ) 2348 | await send( 2349 | { 2350 | "type": "http.response.body", 2351 | "body": message.encode(), 2352 | } 2353 | ) 2354 | 2355 | 2356 | async def main(server_type="stdio", port=8080, oauth_enabled=False): 2357 | """Main entry point with server type selection""" 2358 | if server_type == "http": 2359 | if oauth_enabled: 2360 | logger.info(f"Starting Streamable HTTP server with OAuth on port {port}") 2361 | else: 2362 | logger.info(f"Starting Streamable HTTP server on port {port}") 2363 | await run_streamable_http_server(port=port, oauth_enabled=oauth_enabled) 2364 | else: 2365 | logger.info("Starting stdio server") 2366 | await run_stdio_server() 2367 | ```