alibaba-cloud-ops-mcp-server 0.8.9__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/PKG-INFO +3 -1
  2. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/README.md +2 -0
  3. alibaba_cloud_ops_mcp_server-0.9.0/README_mcp_args.md +22 -0
  4. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/README_zh.md +2 -0
  5. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/pyproject.toml +2 -2
  6. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/alibabacloud/api_meta_client.py +10 -2
  7. alibaba_cloud_ops_mcp_server-0.9.0/src/alibaba_cloud_ops_mcp_server/alibabacloud/static/PROMPT_UNDERSTANDING.md +134 -0
  8. alibaba_cloud_ops_mcp_server-0.9.0/src/alibaba_cloud_ops_mcp_server/alibabacloud/static/__init__.py +8 -0
  9. alibaba_cloud_ops_mcp_server-0.9.0/src/alibaba_cloud_ops_mcp_server/server.py +78 -0
  10. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/tools/api_tools.py +27 -1
  11. alibaba_cloud_ops_mcp_server-0.9.0/src/alibaba_cloud_ops_mcp_server/tools/common_api_tools.py +74 -0
  12. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/alibabacloud/test_api_meta_client.py +29 -7
  13. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/test_server.py +5 -3
  14. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/tools/test_api_tools.py +65 -0
  15. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/uv.lock +66 -65
  16. alibaba_cloud_ops_mcp_server-0.8.9/src/alibaba_cloud_ops_mcp_server/server.py +0 -51
  17. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/.github/workflows/python-ci.yml +0 -0
  18. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/.gitignore +0 -0
  19. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/LICENSE +0 -0
  20. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/examples/openapi_mcp_quickstart/server.py +0 -0
  21. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/image/Alibaba-Cloud-Ops-MCP-User-Group-en.png +0 -0
  22. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/image/Alibaba-Cloud-Ops-MCP-User-Group-zh.png +0 -0
  23. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/image/alibaba-cloud.png +0 -0
  24. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/__init__.py +0 -0
  25. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/__init__.py +0 -0
  26. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/alibabacloud/__init__.py +0 -0
  27. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/alibabacloud/exception.py +0 -0
  28. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/alibabacloud/utils.py +0 -0
  29. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/config.py +0 -0
  30. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/tools/__init__.py +0 -0
  31. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/tools/cms_tools.py +0 -0
  32. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/tools/oos_tools.py +0 -0
  33. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/src/alibaba_cloud_ops_mcp_server/tools/oss_tools.py +0 -0
  34. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/alibabacloud/test_exception.py +0 -0
  35. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/alibabacloud/test_utils.py +0 -0
  36. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/test_init.py +0 -0
  37. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/tools/test_cms_tools.py +0 -0
  38. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/tools/test_oos_tools.py +0 -0
  39. {alibaba_cloud_ops_mcp_server-0.8.9 → alibaba_cloud_ops_mcp_server-0.9.0}/tests/tools/test_oss_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alibaba-cloud-ops-mcp-server
3
- Version: 0.8.9
3
+ Version: 0.9.0
4
4
  Summary: A MCP server for Alibaba Cloud
5
5
  Author-email: Zheng Dayu <dayu.zdy@alibaba-inc.com>
6
6
  License-File: LICENSE
@@ -55,6 +55,8 @@ To use `alibaba-cloud-ops-mcp-server` MCP Server with any other MCP Client, you
55
55
  }
56
56
  ```
57
57
 
58
+ [For detailed parameter description, see MCP startup parameter document](./README_mcp_args.md)
59
+
58
60
  ## MCP Maketplace Integration
59
61
 
60
62
  * [Cline](https://cline.bot/mcp-marketplace)
@@ -39,6 +39,8 @@ To use `alibaba-cloud-ops-mcp-server` MCP Server with any other MCP Client, you
39
39
  }
40
40
  ```
41
41
 
42
+ [For detailed parameter description, see MCP startup parameter document](./README_mcp_args.md)
43
+
42
44
  ## MCP Maketplace Integration
43
45
 
44
46
  * [Cline](https://cline.bot/mcp-marketplace)
@@ -0,0 +1,22 @@
1
+ # MCP Startup Parameters Guide
2
+
3
+ This document provides a detailed introduction to the available parameters for starting the Alibaba Cloud MCP Server, helping users configure the server according to their needs.
4
+
5
+ ## Parameter Table
6
+
7
+ | Parameter | Required | Type | Default | Description |
8
+ |:--------------:|:--------:|:------:|:----------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
9
+ | `--transport` | No | string | `stdio` | Transport protocol for MCP Server communication.<br>Options:<br>&nbsp;&nbsp;&nbsp;&nbsp;• `stdio` <br>&nbsp;&nbsp;&nbsp;&nbsp;• `sse` <br>&nbsp;&nbsp;&nbsp;&nbsp;• `streamable-http` |
10
+ | `--port` | No | int | `8000` | Specifies the port number MCP Server listens on. Make sure the port is not occupied. |
11
+ | `--host` | No | string | `127.0.0.1`| Specifies the host address MCP Server listens on. `0.0.0.0` means listening on all network interfaces. |
12
+ | `--services` | No | string | None | Comma-separated services, e.g., `ecs,vpc`.<br>Supported services:<br>&nbsp;&nbsp;&nbsp;&nbsp;• `ecs`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `oos`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `rds`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `vpc`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `slb`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `ess`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `ros`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `cbn`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `dds`<br>&nbsp;&nbsp;&nbsp;&nbsp;• `r-kvstore` |
13
+
14
+ ## Usage Example
15
+
16
+ ```bash
17
+ uv run src/alibaba_cloud_ops_mcp_server/server.py --transport sse --port 8080 --host 0.0.0.0 --services ecs,vpc
18
+ ```
19
+
20
+ ---
21
+
22
+ For more help, please refer to the main project documentation or contact the maintainer.
@@ -39,6 +39,8 @@ curl -LsSf https://astral.sh/uv/install.sh | sh
39
39
  }
