Skip to content

Commit eabf785

Browse files
Common api caller (#32)
* add readme * update open api common caller * update image url * Update Common API Caller * Update Common API Caller * Update Common API Caller * Update Common API Caller * unittest * unittest * unittest * unittest * unittest * unittest * unittest * unittest * unittest * unittest * unittest * unittest * unittest * unittest
1 parent 461b1b3 commit eabf785

File tree

14 files changed

+475
-82
lines changed

14 files changed

+475
-82
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ To use `alibaba-cloud-ops-mcp-server` MCP Server with any other MCP Client, you
3939
}
4040
```
4141

42+
[For detailed parameter description, see MCP startup parameter document](./README_mcp_args.md)
43+
4244
## MCP Maketplace Integration
4345

4446
* [Cline](https://cline.bot/mcp-marketplace)

README_mcp_args.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.

README_zh.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ curl -LsSf https://astral.sh/uv/install.sh | sh
3939
}
4040
```
4141

42+
[详细参数说明见 MCP 启动参数文档](./README_mcp_args.md)
43+
4244
## MCP市场集成
4345

4446
* [Cline](https://cline.bot/mcp-marketplace)

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "alibaba-cloud-ops-mcp-server"
3-
version = "0.8.9"
3+
version = "0.9.0"
44
description = "A MCP server for Alibaba Cloud"
55
readme = "README.md"
66
authors = [
@@ -34,4 +34,4 @@ dev = [
3434
]
3535

3636
[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"

src/alibaba_cloud_ops_mcp_server/alibabacloud/api_meta_client.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,16 @@ def get_response_from_pop_api(cls, pop_api_name, service=None, api=None, version
4747
@classmethod
4848
def get_service_version(cls, service):
4949
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)
5151
return version
5252

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+
5360
@classmethod
5461
def get_service_style(cls, service):
5562
data = cls.get_response_from_pop_api(cls.GET_PRODUCT_LIST)
@@ -147,7 +154,8 @@ def get_ref(data, _):
147154
return combined_params
148155

149156
@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)
151159
data = cls.get_response_from_pop_api(cls.GET_API_OVERVIEW, service=service, version=version)
152160
apis = list(data[APIS].keys())
153161
return apis
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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()

src/alibaba_cloud_ops_mcp_server/server.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,25 @@
22
import click
33
import logging
44

5+
from alibaba_cloud_ops_mcp_server.tools.common_api_tools import set_custom_service_list
56
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+
from alibaba_cloud_ops_mcp_server.tools import cms_tools, oos_tools, oss_tools, api_tools, common_api_tools
78

89
logger = logging.getLogger(__name__)
910

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+
1024

1125
@click.command()
1226
@click.option(
@@ -27,13 +41,26 @@
2741
default="127.0.0.1",
2842
help="Host",
2943
)
30-
def main(transport: str, port: int, host: str):
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):
3151
# Create an MCP server
3252
mcp = FastMCP(
3353
name="alibaba-cloud-ops-mcp-server",
3454
port=port,
3555
host=host
3656
)
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)
3764
for tool in oos_tools.tools:
3865
mcp.add_tool(tool)
3966
for tool in cms_tools.tools:

src/alibaba_cloud_ops_mcp_server/tools/api_tools.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,38 @@
2424
'number': float
2525
}
2626

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+
2753

2854
def create_client(service: str, region_id: str) -> OpenApiClient:
2955
config = create_config()
3056
if isinstance(service, str):
3157
service = service.lower()
32-
config.endpoint = f'{service}.{region_id}.aliyuncs.com'
58+
config.endpoint = _get_service_endpoint(service, region_id.lower())
3359
return OpenApiClient(config)
3460

3561

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)

0 commit comments

Comments
 (0)