diff --git a/server/mcp_server_apmplus/.gitignore b/server/mcp_server_apmplus/.gitignore new file mode 100644 index 00000000..3f0534d0 --- /dev/null +++ b/server/mcp_server_apmplus/.gitignore @@ -0,0 +1,159 @@ +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +.idea/ +.DS_Store diff --git a/server/mcp_server_apmplus/README.md b/server/mcp_server_apmplus/README.md index ac351865..d97711f4 100644 --- a/server/mcp_server_apmplus/README.md +++ b/server/mcp_server_apmplus/README.md @@ -2,38 +2,69 @@ The MCP Server officially launched by the Application Performance Monitoring service can accurately convert natural language into observable analysis statements. It efficiently analyzes observable data including metrics, traces, and logs, helping you comprehensively ensure the entire lifecycle of your applications and improve the efficiency of troubleshooting and problem-solving. -| Version | v0.1.0 | -| :-: |:----------------:| +| Version | v0.2.0 | +| :-: |:-------------------------------------------------------------------------------------------------:| | Description | The APMPlus MCP Server helps you comprehensively ensure the entire lifecycle of your applications | -| Category | Observability | -| Tags | Observability, Traces, Metrics, Logs, Performance Monitoring | +| Category | Observability | +| Tags | Observability, Traces, Metrics, Logs, Performance Monitoring | ## Tools This MCP Server product provides the following Tools (capabilities): ### 1. apmplus_server_list_alert_rule -Query the alert rules for APMPlus - Server Monitoring in a specified region. +Query the alert rules from APMPlus - Server Monitoring in a specified region. - Parameters: - - `region_id`: [str] Region ID - - `keyword`: [str] Search keyword - - `page_number`: [int] Page number for pagination - - `page_size`: [int] Page size for pagination + - `region`: [str, optional] Region ID. Defaults to cn-beijing. + - `keyword`: [str, optional] Search keyword. Defaults to "". + - `page_number`: [int, optional] Page number for pagination. Defaults to 1. + - `page_size`: [int, optional] Page size for pagination. Defaults to 10. ### 2. apmplus_server_list_notify_group -Query the notification group information for APMPlus - Server Monitoring in a specified region. +Query the notification group information from APMPlus - Server Monitoring in a specified region. - Parameters: - - `region_id`: [str] Region ID - - `keyword`: [str] Search keyword - - `page_number`: [int] Page number for pagination - - `page_size`: [int] Page size for pagination + - `region`: [str, optional] Region ID. Defaults to cn-beijing. + - `keyword`: [str, optional] Search keyword. Defaults to "". + - `page_number`: [int, optional] Page number for pagination. Defaults to 1. + - `page_size`: [int, optional] Page size for pagination. Defaults to 10. ### 3. apmplus_server_query_metrics -Query the metrics for APMPlus - Server Monitoring in a specified region. +Query the metrics from APMPlus - Server Monitoring in a specified region. - Parameters: - - `region_id`: [str] Region ID + - `region`: [str, optional] Region ID. Defaults to cn-beijing. - `query`: [str] Metric expression, in PromQL format - `start_time`: [int] Start time, in seconds - `end_time`: [int] End time, in seconds +### 4. apmplus_server_get_trace_detail +Get trace detail information from APMPlus - Server Monitoring in a specified region. +- Parameters: + - `trace_id`: [str, optional] Trace ID. + - `suggest_time`: [int, optional] Suggest time in seconds. + - `region`: [str, optional] Region ID. Defaults to cn-beijing. + +### 5. apmplus_server_list_span +Get a list of trace span from APMPlus - Server Monitoring in a specified region. +- Parameters: + - `start_time`: [int] Start time in seconds, example: 1693536000 + - `end_time`: [int] End time in seconds, example: 1693546000 + - `filters`: [list[dict], optional] Filter expression. + Each dict contains: + - 'Op' (str): in, not_in + - 'Key' (str): Filter key + - 'Values' (list[str]): Filter values + - `order`: [str, optional] Order direction. Defaults to DESC. + - `order_by`: [str, optional] Order by field. Defaults to "". + - `offset`: [int, optional] Offset for pagination. Defaults to 0. + - `limit`: [int, optional] Limit for pagination. Defaults to 10. + - `min_call_cost_millisecond`: [int, optional] Minimum call cost in milliseconds. Defaults to 0. + - `max_call_cost_millisecond`: [int, optional] Maximum call cost in milliseconds. Defaults to 0. + - `project_name`: [str, optional] The project name. + - `tag_filters`: [list[dict], optional] List of tag filters. Each dict contains: + - 'Key' (str): Tag key + - 'Value' (list[str]): Tag value + Max 10 tag pairs. + Empty value means no restriction on tag value. + - `region`: [str, optional] Region ID. Defaults to cn-beijing. + ## Compatible Platforms You can use cline, cursor, claude desktop, or other terminals that support MCP server calls. diff --git a/server/mcp_server_apmplus/README_zh.md b/server/mcp_server_apmplus/README_zh.md index 4691a891..81395926 100644 --- a/server/mcp_server_apmplus/README_zh.md +++ b/server/mcp_server_apmplus/README_zh.md @@ -2,37 +2,67 @@ 应用性能监控服务官方推出的 MCP Server,可以将自然语言精准转化为可观测分析语句,高效分析包含指标、链路和日志在内的可观测数据,助您全面保障应用的全生命周期,提升异常问题排查与解决的效率。 -| 版本 | v0.1.0 | -| :-: |:----------------:| +| 版本 | v0.2.0 | +| :-: |:---------------------------------:| | 描述 | APMPlus MCP Server 助您全面保障应用的全生命周期 | -| 分类 | 可观测 | -| 标签 | 可观测,链路,指标,日志,性能监控 | +| 分类 | 可观测 | +| 标签 | 可观测,链路,指标,日志,性能监控 | ## Tools 本 MCP Server 产品提供以下 Tools (工具/能力): ### 1. apmplus_server_list_alert_rule 查询应用性能监控-服务端监控在指定区域下的告警规则 - 参数: - - `region_id`: [str] 地域 id - - `keyword`: [str] 搜索关键词 - - `page_number`: [int] 分页页码 - - `page_size`: [int] 分页大小 + - `region`: [str, optional] 地域 ID。默认为 cn-beijing。 + - `keyword`: [str, optional] 搜索关键词。默认为空。 + - `page_number`: [int, optional] 分页页码。默认为1。 + - `page_size`: [int, optional] 分页大小。默认为10。 ### 2. apmplus_server_list_notify_group 查询应用性能监控-服务端监控在指定区域下的通知组信息 - 参数: - - `region_id`: [str] 地域 id - - `keyword`: [str] 搜索关键词 - - `page_number`: [int] 分页页码 - - `page_size`: [int] 分页大小 + - `region`: [str, optional] 地域 ID。默认为 cn-beijing。 + - `keyword`: [str, optional] 搜索关键词。默认为空。 + - `page_number`: [int, optional] 分页页码。默认为1。 + - `page_size`: [int, optional] 分页大小。默认为10。 ### 3. apmplus_server_query_metrics 查询应用性能监控-服务端监控在指定区域下的指标 - 参数: - - `region_id`: [str] 地域 id - - `query`: [str] 指标表达式,PromQL格式 - - `start_time`: [int] 开始时间,单位为秒 - - `end_time`: [int] 结束时间,单位为秒 + - `region`: [str, optional] 地域 ID。默认为 cn-beijing。 + - `query`: [str] 指标表达式,PromQL格式。 + - `start_time`: [int] 开始时间,单位为秒。 + - `end_time`: [int] 结束时间,单位为秒。 + +### 4. apmplus_server_get_trace_detail +查询应用性能监控-服务端监控在指定区域下的链路详情信息 +- 参数: + - `trace_id`: [str, optional] 链路 ID。 + - `suggest_time`: [int, optional] 链路发生的大致时间(秒)。 + - `region`: [str, optional] 地域 ID。默认为 cn-beijing。 + +### 5. apmplus_server_list_span +查询应用性能监控-服务端监控在指定区域下的链路Span列表 +- 参数: + - `start_time`: [int] 开始时间(秒),例如:1693536000。 + - `end_time`: [int] 结束时间(秒),例如:1693546000。 + - `filters`: [list[dict], optional] 过滤表达式。每个字典包含: + - 'Op' (str): in, not_in + - 'Key' (str): 过滤键 + - 'Values' (list[str]): 过滤值 + - `order`: [str, optional] 排序方向。默认为 DESC。 + - `order_by`: [str, optional] 排序字段。默认为空字符串。 + - `offset`: [int, optional] 分页偏移量。默认为 0。 + - `limit`: [int, optional] 分页限制。默认为 10。 + - `min_call_cost_millisecond`: [int, optional] 最小调用耗时(毫秒)。默认为 0。 + - `max_call_cost_millisecond`: [int, optional] 最大调用耗时(毫秒)。默认为 0。 + - `project_name`: [str, optional] 项目名称。 + - `tag_filters`: [list[dict], optional] 标签过滤列表。每个字典包含: + - 'Key' (str): 标签键 + - 'Value' (list[str]): 标签值 + Max 10 tag pairs. + 最多 10 个标签对。空值表示对标签值无限制。 + - `region`: [str, optional] 地域 ID。默认为 cn-beijing。 ## 可适配平台 可以使用cline、cursor、claude desktop或支持MCP server调用的其它终端 diff --git a/server/mcp_server_apmplus/pyproject.toml b/server/mcp_server_apmplus/pyproject.toml index c9c5062a..de29eb75 100644 --- a/server/mcp_server_apmplus/pyproject.toml +++ b/server/mcp_server_apmplus/pyproject.toml @@ -1,11 +1,12 @@ [project] name = "mcp-server-apmplus" -version = "0.1.0" +version = "0.2.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.10" dependencies = [ - "mcp==1.10.0", + "black>=26.1.0", + "mcp==1.12.4", "requests>=2.32.3", "volcengine-python-sdk>=3.0.1", ] @@ -20,5 +21,8 @@ build-backend = "hatchling.build" [tool.hatch.metadata] allow-direct-references = true +[tool.uv.sources] +volcengine-python-sdk = { git = "ssh://git@code.byted.org/iaasng/volcengine-python-sdk", rev = "apmplus_server-Python-2026-01-01-online-2296-2026_02_26_16_41_42" } + #[tool.uv.sources] #mcp = { git = "https://github.com/zihengli-bytedance/python-sdk.git", rev = "temp-for-volc" } diff --git a/server/mcp_server_apmplus/requirements.txt b/server/mcp_server_apmplus/requirements.txt index d1be3197..610b4337 100644 --- a/server/mcp_server_apmplus/requirements.txt +++ b/server/mcp_server_apmplus/requirements.txt @@ -77,5 +77,5 @@ urllib3==2.4.0 # volcengine-python-sdk uvicorn==0.34.2 # via mcp -volcengine-python-sdk==3.0.1 +volcengine-python-sdk @ git+ssh://git@code.byted.org/iaasng/volcengine-python-sdk@apmplus_server-Python-2026-01-01-online-2296-2026_02_26_16_41_42 # via mcp-server-apmplus (pyproject.toml) diff --git a/server/mcp_server_apmplus/src/mcp_server_apmplus/api.py b/server/mcp_server_apmplus/src/mcp_server_apmplus/api.py index eb33b4eb..4a7ea752 100644 --- a/server/mcp_server_apmplus/src/mcp_server_apmplus/api.py +++ b/server/mcp_server_apmplus/src/mcp_server_apmplus/api.py @@ -2,6 +2,8 @@ from urllib.parse import urlparse import requests +import volcenginesdkcore +from volcenginesdkapmplusserver import APMPLUSSERVERApi, models from mcp_server_apmplus.config import ApmplusConfig from mcp_server_apmplus.model import * @@ -11,15 +13,28 @@ class ApmplusApi(object): + cred: ApmplusConfig + apmplusApiClient: APMPLUSSERVERApi + def __init__(self, cred: ApmplusConfig): if cred.access_key == "" or cred.secret_key == "" or cred.endpoint == "": raise ValueError("access_key, secret_key or endpoint is empty") self.cred = cred + self.apmplusApiClient = APMPLUSSERVERApi( + volcenginesdkcore.ApiClient(configuration=cred.to_volc_configuration()) + ) + + def _get_volc_client(self, dynamic_conf: ApmplusConfig) -> APMPLUSSERVERApi: + return APMPLUSSERVERApi( + volcenginesdkcore.ApiClient( + configuration=dynamic_conf.to_volc_configuration() + ) + ) def do_request(self, service, region, req: requests.Request) -> requests.Response: # 添加header req.headers["Content-Type"] = "application/json" - req.headers["Host"] = urlparse(self.cred.endpoint).hostname + req.headers["Host"] = urlparse(req.url).hostname # 签名 self.cred.append_authorization( urlparse(req.url).path, @@ -41,15 +56,15 @@ def server_list_alert_rule(self, req: ApmplusServerListAlertRuleRequest) -> str: query = { "Action": "GetAlertRuleList", "Version": "2022-07-11", - "Region": req.region_id, + "Region": req.region, } request = requests.Request( method="POST", - url=self.cred.endpoint, + url="https://" + self.cred.endpoint, data=req_json, params=query, ) - response = self.do_request(SERVER_SERVICE, req.region_id, request) + response = self.do_request(SERVER_SERVICE, req.region, request) if response.status_code != 200: raise Exception( f"get_result failed, status_code: {response.status_code}, response: {response.text},request_headers: {request.headers}, request_url:{request.url}, request_params:{request.params}, request_data:{request.data},request_body:{request.json}" @@ -61,15 +76,15 @@ def server_list_notify_group(self, req: ApmplusServerListNotifyGroupRequest) -> query = { "Action": "NotifyGroupList", "Version": "2022-07-11", - "Region": req.region_id, + "Region": req.region, } request = requests.Request( method="POST", - url=self.cred.endpoint, + url="https://" + self.cred.endpoint, data=req_json, params=query, ) - response = self.do_request(SERVER_SERVICE, req.region_id, request) + response = self.do_request(SERVER_SERVICE, req.region, request) if response.status_code != 200: raise Exception( f"get_result failed, status_code: {response.status_code}, response: {response.text},request_headers: {request.headers}, request_url:{request.url}, request_params:{request.params}, request_data:{request.data},request_body:{request.json}" @@ -77,41 +92,41 @@ def server_list_notify_group(self, req: ApmplusServerListNotifyGroupRequest) -> return response.text def server_query_metrics(self, req: ApmplusServerQueryMetricsRequest) -> str: - if not req.region_id: - req.region_id = DEFAULT_REGION + if not req.region: + req.region = DEFAULT_REGION req_json = json.dumps(req.to_dict()) query = { "Action": "Draw", "Version": "2022-11-09", - "Region": req.region_id, + "Region": req.region, } request = requests.Request( method="POST", - url=self.cred.endpoint, + url="https://" + self.cred.endpoint, data=req_json, params=query, ) - response = self.do_request(SERVER_SERVICE, req.region_id, request) + response = self.do_request(SERVER_SERVICE, req.region, request) if response.status_code != 200: raise Exception( f"get_result failed, status_code: {response.status_code}, response: {response.text},request_headers: {request.headers}, request_url:{request.url}, request_params:{request.params}, request_data:{request.data},request_body:{request.json}" ) return response.text + async def server_get_trace_detail( + self, args: dict, dynamic_conf: ApmplusConfig = None + ) -> models.get_trace_detail_response.GetTraceDetailResponse: + client = self.apmplusApiClient + if dynamic_conf is not None: + client = self._get_volc_client(dynamic_conf) + return client.get_trace_detail( + models.get_trace_detail_request.GetTraceDetailRequest(**args) + ) -if __name__ == "__main__": - req = ApmplusServerQueryMetricsRequest( - region_id="", - query="histogram_quantile(0.99, sum(rate(gen_ai_client_operation_duration_bucket{}[5m])) by (le))", - start_time=1746777063, - end_time=1746780663, - ) - # Body的格式需要配合Content-Type,API使用的类型请阅读具体的官方文档,如:json格式需要json.dumps(obj) - config = ApmplusConfig( - access_key="", - secret_key="", - endpoint="https://open.volcengineapi.com", - ) - api = ApmplusApi(config) - response_body = api.server_query_metrics(req) - print(response_body) + async def server_list_span( + self, args: dict, dynamic_conf: ApmplusConfig = None + ) -> dict: + client = self.apmplusApiClient + if dynamic_conf is not None: + client = self._get_volc_client(dynamic_conf) + return client.list_span(models.list_span_request.ListSpanRequest(**args)) diff --git a/server/mcp_server_apmplus/src/mcp_server_apmplus/config.py b/server/mcp_server_apmplus/src/mcp_server_apmplus/config.py index 9c3da26a..2cad8959 100644 --- a/server/mcp_server_apmplus/src/mcp_server_apmplus/config.py +++ b/server/mcp_server_apmplus/src/mcp_server_apmplus/config.py @@ -4,6 +4,7 @@ import os from dataclasses import dataclass +import volcenginesdkcore from volcenginesdkcore.signv4 import SignerV4 logger = logging.getLogger(__name__) @@ -19,7 +20,9 @@ ENV_MCP_SERVER_PORT = "MCP_SERVER_PORT" ENV_MCP_SERVER_HOST = "MCP_SERVER_HOST" -DEFAULT_ENDPOINT = "https://open.volcengineapi.com" +ENV_POOL_CONCURRENCY = "POOL_CONCURRENCY" + +ENV_MCP_DEV_MODE = "MCP_DEV_MODE" @dataclass @@ -35,6 +38,8 @@ class ApmplusConfig: access_key: str secret_key: str session_token: str + region: str + pool_concurrency: int def is_valid(self) -> bool: """Check if the configuration is valid.""" @@ -59,6 +64,17 @@ def append_authorization( self.session_token, ) + def to_volc_configuration(self) -> volcenginesdkcore.Configuration: + """Convert to volcengine configuration.""" + volc_conf = volcenginesdkcore.Configuration() + volc_conf.host = self.endpoint + volc_conf.region = self.region + volc_conf.ak = self.access_key + volc_conf.sk = self.secret_key + volc_conf.session_token = self.session_token + volc_conf.connection_pool_maxsize = self.pool_concurrency + return volc_conf + def validate_required_vars(): """ @@ -84,7 +100,13 @@ def load_config() -> ApmplusConfig: access_key=os.getenv(ENV_VOLCENGINE_ACCESS_KEY, ""), secret_key=os.getenv(ENV_VOLCENGINE_SECRET_KEY, ""), session_token=os.getenv(ENV_VOLCENGINE_SESSION_TOKEN, ""), - endpoint=os.getenv(ENV_VOLCENGINE_ENDPOINT, DEFAULT_ENDPOINT), + endpoint=os.getenv( + ENV_VOLCENGINE_ENDPOINT, + "apmplus-server.cn-beijing.volcengineapi.com", + ), + region=os.getenv(ENV_VOLCENGINE_REGION, "cn-beijing"), + pool_concurrency=int(os.getenv(ENV_POOL_CONCURRENCY, "0")) + or os.cpu_count() * 32 + 1, ) logger.info(f"Loaded configuration") @@ -98,5 +120,5 @@ def parse_authorization(authorization: str) -> ApmplusConfig: access_key=auth_obj["AccessKeyId"], secret_key=auth_obj["SecretAccessKey"], session_token=auth_obj["SessionToken"], - endpoint=os.getenv(ENV_VOLCENGINE_ENDPOINT, DEFAULT_ENDPOINT), + endpoint=os.getenv(ENV_VOLCENGINE_ENDPOINT, ""), ) diff --git a/server/mcp_server_apmplus/src/mcp_server_apmplus/main.py b/server/mcp_server_apmplus/src/mcp_server_apmplus/main.py deleted file mode 100644 index 5fc0d8c1..00000000 --- a/server/mcp_server_apmplus/src/mcp_server_apmplus/main.py +++ /dev/null @@ -1,47 +0,0 @@ -import argparse -import logging -import os -from typing import Optional - -from mcp_server_apmplus.config import load_config, ApmplusConfig, ENV_MCP_SERVER_MODE -from mcp_server_apmplus.server import mcp - -# Configure logging -logging.basicConfig( - level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" -) -logger = logging.getLogger(__name__) - -# Global variables -config: Optional[ApmplusConfig] = None - - -def main(): - parser = argparse.ArgumentParser(description="Run the APMPlus MCP Server") - parser.add_argument( - "--transport", - "-t", - choices=["sse", "stdio", "streamable-http"], - default=os.getenv(ENV_MCP_SERVER_MODE, "stdio"), - help="Transport protocol to use (sse, stdio or streamable-http)", - ) - - args = parser.parse_args() - - try: - # Load configuration from environment variables - global config - - config = load_config() - - # Run the MCP server - logger.info(f"Starting APMPlus MCP Server with {args.transport} transport") - - mcp.run(transport=args.transport) - except Exception as e: - logger.error(f"Error starting APMPlus MCP Server: {str(e)}") - raise - - -if __name__ == "__main__": - main() diff --git a/server/mcp_server_apmplus/src/mcp_server_apmplus/model.py b/server/mcp_server_apmplus/src/mcp_server_apmplus/model.py index 15fdba13..0e0b0a12 100644 --- a/server/mcp_server_apmplus/src/mcp_server_apmplus/model.py +++ b/server/mcp_server_apmplus/src/mcp_server_apmplus/model.py @@ -42,7 +42,7 @@ def get_default_response_metadata(): @dataclass class ApmplusServerListAlertRuleRequest: - region_id: str + region: str keyword: str page_number: int page_size: int @@ -57,7 +57,7 @@ def to_dict(self): @dataclass class ApmplusServerListNotifyGroupRequest: - region_id: str + region: str keyword: str page_number: int page_size: int @@ -72,7 +72,7 @@ def to_dict(self): @dataclass class ApmplusServerQueryMetricsRequest: - region_id: str + region: str start_time: int end_time: int query: str diff --git a/server/mcp_server_apmplus/src/mcp_server_apmplus/server.py b/server/mcp_server_apmplus/src/mcp_server_apmplus/server.py index f84441e5..fed8cb9a 100644 --- a/server/mcp_server_apmplus/src/mcp_server_apmplus/server.py +++ b/server/mcp_server_apmplus/src/mcp_server_apmplus/server.py @@ -1,5 +1,8 @@ +import argparse +import base64 import logging import os +from typing import Optional from mcp.server.fastmcp import Context, FastMCP from mcp.server.session import ServerSession @@ -8,10 +11,11 @@ from mcp_server_apmplus.api import * from mcp_server_apmplus.config import ( load_config, - parse_authorization, ENV_MCP_SERVER_PORT, ENV_MCP_SERVER_NAME, ENV_MCP_SERVER_HOST, + ENV_MCP_SERVER_MODE, + ENV_MCP_DEV_MODE, ) from mcp_server_apmplus.model import * @@ -22,38 +26,49 @@ host=os.getenv(ENV_MCP_SERVER_HOST, "127.0.0.1"), ) +apmplus_api: ApmplusApi = None + +# Configure logging +logging.basicConfig( + level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + +# Global variables +config: Optional[ApmplusConfig] = None + @mcp.tool() async def apmplus_server_list_alert_rule( - region_id: str, - keyword: str, - page_number: int, - page_size: int, + region: str = "cn-beijing", + keyword: str = "", + page_number: int = 1, + page_size: int = 10, ): """ List alert rules. Args: - region_id: Region ID. - keyword: query keyword. - page_number: Page number for pagination. - page_size: Page size for pagination. + region (str, optional): Region ID. Defaults to cn-beijing. + keyword (str, optional): Search keyword. Defaults to "". + page_number (int, optional): Page number for pagination. Defaults to 1. + page_size (int, optional): Page size for pagination. Defaults to 10. Returns: A list of alert rules. """ try: - if isinstance(region_id, str) and not region_id.strip(): - region_id = DEFAULT_REGION + if isinstance(region, str) and not region.strip(): + region = DEFAULT_REGION if isinstance(keyword, str) and not keyword.strip(): keyword = None req = ApmplusServerListAlertRuleRequest( - region_id=region_id, + region=region, keyword=keyword, page_number=page_number, page_size=page_size, ) - config = init_auth_config() + config = init_auth_config(region) api = ApmplusApi(config) return api.server_list_alert_rule(req) except Exception as e: @@ -63,35 +78,35 @@ async def apmplus_server_list_alert_rule( @mcp.tool() async def apmplus_server_list_notify_group( - region_id: str, - keyword: str, - page_number: int, - page_size: int, + region: str = "cn-beijing", + keyword: str = "", + page_number: int = 1, + page_size: int = 10, ): """ List notify group. Args: - region_id: Region ID. - keyword: query keyword. - page_number: Page number for pagination. - page_size: Page size for pagination. + region (str, optional): Region ID. Defaults to cn-beijing. + keyword (str, optional): Search keyword. Defaults to "". + page_number (int, optional): Page number for pagination. Defaults to 1. + page_size (int, optional): Page size for pagination. Defaults to 10. Returns: A list of notify group. """ try: - if isinstance(region_id, str) and not region_id.strip(): - region_id = DEFAULT_REGION + if isinstance(region, str) and not region.strip(): + region = DEFAULT_REGION if isinstance(keyword, str) and not keyword.strip(): keyword = None req = ApmplusServerListNotifyGroupRequest( - region_id=region_id, + region=region, keyword=keyword, page_number=page_number, page_size=page_size, ) - config = init_auth_config() + config = init_auth_config(region) api = ApmplusApi(config) return api.server_list_notify_group(req) except Exception as e: @@ -101,33 +116,33 @@ async def apmplus_server_list_notify_group( @mcp.tool() async def apmplus_server_query_metrics( - region_id: str, - query: str, - start_time: int, - end_time: int, + region: str = "cn-beijing", + query: str = "", + start_time: int = None, + end_time: int = None, ): """ Query metrics. Args: - region_id: Region ID. - query: Metric expression in PromQL format. - start_time: Start time in seconds. - end_time: End time in seconds. + region (str, optional): Region ID. Defaults to cn-beijing. + query (str): Metric expression in PromQL format. + start_time (int): Start time in seconds. + end_time (int): End time in seconds. Returns: metrics. """ try: - if isinstance(region_id, str) and not region_id.strip(): - region_id = DEFAULT_REGION + if isinstance(region, str) and not region.strip(): + region = DEFAULT_REGION req = ApmplusServerQueryMetricsRequest( - region_id=region_id, + region=region, query=query, start_time=start_time, end_time=end_time, ) - config = init_auth_config() + config = init_auth_config(region) api = ApmplusApi(config) return api.server_query_metrics(req) except Exception as e: @@ -135,32 +150,167 @@ async def apmplus_server_query_metrics( raise -def init_auth_config() -> ApmplusConfig: +@mcp.tool() +async def apmplus_server_get_trace_detail( + trace_id: str, + suggest_time: int, + region: str = "cn-beijing", +): + """ + Get trace detail information. + Args: + trace_id (str, optional): Trace ID. + suggest_time (int, optional): Suggest time in seconds. + region (str, optional): Region ID. Defaults to cn-beijing. + Returns: + trace detail information. + """ + try: + conf = init_auth_config(region) + req = {"suggest_time": suggest_time, "trace_id": trace_id} + return await apmplus_api.server_get_trace_detail(req, conf) + except Exception as e: + logging.error(f"Error in apmplus_server_get_trace_detail: {e}") + raise + + +@mcp.tool() +async def apmplus_server_list_span( + start_time: int, + end_time: int, + filters: list[dict] = None, + order: str = "DESC", + order_by: str = "", + offset: int = 0, + limit: int = 10, + min_call_cost_millisecond: int = 0, + max_call_cost_millisecond: int = 0, + project_name: str = None, + tag_filters: list[dict] = None, + region: str = "cn-beijing", +): + """ + Get a list of trace span. + Args: + start_time (int): Start time in seconds, example: 1693536000 + end_time (int): End time in seconds, example: 1693546000 + filters (list[dict], optional): Filter expression. + Each dict contains: + - 'Op' (str): in, not_in + - 'Key' (str): Filter key + - 'Values' (list[str]): Filter values + order (str, optional): Order direction. Defaults to DESC. + order_by (str, optional): Order by field. Defaults to "". + offset (int, optional): Offset for pagination. Defaults to 0. + limit (int, optional): Limit for pagination. Defaults to 10. + min_call_cost_millisecond (int, optional): Minimum call cost in milliseconds. Defaults to 0. + max_call_cost_millisecond (int, optional): Maximum call cost in milliseconds. Defaults to 0. + project_name (str, optional): The project name. + tag_filters (list[dict], optional): List of tag filters. Each dict contains: + - 'Key' (str): Tag key + - 'Value' (list[str]): Tag value + Max 10 tag pairs. + Empty value means no restriction on tag value. + region (str, optional): Region ID. Defaults to cn-beijing. + Returns: + A list of span. + """ + try: + conf = init_auth_config(region) + req = { + "start_time": start_time, + "end_time": end_time, + "filters": filters, + "order": order, + "order_by": order_by, + "offset": offset, + "limit": limit, + "min_call_cost_millisecond": min_call_cost_millisecond, + "max_call_cost_millisecond": max_call_cost_millisecond, + "project_name": project_name, + "tag_filters": tag_filters, + } + return await apmplus_api.server_list_span(req, conf) + except Exception as e: + logging.error(f"Error in apmplus_server_list_span: {e}") + raise + + +def init_auth_config(region: str) -> ApmplusConfig: """Initialize auth config from env or request context.""" conf = load_config() # load default config from env + if region and len(region) > 0: + conf.region = region + if conf.endpoint is None or len(conf.endpoint) == 0: + conf.endpoint = get_endpoint_by_region(region) + + if os.getenv(ENV_MCP_DEV_MODE, "False") != "True": + # 从 context 中获取 header + ctx: Context[ServerSession, object] = mcp.get_context() + raw_request: Request | None = ctx.request_context.request + + auth = None + if raw_request: + # 从 header 的 authorization 字段读取 base64 编码后的 sts json + auth = raw_request.headers.get("authorization", None) + if auth is None: + # 如果 header 中没有认证信息,可能是 stdio 模式,尝试从环境变量获取 + auth = os.getenv("authorization", None) + if auth is not None: + if " " in auth: + _, base64_data = auth.split(" ", 1) + else: + base64_data = auth - # 从 context 中获取 header - ctx: Context[ServerSession, object] = mcp.get_context() - raw_request: Request = ctx.request_context.request - - auth = None - if raw_request: - # 从 header 的 authorization 字段读取 base64 编码后的 sts json - auth = raw_request.headers.get("authorization", None) - if auth is None: - # 如果 header 中没有认证信息,可能是 stdio 模式,尝试从环境变量获取 - auth = os.getenv("authorization", None) - if auth is not None: - if " " in auth: - _, base64_data = auth.split(" ", 1) - else: - base64_data = auth - - try: - config = parse_authorization(base64_data) - return config - except Exception as e: - raise ValueError("Decode authorization info error", e) + try: + # 解码 Base64 + decoded_str = base64.b64decode(base64_data).decode("utf-8") + data = json.loads(decoded_str) + # 获取字段 + conf.access_key = data.get("AccessKeyId") + conf.secret_key = data.get("SecretAccessKey") + conf.session_token = data.get("SessionToken") + return conf + except Exception as e: + raise ValueError("Decode authorization info error", e) if not conf.is_valid(): raise ValueError("No valid auth info found") return conf + + +def get_endpoint_by_region(region: str = None) -> str: + return f"apmplus-server.{region}.volcengineapi.com" + + +def main(): + parser = argparse.ArgumentParser(description="Run the APMPlus MCP Server") + parser.add_argument( + "--transport", + "-t", + choices=["sse", "stdio", "streamable-http"], + default=os.getenv(ENV_MCP_SERVER_MODE, "stdio"), + help="Transport protocol to use (sse, stdio or streamable-http)", + ) + + args = parser.parse_args() + + try: + # Load configuration from environment variables + global config + + config = load_config() + volcenginesdkcore.Configuration.set_default(config.to_volc_configuration()) + global apmplus_api + apmplus_api = ApmplusApi(config) + + # Run the MCP server + logger.info(f"Starting APMPlus MCP Server with {args.transport} transport") + + mcp.run(transport=args.transport) + except Exception as e: + logger.error(f"Error starting APMPlus MCP Server: {str(e)}") + raise + + +if __name__ == "__main__": + main() diff --git a/server/mcp_server_apmplus/src/mcp_server_apmplus/test.py b/server/mcp_server_apmplus/src/mcp_server_apmplus/test.py new file mode 100644 index 00000000..d190417e --- /dev/null +++ b/server/mcp_server_apmplus/src/mcp_server_apmplus/test.py @@ -0,0 +1,104 @@ +import unittest +from unittest.mock import patch + +import mcp_server_apmplus.server as server +from mcp_server_apmplus.api import * +from mcp_server_apmplus.config import * + +AK = "" +SK = "" + + +class TestModels(unittest.IsolatedAsyncioTestCase): + async def test_list_alert_rule(self): + with patch.dict( + os.environ, + { + ENV_VOLCENGINE_ACCESS_KEY: AK, + ENV_VOLCENGINE_SECRET_KEY: SK, + ENV_MCP_DEV_MODE: "True", + }, + clear=False, + ): + resp = await server.apmplus_server_list_alert_rule( + keyword="test", + ) + print(resp) + + async def test_list_notify_group(self): + with patch.dict( + os.environ, + { + ENV_VOLCENGINE_ACCESS_KEY: AK, + ENV_VOLCENGINE_SECRET_KEY: SK, + ENV_MCP_DEV_MODE: "True", + }, + clear=False, + ): + resp = await server.apmplus_server_list_notify_group( + keyword="test", + ) + print(resp) + + async def test_query_metrics(self): + with patch.dict( + os.environ, + { + ENV_VOLCENGINE_ACCESS_KEY: AK, + ENV_VOLCENGINE_SECRET_KEY: SK, + ENV_MCP_DEV_MODE: "True", + }, + clear=False, + ): + resp = await server.apmplus_server_query_metrics( + query="histogram_quantile(0.99, sum(rate(gen_ai_client_operation_duration_bucket{}[5m])) by (le))", + start_time=1746777063, + end_time=1746780663, + ) + print(resp) + + async def test_apmplus_server_get_trace_detail(self): + with patch.dict( + os.environ, + { + ENV_VOLCENGINE_ACCESS_KEY: AK, + ENV_VOLCENGINE_SECRET_KEY: SK, + ENV_MCP_DEV_MODE: "True", + }, + clear=False, + ): + init_config() + resp = await server.apmplus_server_get_trace_detail( + trace_id="test", + suggest_time=1746777063, + ) + print(resp) + + async def test_apmplus_server_list_span(self): + with patch.dict( + os.environ, + { + ENV_VOLCENGINE_ACCESS_KEY: AK, + ENV_VOLCENGINE_SECRET_KEY: SK, + ENV_MCP_DEV_MODE: "True", + }, + clear=False, + ): + init_config() + resp = await server.apmplus_server_list_span( + start_time=1746777063, + end_time=1746780663, + ) + print(resp) + + +def init_config(): + config = load_config() + server.config = volcenginesdkcore.Configuration.set_default( + config.to_volc_configuration() + ) + server.apmplus_api = ApmplusApi(config) + + +if __name__ == "__main__": + unittest.main() diff --git a/server/mcp_server_apmplus/uv.lock b/server/mcp_server_apmplus/uv.lock index 95fd8ce7..3ea02a5e 100644 --- a/server/mcp_server_apmplus/uv.lock +++ b/server/mcp_server_apmplus/uv.lock @@ -35,6 +35,50 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, ] +[[package]] +name = "black" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pytokens" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/88/560b11e521c522440af991d46848a2bde64b5f7202ec14e1f46f9509d328/black-26.1.0.tar.gz", hash = "sha256:d294ac3340eef9c9eb5d29288e96dc719ff269a88e27b396340459dd85da4c58", size = 658785, upload-time = "2026-01-18T04:50:11.993Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/1b/523329e713f965ad0ea2b7a047eeb003007792a0353622ac7a8cb2ee6fef/black-26.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ca699710dece84e3ebf6e92ee15f5b8f72870ef984bf944a57a777a48357c168", size = 1849661, upload-time = "2026-01-18T04:59:12.425Z" }, + { url = "https://files.pythonhosted.org/packages/14/82/94c0640f7285fa71c2f32879f23e609dd2aa39ba2641f395487f24a578e7/black-26.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5e8e75dabb6eb83d064b0db46392b25cabb6e784ea624219736e8985a6b3675d", size = 1689065, upload-time = "2026-01-18T04:59:13.993Z" }, + { url = "https://files.pythonhosted.org/packages/f0/78/474373cbd798f9291ed8f7107056e343fd39fef42de4a51c7fd0d360840c/black-26.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eb07665d9a907a1a645ee41a0df8a25ffac8ad9c26cdb557b7b88eeeeec934e0", size = 1751502, upload-time = "2026-01-18T04:59:15.971Z" }, + { url = "https://files.pythonhosted.org/packages/29/89/59d0e350123f97bc32c27c4d79563432d7f3530dca2bff64d855c178af8b/black-26.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:7ed300200918147c963c87700ccf9966dceaefbbb7277450a8d646fc5646bf24", size = 1400102, upload-time = "2026-01-18T04:59:17.8Z" }, + { url = "https://files.pythonhosted.org/packages/e1/bc/5d866c7ae1c9d67d308f83af5462ca7046760158bbf142502bad8f22b3a1/black-26.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:c5b7713daea9bf943f79f8c3b46f361cc5229e0e604dcef6a8bb6d1c37d9df89", size = 1207038, upload-time = "2026-01-18T04:59:19.543Z" }, + { url = "https://files.pythonhosted.org/packages/30/83/f05f22ff13756e1a8ce7891db517dbc06200796a16326258268f4658a745/black-26.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3cee1487a9e4c640dc7467aaa543d6c0097c391dc8ac74eb313f2fbf9d7a7cb5", size = 1831956, upload-time = "2026-01-18T04:59:21.38Z" }, + { url = "https://files.pythonhosted.org/packages/7d/f2/b2c570550e39bedc157715e43927360312d6dd677eed2cc149a802577491/black-26.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d62d14ca31c92adf561ebb2e5f2741bf8dea28aef6deb400d49cca011d186c68", size = 1672499, upload-time = "2026-01-18T04:59:23.257Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d7/990d6a94dc9e169f61374b1c3d4f4dd3037e93c2cc12b6f3b12bc663aa7b/black-26.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fb1dafbbaa3b1ee8b4550a84425aac8874e5f390200f5502cf3aee4a2acb2f14", size = 1735431, upload-time = "2026-01-18T04:59:24.729Z" }, + { url = "https://files.pythonhosted.org/packages/36/1c/cbd7bae7dd3cb315dfe6eeca802bb56662cc92b89af272e014d98c1f2286/black-26.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:101540cb2a77c680f4f80e628ae98bd2bd8812fb9d72ade4f8995c5ff019e82c", size = 1400468, upload-time = "2026-01-18T04:59:27.381Z" }, + { url = "https://files.pythonhosted.org/packages/59/b1/9fe6132bb2d0d1f7094613320b56297a108ae19ecf3041d9678aec381b37/black-26.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:6f3977a16e347f1b115662be07daa93137259c711e526402aa444d7a88fdc9d4", size = 1207332, upload-time = "2026-01-18T04:59:28.711Z" }, + { url = "https://files.pythonhosted.org/packages/f5/13/710298938a61f0f54cdb4d1c0baeb672c01ff0358712eddaf29f76d32a0b/black-26.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6eeca41e70b5f5c84f2f913af857cf2ce17410847e1d54642e658e078da6544f", size = 1878189, upload-time = "2026-01-18T04:59:30.682Z" }, + { url = "https://files.pythonhosted.org/packages/79/a6/5179beaa57e5dbd2ec9f1c64016214057b4265647c62125aa6aeffb05392/black-26.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dd39eef053e58e60204f2cdf059e2442e2eb08f15989eefe259870f89614c8b6", size = 1700178, upload-time = "2026-01-18T04:59:32.387Z" }, + { url = "https://files.pythonhosted.org/packages/8c/04/c96f79d7b93e8f09d9298b333ca0d31cd9b2ee6c46c274fd0f531de9dc61/black-26.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9459ad0d6cd483eacad4c6566b0f8e42af5e8b583cee917d90ffaa3778420a0a", size = 1777029, upload-time = "2026-01-18T04:59:33.767Z" }, + { url = "https://files.pythonhosted.org/packages/49/f9/71c161c4c7aa18bdda3776b66ac2dc07aed62053c7c0ff8bbda8c2624fe2/black-26.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a19915ec61f3a8746e8b10adbac4a577c6ba9851fa4a9e9fbfbcf319887a5791", size = 1406466, upload-time = "2026-01-18T04:59:35.177Z" }, + { url = "https://files.pythonhosted.org/packages/4a/8b/a7b0f974e473b159d0ac1b6bcefffeb6bec465898a516ee5cc989503cbc7/black-26.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:643d27fb5facc167c0b1b59d0315f2674a6e950341aed0fc05cf307d22bf4954", size = 1216393, upload-time = "2026-01-18T04:59:37.18Z" }, + { url = "https://files.pythonhosted.org/packages/79/04/fa2f4784f7237279332aa735cdfd5ae2e7730db0072fb2041dadda9ae551/black-26.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ba1d768fbfb6930fc93b0ecc32a43d8861ded16f47a40f14afa9bb04ab93d304", size = 1877781, upload-time = "2026-01-18T04:59:39.054Z" }, + { url = "https://files.pythonhosted.org/packages/cf/ad/5a131b01acc0e5336740a039628c0ab69d60cf09a2c87a4ec49f5826acda/black-26.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b807c240b64609cb0e80d2200a35b23c7df82259f80bef1b2c96eb422b4aac9", size = 1699670, upload-time = "2026-01-18T04:59:41.005Z" }, + { url = "https://files.pythonhosted.org/packages/da/7c/b05f22964316a52ab6b4265bcd52c0ad2c30d7ca6bd3d0637e438fc32d6e/black-26.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1de0f7d01cc894066a1153b738145b194414cc6eeaad8ef4397ac9abacf40f6b", size = 1775212, upload-time = "2026-01-18T04:59:42.545Z" }, + { url = "https://files.pythonhosted.org/packages/a6/a3/e8d1526bea0446e040193185353920a9506eab60a7d8beb062029129c7d2/black-26.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:91a68ae46bf07868963671e4d05611b179c2313301bd756a89ad4e3b3db2325b", size = 1409953, upload-time = "2026-01-18T04:59:44.357Z" }, + { url = "https://files.pythonhosted.org/packages/c7/5a/d62ebf4d8f5e3a1daa54adaab94c107b57be1b1a2f115a0249b41931e188/black-26.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:be5e2fe860b9bd9edbf676d5b60a9282994c03fbbd40fe8f5e75d194f96064ca", size = 1217707, upload-time = "2026-01-18T04:59:45.719Z" }, + { url = "https://files.pythonhosted.org/packages/6a/83/be35a175aacfce4b05584ac415fd317dd6c24e93a0af2dcedce0f686f5d8/black-26.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9dc8c71656a79ca49b8d3e2ce8103210c9481c57798b48deeb3a8bb02db5f115", size = 1871864, upload-time = "2026-01-18T04:59:47.586Z" }, + { url = "https://files.pythonhosted.org/packages/a5/f5/d33696c099450b1274d925a42b7a030cd3ea1f56d72e5ca8bbed5f52759c/black-26.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b22b3810451abe359a964cc88121d57f7bce482b53a066de0f1584988ca36e79", size = 1701009, upload-time = "2026-01-18T04:59:49.443Z" }, + { url = "https://files.pythonhosted.org/packages/1b/87/670dd888c537acb53a863bc15abbd85b22b429237d9de1b77c0ed6b79c42/black-26.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53c62883b3f999f14e5d30b5a79bd437236658ad45b2f853906c7cbe79de00af", size = 1767806, upload-time = "2026-01-18T04:59:50.769Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9c/cd3deb79bfec5bcf30f9d2100ffeec63eecce826eb63e3961708b9431ff1/black-26.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:f016baaadc423dc960cdddf9acae679e71ee02c4c341f78f3179d7e4819c095f", size = 1433217, upload-time = "2026-01-18T04:59:52.218Z" }, + { url = "https://files.pythonhosted.org/packages/4e/29/f3be41a1cf502a283506f40f5d27203249d181f7a1a2abce1c6ce188035a/black-26.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:66912475200b67ef5a0ab665011964bf924745103f51977a78b4fb92a9fc1bf0", size = 1245773, upload-time = "2026-01-18T04:59:54.457Z" }, + { url = "https://files.pythonhosted.org/packages/e4/3d/51bdb3ecbfadfaf825ec0c75e1de6077422b4afa2091c6c9ba34fbfc0c2d/black-26.1.0-py3-none-any.whl", hash = "sha256:1054e8e47ebd686e078c0bb0eaf31e6ce69c966058d122f2c0c950311f9f3ede", size = 204010, upload-time = "2026-01-18T04:50:09.978Z" }, +] + [[package]] name = "certifi" version = "2025.4.26" @@ -219,7 +263,7 @@ wheels = [ [[package]] name = "mcp" -version = "1.10.0" +version = "1.12.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -229,20 +273,22 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, { name = "sse-starlette" }, { name = "starlette" }, { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c8/1a/d90e42be23a7e6dd35c03e35c7c63fe1036f082d3bb88114b66bd0f2467e/mcp-1.10.0.tar.gz", hash = "sha256:91fb1623c3faf14577623d14755d3213db837c5da5dae85069e1b59124cbe0e9", size = 392961, upload-time = "2025-06-26T13:51:19.025Z" } +sdist = { url = "https://files.pythonhosted.org/packages/31/88/f6cb7e7c260cd4b4ce375f2b1614b33ce401f63af0f49f7141a2e9bf0a45/mcp-1.12.4.tar.gz", hash = "sha256:0765585e9a3a5916a3c3ab8659330e493adc7bd8b2ca6120c2d7a0c43e034ca5", size = 431148, upload-time = "2025-08-07T20:31:18.082Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/52/e1c43c4b5153465fd5d3b4b41bf2d4c7731475e9f668f38d68f848c25c9a/mcp-1.10.0-py3-none-any.whl", hash = "sha256:925c45482d75b1b6f11febddf9736d55edf7739c7ea39b583309f6651cbc9e5c", size = 150894, upload-time = "2025-06-26T13:51:17.342Z" }, + { url = "https://files.pythonhosted.org/packages/ad/68/316cbc54b7163fa22571dcf42c9cc46562aae0a021b974e0a8141e897200/mcp-1.12.4-py3-none-any.whl", hash = "sha256:7aa884648969fab8e78b89399d59a683202972e12e6bc9a1c88ce7eda7743789", size = 160145, upload-time = "2025-08-07T20:31:15.69Z" }, ] [[package]] name = "mcp-server-apmplus" -version = "0.1.0" +version = "0.2.0" source = { editable = "." } dependencies = [ + { name = "black" }, { name = "mcp" }, { name = "requests" }, { name = "volcengine-python-sdk" }, @@ -250,9 +296,46 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "mcp", specifier = "==1.10.0" }, + { name = "black", specifier = ">=26.1.0" }, + { name = "mcp", specifier = "==1.12.4" }, { name = "requests", specifier = ">=2.32.3" }, - { name = "volcengine-python-sdk", specifier = ">=3.0.1" }, + { name = "volcengine-python-sdk", git = "ssh://git@code.byted.org/iaasng/volcengine-python-sdk?rev=apmplus_server-Python-2026-01-01-online-2296-2026_02_26_16_41_42" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "packaging" +version = "26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, +] + +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.9.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394, upload-time = "2026-02-16T03:56:10.574Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168, upload-time = "2026-02-16T03:56:08.891Z" }, ] [[package]] @@ -401,6 +484,67 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, ] +[[package]] +name = "pytokens" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b6/34/b4e015b99031667a7b960f888889c5bd34ef585c85e1cb56a594b92836ac/pytokens-0.4.1.tar.gz", hash = "sha256:292052fe80923aae2260c073f822ceba21f3872ced9a68bb7953b348e561179a", size = 23015, upload-time = "2026-01-30T01:03:45.924Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/24/f206113e05cb8ef51b3850e7ef88f20da6f4bf932190ceb48bd3da103e10/pytokens-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a44ed93ea23415c54f3face3b65ef2b844d96aeb3455b8a69b3df6beab6acc5", size = 161522, upload-time = "2026-01-30T01:02:50.393Z" }, + { url = "https://files.pythonhosted.org/packages/d4/e9/06a6bf1b90c2ed81a9c7d2544232fe5d2891d1cd480e8a1809ca354a8eb2/pytokens-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:add8bf86b71a5d9fb5b89f023a80b791e04fba57960aa790cc6125f7f1d39dfe", size = 246945, upload-time = "2026-01-30T01:02:52.399Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/f6fb1007a4c3d8b682d5d65b7c1fb33257587a5f782647091e3408abe0b8/pytokens-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:670d286910b531c7b7e3c0b453fd8156f250adb140146d234a82219459b9640c", size = 259525, upload-time = "2026-01-30T01:02:53.737Z" }, + { url = "https://files.pythonhosted.org/packages/04/92/086f89b4d622a18418bac74ab5db7f68cf0c21cf7cc92de6c7b919d76c88/pytokens-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4e691d7f5186bd2842c14813f79f8884bb03f5995f0575272009982c5ac6c0f7", size = 262693, upload-time = "2026-01-30T01:02:54.871Z" }, + { url = "https://files.pythonhosted.org/packages/b4/7b/8b31c347cf94a3f900bdde750b2e9131575a61fdb620d3d3c75832262137/pytokens-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:27b83ad28825978742beef057bfe406ad6ed524b2d28c252c5de7b4a6dd48fa2", size = 103567, upload-time = "2026-01-30T01:02:56.414Z" }, + { url = "https://files.pythonhosted.org/packages/3d/92/790ebe03f07b57e53b10884c329b9a1a308648fc083a6d4a39a10a28c8fc/pytokens-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d70e77c55ae8380c91c0c18dea05951482e263982911fc7410b1ffd1dadd3440", size = 160864, upload-time = "2026-01-30T01:02:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/13/25/a4f555281d975bfdd1eba731450e2fe3a95870274da73fb12c40aeae7625/pytokens-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a58d057208cb9075c144950d789511220b07636dd2e4708d5645d24de666bdc", size = 248565, upload-time = "2026-01-30T01:02:59.912Z" }, + { url = "https://files.pythonhosted.org/packages/17/50/bc0394b4ad5b1601be22fa43652173d47e4c9efbf0044c62e9a59b747c56/pytokens-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b49750419d300e2b5a3813cf229d4e5a4c728dae470bcc89867a9ad6f25a722d", size = 260824, upload-time = "2026-01-30T01:03:01.471Z" }, + { url = "https://files.pythonhosted.org/packages/4e/54/3e04f9d92a4be4fc6c80016bc396b923d2a6933ae94b5f557c939c460ee0/pytokens-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9907d61f15bf7261d7e775bd5d7ee4d2930e04424bab1972591918497623a16", size = 264075, upload-time = "2026-01-30T01:03:04.143Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1b/44b0326cb5470a4375f37988aea5d61b5cc52407143303015ebee94abfd6/pytokens-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee44d0f85b803321710f9239f335aafe16553b39106384cef8e6de40cb4ef2f6", size = 103323, upload-time = "2026-01-30T01:03:05.412Z" }, + { url = "https://files.pythonhosted.org/packages/41/5d/e44573011401fb82e9d51e97f1290ceb377800fb4eed650b96f4753b499c/pytokens-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:140709331e846b728475786df8aeb27d24f48cbcf7bcd449f8de75cae7a45083", size = 160663, upload-time = "2026-01-30T01:03:06.473Z" }, + { url = "https://files.pythonhosted.org/packages/f0/e6/5bbc3019f8e6f21d09c41f8b8654536117e5e211a85d89212d59cbdab381/pytokens-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d6c4268598f762bc8e91f5dbf2ab2f61f7b95bdc07953b602db879b3c8c18e1", size = 255626, upload-time = "2026-01-30T01:03:08.177Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3c/2d5297d82286f6f3d92770289fd439956b201c0a4fc7e72efb9b2293758e/pytokens-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24afde1f53d95348b5a0eb19488661147285ca4dd7ed752bbc3e1c6242a304d1", size = 269779, upload-time = "2026-01-30T01:03:09.756Z" }, + { url = "https://files.pythonhosted.org/packages/20/01/7436e9ad693cebda0551203e0bf28f7669976c60ad07d6402098208476de/pytokens-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ad948d085ed6c16413eb5fec6b3e02fa00dc29a2534f088d3302c47eb59adf9", size = 268076, upload-time = "2026-01-30T01:03:10.957Z" }, + { url = "https://files.pythonhosted.org/packages/2e/df/533c82a3c752ba13ae7ef238b7f8cdd272cf1475f03c63ac6cf3fcfb00b6/pytokens-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:3f901fe783e06e48e8cbdc82d631fca8f118333798193e026a50ce1b3757ea68", size = 103552, upload-time = "2026-01-30T01:03:12.066Z" }, + { url = "https://files.pythonhosted.org/packages/cb/dc/08b1a080372afda3cceb4f3c0a7ba2bde9d6a5241f1edb02a22a019ee147/pytokens-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8bdb9d0ce90cbf99c525e75a2fa415144fd570a1ba987380190e8b786bc6ef9b", size = 160720, upload-time = "2026-01-30T01:03:13.843Z" }, + { url = "https://files.pythonhosted.org/packages/64/0c/41ea22205da480837a700e395507e6a24425151dfb7ead73343d6e2d7ffe/pytokens-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5502408cab1cb18e128570f8d598981c68a50d0cbd7c61312a90507cd3a1276f", size = 254204, upload-time = "2026-01-30T01:03:14.886Z" }, + { url = "https://files.pythonhosted.org/packages/e0/d2/afe5c7f8607018beb99971489dbb846508f1b8f351fcefc225fcf4b2adc0/pytokens-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29d1d8fb1030af4d231789959f21821ab6325e463f0503a61d204343c9b355d1", size = 268423, upload-time = "2026-01-30T01:03:15.936Z" }, + { url = "https://files.pythonhosted.org/packages/68/d4/00ffdbd370410c04e9591da9220a68dc1693ef7499173eb3e30d06e05ed1/pytokens-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b08dd6b86058b6dc07efe9e98414f5102974716232d10f32ff39701e841c4", size = 266859, upload-time = "2026-01-30T01:03:17.458Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c9/c3161313b4ca0c601eeefabd3d3b576edaa9afdefd32da97210700e47652/pytokens-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:9bd7d7f544d362576be74f9d5901a22f317efc20046efe2034dced238cbbfe78", size = 103520, upload-time = "2026-01-30T01:03:18.652Z" }, + { url = "https://files.pythonhosted.org/packages/8f/a7/b470f672e6fc5fee0a01d9e75005a0e617e162381974213a945fcd274843/pytokens-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4a14d5f5fc78ce85e426aa159489e2d5961acf0e47575e08f35584009178e321", size = 160821, upload-time = "2026-01-30T01:03:19.684Z" }, + { url = "https://files.pythonhosted.org/packages/80/98/e83a36fe8d170c911f864bfded690d2542bfcfacb9c649d11a9e6eb9dc41/pytokens-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f50fd18543be72da51dd505e2ed20d2228c74e0464e4262e4899797803d7fa", size = 254263, upload-time = "2026-01-30T01:03:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/0f/95/70d7041273890f9f97a24234c00b746e8da86df462620194cef1d411ddeb/pytokens-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc74c035f9bfca0255c1af77ddd2d6ae8419012805453e4b0e7513e17904545d", size = 268071, upload-time = "2026-01-30T01:03:21.888Z" }, + { url = "https://files.pythonhosted.org/packages/da/79/76e6d09ae19c99404656d7db9c35dfd20f2086f3eb6ecb496b5b31163bad/pytokens-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f66a6bbe741bd431f6d741e617e0f39ec7257ca1f89089593479347cc4d13324", size = 271716, upload-time = "2026-01-30T01:03:23.633Z" }, + { url = "https://files.pythonhosted.org/packages/79/37/482e55fa1602e0a7ff012661d8c946bafdc05e480ea5a32f4f7e336d4aa9/pytokens-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:b35d7e5ad269804f6697727702da3c517bb8a5228afa450ab0fa787732055fc9", size = 104539, upload-time = "2026-01-30T01:03:24.788Z" }, + { url = "https://files.pythonhosted.org/packages/30/e8/20e7db907c23f3d63b0be3b8a4fd1927f6da2395f5bcc7f72242bb963dfe/pytokens-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8fcb9ba3709ff77e77f1c7022ff11d13553f3c30299a9fe246a166903e9091eb", size = 168474, upload-time = "2026-01-30T01:03:26.428Z" }, + { url = "https://files.pythonhosted.org/packages/d6/81/88a95ee9fafdd8f5f3452107748fd04c24930d500b9aba9738f3ade642cc/pytokens-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79fc6b8699564e1f9b521582c35435f1bd32dd06822322ec44afdeba666d8cb3", size = 290473, upload-time = "2026-01-30T01:03:27.415Z" }, + { url = "https://files.pythonhosted.org/packages/cf/35/3aa899645e29b6375b4aed9f8d21df219e7c958c4c186b465e42ee0a06bf/pytokens-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d31b97b3de0f61571a124a00ffe9a81fb9939146c122c11060725bd5aea79975", size = 303485, upload-time = "2026-01-30T01:03:28.558Z" }, + { url = "https://files.pythonhosted.org/packages/52/a0/07907b6ff512674d9b201859f7d212298c44933633c946703a20c25e9d81/pytokens-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:967cf6e3fd4adf7de8fc73cd3043754ae79c36475c1c11d514fc72cf5490094a", size = 306698, upload-time = "2026-01-30T01:03:29.653Z" }, + { url = "https://files.pythonhosted.org/packages/39/2a/cbbf9250020a4a8dd53ba83a46c097b69e5eb49dd14e708f496f548c6612/pytokens-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:584c80c24b078eec1e227079d56dc22ff755e0ba8654d8383b2c549107528918", size = 116287, upload-time = "2026-01-30T01:03:30.912Z" }, + { url = "https://files.pythonhosted.org/packages/c6/78/397db326746f0a342855b81216ae1f0a32965deccfd7c830a2dbc66d2483/pytokens-0.4.1-py3-none-any.whl", hash = "sha256:26cef14744a8385f35d0e095dc8b3a7583f6c953c2e3d269c7f82484bf5ad2de", size = 13729, upload-time = "2026-01-30T01:03:45.029Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, + { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, + { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, + { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, + { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + [[package]] name = "referencing" version = "0.36.2" @@ -599,6 +743,60 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, ] +[[package]] +name = "tomli" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" }, + { url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" }, + { url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" }, + { url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" }, + { url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" }, + { url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" }, + { url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" }, + { url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" }, + { url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" }, + { url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" }, + { url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" }, + { url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" }, + { url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" }, + { url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" }, + { url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" }, + { url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" }, + { url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" }, + { url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" }, + { url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" }, + { url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" }, + { url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" }, + { url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" }, + { url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" }, + { url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" }, + { url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" }, + { url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" }, + { url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" }, + { url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, +] + [[package]] name = "typing-extensions" version = "4.13.2" @@ -645,12 +843,11 @@ wheels = [ [[package]] name = "volcengine-python-sdk" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } +version = "5.0.11" +source = { git = "ssh://git@code.byted.org/iaasng/volcengine-python-sdk?rev=apmplus_server-Python-2026-01-01-online-2296-2026_02_26_16_41_42#3553ef611f36f12c9481f21bc663805a9c135bad" } dependencies = [ { name = "certifi" }, { name = "python-dateutil" }, { name = "six" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/cf/d841e615a6d541888545281b15ab381e73c098edc11375ef231b9ccde7a8/volcengine-python-sdk-3.0.1.tar.gz", hash = "sha256:2f1b95ec46a2ad74be298724692d025f35ff870b26584edebee3db89b8a10e55", size = 3981206, upload-time = "2025-05-14T03:47:24.545Z" }