Skip to content

Commit 3ee9f5e

Browse files
authored
support header credentials (#39)
2 parents eabf785 + ecfeace commit 3ee9f5e

File tree

13 files changed

+368
-80
lines changed

13 files changed

+368
-80
lines changed

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.9.0"
3+
version = "0.9.1"
44
description = "A MCP server for Alibaba Cloud"
55
readme = "README.md"
66
authors = [
@@ -14,7 +14,7 @@ dependencies = [
1414
"alibabacloud_oss_v2>=1.1.0",
1515
"alibabacloud-credentials>=1.0.0",
1616
"click>=8.1.8",
17-
"mcp[cli]>=1.9.0",
17+
"fastmcp>=2.8.0"
1818
]
1919

2020
[build-system]
Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,46 @@
1+
import logging
2+
13
from alibabacloud_credentials.client import Client as CredClient
24
from alibabacloud_tea_openapi.models import Config
5+
from fastmcp.server.dependencies import get_http_request
6+
7+
logger = logging.getLogger(__name__)
8+
9+
10+
def get_credentials_from_header():
11+
credentials = None
12+
try:
13+
request = get_http_request()
14+
headers = request.headers
15+
access_key_id = headers.get('x-acs-accesskey-id', None)
16+
access_key_secret = headers.get('x-acs-accesskey-secret', None)
17+
token = headers.get('x-acs-security-token', None)
18+
19+
if access_key_id:
20+
credentials = {
21+
'AccessKeyId': access_key_id,
22+
'AccessKeySecret': access_key_secret,
23+
'SecurityToken': token
24+
}
25+
26+
except Exception as e:
27+
logger.info(f'get_credentials_from_header error: {e}')
28+
return credentials
329

430

531
def create_config():
6-
credentialsClient = CredClient()
7-
config = Config(credential=credentialsClient)
32+
credentials = get_credentials_from_header()
33+
if credentials:
34+
access_key_id = credentials.get('AccessKeyId', None)
35+
access_key_secret = credentials.get('AccessKeySecret', None)
36+
token = credentials.get('SecurityToken', None)
37+
config = Config(
38+
access_key_id=access_key_id,
39+
access_key_secret=access_key_secret,
40+
security_token=token
41+
)
42+
else:
43+
credentialsClient = CredClient()
44+
config = Config(credential=credentialsClient)
845
config.user_agent = 'alibaba-cloud-ops-mcp-server'
946
return config

src/alibaba_cloud_ops_mcp_server/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
],
2222
'rds': [
2323
'DescribeDBInstances'
24-
],
24+
]
2525
}
2626

2727

src/alibaba_cloud_ops_mcp_server/server.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from mcp.server.fastmcp import FastMCP
1+
from fastmcp import FastMCP
22
import click
33
import logging
44

@@ -60,13 +60,13 @@ def main(transport: str, port: int, host: str, services: str):
6060
service_list = [(key, SUPPORTED_SERVICES_MAP.get(key, key)) for key in service_keys]
6161
set_custom_service_list(service_list)
6262
for tool in common_api_tools.tools:
63-
mcp.add_tool(tool)
63+
mcp.tool(tool)
6464
for tool in oos_tools.tools:
65-
mcp.add_tool(tool)
65+
mcp.tool(tool)
6666
for tool in cms_tools.tools:
67-
mcp.add_tool(tool)
67+
mcp.tool(tool)
6868
for tool in oss_tools.tools:
69-
mcp.add_tool(tool)
69+
mcp.tool(tool)
7070
api_tools.create_api_tools(mcp, config)
7171

7272
# Initialize and run the server

