alibaba-cloud-ops-mcp-server 0.9.2__py3-none-any.whl → 0.9.4__py3-none-any.whl
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.
- alibaba_cloud_ops_mcp_server/__main__.py +4 -0
- alibaba_cloud_ops_mcp_server/alibabacloud/static/PROMPT_UNDERSTANDING.md +1 -0
- alibaba_cloud_ops_mcp_server/alibabacloud/utils.py +10 -5
- alibaba_cloud_ops_mcp_server/server.py +14 -4
- alibaba_cloud_ops_mcp_server/settings.py +8 -0
- alibaba_cloud_ops_mcp_server/tools/api_tools.py +42 -12
- alibaba_cloud_ops_mcp_server/tools/cms_tools.py +4 -0
- {alibaba_cloud_ops_mcp_server-0.9.2.dist-info → alibaba_cloud_ops_mcp_server-0.9.4.dist-info}/METADATA +1 -1
- {alibaba_cloud_ops_mcp_server-0.9.2.dist-info → alibaba_cloud_ops_mcp_server-0.9.4.dist-info}/RECORD +12 -10
- {alibaba_cloud_ops_mcp_server-0.9.2.dist-info → alibaba_cloud_ops_mcp_server-0.9.4.dist-info}/WHEEL +0 -0
- {alibaba_cloud_ops_mcp_server-0.9.2.dist-info → alibaba_cloud_ops_mcp_server-0.9.4.dist-info}/entry_points.txt +0 -0
- {alibaba_cloud_ops_mcp_server-0.9.2.dist-info → alibaba_cloud_ops_mcp_server-0.9.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -39,6 +39,7 @@ When a user submits a request, analyze their needs and check if matching tools e
|
|
|
39
39
|
- cbn: Cloud Enterprise Network (CBN)
|
|
40
40
|
- dds: MongoDB Database Service (DDS)
|
|
41
41
|
- r-kvstore: Cloud database Tair (compatible with Redis) (R-KVStore)
|
|
42
|
+
- bssopenapi: Billing and Cost Management (BssOpenAPI)
|
|
42
43
|
|
|
43
44
|
2. **API Process**
|
|
44
45
|
- Use `ListAPIs` for available APIs
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
from alibabacloud_credentials.client import Client as CredClient
|
|
4
4
|
from alibabacloud_tea_openapi.models import Config
|
|
5
5
|
from fastmcp.server.dependencies import get_http_request
|
|
6
|
+
from alibaba_cloud_ops_mcp_server.settings import settings
|
|
6
7
|
|
|
7
8
|
logger = logging.getLogger(__name__)
|
|
8
9
|
|
|
@@ -30,17 +31,21 @@ def get_credentials_from_header():
|
|
|
30
31
|
|
|
31
32
|
def create_config():
|
|
32
33
|
credentials = get_credentials_from_header()
|
|
34
|
+
|
|
33
35
|
if credentials:
|
|
34
|
-
access_key_id = credentials.get('AccessKeyId'
|
|
35
|
-
access_key_secret = credentials.get('AccessKeySecret'
|
|
36
|
-
token = credentials.get('SecurityToken'
|
|
36
|
+
access_key_id = credentials.get('AccessKeyId')
|
|
37
|
+
access_key_secret = credentials.get('AccessKeySecret')
|
|
38
|
+
token = credentials.get('SecurityToken')
|
|
37
39
|
config = Config(
|
|
38
40
|
access_key_id=access_key_id,
|
|
39
41
|
access_key_secret=access_key_secret,
|
|
40
42
|
security_token=token
|
|
41
43
|
)
|
|
44
|
+
elif settings.headers_credential_only:
|
|
45
|
+
config = Config()
|
|
42
46
|
else:
|
|
43
|
-
|
|
44
|
-
config = Config(credential=
|
|
47
|
+
credentials_client = CredClient()
|
|
48
|
+
config = Config(credential=credentials_client)
|
|
49
|
+
|
|
45
50
|
config.user_agent = 'alibaba-cloud-ops-mcp-server'
|
|
46
51
|
return config
|
|
@@ -5,6 +5,7 @@ import logging
|
|
|
5
5
|
from alibaba_cloud_ops_mcp_server.tools.common_api_tools import set_custom_service_list
|
|
6
6
|
from alibaba_cloud_ops_mcp_server.config import config
|
|
7
7
|
from alibaba_cloud_ops_mcp_server.tools import cms_tools, oos_tools, oss_tools, api_tools, common_api_tools
|
|
8
|
+
from alibaba_cloud_ops_mcp_server.settings import settings
|
|
8
9
|
|
|
9
10
|
logger = logging.getLogger(__name__)
|
|
10
11
|
|
|
@@ -18,7 +19,8 @@ SUPPORTED_SERVICES_MAP = {
|
|
|
18
19
|
"ros": "Resource Orchestration Service (ROS)",
|
|
19
20
|
"cbn": "Cloud Enterprise Network (CBN)",
|
|
20
21
|
"dds": "MongoDB Database Service (DDS)",
|
|
21
|
-
"r-kvstore": "Cloud database Tair (compatible with Redis) (R-KVStore)"
|
|
22
|
+
"r-kvstore": "Cloud database Tair (compatible with Redis) (R-KVStore)",
|
|
23
|
+
"bssopenapi": "Billing and Cost Management (BssOpenAPI)"
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
|
|
@@ -47,14 +49,22 @@ SUPPORTED_SERVICES_MAP = {
|
|
|
47
49
|
default=None,
|
|
48
50
|
help="Comma-separated list of supported services, e.g., 'ecs,vpc,rds'",
|
|
49
51
|
)
|
|
50
|
-
|
|
52
|
+
@click.option(
|
|
53
|
+
"--headers-credential-only",
|
|
54
|
+
type=bool,
|
|
55
|
+
default=False,
|
|
56
|
+
help="Whether to use credentials only from headers",
|
|
57
|
+
)
|
|
58
|
+
def main(transport: str, port: int, host: str, services: str, headers_credential_only: bool):
|
|
51
59
|
# Create an MCP server
|
|
52
60
|
mcp = FastMCP(
|
|
53
61
|
name="alibaba-cloud-ops-mcp-server",
|
|
54
62
|
port=port,
|
|
55
|
-
host=host
|
|
63
|
+
host=host,
|
|
64
|
+
stateless_http=True
|
|
56
65
|
)
|
|
57
|
-
|
|
66
|
+
if headers_credential_only:
|
|
67
|
+
settings.headers_credential_only = headers_credential_only
|
|
58
68
|
if services:
|
|
59
69
|
service_keys = [s.strip().lower() for s in services.split(",")]
|
|
60
70
|
service_list = [(key, SUPPORTED_SERVICES_MAP.get(key, key)) for key in service_keys]
|
|
@@ -14,6 +14,7 @@ from alibabacloud_openapi_util.client import Client as OpenApiUtilClient
|
|
|
14
14
|
from alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client import ApiMetaClient
|
|
15
15
|
from alibaba_cloud_ops_mcp_server.alibabacloud.utils import create_config
|
|
16
16
|
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
18
19
|
type_map = {
|
|
19
20
|
'string': str,
|
|
@@ -29,37 +30,62 @@ REGION_ENDPOINT_SERVICE = ['ecs', 'oos', 'vpc', 'slb']
|
|
|
29
30
|
DOUBLE_ENDPOINT_SERVICE = {
|
|
30
31
|
'rds': ['cn-qingdao', 'cn-beijing', 'cn-hangzhou', 'cn-shanghai', 'cn-shenzhen', 'cn-heyuan', 'cn-guangzhou', 'cn-hongkong'],
|
|
31
32
|
'ess': ['cn-qingdao', 'cn-beijing', 'cn-hangzhou', 'cn-shanghai', 'cn-nanjing', 'cn-shenzhen'],
|
|
32
|
-
'ros': ['cn-qingdao'],
|
|
33
33
|
'dds': ['cn-qingdao', 'cn-beijing', 'cn-wulanchabu', 'cn-hangzhou', 'cn-shanghai', 'cn-shenzhen', 'cn-heyuan', 'cn-guangzhou'],
|
|
34
34
|
'r-kvstore': ['cn-qingdao', 'cn-beijing', 'cn-wulanchabu', 'cn-hangzhou', 'cn-shanghai', 'cn-shenzhen', 'cn-heyuan']
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
CENTRAL_SERVICE = ['cbn', 'ros', 'ram']
|
|
38
|
+
|
|
39
|
+
CENTRAL_SERVICE_ENDPOINTS = {
|
|
40
|
+
'bssopenapi': {
|
|
41
|
+
'DomesticEndpoint': 'business.aliyuncs.com',
|
|
42
|
+
'InternationalEndpoint': 'business.ap-southeast-1.aliyuncs.com',
|
|
43
|
+
'DomesticRegion': ['cn-qingdao', 'cn-beijing', 'cn-zhangjiakou', 'cn-huhehaote', 'cn-wulanchabu',
|
|
44
|
+
'cn-hangzhou', 'cn-shanghai', 'cn-shenzhen', 'cn-chengdu', 'cn-hongkong']
|
|
45
|
+
}
|
|
46
|
+
}
|
|
38
47
|
|
|
39
48
|
|
|
40
49
|
def _get_service_endpoint(service: str, region_id: str):
|
|
41
50
|
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
51
|
|
|
46
|
-
|
|
52
|
+
# Prioritizing central service endpoints
|
|
53
|
+
central = CENTRAL_SERVICE_ENDPOINTS.get(service)
|
|
54
|
+
if central:
|
|
55
|
+
if region_id in central.get('DomesticRegion', []):
|
|
56
|
+
return central['DomesticEndpoint']
|
|
57
|
+
else:
|
|
58
|
+
return central['InternationalEndpoint']
|
|
59
|
+
|
|
60
|
+
# Determine whether to use regional endpoints
|
|
61
|
+
if service in REGION_ENDPOINT_SERVICE:
|
|
47
62
|
return f'{service}.{region_id}.aliyuncs.com'
|
|
48
|
-
|
|
63
|
+
|
|
64
|
+
if service in DOUBLE_ENDPOINT_SERVICE:
|
|
65
|
+
not_in_central = region_id not in DOUBLE_ENDPOINT_SERVICE[service]
|
|
66
|
+
if not_in_central:
|
|
67
|
+
return f'{service}.{region_id}.aliyuncs.com'
|
|
68
|
+
else:
|
|
69
|
+
return f'{service}.aliyuncs.com'
|
|
70
|
+
|
|
71
|
+
if service in CENTRAL_SERVICE:
|
|
49
72
|
return f'{service}.aliyuncs.com'
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
|
|
74
|
+
# Default
|
|
75
|
+
return f'{service}.{region_id}.aliyuncs.com'
|
|
52
76
|
|
|
53
77
|
|
|
54
78
|
def create_client(service: str, region_id: str) -> OpenApiClient:
|
|
55
79
|
config = create_config()
|
|
56
80
|
if isinstance(service, str):
|
|
57
81
|
service = service.lower()
|
|
58
|
-
|
|
82
|
+
endpoint = _get_service_endpoint(service, region_id.lower())
|
|
83
|
+
config.endpoint = endpoint
|
|
84
|
+
logger.info(f'Service Endpoint: {endpoint}')
|
|
59
85
|
return OpenApiClient(config)
|
|
60
86
|
|
|
61
87
|
|
|
62
|
-
#
|
|
88
|
+
# JSON array parameter of type String
|
|
63
89
|
ECS_LIST_PARAMETERS = {
|
|
64
90
|
'HpcClusterIds', 'DedicatedHostClusterIds', 'DedicatedHostIds',
|
|
65
91
|
'InstanceIds', 'DeploymentSetIds', 'KeyPairNames', 'SecurityGroupIds',
|
|
@@ -76,8 +102,9 @@ def _tools_api_call(service: str, api: str, parameters: dict, ctx: Context):
|
|
|
76
102
|
path = api_meta.get('path', '/')
|
|
77
103
|
style = ApiMetaClient.get_service_style(service)
|
|
78
104
|
|
|
79
|
-
#
|
|
105
|
+
# Handling special parameter formats
|
|
80
106
|
processed_parameters = parameters.copy()
|
|
107
|
+
processed_parameters = {k: v for k, v in processed_parameters.items() if v is not None}
|
|
81
108
|
if service == 'ecs':
|
|
82
109
|
for param_name, param_value in parameters.items():
|
|
83
110
|
if param_name in ECS_LIST_PARAMETERS and isinstance(param_value, list):
|
|
@@ -97,8 +124,11 @@ def _tools_api_call(service: str, api: str, parameters: dict, ctx: Context):
|
|
|
97
124
|
req_body_type='formData',
|
|
98
125
|
body_type='json'
|
|
99
126
|
)
|
|
127
|
+
logger.info(f'Call API Request: Service: {service} API: {api} Method: {method} Parameters: {processed_parameters}')
|
|
100
128
|
client = create_client(service, processed_parameters.get('RegionId', 'cn-hangzhou'))
|
|
101
129
|
runtime = util_models.RuntimeOptions()
|
|
130
|
+
resp = client.call_api(params, req, runtime)
|
|
131
|
+
logger.info(f'Call API Response: {resp}')
|
|
102
132
|
return client.call_api(params, req, runtime)
|
|
103
133
|
|
|
104
134
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
1
3
|
from pydantic import Field
|
|
2
4
|
from typing import List
|
|
3
5
|
import os
|
|
@@ -10,6 +12,7 @@ from alibaba_cloud_ops_mcp_server.alibabacloud.utils import create_config
|
|
|
10
12
|
|
|
11
13
|
END_STATUSES = ['Success', 'Failed', 'Cancelled']
|
|
12
14
|
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
13
16
|
|
|
14
17
|
tools = []
|
|
15
18
|
|
|
@@ -33,6 +36,7 @@ def _get_cms_metric_data(region_id: str, instance_ids: List[str], metric_name: s
|
|
|
33
36
|
dimensions=json.dumps(dimesion),
|
|
34
37
|
)
|
|
35
38
|
describe_metric_last_resp = client.describe_metric_last(describe_metric_last_request)
|
|
39
|
+
logger.info(f'CMS Tools response: {describe_metric_last_resp.body}')
|
|
36
40
|
return describe_metric_last_resp.body.datapoints
|
|
37
41
|
|
|
38
42
|
@tools.append
|
{alibaba_cloud_ops_mcp_server-0.9.2.dist-info → alibaba_cloud_ops_mcp_server-0.9.4.dist-info}/RECORD
RENAMED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
alibaba_cloud_ops_mcp_server/__init__.py,sha256=BaluUNyRz8Qw-X7Y0ywDezwbkqiSvWlSYn2452XeGcA,213
|
|
2
|
+
alibaba_cloud_ops_mcp_server/__main__.py,sha256=Q40p2HtWGvxj1JLvS7dn95NLzDhJNQ6JAgLLyCb4Y50,63
|
|
2
3
|
alibaba_cloud_ops_mcp_server/config.py,sha256=PizctjXsQUWoMWBY1dFjNffVlZr9K6hNvqA4DpayR_o,513
|
|
3
|
-
alibaba_cloud_ops_mcp_server/server.py,sha256=
|
|
4
|
+
alibaba_cloud_ops_mcp_server/server.py,sha256=zmEL-4X35CklntDuWFk6Mc8QrHq-jvsaF1XLEyhKFSc,2639
|
|
5
|
+
alibaba_cloud_ops_mcp_server/settings.py,sha256=fqbTHaAw59nK7fJo6MyTCY_-M0K9YAD66WpybQalo9I,141
|
|
4
6
|
alibaba_cloud_ops_mcp_server/alibabacloud/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
7
|
alibaba_cloud_ops_mcp_server/alibabacloud/api_meta_client.py,sha256=t2TSc0Gzcy_uEcaCgiHHuLoMiEGu3-NCtYmwYjyPWsY,7973
|
|
6
8
|
alibaba_cloud_ops_mcp_server/alibabacloud/exception.py,sha256=7PdhgqgXEGrTPL1cj98h9EH-RrM6-2TT89PDtcmlpmU,1230
|
|
7
|
-
alibaba_cloud_ops_mcp_server/alibabacloud/utils.py,sha256=
|
|
8
|
-
alibaba_cloud_ops_mcp_server/alibabacloud/static/PROMPT_UNDERSTANDING.md,sha256=
|
|
9
|
+
alibaba_cloud_ops_mcp_server/alibabacloud/utils.py,sha256=tZQAEqGKS6Rx6Te9zNYfPBJ75GnAA-wX7hs6uP_JN0M,1609
|
|
10
|
+
alibaba_cloud_ops_mcp_server/alibabacloud/static/PROMPT_UNDERSTANDING.md,sha256=QPubudP1bwDbWu0Js6MYb4cJd1B2zM_JGp53twYv5yc,3611
|
|
9
11
|
alibaba_cloud_ops_mcp_server/alibabacloud/static/__init__.py,sha256=wJrYamaIb7e_kA4ILZpdP1f1TUUTXMGqEhA4IbSZ2Ts,230
|
|
10
12
|
alibaba_cloud_ops_mcp_server/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
alibaba_cloud_ops_mcp_server/tools/api_tools.py,sha256=
|
|
12
|
-
alibaba_cloud_ops_mcp_server/tools/cms_tools.py,sha256=
|
|
13
|
+
alibaba_cloud_ops_mcp_server/tools/api_tools.py,sha256=nkYLrrcZ1LVoc-4-sQoyHO4aO-G6Brz_xO5dz6NL9BI,9414
|
|
14
|
+
alibaba_cloud_ops_mcp_server/tools/cms_tools.py,sha256=BmPTiP8wu9DsEHBQsvR7JH9nFkcKMTBuNuafFqSfVxU,4308
|
|
13
15
|
alibaba_cloud_ops_mcp_server/tools/common_api_tools.py,sha256=ccQAWqS1I9F-fdOdjLcXN-dIhNqSbZV8T5ODuGXlfXM,2711
|
|
14
16
|
alibaba_cloud_ops_mcp_server/tools/oos_tools.py,sha256=8CLidg8Vrzpxv4lEOokPdScv31xlg_gX7glifiSqa8g,10063
|
|
15
17
|
alibaba_cloud_ops_mcp_server/tools/oss_tools.py,sha256=MUAiYL4VlsYQPoR_JtHOLcF1i4VYK9KE6ff9BTqJr9E,5014
|
|
16
|
-
alibaba_cloud_ops_mcp_server-0.9.
|
|
17
|
-
alibaba_cloud_ops_mcp_server-0.9.
|
|
18
|
-
alibaba_cloud_ops_mcp_server-0.9.
|
|
19
|
-
alibaba_cloud_ops_mcp_server-0.9.
|
|
20
|
-
alibaba_cloud_ops_mcp_server-0.9.
|
|
18
|
+
alibaba_cloud_ops_mcp_server-0.9.4.dist-info/METADATA,sha256=asXs9bS4X4omeQvusc63uF75qvNqs0DW4_V0YGNZKp4,5965
|
|
19
|
+
alibaba_cloud_ops_mcp_server-0.9.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
20
|
+
alibaba_cloud_ops_mcp_server-0.9.4.dist-info/entry_points.txt,sha256=ESGAWXKEp184forhs7VzTD4P1AUdZz6vCW6hRUKITGw,83
|
|
21
|
+
alibaba_cloud_ops_mcp_server-0.9.4.dist-info/licenses/LICENSE,sha256=gQgVkp2ttRCjodiPpXZZR-d7JnrYIYNiHk1YDUYgpa4,11331
|
|
22
|
+
alibaba_cloud_ops_mcp_server-0.9.4.dist-info/RECORD,,
|
{alibaba_cloud_ops_mcp_server-0.9.2.dist-info → alibaba_cloud_ops_mcp_server-0.9.4.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|