├── .python-version ├── .env.example ├── pyproject.toml ├── LICENSE ├── README.md ├── .gitignore ├── server.py └── uv.lock /.python-version: -------------------------------------------------------------------------------- 1 | 3.11 2 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Get your Financial Datasets API key from https://financialdatasets.ai/ 2 | FINANCIAL_DATASETS_API_KEY=your-financial-datasets-api-key -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "mcp-server" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.11" 7 | dependencies = [ 8 | "httpx>=0.28.1", 9 | "mcp[cli]>=1.3.0", 10 | "python-dotenv>=1.0.0", 11 | ] 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Financial Datasets 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Financial Datasets MCP Server 2 | 3 | ## Introduction 4 | 5 | This is a Model Context Protocol (MCP) server that provides access to stock market data from [Financial Datasets](https://www.financialdatasets.ai/). 6 | 7 | It allows Claude and other AI assistants to retrieve income statements, balance sheets, cash flow statements, stock prices, and market news directly through the MCP interface. 8 | 9 | ## Available Tools 10 | 11 | This MCP server provides the following tools: 12 | - **get_income_statements**: Get income statements for a company. 13 | - **get_balance_sheets**: Get balance sheets for a company. 14 | - **get_cash_flow_statements**: Get cash flow statements for a company. 15 | - **get_current_stock_price**: Get the current / latest price of a company. 16 | - **get_historical_stock_prices**: Gets historical stock prices for a company. 17 | - **get_company_news**: Get news for a company. 18 | - **get_available_crypto_tickers**: Gets all available crypto tickers. 19 | - **get_crypto_prices**: Gets historical prices for a crypto currency. 20 | - **get_historical_crypto_prices**: Gets historical prices for a crypto currency. 21 | - **get_current_crypto_price**: Get the current / latest price of a crypto currency. 22 | 23 | ## Setup 24 | 25 | ### Prerequisites 26 | 27 | - Python 3.10 or higher 28 | - [uv](https://github.com/astral-sh/uv) package manager 29 | 30 | ### Installation 31 | 32 | 1. Clone this repository: 33 | ```bash 34 | git clone https://github.com/financial-datasets/mcp-server 35 | cd mcp-server 36 | ``` 37 | 38 | 2. If you don't have uv installed, install it: 39 | ```bash 40 | # macOS/Linux 41 | curl -LsSf https://astral.sh/uv/install.sh | sh 42 | 43 | # Windows 44 | curl -LsSf https://astral.sh/uv/install.ps1 | powershell 45 | ``` 46 | 47 | 3. Install dependencies: 48 | ```bash 49 | # Create virtual env and activate it 50 | uv venv 51 | source .venv/bin/activate # On Windows: .venv\Scripts\activate 52 | 53 | # Install dependencies 54 | uv add "mcp[cli]" httpx # On Windows: uv add mcp[cli] httpx 55 | 56 | ``` 57 | 58 | 4. Set up environment variables: 59 | ```bash 60 | # Create .env file for your API keys 61 | cp .env.example .env 62 | 63 | # Set API key in .env 64 | FINANCIAL_DATASETS_API_KEY=your-financial-datasets-api-key 65 | ``` 66 | 67 | 5. Run the server: 68 | ```bash 69 | uv run server.py 70 | ``` 71 | 72 | ## Connecting to Claude Desktop 73 | 74 | 1. Install [Claude Desktop](https://claude.ai/desktop) if you haven't already 75 | 76 | 2. Create or edit the Claude Desktop configuration file: 77 | ```bash 78 | # macOS 79 | mkdir -p ~/Library/Application\ Support/Claude/ 80 | nano ~/Library/Application\ Support/Claude/claude_desktop_config.json 81 | ``` 82 | 83 | 3. Add the following configuration: 84 | ```json 85 | { 86 | "mcpServers": { 87 | "financial-datasets": { 88 | "command": "/path/to/uv", 89 | "args": [ 90 | "--directory", 91 | "/absolute/path/to/financial-datasets-mcp", 92 | "run", 93 | "server.py" 94 | ] 95 | } 96 | } 97 | } 98 | ``` 99 | 100 | Replace `/path/to/uv` with the result of `which uv` and `/absolute/path/to/financial-datasets-mcp` with the absolute path to this project. 101 | 102 | 4. Restart Claude Desktop 103 | 104 | 5. You should now see the financial tools available in Claude Desktop's tools menu (hammer icon) 105 | 106 | 6. Try asking Claude questions like: 107 | - "What are Apple's recent income statements?" 108 | - "Show me the current price of Tesla stock" 109 | - "Get historical prices for MSFT from 2024-01-01 to 2024-12-31" 110 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # UV 98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | #uv.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 116 | .pdm.toml 117 | .pdm-python 118 | .pdm-build/ 119 | 120 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 121 | __pypackages__/ 122 | 123 | # Celery stuff 124 | celerybeat-schedule 125 | celerybeat.pid 126 | 127 | # SageMath parsed files 128 | *.sage.py 129 | 130 | # Environments 131 | .env 132 | .venv 133 | env/ 134 | venv/ 135 | ENV/ 136 | env.bak/ 137 | venv.bak/ 138 | 139 | # Spyder project settings 140 | .spyderproject 141 | .spyproject 142 | 143 | # Rope project settings 144 | .ropeproject 145 | 146 | # mkdocs documentation 147 | /site 148 | 149 | # mypy 150 | .mypy_cache/ 151 | .dmypy.json 152 | dmypy.json 153 | 154 | # Pyre type checker 155 | .pyre/ 156 | 157 | # pytype static type analyzer 158 | .pytype/ 159 | 160 | # Cython debug symbols 161 | cython_debug/ 162 | 163 | # PyCharm 164 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 165 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 166 | # and can be added to the global gitignore or merged into this file. For a more nuclear 167 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 168 | #.idea/ 169 | 170 | # PyPI configuration file 171 | .pypirc 172 | 173 | .DS_Store 174 | 175 | # Ignore vscode 176 | .vscode/ -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import httpx 4 | import logging 5 | import sys 6 | from mcp.server.fastmcp import FastMCP 7 | from dotenv import load_dotenv 8 | 9 | # Configure logging to write to stderr 10 | logging.basicConfig( 11 | level=logging.INFO, 12 | format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", 13 | stream=sys.stderr, 14 | ) 15 | logger = logging.getLogger("financial-datasets-mcp") 16 | 17 | # Initialize FastMCP server 18 | mcp = FastMCP("financial-datasets") 19 | 20 | # Constants 21 | FINANCIAL_DATASETS_API_BASE = "https://api.financialdatasets.ai" 22 | 23 | 24 | # Helper function to make API requests 25 | async def make_request(url: str) -> dict[str, any] | None: 26 | """Make a request to the Financial Datasets API with proper error handling.""" 27 | # Load environment variables from .env file 28 | load_dotenv() 29 | 30 | headers = {} 31 | if api_key := os.environ.get("FINANCIAL_DATASETS_API_KEY"): 32 | headers["X-API-KEY"] = api_key 33 | 34 | async with httpx.AsyncClient() as client: 35 | try: 36 | response = await client.get(url, headers=headers, timeout=30.0) 37 | response.raise_for_status() 38 | return response.json() 39 | except Exception as e: 40 | return {"Error": str(e)} 41 | 42 | 43 | @mcp.tool() 44 | async def get_income_statements( 45 | ticker: str, 46 | period: str = "annual", 47 | limit: int = 4, 48 | ) -> str: 49 | """Get income statements for a company. 50 | 51 | Args: 52 | ticker: Ticker symbol of the company (e.g. AAPL, GOOGL) 53 | period: Period of the income statement (e.g. annual, quarterly, ttm) 54 | limit: Number of income statements to return (default: 4) 55 | """ 56 | # Fetch data from the API 57 | url = f"{FINANCIAL_DATASETS_API_BASE}/financials/income-statements/?ticker={ticker}&period={period}&limit={limit}" 58 | data = await make_request(url) 59 | 60 | # Check if data is found 61 | if not data: 62 | return "Unable to fetch income statements or no income statements found." 63 | 64 | # Extract the income statements 65 | income_statements = data.get("income_statements", []) 66 | 67 | # Check if income statements are found 68 | if not income_statements: 69 | return "Unable to fetch income statements or no income statements found." 70 | 71 | # Stringify the income statements 72 | return json.dumps(income_statements, indent=2) 73 | 74 | 75 | @mcp.tool() 76 | async def get_balance_sheets( 77 | ticker: str, 78 | period: str = "annual", 79 | limit: int = 4, 80 | ) -> str: 81 | """Get balance sheets for a company. 82 | 83 | Args: 84 | ticker: Ticker symbol of the company (e.g. AAPL, GOOGL) 85 | period: Period of the balance sheet (e.g. annual, quarterly, ttm) 86 | limit: Number of balance sheets to return (default: 4) 87 | """ 88 | # Fetch data from the API 89 | url = f"{FINANCIAL_DATASETS_API_BASE}/financials/balance-sheets/?ticker={ticker}&period={period}&limit={limit}" 90 | data = await make_request(url) 91 | 92 | # Check if data is found 93 | if not data: 94 | return "Unable to fetch balance sheets or no balance sheets found." 95 | 96 | # Extract the balance sheets 97 | balance_sheets = data.get("balance_sheets", []) 98 | 99 | # Check if balance sheets are found 100 | if not balance_sheets: 101 | return "Unable to fetch balance sheets or no balance sheets found." 102 | 103 | # Stringify the balance sheets 104 | return json.dumps(balance_sheets, indent=2) 105 | 106 | 107 | @mcp.tool() 108 | async def get_cash_flow_statements( 109 | ticker: str, 110 | period: str = "annual", 111 | limit: int = 4, 112 | ) -> str: 113 | """Get cash flow statements for a company. 114 | 115 | Args: 116 | ticker: Ticker symbol of the company (e.g. AAPL, GOOGL) 117 | period: Period of the cash flow statement (e.g. annual, quarterly, ttm) 118 | limit: Number of cash flow statements to return (default: 4) 119 | """ 120 | # Fetch data from the API 121 | url = f"{FINANCIAL_DATASETS_API_BASE}/financials/cash-flow-statements/?ticker={ticker}&period={period}&limit={limit}" 122 | data = await make_request(url) 123 | 124 | # Check if data is found 125 | if not data: 126 | return "Unable to fetch cash flow statements or no cash flow statements found." 127 | 128 | # Extract the cash flow statements 129 | cash_flow_statements = data.get("cash_flow_statements", []) 130 | 131 | # Check if cash flow statements are found 132 | if not cash_flow_statements: 133 | return "Unable to fetch cash flow statements or no cash flow statements found." 134 | 135 | # Stringify the cash flow statements 136 | return json.dumps(cash_flow_statements, indent=2) 137 | 138 | 139 | @mcp.tool() 140 | async def get_current_stock_price(ticker: str) -> str: 141 | """Get the current / latest price of a company. 142 | 143 | Args: 144 | ticker: Ticker symbol of the company (e.g. AAPL, GOOGL) 145 | """ 146 | # Fetch data from the API 147 | url = f"{FINANCIAL_DATASETS_API_BASE}/prices/snapshot/?ticker={ticker}" 148 | data = await make_request(url) 149 | 150 | # Check if data is found 151 | if not data: 152 | return "Unable to fetch current price or no current price found." 153 | 154 | # Extract the current price 155 | snapshot = data.get("snapshot", {}) 156 | 157 | # Check if current price is found 158 | if not snapshot: 159 | return "Unable to fetch current price or no current price found." 160 | 161 | # Stringify the current price 162 | return json.dumps(snapshot, indent=2) 163 | 164 | 165 | @mcp.tool() 166 | async def get_historical_stock_prices( 167 | ticker: str, 168 | start_date: str, 169 | end_date: str, 170 | interval: str = "day", 171 | interval_multiplier: int = 1, 172 | ) -> str: 173 | """Gets historical stock prices for a company. 174 | 175 | Args: 176 | ticker: Ticker symbol of the company (e.g. AAPL, GOOGL) 177 | start_date: Start date of the price data (e.g. 2020-01-01) 178 | end_date: End date of the price data (e.g. 2020-12-31) 179 | interval: Interval of the price data (e.g. minute, hour, day, week, month) 180 | interval_multiplier: Multiplier of the interval (e.g. 1, 2, 3) 181 | """ 182 | # Fetch data from the API 183 | url = f"{FINANCIAL_DATASETS_API_BASE}/prices/?ticker={ticker}&interval={interval}&interval_multiplier={interval_multiplier}&start_date={start_date}&end_date={end_date}" 184 | data = await make_request(url) 185 | 186 | # Check if data is found 187 | if not data: 188 | return "Unable to fetch prices or no prices found." 189 | 190 | # Extract the prices 191 | prices = data.get("prices", []) 192 | 193 | # Check if prices are found 194 | if not prices: 195 | return "Unable to fetch prices or no prices found." 196 | 197 | # Stringify the prices 198 | return json.dumps(prices, indent=2) 199 | 200 | 201 | @mcp.tool() 202 | async def get_company_news(ticker: str) -> str: 203 | """Get news for a company. 204 | 205 | Args: 206 | ticker: Ticker symbol of the company (e.g. AAPL, GOOGL) 207 | """ 208 | # Fetch data from the API 209 | url = f"{FINANCIAL_DATASETS_API_BASE}/news/?ticker={ticker}" 210 | data = await make_request(url) 211 | 212 | # Check if data is found 213 | if not data: 214 | return "Unable to fetch news or no news found." 215 | 216 | # Extract the news 217 | news = data.get("news", []) 218 | 219 | # Check if news are found 220 | if not news: 221 | return "Unable to fetch news or no news found." 222 | return json.dumps(news, indent=2) 223 | 224 | 225 | @mcp.tool() 226 | async def get_available_crypto_tickers() -> str: 227 | """ 228 | Gets all available crypto tickers. 229 | """ 230 | # Fetch data from the API 231 | url = f"{FINANCIAL_DATASETS_API_BASE}/crypto/prices/tickers" 232 | data = await make_request(url) 233 | 234 | # Check if data is found 235 | if not data: 236 | return "Unable to fetch available crypto tickers or no available crypto tickers found." 237 | 238 | # Extract the available crypto tickers 239 | tickers = data.get("tickers", []) 240 | 241 | # Stringify the available crypto tickers 242 | return json.dumps(tickers, indent=2) 243 | 244 | 245 | @mcp.tool() 246 | async def get_crypto_prices( 247 | ticker: str, 248 | start_date: str, 249 | end_date: str, 250 | interval: str = "day", 251 | interval_multiplier: int = 1, 252 | ) -> str: 253 | """ 254 | Gets historical prices for a crypto currency. 255 | """ 256 | # Fetch data from the API 257 | url = f"{FINANCIAL_DATASETS_API_BASE}/crypto/prices/?ticker={ticker}&interval={interval}&interval_multiplier={interval_multiplier}&start_date={start_date}&end_date={end_date}" 258 | data = await make_request(url) 259 | 260 | # Check if data is found 261 | if not data: 262 | return "Unable to fetch prices or no prices found." 263 | 264 | # Extract the prices 265 | prices = data.get("prices", []) 266 | 267 | # Check if prices are found 268 | if not prices: 269 | return "Unable to fetch prices or no prices found." 270 | 271 | # Stringify the prices 272 | return json.dumps(prices, indent=2) 273 | 274 | 275 | @mcp.tool() 276 | async def get_historical_crypto_prices( 277 | ticker: str, 278 | start_date: str, 279 | end_date: str, 280 | interval: str = "day", 281 | interval_multiplier: int = 1, 282 | ) -> str: 283 | """Gets historical prices for a crypto currency. 284 | 285 | Args: 286 | ticker: Ticker symbol of the crypto currency (e.g. BTC-USD). The list of available crypto tickers can be retrieved via the get_available_crypto_tickers tool. 287 | start_date: Start date of the price data (e.g. 2020-01-01) 288 | end_date: End date of the price data (e.g. 2020-12-31) 289 | interval: Interval of the price data (e.g. minute, hour, day, week, month) 290 | interval_multiplier: Multiplier of the interval (e.g. 1, 2, 3) 291 | """ 292 | # Fetch data from the API 293 | url = f"{FINANCIAL_DATASETS_API_BASE}/crypto/prices/?ticker={ticker}&interval={interval}&interval_multiplier={interval_multiplier}&start_date={start_date}&end_date={end_date}" 294 | data = await make_request(url) 295 | 296 | # Check if data is found 297 | if not data: 298 | return "Unable to fetch prices or no prices found." 299 | 300 | # Extract the prices 301 | prices = data.get("prices", []) 302 | 303 | # Check if prices are found 304 | if not prices: 305 | return "Unable to fetch prices or no prices found." 306 | 307 | # Stringify the prices 308 | return json.dumps(prices, indent=2) 309 | 310 | 311 | @mcp.tool() 312 | async def get_current_crypto_price(ticker: str) -> str: 313 | """Get the current / latest price of a crypto currency. 314 | 315 | Args: 316 | ticker: Ticker symbol of the crypto currency (e.g. BTC-USD). The list of available crypto tickers can be retrieved via the get_available_crypto_tickers tool. 317 | """ 318 | # Fetch data from the API 319 | url = f"{FINANCIAL_DATASETS_API_BASE}/crypto/prices/snapshot/?ticker={ticker}" 320 | data = await make_request(url) 321 | 322 | # Check if data is found 323 | if not data: 324 | return "Unable to fetch current price or no current price found." 325 | 326 | # Extract the current price 327 | snapshot = data.get("snapshot", {}) 328 | 329 | # Check if current price is found 330 | if not snapshot: 331 | return "Unable to fetch current price or no current price found." 332 | 333 | # Stringify the current price 334 | return json.dumps(snapshot, indent=2) 335 | 336 | 337 | @mcp.tool() 338 | async def get_sec_filings( 339 | ticker: str, 340 | limit: int = 10, 341 | filing_type: str | None = None, 342 | ) -> str: 343 | """Get all SEC filings for a company. 344 | 345 | Args: 346 | ticker: Ticker symbol of the company (e.g. AAPL, GOOGL) 347 | limit: Number of SEC filings to return (default: 10) 348 | filing_type: Type of SEC filing (e.g. 10-K, 10-Q, 8-K) 349 | """ 350 | # Fetch data from the API 351 | url = f"{FINANCIAL_DATASETS_API_BASE}/filings/?ticker={ticker}&limit={limit}" 352 | if filing_type: 353 | url += f"&filing_type={filing_type}" 354 | 355 | # Call the API 356 | data = await make_request(url) 357 | 358 | # Extract the SEC filings 359 | filings = data.get("filings", []) 360 | 361 | # Check if SEC filings are found 362 | if not filings: 363 | return f"Unable to fetch SEC filings or no SEC filings found." 364 | 365 | # Stringify the SEC filings 366 | return json.dumps(filings, indent=2) 367 | 368 | if __name__ == "__main__": 369 | # Log server startup 370 | logger.info("Starting Financial Datasets MCP Server...") 371 | 372 | # Initialize and run the server 373 | mcp.run(transport="stdio") 374 | 375 | # This line won't be reached during normal operation 376 | logger.info("Server stopped") 377 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 1 3 | requires-python = ">=3.11" 4 | 5 | [[package]] 6 | name = "annotated-types" 7 | version = "0.7.0" 8 | source = { registry = "https://pypi.org/simple" } 9 | sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } 10 | wheels = [ 11 | { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, 12 | ] 13 | 14 | [[package]] 15 | name = "anyio" 16 | version = "4.8.0" 17 | source = { registry = "https://pypi.org/simple" } 18 | dependencies = [ 19 | { name = "idna" }, 20 | { name = "sniffio" }, 21 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, 22 | ] 23 | sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } 24 | wheels = [ 25 | { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, 26 | ] 27 | 28 | [[package]] 29 | name = "certifi" 30 | version = "2025.1.31" 31 | source = { registry = "https://pypi.org/simple" } 32 | sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } 33 | wheels = [ 34 | { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, 35 | ] 36 | 37 | [[package]] 38 | name = "click" 39 | version = "8.1.8" 40 | source = { registry = "https://pypi.org/simple" } 41 | dependencies = [ 42 | { name = "colorama", marker = "sys_platform == 'win32'" }, 43 | ] 44 | sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } 45 | wheels = [ 46 | { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, 47 | ] 48 | 49 | [[package]] 50 | name = "colorama" 51 | version = "0.4.6" 52 | source = { registry = "https://pypi.org/simple" } 53 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } 54 | wheels = [ 55 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, 56 | ] 57 | 58 | [[package]] 59 | name = "h11" 60 | version = "0.14.0" 61 | source = { registry = "https://pypi.org/simple" } 62 | sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } 63 | wheels = [ 64 | { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, 65 | ] 66 | 67 | [[package]] 68 | name = "httpcore" 69 | version = "1.0.7" 70 | source = { registry = "https://pypi.org/simple" } 71 | dependencies = [ 72 | { name = "certifi" }, 73 | { name = "h11" }, 74 | ] 75 | sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } 76 | wheels = [ 77 | { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, 78 | ] 79 | 80 | [[package]] 81 | name = "httpx" 82 | version = "0.28.1" 83 | source = { registry = "https://pypi.org/simple" } 84 | dependencies = [ 85 | { name = "anyio" }, 86 | { name = "certifi" }, 87 | { name = "httpcore" }, 88 | { name = "idna" }, 89 | ] 90 | sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } 91 | wheels = [ 92 | { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, 93 | ] 94 | 95 | [[package]] 96 | name = "httpx-sse" 97 | version = "0.4.0" 98 | source = { registry = "https://pypi.org/simple" } 99 | sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 } 100 | wheels = [ 101 | { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 }, 102 | ] 103 | 104 | [[package]] 105 | name = "idna" 106 | version = "3.10" 107 | source = { registry = "https://pypi.org/simple" } 108 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } 109 | wheels = [ 110 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, 111 | ] 112 | 113 | [[package]] 114 | name = "markdown-it-py" 115 | version = "3.0.0" 116 | source = { registry = "https://pypi.org/simple" } 117 | dependencies = [ 118 | { name = "mdurl" }, 119 | ] 120 | sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } 121 | wheels = [ 122 | { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, 123 | ] 124 | 125 | [[package]] 126 | name = "mcp" 127 | version = "1.3.0" 128 | source = { registry = "https://pypi.org/simple" } 129 | dependencies = [ 130 | { name = "anyio" }, 131 | { name = "httpx" }, 132 | { name = "httpx-sse" }, 133 | { name = "pydantic" }, 134 | { name = "pydantic-settings" }, 135 | { name = "sse-starlette" }, 136 | { name = "starlette" }, 137 | { name = "uvicorn" }, 138 | ] 139 | sdist = { url = "https://files.pythonhosted.org/packages/6b/b6/81e5f2490290351fc97bf46c24ff935128cb7d34d68e3987b522f26f7ada/mcp-1.3.0.tar.gz", hash = "sha256:f409ae4482ce9d53e7ac03f3f7808bcab735bdfc0fba937453782efb43882d45", size = 150235 } 140 | wheels = [ 141 | { url = "https://files.pythonhosted.org/packages/d0/d2/a9e87b506b2094f5aa9becc1af5178842701b27217fa43877353da2577e3/mcp-1.3.0-py3-none-any.whl", hash = "sha256:2829d67ce339a249f803f22eba5e90385eafcac45c94b00cab6cef7e8f217211", size = 70672 }, 142 | ] 143 | 144 | [package.optional-dependencies] 145 | cli = [ 146 | { name = "python-dotenv" }, 147 | { name = "typer" }, 148 | ] 149 | 150 | [[package]] 151 | name = "mcp-server" 152 | version = "0.1.0" 153 | source = { virtual = "." } 154 | dependencies = [ 155 | { name = "httpx" }, 156 | { name = "mcp", extra = ["cli"] }, 157 | { name = "python-dotenv" }, 158 | ] 159 | 160 | [package.metadata] 161 | requires-dist = [ 162 | { name = "httpx", specifier = ">=0.28.1" }, 163 | { name = "mcp", extras = ["cli"], specifier = ">=1.3.0" }, 164 | { name = "python-dotenv", specifier = ">=1.0.0" }, 165 | ] 166 | 167 | [[package]] 168 | name = "mdurl" 169 | version = "0.1.2" 170 | source = { registry = "https://pypi.org/simple" } 171 | sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } 172 | wheels = [ 173 | { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, 174 | ] 175 | 176 | [[package]] 177 | name = "pydantic" 178 | version = "2.10.6" 179 | source = { registry = "https://pypi.org/simple" } 180 | dependencies = [ 181 | { name = "annotated-types" }, 182 | { name = "pydantic-core" }, 183 | { name = "typing-extensions" }, 184 | ] 185 | sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681 } 186 | wheels = [ 187 | { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696 }, 188 | ] 189 | 190 | [[package]] 191 | name = "pydantic-core" 192 | version = "2.27.2" 193 | source = { registry = "https://pypi.org/simple" } 194 | dependencies = [ 195 | { name = "typing-extensions" }, 196 | ] 197 | sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } 198 | wheels = [ 199 | { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421 }, 200 | { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998 }, 201 | { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167 }, 202 | { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071 }, 203 | { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244 }, 204 | { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470 }, 205 | { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291 }, 206 | { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613 }, 207 | { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355 }, 208 | { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661 }, 209 | { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261 }, 210 | { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361 }, 211 | { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484 }, 212 | { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102 }, 213 | { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 }, 214 | { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 }, 215 | { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 }, 216 | { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 }, 217 | { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 }, 218 | { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 }, 219 | { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 }, 220 | { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 }, 221 | { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 }, 222 | { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 }, 223 | { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 }, 224 | { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 }, 225 | { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 }, 226 | { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 }, 227 | { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 }, 228 | { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 }, 229 | { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 }, 230 | { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 }, 231 | { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 }, 232 | { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 }, 233 | { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 }, 234 | { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 }, 235 | { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 }, 236 | { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 }, 237 | { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 }, 238 | { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 }, 239 | { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 }, 240 | { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, 241 | ] 242 | 243 | [[package]] 244 | name = "pydantic-settings" 245 | version = "2.8.1" 246 | source = { registry = "https://pypi.org/simple" } 247 | dependencies = [ 248 | { name = "pydantic" }, 249 | { name = "python-dotenv" }, 250 | ] 251 | sdist = { url = "https://files.pythonhosted.org/packages/88/82/c79424d7d8c29b994fb01d277da57b0a9b09cc03c3ff875f9bd8a86b2145/pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585", size = 83550 } 252 | wheels = [ 253 | { url = "https://files.pythonhosted.org/packages/0b/53/a64f03044927dc47aafe029c42a5b7aabc38dfb813475e0e1bf71c4a59d0/pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c", size = 30839 }, 254 | ] 255 | 256 | [[package]] 257 | name = "pygments" 258 | version = "2.19.1" 259 | source = { registry = "https://pypi.org/simple" } 260 | sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } 261 | wheels = [ 262 | { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, 263 | ] 264 | 265 | [[package]] 266 | name = "python-dotenv" 267 | version = "1.0.1" 268 | source = { registry = "https://pypi.org/simple" } 269 | sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } 270 | wheels = [ 271 | { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, 272 | ] 273 | 274 | [[package]] 275 | name = "rich" 276 | version = "13.9.4" 277 | source = { registry = "https://pypi.org/simple" } 278 | dependencies = [ 279 | { name = "markdown-it-py" }, 280 | { name = "pygments" }, 281 | ] 282 | sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } 283 | wheels = [ 284 | { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, 285 | ] 286 | 287 | [[package]] 288 | name = "shellingham" 289 | version = "1.5.4" 290 | source = { registry = "https://pypi.org/simple" } 291 | sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } 292 | wheels = [ 293 | { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, 294 | ] 295 | 296 | [[package]] 297 | name = "sniffio" 298 | version = "1.3.1" 299 | source = { registry = "https://pypi.org/simple" } 300 | sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } 301 | wheels = [ 302 | { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, 303 | ] 304 | 305 | [[package]] 306 | name = "sse-starlette" 307 | version = "2.2.1" 308 | source = { registry = "https://pypi.org/simple" } 309 | dependencies = [ 310 | { name = "anyio" }, 311 | { name = "starlette" }, 312 | ] 313 | sdist = { url = "https://files.pythonhosted.org/packages/71/a4/80d2a11af59fe75b48230846989e93979c892d3a20016b42bb44edb9e398/sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419", size = 17376 } 314 | wheels = [ 315 | { url = "https://files.pythonhosted.org/packages/d9/e0/5b8bd393f27f4a62461c5cf2479c75a2cc2ffa330976f9f00f5f6e4f50eb/sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99", size = 10120 }, 316 | ] 317 | 318 | [[package]] 319 | name = "starlette" 320 | version = "0.46.0" 321 | source = { registry = "https://pypi.org/simple" } 322 | dependencies = [ 323 | { name = "anyio" }, 324 | ] 325 | sdist = { url = "https://files.pythonhosted.org/packages/44/b6/fb9a32e3c5d59b1e383c357534c63c2d3caa6f25bf3c59dd89d296ecbaec/starlette-0.46.0.tar.gz", hash = "sha256:b359e4567456b28d473d0193f34c0de0ed49710d75ef183a74a5ce0499324f50", size = 2575568 } 326 | wheels = [ 327 | { url = "https://files.pythonhosted.org/packages/41/94/8af675a62e3c91c2dee47cf92e602cfac86e8767b1a1ac3caf1b327c2ab0/starlette-0.46.0-py3-none-any.whl", hash = "sha256:913f0798bd90ba90a9156383bcf1350a17d6259451d0d8ee27fc0cf2db609038", size = 71991 }, 328 | ] 329 | 330 | [[package]] 331 | name = "typer" 332 | version = "0.15.2" 333 | source = { registry = "https://pypi.org/simple" } 334 | dependencies = [ 335 | { name = "click" }, 336 | { name = "rich" }, 337 | { name = "shellingham" }, 338 | { name = "typing-extensions" }, 339 | ] 340 | sdist = { url = "https://files.pythonhosted.org/packages/8b/6f/3991f0f1c7fcb2df31aef28e0594d8d54b05393a0e4e34c65e475c2a5d41/typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5", size = 100711 } 341 | wheels = [ 342 | { url = "https://files.pythonhosted.org/packages/7f/fc/5b29fea8cee020515ca82cc68e3b8e1e34bb19a3535ad854cac9257b414c/typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc", size = 45061 }, 343 | ] 344 | 345 | [[package]] 346 | name = "typing-extensions" 347 | version = "4.12.2" 348 | source = { registry = "https://pypi.org/simple" } 349 | sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } 350 | wheels = [ 351 | { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, 352 | ] 353 | 354 | [[package]] 355 | name = "uvicorn" 356 | version = "0.34.0" 357 | source = { registry = "https://pypi.org/simple" } 358 | dependencies = [ 359 | { name = "click" }, 360 | { name = "h11" }, 361 | ] 362 | sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 } 363 | wheels = [ 364 | { url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 }, 365 | ] 366 | --------------------------------------------------------------------------------