40
40
  ```
41
41
 
42
+ [详细参数说明见 MCP 启动参数文档](./README_mcp_args.md)
43
+
42
44
  ## MCP市场集成
43
45
 
44
46
  * [Cline](https://cline.bot/mcp-marketplace)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "alibaba-cloud-ops-mcp-server"
3
- version = "0.8.9"
3
+ version = "0.9.0"
4
4
  description = "A MCP server for Alibaba Cloud"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -34,4 +34,4 @@ dev = [
34
34
  ]
35
35
 
36
36
  [project.scripts]
37
- alibaba-cloud-ops-mcp-server = "alibaba_cloud_ops_mcp_server:main"
37
+ alibaba-cloud-ops-mcp-server = "alibaba_cloud_ops_mcp_server:main"
@@ -47,9 +47,16 @@ class ApiMetaClient:
47
47
  @classmethod
48
48
  def get_service_version(cls, service):
49
49
  data = cls.get_response_from_pop_api(cls.GET_PRODUCT_LIST)
50
- version = next((item.get(DEFAULT_VERSION) for item in data if item.get(CODE).lower() == service), None)
50
+ version = next((item.get(DEFAULT_VERSION) for item in data if item.get(CODE).lower() == service.lower()), None)
51
51
  return version
52
52
 
53
+ @classmethod
54
+ def get_all_service_info(cls):
55
+ data = cls.get_response_from_pop_api(cls.GET_PRODUCT_LIST)
56
+ filtered_data = [{"code": item["code"], "name": item["name"]} for item in data]
57
+
58
+ return filtered_data
59
+
53
60
  @classmethod
54
61
  def get_service_style(cls, service):
55
62
  data = cls.get_response_from_pop_api(cls.GET_PRODUCT_LIST)
@@ -147,7 +154,8 @@ class ApiMetaClient:
147
154
  return combined_params
148
155
 
149
156
  @classmethod
150
- def get_apis_in_service(cls, service, version):
157
+ def get_apis_in_service(cls, service):
158
+ version = cls.get_service_version(service)
151
159
  data = cls.get_response_from_pop_api(cls.GET_API_OVERVIEW, service=service, version=version)
152
160
  apis = list(data[APIS].keys())
153
161
  return apis
@@ -0,0 +1,134 @@
1
+ ## Optimized Prompt
2
+
3
+ When a user submits a request, analyze their needs and check if matching tools exist. If yes, use them directly. If not, proceed to the retrieval phase.
4
+
5
+ ---
6
+
7
+ ## Request Flow
8
+
9
+ 1. **Analysis & Selection**
10
+ - Analyze user intent
11
+ - Choose between specific tools or common API flow
12
+ - Verify service support
13
+
14
+ 2. **API Flow** (if no specific tool)
15
+ - Identify service
16
+ - Select API via `ListAPIs`
17
+ - Get params via `GetAPIInfo`
18
+ - Execute via `CommonAPICaller`
19
+
20
+ 3. **Error Handling**
21
+ - Service not supported: "Unfortunately, we currently do not support this service"
22
+ - API failures: Check error code, params, permissions
23
+ - Param validation: Verify types and formats
24
+
25
+ ---
26
+
27
+ ### Retrieval Phase
28
+
29
+ 1. **Service Selection**
30
+
31
+ Supported Services:
32
+ - ecs: Elastic Compute Service (ECS)
33
+ - oos: Operations Orchestration Service (OOS)
34
+ - rds: Relational Database Service (RDS)
35
+ - vpc: Virtual Private Cloud (VPC)
36
+ - slb: Server Load Balancer (SLB)
37
+ - ess: Elastic Scaling (ESS)
38
+ - ros: Resource Orchestration Service (ROS)
39
+ - cbn: Cloud Enterprise Network (CBN)
40
+ - dds: MongoDB Database Service (DDS)
41
+ - r-kvstore: Cloud database Tair (compatible with Redis) (R-KVStore)
42
+
43
+ 2. **API Process**
44
+ - Use `ListAPIs` for available APIs
45
+ - Use `GetAPIInfo` for API details
46
+ - Use `CommonAPICaller` to execute
47
+
48
+ ---
49
+
50
+ ### Notes
51
+ - Filter for most appropriate result
52
+ - Choose based on user context and common usage
53
+ - Validate parameters before calls
54
+ - Handle errors gracefully
55
+
56
+ ---
57
+
58
+ ### Common Scenarios
59
+
60
+ 1. **Instance Management**
61
+ ```
62
+ User: "Start ECS instance i-1234567890abcdef0"
63
+ Action: Use OOS_StartInstances
64
+ ```
65
+
66
+ 2. **Monitoring**
67
+ ```
68
+ User: "Check ECS CPU usage"
69
+ Action: Use CMS_GetCpuUsageData
70
+ ```
71
+
72
+ 3. **Custom API**
73
+ ```
74
+ User: "Create VPC in cn-hangzhou"
75
+ Action: ListAPIs → GetAPIInfo → CommonAPICaller
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Available Tools
81
+
82
+ ### ECS (OOS/API)
83
+ - RunCommand: Execute commands on instances
84
+ - StartInstances: Start ECS instances
85
+ - StopInstances: Stop ECS instances
86
+ - RebootInstances: Reboot ECS instances
87
+ - DescribeInstances: List instance details
88
+ - DescribeRegions: List available regions
89
+ - DescribeZones: List available zones
90
+ - DescribeAvailableResource: Check resource inventory
91
+ - DescribeImages: List available images
92
+ - DescribeSecurityGroups: List security groups
93
+ - RunInstances: Create new instances
94
+ - DeleteInstances: Delete instances
95
+ - ResetPassword: Change instance password
96
+ - ReplaceSystemDisk: Change instance OS
97
+
98
+ ### VPC (API)
99
+ - DescribeVpcs: List VPCs
100
+ - DescribeVSwitches: List VSwitches
101
+
102
+ ### RDS (OOS/API)
103
+ - DescribeDBInstances: List database instances
104
+ - StartDBInstances: Start RDS instances
105
+ - StopDBInstances: Stop RDS instances
106
+ - RestartDBInstances: Restart RDS instances
107
+
108
+ ### OSS (API)
109
+ - ListBuckets: List OSS buckets
110
+ - PutBucket: Create bucket
111
+ - DeleteBucket: Delete bucket
112
+ - ListObjects: List bucket contents
113
+
114
+ ### CloudMonitor (API)
115
+ - GetCpuUsageData: Get instance CPU usage
116
+ - GetCpuLoadavgData: Get 1m CPU load
117
+ - GetCpuloadavg5mData: Get 5m CPU load
118
+ - GetCpuloadavg15mData: Get 15m CPU load
119
+ - GetMemUsedData: Get memory usage
120
+ - GetMemUsageData: Get memory utilization
121
+ - GetDiskUsageData: Get disk utilization
122
+ - GetDiskTotalData: Get total disk space
123
+ - GetDiskUsedData: Get used disk space
124
+
125
+ Note: (OOS) = Operations Orchestration Service, (API) = Direct API call
126
+
127
+ ---
128
+
129
+ ### Best Practices
130
+ - Use pre-defined tools when possible
131
+ - Follow API rate limits
132
+ - Implement proper error handling
133
+ - Validate all parameters
134
+ - Use appropriate endpoints
@@ -0,0 +1,8 @@
1
+ from importlib import resources
2
+
3
+ with (
4
+ resources.files('alibaba_cloud_ops_mcp_server.alibabacloud.static')
5
+ .joinpath('PROMPT_UNDERSTANDING.md')
6
+ .open('r', encoding='utf-8') as f
7
+ ):
8
+ PROMPT_UNDERSTANDING = f.read()
@@ -0,0 +1,78 @@
1
+ from mcp.server.fastmcp import FastMCP
2
+ import click
3
+ import logging
4
+
5
+ from alibaba_cloud_ops_mcp_server.tools.common_api_tools import set_custom_service_list
6
+ from alibaba_cloud_ops_mcp_server.config import config
7
+ from alibaba_cloud_ops_mcp_server.tools import cms_tools, oos_tools, oss_tools, api_tools, common_api_tools
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ SUPPORTED_SERVICES_MAP = {
12
+ "ecs": "Elastic Compute Service (ECS)",
13
+ "oos": "Operations Orchestration Service (OOS)",
14
+ "rds": "Relational Database Service (RDS)",
15
+ "vpc": "Virtual Private Cloud (VPC)",
16
+ "slb": "Server Load Balancer (SLB)",
17
+ "ess": "Elastic Scaling (ESS)",
18
+ "ros": "Resource Orchestration Service (ROS)",
19
+ "cbn": "Cloud Enterprise Network (CBN)",
20
+ "dds": "MongoDB Database Service (DDS)",
21
+ "r-kvstore": "Cloud database Tair (compatible with Redis) (R-KVStore)"
22
+ }
23
+
24
+
25
+ @click.command()
26
+ @click.option(
27
+ "--transport",
28
+ type=click.Choice(["stdio", "sse", "streamable-http"]),
29
+ default="stdio",
30
+ help="Transport type",
31
+ )
32
+ @click.option(
33
+ "--port",
34
+ type=int,
35
+ default=8000,
36
+ help="Port number",
37
+ )
38
+ @click.option(
39
+ "--host",
40
+ type=str,
41
+ default="127.0.0.1",
42
+ help="Host",
43
+ )
44
+ @click.option(
45
+ "--services",
46
+ type=str,
47
+ default=None,
48
+ help="Comma-separated list of supported services, e.g., 'ecs,vpc,rds'",
49
+ )
50
+ def main(transport: str, port: int, host: str, services: str):
51
+ # Create an MCP server
52
+ mcp = FastMCP(
53
+ name="alibaba-cloud-ops-mcp-server",
54
+ port=port,
55
+ host=host
56
+ )
57
+
58
+ if services:
59
+ service_keys = [s.strip().lower() for s in services.split(",")]
60
+ service_list = [(key, SUPPORTED_SERVICES_MAP.get(key, key)) for key in service_keys]
61
+ set_custom_service_list(service_list)
62
+ for tool in common_api_tools.tools:
63
+ mcp.add_tool(tool)
64
+ for tool in oos_tools.tools:
65
+ mcp.add_tool(tool)
66
+ for tool in cms_tools.tools:
67
+ mcp.add_tool(tool)
68
+ for tool in oss_tools.tools:
69
+ mcp.add_tool(tool)
70
+ api_tools.create_api_tools(mcp, config)
71
+
72
+ # Initialize and run the server
73
+ logger.debug(f'mcp server is running on {transport} mode.')
74
+ mcp.run(transport=transport)
75
+
76
+
77
+ if __name__ == "__main__":
78
+ main()
@@ -24,12 +24,38 @@ type_map = {
24
24
  'number': float
25
25
  }
26
26
 
27
+ REGION_ENDPOINT_SERVICE = ['ecs', 'oos', 'vpc', 'slb']
28
+
29
+ DOUBLE_ENDPOINT_SERVICE = {
30
+ 'rds': ['cn-qingdao', 'cn-beijing', 'cn-hangzhou', 'cn-shanghai', 'cn-shenzhen', 'cn-heyuan', 'cn-guangzhou', 'cn-hongkong'],
31
+ 'ess': ['cn-qingdao', 'cn-beijing', 'cn-hangzhou', 'cn-shanghai', 'cn-nanjing', 'cn-shenzhen'],
32
+ 'ros': ['cn-qingdao'],
33
+ 'dds': ['cn-qingdao', 'cn-beijing', 'cn-wulanchabu', 'cn-hangzhou', 'cn-shanghai', 'cn-shenzhen', 'cn-heyuan', 'cn-guangzhou'],
34
+ 'r-kvstore': ['cn-qingdao', 'cn-beijing', 'cn-wulanchabu', 'cn-hangzhou', 'cn-shanghai', 'cn-shenzhen', 'cn-heyuan']
35
+ }
36
+
37
+ CENTRAL_ENDPOINTS_SERVICE = ['cbn']
38
+
39
+
40
+ def _get_service_endpoint(service: str, region_id: str):
41
+ region_id = region_id.lower()
42
+ use_region_endpoint = service in REGION_ENDPOINT_SERVICE or (
43
+ service in DOUBLE_ENDPOINT_SERVICE and region_id in DOUBLE_ENDPOINT_SERVICE[service]
44
+ )
45
+
46
+ if use_region_endpoint:
47
+ return f'{service}.{region_id}.aliyuncs.com'
48
+ elif service in CENTRAL_ENDPOINTS_SERVICE or service in DOUBLE_ENDPOINT_SERVICE:
49
+ return f'{service}.aliyuncs.com'
50
+ else:
51
+ return f'{service}.{region_id}.aliyuncs.com'
52
+
27
53
 