src/alibaba_cloud_ops_mcp_server/tools/api_tools.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,32 +110,54 @@ def _create_function_schemas(service, api, api_meta):
110110
schemas = {}
111111
schemas[api] = {}
112112
parameters = api_meta.get('parameters', [])
113+
114+
required_params = []
115+
optional_params = []
116+
113117
for parameter in parameters:
114118
name = parameter.get('name')
115119
# TODO 目前忽略了带'.'的参数
116120
if '.' in name:
117121
continue
118122
schema = parameter.get('schema', '')
123+
required = schema.get('required', False)
124+
125+
if required:
126+
required_params.append(parameter)
127+
else:
128+
optional_params.append(parameter)
129+
130+
def process_parameter(parameter):
131+
name = parameter.get('name')
132+
schema = parameter.get('schema', '')
119133
description = schema.get('description', '')
120134
example = schema.get('example', '')
121135
type_ = schema.get('type', '')
122136
description = f'{description} 参数类型: {type_},参数示例:{example}'
123137
required = schema.get('required', False)
124-
125-
# 只有在service为ecs时,才对特定参数进行特殊处理
138+
126139
if service.lower() == 'ecs' and name in ECS_LIST_PARAMETERS and type_ == 'string':
127140
python_type = list
128141
else:
129142
python_type = type_map.get(type_, str)
130-
143+
131144
field_info = (
132145
python_type,
133146
field(
134147
default=None,
135148
metadata={'description': description, 'required': required}
136149
)
137150
)
151+
return name, field_info
152+
153+
for parameter in required_params:
154+
name, field_info = process_parameter(parameter)
138155
schemas[api][name] = field_info
156+
157+
for parameter in optional_params:
158+
name, field_info = process_parameter(parameter)
159+
schemas[api][name] = field_info
160+
139161
if 'RegionId' not in schemas[api]:
140162
schemas[api]['RegionId'] = (
141163
str,

src/alibaba_cloud_ops_mcp_server/tools/cms_tools.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,79 +37,79 @@ def _get_cms_metric_data(region_id: str, instance_ids: List[str], metric_name: s
3737

3838
@tools.append
3939
def CMS_GetCpuUsageData(
40-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
4140
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
41+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
4242
):
4343
"""获取ECS实例的CPU使用率数据"""
4444
return _get_cms_metric_data(RegionId, InstanceIds, 'cpu_total')
4545

4646

4747
@tools.append
4848
def CMS_GetCpuLoadavgData(
49-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
5049
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
50+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
5151
):
5252
"""获取CPU一分钟平均负载指标数据"""
5353
return _get_cms_metric_data(RegionId, InstanceIds, 'load_1m')
5454

5555

5656
@tools.append
5757
def CMS_GetCpuloadavg5mData(
58-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
5958
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
59+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
6060
):
6161
"""获取CPU五分钟平均负载指标数据"""
6262
return _get_cms_metric_data(RegionId, InstanceIds, 'load_5m')
6363

6464

6565
@tools.append
6666
def CMS_GetCpuloadavg15mData(
67-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
6867
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
68+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
6969
):
7070
"""获取CPU十五分钟平均负载指标数据"""
7171
return _get_cms_metric_data(RegionId, InstanceIds, 'load_15m')
7272

7373
@tools.append
7474
def CMS_GetMemUsedData(
75-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
7675
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
76+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
7777
):
7878
"""获取内存使用量指标数据"""
7979
return _get_cms_metric_data(RegionId, InstanceIds, 'memory_usedspace')
8080

8181

8282
@tools.append
8383
def CMS_GetMemUsageData(
84-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
8584
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
85+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
8686
):
8787
"""获取内存利用率指标数据"""
8888
return _get_cms_metric_data(RegionId, InstanceIds, 'memory_usedutilization')
8989

9090

9191
@tools.append
9292
def CMS_GetDiskUsageData(
93-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
9493
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
94+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
9595
):
9696
"""获取磁盘利用率指标数据"""
9797
return _get_cms_metric_data(RegionId, InstanceIds, 'diskusage_utilization')
9898

9999

100100
@tools.append
101101
def CMS_GetDiskTotalData(
102-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
103102
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
103+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
104104
):
105105
"""获取磁盘分区总容量指标数据"""
106106
return _get_cms_metric_data(RegionId, InstanceIds, 'diskusage_total')
107107

108108

109109
@tools.append
110110
def CMS_GetDiskUsedData(
111-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
112111
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
112+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
113113
):
114114
"""获取磁盘分区使用量指标数据"""
115115
return _get_cms_metric_data(RegionId, InstanceIds, 'diskusage_used')

src/alibaba_cloud_ops_mcp_server/tools/oos_tools.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ def _start_execution_sync(region_id: str, template_name: str, parameters: dict):
4747
time.sleep(1)
4848
@tools.append
4949
def OOS_RunCommand(
50-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
51-
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
52-
CommandType: str = Field(description='The type of command executed on the ECS instance, optional value:RunShellScript,RunPythonScript,RunPerlScript,RunBatScript,RunPowerShellScript', default='RunShellScript'),
53-
Command: str = Field(description='Content of the command executed on the ECS instance'),
50+
Command: str = Field(description='Content of the command executed on the ECS instance'),
51+
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
52+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
53+
CommandType: str = Field(description='The type of command executed on the ECS instance, optional value:RunShellScript,RunPythonScript,RunPerlScript,RunBatScript,RunPowerShellScript', default='RunShellScript')
5454
):
5555
"""批量在多台ECS实例上运行云助手命令,适用于需要同时管理多台ECS实例的场景,如应用程序管理和资源标记操作等。"""
5656

@@ -74,8 +74,8 @@ def OOS_RunCommand(
7474

7575
@tools.append
7676
def OOS_StartInstances(
77-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
78-
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
77+
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
78+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
7979
):
8080
"""批量启动ECS实例,适用于需要同时管理和启动多台ECS实例的场景,例如应用部署和高可用性场景。"""
8181

@@ -93,9 +93,9 @@ def OOS_StartInstances(
9393

9494
@tools.append
9595
def OOS_StopInstances(
96-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
97-
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
98-
ForeceStop: bool = Field(description='Is forced shutdown required', default=False),
96+
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
97+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
98+
ForeceStop: bool = Field(description='Is forced shutdown required', default=False)
9999
):
100100
"""批量停止ECS实例,适用于需要同时管理和停止多台ECS实例的场景。"""
101101

@@ -114,9 +114,9 @@ def OOS_StopInstances(
114114

115115
@tools.append
116116
def OOS_RebootInstances(
117-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
118-
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
119-
ForeceStop: bool = Field(description='Is forced shutdown required', default=False),
117+
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
118+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
119+
ForeceStop: bool = Field(description='Is forced shutdown required', default=False)
120120
):
121121
"""批量重启ECS实例,适用于需要同时管理和重启多台ECS实例的场景。"""
122122

@@ -135,13 +135,13 @@ def OOS_RebootInstances(
135135

136136
@tools.append
137137
def OOS_RunInstances(
138-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
139138
ImageId: str = Field(description='Image ID'),
140139
InstanceType: str = Field(description='Instance Type'),
141140
SecurityGroupId: str = Field(description='SecurityGroup ID'),
142141
VSwitchId: str = Field(description='VSwitch ID'),
142+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
143143
Amount: int = Field(description='Number of ECS instances', default=1),
144-
InstanceName: str = Field(description='Instance Name', default=''),
144+
InstanceName: str = Field(description='Instance Name', default='')
145145
):
146146
"""批量创建ECS实例,适用于需要同时创建多台ECS实例的场景,例如应用部署和高可用性场景。"""
147147

@@ -158,9 +158,9 @@ def OOS_RunInstances(
158158

159159
@tools.append
160160
def OOS_ResetPassword(
161-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
162161
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
163162
Password: str = Field(description='The password of the ECS instance must be 8-30 characters and must contain only the following characters: lowercase letters, uppercase letters, numbers, and special characters only.()~!@#$%^&*-_+=(40:<>,?/'),
163+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
164164
):
165165
"""批量修改ECS实例的密码,请注意,本操作将会重启ECS实例"""
166166
parameters = {
@@ -177,9 +177,9 @@ def OOS_ResetPassword(
177177

178178
@tools.append
179179
def OOS_ReplaceSystemDisk(
180-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
181-
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
182-
ImageId: str = Field(description='Image ID')
180+
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
181+
ImageId: str = Field(description='Image ID'),
182+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
183183
):
184184
"""批量替换ECS实例的系统盘,更换操作系统"""
185185
parameters = {
@@ -197,8 +197,8 @@ def OOS_ReplaceSystemDisk(
197197

198198
@tools.append
199199
def OOS_StartRDSInstances(
200-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
201-
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
200+
InstanceIds: List[str] = Field(description='AlibabaCloud ECS instance ID List'),
201+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
202202
):
203203
"""批量启动RDS实例,适用于需要同时管理和启动多台RDS实例的场景,例如应用部署和高可用性场景。"""
204204

@@ -216,8 +216,8 @@ def OOS_StartRDSInstances(
216216

217217
@tools.append
218218
def OOS_StopRDSInstances(
219-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
220-
InstanceIds: List[str] = Field(description='AlibabaCloud RDS instance ID List')
219+
InstanceIds: List[str] = Field(description='AlibabaCloud RDS instance ID List'),
220+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
221221
):
222222
"""批量停止RDS实例,适用于需要同时管理和停止多台RDS实例的场景。"""
223223

@@ -235,8 +235,8 @@ def OOS_StopRDSInstances(
235235

236236
@tools.append
237237
def OOS_RebootRDSInstances(
238-
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou'),
239-
InstanceIds: List[str] = Field(description='AlibabaCloud RDS instance ID List')
238+
InstanceIds: List[str] = Field(description='AlibabaCloud RDS instance ID List'),
239+
RegionId: str = Field(description='AlibabaCloud region ID', default='cn-hangzhou')
240240
):
241241
"""批量重启RDS实例,适用于需要同时管理和重启多台RDS实例的场景。"""
242242

0 commit comments

Comments
 (0)