Skip to content

Commit b9e3604

Browse files
authored
feat(vefaas): add GetDependencyInstallTaskLogDownloadURI support (#203)
* feat(vefaas): skip dependency install if node_modules exists * feat(vefaas): add GetDependencyInstallTaskLogDownloadURI support * fix(vefaas): standardize tool output to return JSON strings for validation compatibility * fix(vefaas): add region support for request
1 parent a50419e commit b9e3604

2 files changed

Lines changed: 36 additions & 24 deletions

File tree

server/mcp_server_vefaas_function/src/mcp_server_vefaas_function/sign.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def hash_sha256(content: str):
7979

8080

8181
# 第二步:签名请求函数
82-
def request(method, date, query, header, ak, sk, token, action, body):
82+
def request(method, date, query, header, ak, sk, token, action, body, region = None):
8383
# 第三步:创建身份证明。其中的 Service 和 Region 字段是固定的。ak 和 sk 分别代表
8484
# AccessKeyID 和 SecretAccessKey。同时需要初始化签名结构体。一些签名计算时需要的属性也在这里处理。
8585
# 初始化身份证明结构体
@@ -88,13 +88,14 @@ def request(method, date, query, header, ak, sk, token, action, body):
8888
"access_key_id": ak,
8989
"secret_access_key": sk,
9090
"service": Service,
91-
"region": Region,
91+
"region": region or Region,
9292
}
9393

9494
if token is not None:
9595
credential["session_token"] = token
9696

97-
if action in ['CodeUploadCallback', 'CreateDependencyInstallTask', 'GetDependencyInstallTaskStatus']:
97+
if action in ['CodeUploadCallback', 'CreateDependencyInstallTask', 'GetDependencyInstallTaskStatus',
98+
'GetDependencyInstallTaskLogDownloadURI']:
9899
credential["service"] = "vefaas"
99100

100101
content_type = ContentType

server/mcp_server_vefaas_function/src/mcp_server_vefaas_function/vefaas_server.py

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ def create_api_gateway_trigger(function_id: str, api_gateway_id: str, service_id
371371
"VeFaas": {"FunctionId":function_id}}}
372372

373373
try:
374-
response_body = request("POST", now, {}, {}, ak, sk, token, "CreateUpstream", json.dumps(body))
374+
response_body = request("POST", now, {}, {}, ak, sk, token, "CreateUpstream", json.dumps(body), region)
375375
# Print the full response for debugging
376376
print(f"Response: {json.dumps(response_body)}")
377377
# Check if response contains an error
@@ -407,7 +407,7 @@ def create_api_gateway_trigger(function_id: str, api_gateway_id: str, service_id
407407
}
408408
}
409409
try:
410-
response_body = request("POST", now, {}, {}, ak, sk, token, "CreateRoute", json.dumps(body))
410+
response_body = request("POST", now, {}, {}, ak, sk, token, "CreateRoute", json.dumps(body), region)
411411
except Exception as e:
412412
error_message = f"Error creating route: {str(e)}"
413413
raise ValueError(error_message)
@@ -424,7 +424,7 @@ def list_api_gateways(region: str = None):
424424
except ValueError as e:
425425
raise ValueError(f"Authorization failed: {str(e)}")
426426

427-
response_body = request("GET", now, {"Limit": "10"}, {}, ak, sk, token, "ListGateways", None)
427+
response_body = request("GET", now, {"Limit": "10"}, {}, ak, sk, token, "ListGateways", None, region)
428428
return response_body
429429

430430

@@ -476,7 +476,7 @@ def create_api_gateway(name: str = None, region: str = "cn-beijing") -> str:
476476
raise ValueError(f"Authorization failed: {str(e)}")
477477

478478
try:
479-
response_body = request("POST", now, {}, {}, ak, sk, token, "CreateGateway", json.dumps(body))
479+
response_body = request("POST", now, {}, {}, ak, sk, token, "CreateGateway", json.dumps(body), region)
480480
return response_body
481481
except Exception as e:
482482
return f"Failed to create VeApig gateway with name {gateway_name}: {str(e)}"
@@ -520,8 +520,8 @@ def create_gateway_service(
520520
raise ValueError(f"Authorization failed: {str(e)}")
521521

522522
try:
523-
response_body = request("POST", now, {}, {}, ak, sk, token, "CreateGatewayService", json.dumps(body))
524-
return response_body
523+
response_body = request("POST", now, {}, {}, ak, sk, token, "CreateGatewayService", json.dumps(body), region)
524+
return json.dumps(response_body, ensure_ascii=False, indent=2)
525525
except Exception as e:
526526
return f"Failed to create VeApig gateway service with name {service_name}: {str(e)}"
527527

@@ -542,7 +542,7 @@ def list_api_gateway_services(gateway_id: str, region: str = None):
542542
"Offset": 0,
543543
}
544544

545-
response_body = request("POST", now, {}, {}, ak, sk, token, "ListGatewayServices", json.dumps(body))
545+
response_body = request("POST", now, {}, {}, ak, sk, token, "ListGatewayServices", json.dumps(body), region)
546546
return response_body
547547