28
54
  def create_client(service: str, region_id: str) -> OpenApiClient:
29
55
  config = create_config()
30
56
  if isinstance(service, str):
31
57
  service = service.lower()
32
- config.endpoint = f'{service}.{region_id}.aliyuncs.com'
58
+ config.endpoint = _get_service_endpoint(service, region_id.lower())
33
59
  return OpenApiClient(config)
34
60
 
35
61
 
@@ -0,0 +1,74 @@
1
+ import logging
2
+ import os
3
+ from pydantic import Field
4
+ from alibabacloud_tea_openapi import models as open_api_models
5
+ from alibabacloud_tea_util import models as util_models
6
+ from alibabacloud_tea_openapi.client import Client as OpenApiClient
7
+ from alibabacloud_openapi_util.client import Client as OpenApiUtilClient
8
+ from alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client import ApiMetaClient
9
+ from alibaba_cloud_ops_mcp_server.alibabacloud.static import PROMPT_UNDERSTANDING
10
+ from alibaba_cloud_ops_mcp_server.tools.api_tools import create_client, _tools_api_call
11
+
12
+ END_STATUSES = ['Success', 'Failed', 'Cancelled']
13
+
14
+ tools = []
15
+
16
+ _CUSTOM_SERVICE_LIST = None
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ def set_custom_service_list(service_list):
22
+ global _CUSTOM_SERVICE_LIST
23
+ _CUSTOM_SERVICE_LIST = service_list
24
+
25
+
26
+ @tools.append
27
+ def PromptUnderstanding() -> str:
28
+ """
29
+ Always use this tool first to understand the user's query and convert it into suggestions from Alibaba Cloud experts.
30
+ """
31
+ global _CUSTOM_SERVICE_LIST
32
+
33
+ content = PROMPT_UNDERSTANDING
34
+ if _CUSTOM_SERVICE_LIST:
35
+ import re
36
+ pattern = r'Supported Services\s*:\s*\n(?:\s{3}- .+?\n)+'
37
+ replacement = f"Supported Services:\n - " + "\n - ".join([f"{k}: {v}" for k, v in _CUSTOM_SERVICE_LIST])
38
+ content = re.sub(pattern, replacement, content, flags=re.DOTALL)
39
+
40
+ return content
41
+
42
+
43
+ @tools.append
44
+ def ListAPIs(
45
+ service: str = Field(description='AlibabaCloud service code')
46
+ ):
47
+ """
48
+ Use PromptUnderstanding tool first to understand the user's query, Get the corresponding API list information through the service name to prepare for the subsequent selection of the appropriate API to call
49
+ """
50
+ return ApiMetaClient.get_apis_in_service(service)
51
+
52
+
53
+ @tools.append
54
+ def GetAPIInfo(
55
+ service: str = Field(description='AlibabaCloud service code'),
56
+ api: str = Field(description='AlibabaCloud api name'),
57
+ ):
58
+ """
59
+ Use PromptUnderstanding tool first to understand the user's query, After specifying the service name and API name, get the detailed API META of the corresponding API
60
+ """
61
+ data, version = ApiMetaClient.get_api_meta(service, api)
62
+ return data.get('parameters')
63
+
64
+
65
+ @tools.append
66
+ def CommonAPICaller(
67
+ service: str = Field(description='AlibabaCloud service code'),
68
+ api: str = Field(description='AlibabaCloud api name'),
69
+ parameters: dict = Field(description='AlibabaCloud ECS instance ID List', default={}),
70
+ ):
71
+ """
72
+ Use PromptUnderstanding tool first to understand the user's query, Perform the actual call by specifying the Service, API, and Parameters
73
+ """
74
+ return _tools_api_call(service, api, parameters, None)
@@ -122,8 +122,12 @@ def test_get_api_body_style_none():
122
122
 
123
123
  @patch('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.requests.get')
124
124
  def test_get_apis_in_service(mock_get):
125
- mock_get.return_value.json.return_value = {"apis": {"A": {}, "B": {}}}
126
- apis = api_meta_client.ApiMetaClient.get_apis_in_service('ecs', '2014-05-26')
125
+ # 第一次调用 get_service_version 需要 list,第二次 get_response_from_pop_api 需要 dict
126
+ mock_get.return_value.json.side_effect = [
127
+ [{"code": "ecs", "defaultVersion": "2014-05-26"}], # for get_service_version
128
+ {"apis": {"A": {}, "B": {}}} # for get_response_from_pop_api
129
+ ]
130
+ apis = api_meta_client.ApiMetaClient.get_apis_in_service('ecs')
127
131
  assert set(apis) == {"A", "B"}
128
132
 
129
133
  @patch('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.requests.get')
@@ -152,7 +156,7 @@ def test_get_api_parameters_empty():
152
156
  def test_get_apis_in_service_no_apis(mock_get):
153
157
  mock_get.return_value.json.return_value = {}
154
158
  with pytest.raises(KeyError):
155
- api_meta_client.ApiMetaClient.get_apis_in_service('ecs', '2014-05-26')
159
+ api_meta_client.ApiMetaClient.get_apis_in_service('ecs')
156
160
 
157
161
  @patch('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.requests.get')
158
162
  def test_get_api_parameters_schema_not_dict(mock_get):
@@ -172,8 +176,11 @@ def test_get_api_parameters_schema_not_dict(mock_get):
172
176
  @patch('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.requests.get')
173
177
  def test_get_apis_in_service_normal(mock_get):
174
178
  """测试get_apis_in_service方法正常返回API列表"""
175
- mock_get.return_value.json.return_value = {"apis": {"DescribeInstances": {}, "StartInstance": {}}}
176
- apis = api_meta_client.ApiMetaClient.get_apis_in_service('ecs', '2014-05-26')
179
+ mock_get.return_value.json.side_effect = [
180
+ [{"code": "ecs", "defaultVersion": "2014-05-26"}], # for get_service_version
181
+ {"apis": {"DescribeInstances": {}, "StartInstance": {}}} # for get_response_from_pop_api
182
+ ]
183
+ apis = api_meta_client.ApiMetaClient.get_apis_in_service('ecs')
177
184
  assert set(apis) == {"DescribeInstances", "StartInstance"}
178
185
  assert len(apis) == 2
179
186
 
@@ -216,8 +223,11 @@ def test_get_api_parameters_schema_not_dict_more_cases(mock_get_meta):
216
223
  @patch('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.requests.get')
217
224
  def test_get_apis_in_service_normal(mock_get):
218
225
  """测试get_apis_in_service方法正常返回API列表"""
219
- mock_get.return_value.json.return_value = {"apis": {"DescribeInstances": {}, "StartInstance": {}}}
220
- apis = api_meta_client.ApiMetaClient.get_apis_in_service('ecs', '2014-05-26')
226
+ mock_get.return_value.json.side_effect = [
227
+ [{"code": "ecs", "defaultVersion": "2014-05-26"}], # for get_service_version
228
+ {"apis": {"DescribeInstances": {}, "StartInstance": {}}} # for get_response_from_pop_api
229
+ ]
230
+ apis = api_meta_client.ApiMetaClient.get_apis_in_service('ecs')
221
231
  assert set(apis) == {"DescribeInstances", "StartInstance"}
222
232
  assert len(apis) == 2
223
233
 
@@ -290,3 +300,15 @@ def test_get_ref_api_meta_valid_path(mock_pop_api, mock_std):
290
300
  }
291
301
  }
292
302
  assert result == expected
303
+
304
+ @patch('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_response_from_pop_api')
305
+ def test_get_all_service_info(mock_get):
306
+ mock_get.return_value = [
307
+ {"code": "ecs", "name": "Elastic Compute Service"},
308
+ {"code": "rds", "name": "Relational Database Service"}
309
+ ]
310
+ result = api_meta_client.ApiMetaClient.get_all_service_info()
311
+ assert result == [
312
+ {"code": "ecs", "name": "Elastic Compute Service"},
313
+ {"code": "rds", "name": "Relational Database Service"}
314
+ ]
@@ -11,9 +11,11 @@ def test_main_run(mock_create_api_tools, mock_FastMCP):
11
11
  mcp = MagicMock()
12
12
  mock_FastMCP.return_value = mcp
13
13
  # 调用main函数
14
- server.main.callback(transport='stdio', port=12345, host='127.0.0.1')
15
- mock_FastMCP.assert_called_once_with(name='alibaba-cloud-ops-mcp-server', port=12345, host='127.0.0.1')
16
- assert mcp.add_tool.call_count == 3 # oss/oos/cms 各1
14
+ server.main.callback(transport='stdio', port=12345, host='127.0.0.1', services='ecs')
15
+ mock_FastMCP.assert_called_once_with(
16
+ name='alibaba-cloud-ops-mcp-server',
17
+ port=12345, host='127.0.0.1')
18
+ assert mcp.add_tool.call_count == 7 # common_api_tools 4 + oss/oos/cms 各1
17
19
  mock_create_api_tools.assert_called_once()
18
20
  mcp.run.assert_called_once_with(transport='stdio')
19
21
 
@@ -2,6 +2,10 @@ import pytest
2
2
  from unittest.mock import patch, MagicMock
3
3
  from alibaba_cloud_ops_mcp_server.tools import api_tools
4
4
  import json
5
+ from alibaba_cloud_ops_mcp_server.tools import common_api_tools
6
+ from alibaba_cloud_ops_mcp_server.tools.common_api_tools import (
7
+ PromptUnderstanding, ListAPIs, GetAPIInfo, CommonAPICaller
8
+ )
5
9
 
6
10
  def fake_api_meta(post=False, no_summary=False):
7
11
  meta = {
@@ -322,3 +326,64 @@ def test_create_tool_function_with_signature_bind_with_positional_args():
322
326
  # 验证位置参数被正确绑定
323
327
  assert call_args['param1'] == 'value1'
324
328
  assert call_args['param2'] == 789
329
+
330
+ def test_prompt_understanding_default():
331
+ # _CUSTOM_SERVICE_LIST 为空
332
+ import alibaba_cloud_ops_mcp_server.tools.common_api_tools as ca
333
+ ca._CUSTOM_SERVICE_LIST = None
334
+ fn = ca.tools[0] # PromptUnderstanding
335
+ result = fn()
336
+ assert isinstance(result, str)
337
+ assert 'Supported Services' in result
338
+
339
+ def test_prompt_understanding_with_custom_service():
340
+ # _CUSTOM_SERVICE_LIST 有值
341
+ import alibaba_cloud_ops_mcp_server.tools.common_api_tools as ca
342
+ ca._CUSTOM_SERVICE_LIST = [('ecs', 'ECS服务'), ('rds', 'RDS服务')]
343
+ fn = ca.tools[0] # PromptUnderstanding
344
+ result = fn()
345
+ assert 'ecs: ECS服务' in result and 'rds: RDS服务' in result
346
+
347
+ @patch('alibaba_cloud_ops_mcp_server.tools.common_api_tools.ApiMetaClient.get_apis_in_service')
348
+ def test_list_apis(mock_get):
349
+ import alibaba_cloud_ops_mcp_server.tools.common_api_tools as ca
350
+ fn = ca.tools[1] # ListAPIs
351
+ mock_get.return_value = ['DescribeInstances', 'StartInstance']
352
+ result = fn('ecs')
353
+ assert result == ['DescribeInstances', 'StartInstance']
354
+
355
+ @patch('alibaba_cloud_ops_mcp_server.tools.common_api_tools.ApiMetaClient.get_api_meta')
356
+ def test_get_api_info(mock_get):
357
+ import alibaba_cloud_ops_mcp_server.tools.common_api_tools as ca
358
+ fn = ca.tools[2] # GetAPIInfo
359
+ mock_get.return_value = ({'parameters': [{'name': 'foo'}]}, '2014-05-26')
360
+ result = fn('ecs', 'DescribeInstances')
361
+ assert result == [{'name': 'foo'}]
362
+
363
+ @patch('alibaba_cloud_ops_mcp_server.tools.common_api_tools._tools_api_call')
364
+ def test_common_api_caller(mock_call):
365
+ import alibaba_cloud_ops_mcp_server.tools.common_api_tools as ca
366
+ fn = ca.tools[3] # CommonAPICaller
367
+ mock_call.return_value = {'result': 'ok'}
368
+ result = fn('ecs', 'DescribeInstances', {'foo': 'bar'})
369
+ assert result == {'result': 'ok'}
370
+
371
+ @patch('alibaba_cloud_ops_mcp_server.tools.api_tools.create_config')
372
+ @patch('alibaba_cloud_ops_mcp_server.tools.api_tools.OpenApiClient', autospec=True)
373
+ def test_create_client(mock_client, mock_create_config):
374
+ from alibaba_cloud_ops_mcp_server.tools import api_tools
375
+ mock_create_config.return_value = MagicMock()
376
+ mock_client.return_value = 'client_obj'
377
+ result = api_tools.create_client('ecs', 'cn-hangzhou')
378
+ assert result == 'client_obj'
379
+
380
+ def test_get_service_endpoint_all_branches():
381
+ from alibaba_cloud_ops_mcp_server.tools.api_tools import _get_service_endpoint
382
+ # REGION_ENDPOINT_SERVICE 分支
383
+ assert _get_service_endpoint('ecs', 'cn-hangzhou') == 'ecs.cn-hangzhou.aliyuncs.com'
384
+ # DOUBLE_ENDPOINT_SERVICE 且 region 匹配
385
+ assert _get_service_endpoint('rds', 'cn-hangzhou') == 'rds.cn-hangzhou.aliyuncs.com'
386
+ # CENTRAL_ENDPOINTS_SERVICE 分支
387
+ assert _get_service_endpoint('cbn', 'cn-hangzhou') == 'cbn.aliyuncs.com'
388
+ # 其它分支
389
+ assert _get_service_endpoint('unknown', 'cn-test') == 'unknown.cn-test.aliyuncs.com'
@@ -116,7 +116,7 @@ wheels = [
116
116
 
117
117
  [[package]]
118
118
  name = "alibaba-cloud-ops-mcp-server"
119
- version = "0.8.9"
119
+ version = "0.9.0"
120
120
  source = { editable = "." }
121
121
  dependencies = [
122
122
  { name = "alibabacloud-cms20190101" },
@@ -498,66 +498,66 @@ wheels = [
498
498
 
499
499
  [[package]]
500
500
  name = "coverage"
501
- version = "7.8.2"
501
+ version = "7.9.1"
502
502
  source = { registry = "https://pypi.org/simple" }
503
- sdist = { url = "https://files.pythonhosted.org/packages/ba/07/998afa4a0ecdf9b1981ae05415dad2d4e7716e1b1f00abbd91691ac09ac9/coverage-7.8.2.tar.gz", hash = "sha256:a886d531373a1f6ff9fad2a2ba4a045b68467b779ae729ee0b3b10ac20033b27", size = 812759 }
503
+ sdist = { url = "https://files.pythonhosted.org/packages/e7/e0/98670a80884f64578f0c22cd70c5e81a6e07b08167721c7487b4d70a7ca0/coverage-7.9.1.tar.gz", hash = "sha256:6cf43c78c4282708a28e466316935ec7489a9c487518a77fa68f716c67909cec", size = 813650 }
504
504
  wheels = [
505
- { url = "https://files.pythonhosted.org/packages/26/6b/7dd06399a5c0b81007e3a6af0395cd60e6a30f959f8d407d3ee04642e896/coverage-7.8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd8ec21e1443fd7a447881332f7ce9d35b8fbd2849e761bb290b584535636b0a", size = 211573 },
506
- { url = "https://files.pythonhosted.org/packages/f0/df/2b24090820a0bac1412955fb1a4dade6bc3b8dcef7b899c277ffaf16916d/coverage-7.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26c2396674816deaeae7ded0e2b42c26537280f8fe313335858ffff35019be", size = 212006 },
507
- { url = "https://files.pythonhosted.org/packages/c5/c4/e4e3b998e116625562a872a342419652fa6ca73f464d9faf9f52f1aff427/coverage-7.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1aec326ed237e5880bfe69ad41616d333712c7937bcefc1343145e972938f9b3", size = 241128 },
508
- { url = "https://files.pythonhosted.org/packages/b1/67/b28904afea3e87a895da850ba587439a61699bf4b73d04d0dfd99bbd33b4/coverage-7.8.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e818796f71702d7a13e50c70de2a1924f729228580bcba1607cccf32eea46e6", size = 239026 },
509
- { url = "https://files.pythonhosted.org/packages/8c/0f/47bf7c5630d81bc2cd52b9e13043685dbb7c79372a7f5857279cc442b37c/coverage-7.8.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:546e537d9e24efc765c9c891328f30f826e3e4808e31f5d0f87c4ba12bbd1622", size = 240172 },
510
- { url = "https://files.pythonhosted.org/packages/ba/38/af3eb9d36d85abc881f5aaecf8209383dbe0fa4cac2d804c55d05c51cb04/coverage-7.8.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ab9b09a2349f58e73f8ebc06fac546dd623e23b063e5398343c5270072e3201c", size = 240086 },
511
- { url = "https://files.pythonhosted.org/packages/9e/64/c40c27c2573adeba0fe16faf39a8aa57368a1f2148865d6bb24c67eadb41/coverage-7.8.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fd51355ab8a372d89fb0e6a31719e825cf8df8b6724bee942fb5b92c3f016ba3", size = 238792 },
512
- { url = "https://files.pythonhosted.org/packages/8e/ab/b7c85146f15457671c1412afca7c25a5696d7625e7158002aa017e2d7e3c/coverage-7.8.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0774df1e093acb6c9e4d58bce7f86656aeed6c132a16e2337692c12786b32404", size = 239096 },
513
- { url = "https://files.pythonhosted.org/packages/d3/50/9446dad1310905fb1dc284d60d4320a5b25d4e3e33f9ea08b8d36e244e23/coverage-7.8.2-cp310-cp310-win32.whl", hash = "sha256:00f2e2f2e37f47e5f54423aeefd6c32a7dbcedc033fcd3928a4f4948e8b96af7", size = 214144 },
514
- { url = "https://files.pythonhosted.org/packages/23/ed/792e66ad7b8b0df757db8d47af0c23659cdb5a65ef7ace8b111cacdbee89/coverage-7.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:145b07bea229821d51811bf15eeab346c236d523838eda395ea969d120d13347", size = 215043 },
515
- { url = "https://files.pythonhosted.org/packages/6a/4d/1ff618ee9f134d0de5cc1661582c21a65e06823f41caf801aadf18811a8e/coverage-7.8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b99058eef42e6a8dcd135afb068b3d53aff3921ce699e127602efff9956457a9", size = 211692 },
516
- { url = "https://files.pythonhosted.org/packages/96/fa/c3c1b476de96f2bc7a8ca01a9f1fcb51c01c6b60a9d2c3e66194b2bdb4af/coverage-7.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5feb7f2c3e6ea94d3b877def0270dff0947b8d8c04cfa34a17be0a4dc1836879", size = 212115 },
517
- { url = "https://files.pythonhosted.org/packages/f7/c2/5414c5a1b286c0f3881ae5adb49be1854ac5b7e99011501f81c8c1453065/coverage-7.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:670a13249b957bb9050fab12d86acef7bf8f6a879b9d1a883799276e0d4c674a", size = 244740 },
518
- { url = "https://files.pythonhosted.org/packages/cd/46/1ae01912dfb06a642ef3dd9cf38ed4996fda8fe884dab8952da616f81a2b/coverage-7.8.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0bdc8bf760459a4a4187b452213e04d039990211f98644c7292adf1e471162b5", size = 242429 },
519
- { url = "https://files.pythonhosted.org/packages/06/58/38c676aec594bfe2a87c7683942e5a30224791d8df99bcc8439fde140377/coverage-7.8.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07a989c867986c2a75f158f03fdb413128aad29aca9d4dbce5fc755672d96f11", size = 244218 },
520
- { url = "https://files.pythonhosted.org/packages/80/0c/95b1023e881ce45006d9abc250f76c6cdab7134a1c182d9713878dfefcb2/coverage-7.8.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2db10dedeb619a771ef0e2949ccba7b75e33905de959c2643a4607bef2f3fb3a", size = 243865 },
521
- { url = "https://files.pythonhosted.org/packages/57/37/0ae95989285a39e0839c959fe854a3ae46c06610439350d1ab860bf020ac/coverage-7.8.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e6ea7dba4e92926b7b5f0990634b78ea02f208d04af520c73a7c876d5a8d36cb", size = 242038 },
522
- { url = "https://files.pythonhosted.org/packages/4d/82/40e55f7c0eb5e97cc62cbd9d0746fd24e8caf57be5a408b87529416e0c70/coverage-7.8.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ef2f22795a7aca99fc3c84393a55a53dd18ab8c93fb431004e4d8f0774150f54", size = 242567 },
523
- { url = "https://files.pythonhosted.org/packages/f9/35/66a51adc273433a253989f0d9cc7aa6bcdb4855382cf0858200afe578861/coverage-7.8.2-cp311-cp311-win32.whl", hash = "sha256:641988828bc18a6368fe72355df5f1703e44411adbe49bba5644b941ce6f2e3a", size = 214194 },
524
- { url = "https://files.pythonhosted.org/packages/f6/8f/a543121f9f5f150eae092b08428cb4e6b6d2d134152c3357b77659d2a605/coverage-7.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:8ab4a51cb39dc1933ba627e0875046d150e88478dbe22ce145a68393e9652975", size = 215109 },
525
- { url = "https://files.pythonhosted.org/packages/77/65/6cc84b68d4f35186463cd7ab1da1169e9abb59870c0f6a57ea6aba95f861/coverage-7.8.2-cp311-cp311-win_arm64.whl", hash = "sha256:8966a821e2083c74d88cca5b7dcccc0a3a888a596a04c0b9668a891de3a0cc53", size = 213521 },
526
- { url = "https://files.pythonhosted.org/packages/8d/2a/1da1ada2e3044fcd4a3254fb3576e160b8fe5b36d705c8a31f793423f763/coverage-7.8.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e2f6fe3654468d061942591aef56686131335b7a8325684eda85dacdf311356c", size = 211876 },
527
- { url = "https://files.pythonhosted.org/packages/70/e9/3d715ffd5b6b17a8be80cd14a8917a002530a99943cc1939ad5bb2aa74b9/coverage-7.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76090fab50610798cc05241bf83b603477c40ee87acd358b66196ab0ca44ffa1", size = 212130 },
528
- { url = "https://files.pythonhosted.org/packages/a0/02/fdce62bb3c21649abfd91fbdcf041fb99be0d728ff00f3f9d54d97ed683e/coverage-7.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bd0a0a5054be160777a7920b731a0570284db5142abaaf81bcbb282b8d99279", size = 246176 },
529
- { url = "https://files.pythonhosted.org/packages/a7/52/decbbed61e03b6ffe85cd0fea360a5e04a5a98a7423f292aae62423b8557/coverage-7.8.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da23ce9a3d356d0affe9c7036030b5c8f14556bd970c9b224f9c8205505e3b99", size = 243068 },
530
- { url = "https://files.pythonhosted.org/packages/38/6c/d0e9c0cce18faef79a52778219a3c6ee8e336437da8eddd4ab3dbd8fadff/coverage-7.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9392773cffeb8d7e042a7b15b82a414011e9d2b5fdbbd3f7e6a6b17d5e21b20", size = 245328 },
531
- { url = "https://files.pythonhosted.org/packages/f0/70/f703b553a2f6b6c70568c7e398ed0789d47f953d67fbba36a327714a7bca/coverage-7.8.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:876cbfd0b09ce09d81585d266c07a32657beb3eaec896f39484b631555be0fe2", size = 245099 },
532
- { url = "https://files.pythonhosted.org/packages/ec/fb/4cbb370dedae78460c3aacbdad9d249e853f3bc4ce5ff0e02b1983d03044/coverage-7.8.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3da9b771c98977a13fbc3830f6caa85cae6c9c83911d24cb2d218e9394259c57", size = 243314 },
533
- { url = "https://files.pythonhosted.org/packages/39/9f/1afbb2cb9c8699b8bc38afdce00a3b4644904e6a38c7bf9005386c9305ec/coverage-7.8.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a990f6510b3292686713bfef26d0049cd63b9c7bb17e0864f133cbfd2e6167f", size = 244489 },
534
- { url = "https://files.pythonhosted.org/packages/79/fa/f3e7ec7d220bff14aba7a4786ae47043770cbdceeea1803083059c878837/coverage-7.8.2-cp312-cp312-win32.whl", hash = "sha256:bf8111cddd0f2b54d34e96613e7fbdd59a673f0cf5574b61134ae75b6f5a33b8", size = 214366 },
535
- { url = "https://files.pythonhosted.org/packages/54/aa/9cbeade19b7e8e853e7ffc261df885d66bf3a782c71cba06c17df271f9e6/coverage-7.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:86a323a275e9e44cdf228af9b71c5030861d4d2610886ab920d9945672a81223", size = 215165 },
536
- { url = "https://files.pythonhosted.org/packages/c4/73/e2528bf1237d2448f882bbebaec5c3500ef07301816c5c63464b9da4d88a/coverage-7.8.2-cp312-cp312-win_arm64.whl", hash = "sha256:820157de3a589e992689ffcda8639fbabb313b323d26388d02e154164c57b07f", size = 213548 },
537
- { url = "https://files.pythonhosted.org/packages/1a/93/eb6400a745ad3b265bac36e8077fdffcf0268bdbbb6c02b7220b624c9b31/coverage-7.8.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ea561010914ec1c26ab4188aef8b1567272ef6de096312716f90e5baa79ef8ca", size = 211898 },
538
- { url = "https://files.pythonhosted.org/packages/1b/7c/bdbf113f92683024406a1cd226a199e4200a2001fc85d6a6e7e299e60253/coverage-7.8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cb86337a4fcdd0e598ff2caeb513ac604d2f3da6d53df2c8e368e07ee38e277d", size = 212171 },
539
- { url = "https://files.pythonhosted.org/packages/91/22/594513f9541a6b88eb0dba4d5da7d71596dadef6b17a12dc2c0e859818a9/coverage-7.8.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a4636ddb666971345541b59899e969f3b301143dd86b0ddbb570bd591f1e85", size = 245564 },
540
- { url = "https://files.pythonhosted.org/packages/1f/f4/2860fd6abeebd9f2efcfe0fd376226938f22afc80c1943f363cd3c28421f/coverage-7.8.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5040536cf9b13fb033f76bcb5e1e5cb3b57c4807fef37db9e0ed129c6a094257", size = 242719 },
541
- { url = "https://files.pythonhosted.org/packages/89/60/f5f50f61b6332451520e6cdc2401700c48310c64bc2dd34027a47d6ab4ca/coverage-7.8.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc67994df9bcd7e0150a47ef41278b9e0a0ea187caba72414b71dc590b99a108", size = 244634 },
542
- { url = "https://files.pythonhosted.org/packages/3b/70/7f4e919039ab7d944276c446b603eea84da29ebcf20984fb1fdf6e602028/coverage-7.8.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e6c86888fd076d9e0fe848af0a2142bf606044dc5ceee0aa9eddb56e26895a0", size = 244824 },
543
- { url = "https://files.pythonhosted.org/packages/26/45/36297a4c0cea4de2b2c442fe32f60c3991056c59cdc3cdd5346fbb995c97/coverage-7.8.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:684ca9f58119b8e26bef860db33524ae0365601492e86ba0b71d513f525e7050", size = 242872 },
544
- { url = "https://files.pythonhosted.org/packages/a4/71/e041f1b9420f7b786b1367fa2a375703889ef376e0d48de9f5723fb35f11/coverage-7.8.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8165584ddedb49204c4e18da083913bdf6a982bfb558632a79bdaadcdafd0d48", size = 244179 },
545
- { url = "https://files.pythonhosted.org/packages/bd/db/3c2bf49bdc9de76acf2491fc03130c4ffc51469ce2f6889d2640eb563d77/coverage-7.8.2-cp313-cp313-win32.whl", hash = "sha256:34759ee2c65362163699cc917bdb2a54114dd06d19bab860725f94ef45a3d9b7", size = 214393 },
546
- { url = "https://files.pythonhosted.org/packages/c6/dc/947e75d47ebbb4b02d8babb1fad4ad381410d5bc9da7cfca80b7565ef401/coverage-7.8.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f9bc608fbafaee40eb60a9a53dbfb90f53cc66d3d32c2849dc27cf5638a21e3", size = 215194 },
547
- { url = "https://files.pythonhosted.org/packages/90/31/a980f7df8a37eaf0dc60f932507fda9656b3a03f0abf188474a0ea188d6d/coverage-7.8.2-cp313-cp313-win_arm64.whl", hash = "sha256:9fe449ee461a3b0c7105690419d0b0aba1232f4ff6d120a9e241e58a556733f7", size = 213580 },
548
- { url = "https://files.pythonhosted.org/packages/8a/6a/25a37dd90f6c95f59355629417ebcb74e1c34e38bb1eddf6ca9b38b0fc53/coverage-7.8.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8369a7c8ef66bded2b6484053749ff220dbf83cba84f3398c84c51a6f748a008", size = 212734 },
549
- { url = "https://files.pythonhosted.org/packages/36/8b/3a728b3118988725f40950931abb09cd7f43b3c740f4640a59f1db60e372/coverage-7.8.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:159b81df53a5fcbc7d45dae3adad554fdbde9829a994e15227b3f9d816d00b36", size = 212959 },
550
- { url = "https://files.pythonhosted.org/packages/53/3c/212d94e6add3a3c3f412d664aee452045ca17a066def8b9421673e9482c4/coverage-7.8.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6fcbbd35a96192d042c691c9e0c49ef54bd7ed865846a3c9d624c30bb67ce46", size = 257024 },
551
- { url = "https://files.pythonhosted.org/packages/a4/40/afc03f0883b1e51bbe804707aae62e29c4e8c8bbc365c75e3e4ddeee9ead/coverage-7.8.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05364b9cc82f138cc86128dc4e2e1251c2981a2218bfcd556fe6b0fbaa3501be", size = 252867 },
552
- { url = "https://files.pythonhosted.org/packages/18/a2/3699190e927b9439c6ded4998941a3c1d6fa99e14cb28d8536729537e307/coverage-7.8.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46d532db4e5ff3979ce47d18e2fe8ecad283eeb7367726da0e5ef88e4fe64740", size = 255096 },
553
- { url = "https://files.pythonhosted.org/packages/b4/06/16e3598b9466456b718eb3e789457d1a5b8bfb22e23b6e8bbc307df5daf0/coverage-7.8.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4000a31c34932e7e4fa0381a3d6deb43dc0c8f458e3e7ea6502e6238e10be625", size = 256276 },
554
- { url = "https://files.pythonhosted.org/packages/a7/d5/4b5a120d5d0223050a53d2783c049c311eea1709fa9de12d1c358e18b707/coverage-7.8.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:43ff5033d657cd51f83015c3b7a443287250dc14e69910577c3e03bd2e06f27b", size = 254478 },
555
- { url = "https://files.pythonhosted.org/packages/ba/85/f9ecdb910ecdb282b121bfcaa32fa8ee8cbd7699f83330ee13ff9bbf1a85/coverage-7.8.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94316e13f0981cbbba132c1f9f365cac1d26716aaac130866ca812006f662199", size = 255255 },
556
- { url = "https://files.pythonhosted.org/packages/50/63/2d624ac7d7ccd4ebbd3c6a9eba9d7fc4491a1226071360d59dd84928ccb2/coverage-7.8.2-cp313-cp313t-win32.whl", hash = "sha256:3f5673888d3676d0a745c3d0e16da338c5eea300cb1f4ada9c872981265e76d8", size = 215109 },
557
- { url = "https://files.pythonhosted.org/packages/22/5e/7053b71462e970e869111c1853afd642212568a350eba796deefdfbd0770/coverage-7.8.2-cp313-cp313t-win_amd64.whl", hash = "sha256:2c08b05ee8d7861e45dc5a2cc4195c8c66dca5ac613144eb6ebeaff2d502e73d", size = 216268 },
558
- { url = "https://files.pythonhosted.org/packages/07/69/afa41aa34147655543dbe96994f8a246daf94b361ccf5edfd5df62ce066a/coverage-7.8.2-cp313-cp313t-win_arm64.whl", hash = "sha256:1e1448bb72b387755e1ff3ef1268a06617afd94188164960dba8d0245a46004b", size = 214071 },
559
- { url = "https://files.pythonhosted.org/packages/69/2f/572b29496d8234e4a7773200dd835a0d32d9e171f2d974f3fe04a9dbc271/coverage-7.8.2-pp39.pp310.pp311-none-any.whl", hash = "sha256:ec455eedf3ba0bbdf8f5a570012617eb305c63cb9f03428d39bf544cb2b94837", size = 203636 },
560
- { url = "https://files.pythonhosted.org/packages/a0/1a/0b9c32220ad694d66062f571cc5cedfa9997b64a591e8a500bb63de1bd40/coverage-7.8.2-py3-none-any.whl", hash = "sha256:726f32ee3713f7359696331a18daf0c3b3a70bb0ae71141b9d3c52be7c595e32", size = 203623 },
505
+ { url = "https://files.pythonhosted.org/packages/c1/78/1c1c5ec58f16817c09cbacb39783c3655d54a221b6552f47ff5ac9297603/coverage-7.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc94d7c5e8423920787c33d811c0be67b7be83c705f001f7180c7b186dcf10ca", size = 212028 },
506
+ { url = "https://files.pythonhosted.org/packages/98/db/e91b9076f3a888e3b4ad7972ea3842297a52cc52e73fd1e529856e473510/coverage-7.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16aa0830d0c08a2c40c264cef801db8bc4fc0e1892782e45bcacbd5889270509", size = 212420 },
507
+ { url = "https://files.pythonhosted.org/packages/0e/d0/2b3733412954576b0aea0a16c3b6b8fbe95eb975d8bfa10b07359ead4252/coverage-7.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf95981b126f23db63e9dbe4cf65bd71f9a6305696fa5e2262693bc4e2183f5b", size = 241529 },
508
+ { url = "https://files.pythonhosted.org/packages/b3/00/5e2e5ae2e750a872226a68e984d4d3f3563cb01d1afb449a17aa819bc2c4/coverage-7.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f05031cf21699785cd47cb7485f67df619e7bcdae38e0fde40d23d3d0210d3c3", size = 239403 },
509
+ { url = "https://files.pythonhosted.org/packages/37/3b/a2c27736035156b0a7c20683afe7df498480c0dfdf503b8c878a21b6d7fb/coverage-7.9.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4fbcab8764dc072cb651a4bcda4d11fb5658a1d8d68842a862a6610bd8cfa3", size = 240548 },
510
+ { url = "https://files.pythonhosted.org/packages/98/f5/13d5fc074c3c0e0dc80422d9535814abf190f1254d7c3451590dc4f8b18c/coverage-7.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0f16649a7330ec307942ed27d06ee7e7a38417144620bb3d6e9a18ded8a2d3e5", size = 240459 },
511
+ { url = "https://files.pythonhosted.org/packages/36/24/24b9676ea06102df824c4a56ffd13dc9da7904478db519efa877d16527d5/coverage-7.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cea0a27a89e6432705fffc178064503508e3c0184b4f061700e771a09de58187", size = 239128 },
512
+ { url = "https://files.pythonhosted.org/packages/be/05/242b7a7d491b369ac5fee7908a6e5ba42b3030450f3ad62c645b40c23e0e/coverage-7.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e980b53a959fa53b6f05343afbd1e6f44a23ed6c23c4b4c56c6662bbb40c82ce", size = 239402 },
513
+ { url = "https://files.pythonhosted.org/packages/73/e0/4de7f87192fa65c9c8fbaeb75507e124f82396b71de1797da5602898be32/coverage-7.9.1-cp310-cp310-win32.whl", hash = "sha256:70760b4c5560be6ca70d11f8988ee6542b003f982b32f83d5ac0b72476607b70", size = 214518 },
514
+ { url = "https://files.pythonhosted.org/packages/d5/ab/5e4e2fe458907d2a65fab62c773671cfc5ac704f1e7a9ddd91996f66e3c2/coverage-7.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a66e8f628b71f78c0e0342003d53b53101ba4e00ea8dabb799d9dba0abbbcebe", size = 215436 },
515
+ { url = "https://files.pythonhosted.org/packages/60/34/fa69372a07d0903a78ac103422ad34db72281c9fc625eba94ac1185da66f/coverage-7.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:95c765060e65c692da2d2f51a9499c5e9f5cf5453aeaf1420e3fc847cc060582", size = 212146 },
516
+ { url = "https://files.pythonhosted.org/packages/27/f0/da1894915d2767f093f081c42afeba18e760f12fdd7a2f4acbe00564d767/coverage-7.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba383dc6afd5ec5b7a0d0c23d38895db0e15bcba7fb0fa8901f245267ac30d86", size = 212536 },
517
+ { url = "https://files.pythonhosted.org/packages/10/d5/3fc33b06e41e390f88eef111226a24e4504d216ab8e5d1a7089aa5a3c87a/coverage-7.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37ae0383f13cbdcf1e5e7014489b0d71cc0106458878ccde52e8a12ced4298ed", size = 245092 },
518
+ { url = "https://files.pythonhosted.org/packages/0a/39/7aa901c14977aba637b78e95800edf77f29f5a380d29768c5b66f258305b/coverage-7.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69aa417a030bf11ec46149636314c24c8d60fadb12fc0ee8f10fda0d918c879d", size = 242806 },
519
+ { url = "https://files.pythonhosted.org/packages/43/fc/30e5cfeaf560b1fc1989227adedc11019ce4bb7cce59d65db34fe0c2d963/coverage-7.9.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a4be2a28656afe279b34d4f91c3e26eccf2f85500d4a4ff0b1f8b54bf807338", size = 244610 },
520
+ { url = "https://files.pythonhosted.org/packages/bf/15/cca62b13f39650bc87b2b92bb03bce7f0e79dd0bf2c7529e9fc7393e4d60/coverage-7.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:382e7ddd5289f140259b610e5f5c58f713d025cb2f66d0eb17e68d0a94278875", size = 244257 },
521
+ { url = "https://files.pythonhosted.org/packages/cd/1a/c0f2abe92c29e1464dbd0ff9d56cb6c88ae2b9e21becdb38bea31fcb2f6c/coverage-7.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e5532482344186c543c37bfad0ee6069e8ae4fc38d073b8bc836fc8f03c9e250", size = 242309 },
522
+ { url = "https://files.pythonhosted.org/packages/57/8d/c6fd70848bd9bf88fa90df2af5636589a8126d2170f3aade21ed53f2b67a/coverage-7.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a39d18b3f50cc121d0ce3838d32d58bd1d15dab89c910358ebefc3665712256c", size = 242898 },
523
+ { url = "https://files.pythonhosted.org/packages/c2/9e/6ca46c7bff4675f09a66fe2797cd1ad6a24f14c9c7c3b3ebe0470a6e30b8/coverage-7.9.1-cp311-cp311-win32.whl", hash = "sha256:dd24bd8d77c98557880def750782df77ab2b6885a18483dc8588792247174b32", size = 214561 },
524
+ { url = "https://files.pythonhosted.org/packages/a1/30/166978c6302010742dabcdc425fa0f938fa5a800908e39aff37a7a876a13/coverage-7.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:6b55ad10a35a21b8015eabddc9ba31eb590f54adc9cd39bcf09ff5349fd52125", size = 215493 },
525
+ { url = "https://files.pythonhosted.org/packages/60/07/a6d2342cd80a5be9f0eeab115bc5ebb3917b4a64c2953534273cf9bc7ae6/coverage-7.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ad935f0016be24c0e97fc8c40c465f9c4b85cbbe6eac48934c0dc4d2568321e", size = 213869 },
526
+ { url = "https://files.pythonhosted.org/packages/68/d9/7f66eb0a8f2fce222de7bdc2046ec41cb31fe33fb55a330037833fb88afc/coverage-7.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8de12b4b87c20de895f10567639c0797b621b22897b0af3ce4b4e204a743626", size = 212336 },
527
+ { url = "https://files.pythonhosted.org/packages/20/20/e07cb920ef3addf20f052ee3d54906e57407b6aeee3227a9c91eea38a665/coverage-7.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5add197315a054e92cee1b5f686a2bcba60c4c3e66ee3de77ace6c867bdee7cb", size = 212571 },
528
+ { url = "https://files.pythonhosted.org/packages/78/f8/96f155de7e9e248ca9c8ff1a40a521d944ba48bec65352da9be2463745bf/coverage-7.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600a1d4106fe66f41e5d0136dfbc68fe7200a5cbe85610ddf094f8f22e1b0300", size = 246377 },
529
+ { url = "https://files.pythonhosted.org/packages/3e/cf/1d783bd05b7bca5c10ded5f946068909372e94615a4416afadfe3f63492d/coverage-7.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a876e4c3e5a2a1715a6608906aa5a2e0475b9c0f68343c2ada98110512ab1d8", size = 243394 },
530
+ { url = "https://files.pythonhosted.org/packages/02/dd/e7b20afd35b0a1abea09fb3998e1abc9f9bd953bee548f235aebd2b11401/coverage-7.9.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81f34346dd63010453922c8e628a52ea2d2ccd73cb2487f7700ac531b247c8a5", size = 245586 },
531
+ { url = "https://files.pythonhosted.org/packages/4e/38/b30b0006fea9d617d1cb8e43b1bc9a96af11eff42b87eb8c716cf4d37469/coverage-7.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:888f8eee13f2377ce86d44f338968eedec3291876b0b8a7289247ba52cb984cd", size = 245396 },
532
+ { url = "https://files.pythonhosted.org/packages/31/e4/4d8ec1dc826e16791f3daf1b50943e8e7e1eb70e8efa7abb03936ff48418/coverage-7.9.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9969ef1e69b8c8e1e70d591f91bbc37fc9a3621e447525d1602801a24ceda898", size = 243577 },
533
+ { url = "https://files.pythonhosted.org/packages/25/f4/b0e96c5c38e6e40ef465c4bc7f138863e2909c00e54a331da335faf0d81a/coverage-7.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:60c458224331ee3f1a5b472773e4a085cc27a86a0b48205409d364272d67140d", size = 244809 },
534
+ { url = "https://files.pythonhosted.org/packages/8a/65/27e0a1fa5e2e5079bdca4521be2f5dabf516f94e29a0defed35ac2382eb2/coverage-7.9.1-cp312-cp312-win32.whl", hash = "sha256:5f646a99a8c2b3ff4c6a6e081f78fad0dde275cd59f8f49dc4eab2e394332e74", size = 214724 },
535
+ { url = "https://files.pythonhosted.org/packages/9b/a8/d5b128633fd1a5e0401a4160d02fa15986209a9e47717174f99dc2f7166d/coverage-7.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:30f445f85c353090b83e552dcbbdad3ec84c7967e108c3ae54556ca69955563e", size = 215535 },
536
+ { url = "https://files.pythonhosted.org/packages/a3/37/84bba9d2afabc3611f3e4325ee2c6a47cd449b580d4a606b240ce5a6f9bf/coverage-7.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:af41da5dca398d3474129c58cb2b106a5d93bbb196be0d307ac82311ca234342", size = 213904 },
537
+ { url = "https://files.pythonhosted.org/packages/d0/a7/a027970c991ca90f24e968999f7d509332daf6b8c3533d68633930aaebac/coverage-7.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:31324f18d5969feef7344a932c32428a2d1a3e50b15a6404e97cba1cc9b2c631", size = 212358 },
538
+ { url = "https://files.pythonhosted.org/packages/f2/48/6aaed3651ae83b231556750280682528fea8ac7f1232834573472d83e459/coverage-7.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0c804506d624e8a20fb3108764c52e0eef664e29d21692afa375e0dd98dc384f", size = 212620 },
539
+ { url = "https://files.pythonhosted.org/packages/6c/2a/f4b613f3b44d8b9f144847c89151992b2b6b79cbc506dee89ad0c35f209d/coverage-7.9.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef64c27bc40189f36fcc50c3fb8f16ccda73b6a0b80d9bd6e6ce4cffcd810bbd", size = 245788 },
540
+ { url = "https://files.pythonhosted.org/packages/04/d2/de4fdc03af5e4e035ef420ed26a703c6ad3d7a07aff2e959eb84e3b19ca8/coverage-7.9.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4fe2348cc6ec372e25adec0219ee2334a68d2f5222e0cba9c0d613394e12d86", size = 243001 },
541
+ { url = "https://files.pythonhosted.org/packages/f5/e8/eed18aa5583b0423ab7f04e34659e51101135c41cd1dcb33ac1d7013a6d6/coverage-7.9.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34ed2186fe52fcc24d4561041979a0dec69adae7bce2ae8d1c49eace13e55c43", size = 244985 },
542
+ { url = "https://files.pythonhosted.org/packages/17/f8/ae9e5cce8885728c934eaa58ebfa8281d488ef2afa81c3dbc8ee9e6d80db/coverage-7.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:25308bd3d00d5eedd5ae7d4357161f4df743e3c0240fa773ee1b0f75e6c7c0f1", size = 245152 },
543
+ { url = "https://files.pythonhosted.org/packages/5a/c8/272c01ae792bb3af9b30fac14d71d63371db227980682836ec388e2c57c0/coverage-7.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73e9439310f65d55a5a1e0564b48e34f5369bee943d72c88378f2d576f5a5751", size = 243123 },
544
+ { url = "https://files.pythonhosted.org/packages/8c/d0/2819a1e3086143c094ab446e3bdf07138527a7b88cb235c488e78150ba7a/coverage-7.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:37ab6be0859141b53aa89412a82454b482c81cf750de4f29223d52268a86de67", size = 244506 },
545
+ { url = "https://files.pythonhosted.org/packages/8b/4e/9f6117b89152df7b6112f65c7a4ed1f2f5ec8e60c4be8f351d91e7acc848/coverage-7.9.1-cp313-cp313-win32.whl", hash = "sha256:64bdd969456e2d02a8b08aa047a92d269c7ac1f47e0c977675d550c9a0863643", size = 214766 },
546
+ { url = "https://files.pythonhosted.org/packages/27/0f/4b59f7c93b52c2c4ce7387c5a4e135e49891bb3b7408dcc98fe44033bbe0/coverage-7.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:be9e3f68ca9edb897c2184ad0eee815c635565dbe7a0e7e814dc1f7cbab92c0a", size = 215568 },
547
+ { url = "https://files.pythonhosted.org/packages/09/1e/9679826336f8c67b9c39a359352882b24a8a7aee48d4c9cad08d38d7510f/coverage-7.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:1c503289ffef1d5105d91bbb4d62cbe4b14bec4d13ca225f9c73cde9bb46207d", size = 213939 },
548
+ { url = "https://files.pythonhosted.org/packages/bb/5b/5c6b4e7a407359a2e3b27bf9c8a7b658127975def62077d441b93a30dbe8/coverage-7.9.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0b3496922cb5f4215bf5caaef4cf12364a26b0be82e9ed6d050f3352cf2d7ef0", size = 213079 },
549
+ { url = "https://files.pythonhosted.org/packages/a2/22/1e2e07279fd2fd97ae26c01cc2186e2258850e9ec125ae87184225662e89/coverage-7.9.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9565c3ab1c93310569ec0d86b017f128f027cab0b622b7af288696d7ed43a16d", size = 213299 },
550
+ { url = "https://files.pythonhosted.org/packages/14/c0/4c5125a4b69d66b8c85986d3321520f628756cf524af810baab0790c7647/coverage-7.9.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2241ad5dbf79ae1d9c08fe52b36d03ca122fb9ac6bca0f34439e99f8327ac89f", size = 256535 },
551
+ { url = "https://files.pythonhosted.org/packages/81/8b/e36a04889dda9960be4263e95e777e7b46f1bb4fc32202612c130a20c4da/coverage-7.9.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bb5838701ca68b10ebc0937dbd0eb81974bac54447c55cd58dea5bca8451029", size = 252756 },
552
+ { url = "https://files.pythonhosted.org/packages/98/82/be04eff8083a09a4622ecd0e1f31a2c563dbea3ed848069e7b0445043a70/coverage-7.9.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a25f814591a8c0c5372c11ac8967f669b97444c47fd794926e175c4047ece", size = 254912 },
553
+ { url = "https://files.pythonhosted.org/packages/0f/25/c26610a2c7f018508a5ab958e5b3202d900422cf7cdca7670b6b8ca4e8df/coverage-7.9.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2d04b16a6062516df97969f1ae7efd0de9c31eb6ebdceaa0d213b21c0ca1a683", size = 256144 },
554
+ { url = "https://files.pythonhosted.org/packages/c5/8b/fb9425c4684066c79e863f1e6e7ecebb49e3a64d9f7f7860ef1688c56f4a/coverage-7.9.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7931b9e249edefb07cd6ae10c702788546341d5fe44db5b6108a25da4dca513f", size = 254257 },
555
+ { url = "https://files.pythonhosted.org/packages/93/df/27b882f54157fc1131e0e215b0da3b8d608d9b8ef79a045280118a8f98fe/coverage-7.9.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:52e92b01041151bf607ee858e5a56c62d4b70f4dac85b8c8cb7fb8a351ab2c10", size = 255094 },
556
+ { url = "https://files.pythonhosted.org/packages/41/5f/cad1c3dbed8b3ee9e16fa832afe365b4e3eeab1fb6edb65ebbf745eabc92/coverage-7.9.1-cp313-cp313t-win32.whl", hash = "sha256:684e2110ed84fd1ca5f40e89aa44adf1729dc85444004111aa01866507adf363", size = 215437 },
557
+ { url = "https://files.pythonhosted.org/packages/99/4d/fad293bf081c0e43331ca745ff63673badc20afea2104b431cdd8c278b4c/coverage-7.9.1-cp313-cp313t-win_amd64.whl", hash = "sha256:437c576979e4db840539674e68c84b3cda82bc824dd138d56bead1435f1cb5d7", size = 216605 },
558
+ { url = "https://files.pythonhosted.org/packages/1f/56/4ee027d5965fc7fc126d7ec1187529cc30cc7d740846e1ecb5e92d31b224/coverage-7.9.1-cp313-cp313t-win_arm64.whl", hash = "sha256:18a0912944d70aaf5f399e350445738a1a20b50fbea788f640751c2ed9208b6c", size = 214392 },
559
+ { url = "https://files.pythonhosted.org/packages/3e/e5/c723545c3fd3204ebde3b4cc4b927dce709d3b6dc577754bb57f63ca4a4a/coverage-7.9.1-pp39.pp310.pp311-none-any.whl", hash = "sha256:db0f04118d1db74db6c9e1cb1898532c7dcc220f1d2718f058601f7c3f499514", size = 204009 },
560
+ { url = "https://files.pythonhosted.org/packages/08/b8/7ddd1e8ba9701dea08ce22029917140e6f66a859427406579fd8d0ca7274/coverage-7.9.1-py3-none-any.whl", hash = "sha256:66b974b145aa189516b6bf2d8423e888b742517d37872f6ee4c5be0073bd9a3c", size = 204000 },
561
561
  ]
562
562
 
563
563
  [package.optional-dependencies]
@@ -1194,7 +1194,7 @@ wheels = [
1194
1194
 
1195
1195
  [[package]]
1196
1196
  name = "pytest"
1197
- version = "8.4.0"
1197
+ version = "8.4.1"
1198
1198
  source = { registry = "https://pypi.org/simple" }
1199
1199
  dependencies = [
1200
1200
  { name = "colorama", marker = "sys_platform == 'win32'" },
@@ -1205,22 +1205,23 @@ dependencies = [
1205
1205
  { name = "pygments" },
1206
1206
  { name = "tomli", marker = "python_full_version < '3.11'" },
1207
1207
  ]
1208
- sdist = { url = "https://files.pythonhosted.org/packages/fb/aa/405082ce2749be5398045152251ac69c0f3578c7077efc53431303af97ce/pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6", size = 1515232 }
1208
+ sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714 }
1209
1209
  wheels = [
1210
- { url = "https://files.pythonhosted.org/packages/2f/de/afa024cbe022b1b318a3d224125aa24939e99b4ff6f22e0ba639a2eaee47/pytest-8.4.0-py3-none-any.whl", hash = "sha256:f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e", size = 363797 },
1210
+ { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474 },
1211
1211
  ]
1212
1212
 
1213
1213
  [[package]]
1214
1214
  name = "pytest-cov"
1215
- version = "6.1.1"
1215
+ version = "6.2.1"
1216
1216
  source = { registry = "https://pypi.org/simple" }
1217
1217
  dependencies = [
1218
1218
  { name = "coverage", extra = ["toml"] },
1219
+ { name = "pluggy" },
1219
1220
  { name = "pytest" },
1220
1221
  ]
1221
- sdist = { url = "https://files.pythonhosted.org/packages/25/69/5f1e57f6c5a39f81411b550027bf72842c4567ff5fd572bed1edc9e4b5d9/pytest_cov-6.1.1.tar.gz", hash = "sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a", size = 66857 }
1222
+ sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432 }
1222
1223
  wheels = [
1223
- { url = "https://files.pythonhosted.org/packages/28/d0/def53b4a790cfb21483016430ed828f64830dd981ebe1089971cd10cab25/pytest_cov-6.1.1-py3-none-any.whl", hash = "sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde", size = 23841 },
1224
+ { url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644 },
1224
1225
  ]
1225
1226
 
1226
1227
  [[package]]
@@ -1,51 +0,0 @@
1
- from mcp.server.fastmcp import FastMCP
2
- import click
3
- import logging
4
-
5
- from alibaba_cloud_ops_mcp_server.config import config
6
- from alibaba_cloud_ops_mcp_server.tools import cms_tools, oos_tools, oss_tools, api_tools
7
-
8
- logger = logging.getLogger(__name__)
9
-
10
-
11
- @click.command()
12
- @click.option(
13
- "--transport",
14
- type=click.Choice(["stdio", "sse", "streamable-http"]),
15
- default="stdio",
16
- help="Transport type",
17
- )
18
- @click.option(
19
- "--port",
20
- type=int,
21
- default=8000,
22
- help="Port number",
23
- )
24
- @click.option(
25
- "--host",
26
- type=str,
27
- default="127.0.0.1",
28
- help="Host",
29
- )
30
- def main(transport: str, port: int, host: str):
31
- # Create an MCP server
32
- mcp = FastMCP(
33
- name="alibaba-cloud-ops-mcp-server",
34
- port=port,
35
- host=host
36
- )
37
- for tool in oos_tools.tools:
38
- mcp.add_tool(tool)
39
- for tool in cms_tools.tools:
40
- mcp.add_tool(tool)
41
- for tool in oss_tools.tools:
42
- mcp.add_tool(tool)
43
- api_tools.create_api_tools(mcp, config)
44
-
45
- # Initialize and run the server
46
- logger.debug(f'mcp server is running on {transport} mode.')
47
- mcp.run(transport=transport)
48
-
49
-
50
- if __name__ == "__main__":
51
- main()