548548
@mcp.tool(description="""Lists all routes of an upstream.
@@ -559,7 +559,7 @@ def list_routes(upstream_id: str, region: str = None):
559559
"UpstreamId": upstream_id
560560
}
561561

562-
response_body = request("POST", now, {}, {}, ak, sk, token, "ListRoutes", json.dumps(body))
562+
response_body = request("POST", now, {}, {}, ak, sk, token, "ListRoutes", json.dumps(body), region)
563563
return response_body
564564

565565
def ensure_executable_permissions(folder_path: str):
@@ -690,7 +690,7 @@ def _get_upload_code_description() -> str:
690690
return base_desc + note + tail
691691

692692
@mcp.tool(description=_get_upload_code_description())
693-
def upload_code(region: str, function_id: str, local_folder_path: Optional[str] = None, file_dict: Optional[dict[str, Union[str, bytes]]] = None) -> bytes:
693+
def upload_code(region: str, function_id: str, local_folder_path: Optional[str] = None, file_dict: Optional[dict[str, Union[str, bytes]]] = None) -> str:
694694
region = validate_and_set_region(region)
695695

696696
api_instance = init_client(region, mcp.get_context())
@@ -714,13 +714,13 @@ def upload_code(region: str, function_id: str, local_folder_path: Optional[str]
714714
else:
715715
raise ValueError("Either local_folder_path or file_dict must be provided.")
716716
response_body = upload_code_zip_for_function(api_instance=api_instance, function_id=function_id, code_zip_size=size,
717-
zip_bytes=data, ak=ak, sk=sk, token=token)
717+
zip_bytes=data, ak=ak, sk=sk, token=token, region=region)
718718
handle_dependency(api_instance=api_instance, function_id=function_id, local_folder_path=local_folder_path,
719-
file_dict= file_dict, ak=ak, sk=sk, token=token)
720-
return response_body
719+
file_dict= file_dict, ak=ak, sk=sk, token=token, region=region)
720+
return json.dumps(response_body, ensure_ascii=False, indent=2)
721721

722722
def handle_dependency(api_instance: VEFAASApi, function_id: str, local_folder_path, file_dict,
723-
ak: str, sk: str, token: str):
723+
ak: str, sk: str, token: str, region: str = None):
724724
req = volcenginesdkvefaas.GetFunctionRequest(
725725
id=function_id
726726
)
@@ -745,12 +745,20 @@ def handle_dependency(api_instance: VEFAASApi, function_id: str, local_folder_pa
745745
or (file_dict is not None and "package.json" in file_dict)
746746
)
747747

748+
has_node_modules = (
749+
(local_folder_path is not None and os.path.exists(os.path.join(local_folder_path, "node_modules")))
750+
or (file_dict is not None and "node_modules" in file_dict)
751+
)
752+
748753
if is_native_python and not has_requirements:
749754
print("Python runtime detected, but no requirements.txt found. Skipping dependency install.")
750755
return
751756
if is_native_nodejs and not has_package_json:
752757
print("Node.js runtime detected, but no package.json found. Skipping dependency install.")
753758
return
759+
if is_native_nodejs and has_package_json and has_node_modules:
760+
print("Node.js runtime detected, package.json found, but has node_modules. Skipping dependency install.")
761+
return
754762
if not is_native_python and not is_native_nodejs:
755763
print("Runtime is not native-python or native-nodejs. Skipping dependency install.")
756764
return
@@ -760,22 +768,25 @@ def handle_dependency(api_instance: VEFAASApi, function_id: str, local_folder_pa
760768

761769
try:
762770
response_body = request("POST", now, {}, {}, ak, sk, token,
763-
"CreateDependencyInstallTask", json.dumps(body))
771+
"CreateDependencyInstallTask", json.dumps(body), region)
764772
print(response_body)
765773

766774
timeout_seconds = 300
767775
start_time = time.time()
768776
while True:
769777
status_resp = request("POST", now, {}, {}, ak, sk, token,
770-
"GetDependencyInstallTaskStatus", json.dumps(body))
778+
"GetDependencyInstallTaskStatus", json.dumps(body), region)
771779
print(status_resp)
772780

773781
status = status_resp['Result']['Status']
774782
if status == 'Failed':
775-
# log_download_resp = request("POST", now, {}, {}, ak, sk, token,
776-
# "GetDependencyInstallTaskLogDownloadURI", json.dumps(body))
777-
# url = log_download_resp['Result']['DownloadURL']
778-
raise ValueError("Dependency installation failed.")
783+
log_download_resp = request("POST", now, {}, {}, ak, sk, token,
784+
"GetDependencyInstallTaskLogDownloadURI", json.dumps(body), region)
785+
url = log_download_resp['Result']['DownloadURL']
786+
url = url.replace("\\u0026", "&")
787+
response = requests.get(url, timeout=30)
788+
install_log = response.text
789+
raise ValueError("Dependency installation failed. Install log \n" + install_log)
779790
elif status == 'Succeeded':
780791
print("Dependency installation succeeded.")
781792
break
@@ -787,7 +798,7 @@ def handle_dependency(api_instance: VEFAASApi, function_id: str, local_folder_pa
787798

788799

789800
def upload_code_zip_for_function(api_instance: VEFAASApi(object), function_id: str, code_zip_size: int, zip_bytes,
790-
ak: str, sk: str, token: str,) -> bytes:
801+
ak: str, sk: str, token: str, region: str,) -> bytes:
791802
req = volcenginesdkvefaas.GetCodeUploadAddressRequest(
792803
function_id=function_id,
793804
content_length=code_zip_size
@@ -817,7 +828,7 @@ def upload_code_zip_for_function(api_instance: VEFAASApi(object), function_id: s
817828
}
818829

819830
try:
820-
response_body = request("POST", now, {}, {}, ak, sk, token, "CodeUploadCallback", json.dumps(body))
831+
response_body = request("POST", now, {}, {}, ak, sk, token, "CodeUploadCallback", json.dumps(body), region)
821832
return response_body
822833
except Exception as e:
823834
error_message = f"Error creating upstream: {str(e)}"

0 commit comments

Comments
 (0)