diff --git a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/__pycache__/main.cpython-312.pyc b/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/__pycache__/main.cpython-312.pyc deleted file mode 100644 index 22b6656..0000000 Binary files a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/__pycache__/main.cpython-312.pyc and /dev/null differ diff --git a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/__pycache__/schema_converter.cpython-312.pyc b/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/__pycache__/schema_converter.cpython-312.pyc deleted file mode 100644 index 8449988..0000000 Binary files a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/__pycache__/schema_converter.cpython-312.pyc and /dev/null differ diff --git a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/main.py b/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/main.py index ef76b10..5c2756a 100644 --- a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/main.py +++ b/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/main.py @@ -177,27 +177,47 @@ async def handle_list_tools() -> list[types.Tool]: logger.debug(f"处理工具配置: name={name}, description={description[:50] if description else 'None'}...") - # 优先使用 inputJsonSchema,如果不存在则从 sqlParams 转换 - input_json_schema = query.get("inputJsonSchema") - if input_json_schema: + # 优先从 sqlParams 转换,因为它包含更详细的文件配置信息 + sql_params = query.get("sqlParams") + if sql_params: try: - # inputJsonSchema 是 JSON 字符串,需要解析 - if isinstance(input_json_schema, str): - input_schema = json.loads(input_json_schema) - else: - input_schema = input_json_schema - # 清理 schema,确保 enum 只包含字符串 - input_schema = sanitize_json_schema(input_schema) - logger.debug(f"使用 inputJsonSchema (已清理): {json.dumps(input_schema, ensure_ascii=False)}") - except (json.JSONDecodeError, TypeError) as e: - logger.warning(f"解析 inputJsonSchema 失败: {e},回退到 sqlParams") - sql_params = query.get("sqlParams", "[]") input_schema = convert_sql_params_to_input_schema(sql_params) + logger.debug(f"从 sqlParams 转换的 inputSchema: {json.dumps(input_schema, ensure_ascii=False)}") + except Exception as e: + logger.warning(f"从 sqlParams 转换失败: {e},尝试使用 inputJsonSchema") + # 回退到 inputJsonSchema + input_json_schema = query.get("inputJsonSchema") + if input_json_schema: + try: + if isinstance(input_json_schema, str): + input_schema = json.loads(input_json_schema) + else: + input_schema = input_json_schema + input_schema = sanitize_json_schema(input_schema) + logger.debug(f"使用 inputJsonSchema (已清理): {json.dumps(input_schema, ensure_ascii=False)}") + except (json.JSONDecodeError, TypeError) as e2: + logger.error(f"解析 inputJsonSchema 也失败: {e2},使用空 schema") + input_schema = {"type": "object", "properties": {}, "required": []} + else: + logger.warning("sqlParams 和 inputJsonSchema 都不可用,使用空 schema") + input_schema = {"type": "object", "properties": {}, "required": []} else: - # 从 sqlParams 转换 - sql_params = query.get("sqlParams", "[]") - input_schema = convert_sql_params_to_input_schema(sql_params) - logger.debug(f"从 sqlParams 转换的 inputSchema: {json.dumps(input_schema, ensure_ascii=False)}") + # 如果没有 sqlParams,尝试使用 inputJsonSchema + input_json_schema = query.get("inputJsonSchema") + if input_json_schema: + try: + if isinstance(input_json_schema, str): + input_schema = json.loads(input_json_schema) + else: + input_schema = input_json_schema + input_schema = sanitize_json_schema(input_schema) + logger.debug(f"使用 inputJsonSchema (已清理): {json.dumps(input_schema, ensure_ascii=False)}") + except (json.JSONDecodeError, TypeError) as e: + logger.error(f"解析 inputJsonSchema 失败: {e},使用空 schema") + input_schema = {"type": "object", "properties": {}, "required": []} + else: + logger.warning("sqlParams 和 inputJsonSchema 都不存在,使用空 schema") + input_schema = {"type": "object", "properties": {}, "required": []} tools.append( types.Tool( diff --git a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/schema_converter.py b/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/schema_converter.py index f497d4d..640a4a5 100644 --- a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/schema_converter.py +++ b/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/schema_converter.py @@ -7,6 +7,8 @@ Schema 转换器 - paragraph: 段落/多行文本 - select: 下拉选项 - number: 数字输入 +- file: 单文件上传 +- fileList: 多文件上传 """ import json from typing import Any @@ -60,7 +62,13 @@ def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]: "maxLength": 200, "defaultValue": "", "required": true, - "options": ["选项1", "选项2"] # 仅 select 类型 + "options": ["选项1", "选项2"], # 仅 select 类型 + "fileConfig": { # 仅 file/fileList 类型 + "uploadMode": "both", + "typeCategories": ["image"], + "customAccept": "", + "accept": ".jpg,.jpeg,.png" + } } Returns: @@ -73,6 +81,7 @@ def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]: max_length = param.get("maxLength") is_required = param.get("required", False) options = param.get("options", []) + file_config = param.get("fileConfig", {}) property_schema = { "description": display_name @@ -112,12 +121,49 @@ def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]: elif param_type == "number": property_schema["type"] = "number" + elif param_type == "file": + # 单文件上传 + property_schema["type"] = "string" + property_schema["format"] = "url" + property_schema["x-file-type"] = "single" + + # 添加文件配置信息 + if file_config: + if file_config.get("accept"): + property_schema["x-accept"] = file_config["accept"] + if file_config.get("typeCategories"): + property_schema["x-type-categories"] = file_config["typeCategories"] + if file_config.get("uploadMode"): + property_schema["x-upload-mode"] = file_config["uploadMode"] + # 保留完整配置 + property_schema["x-file-config"] = file_config + + elif param_type == "fileList": + # 多文件上传 + property_schema["type"] = "array" + property_schema["items"] = { + "type": "string", + "format": "url" + } + property_schema["x-file-type"] = "multiple" + + # 添加文件配置信息 + if file_config: + if file_config.get("accept"): + property_schema["x-accept"] = file_config["accept"] + if file_config.get("typeCategories"): + property_schema["x-type-categories"] = file_config["typeCategories"] + if file_config.get("uploadMode"): + property_schema["x-upload-mode"] = file_config["uploadMode"] + # 保留完整配置 + property_schema["x-file-config"] = file_config + else: # 默认当作 string 处理 property_schema["type"] = "string" - # 添加默认值 - if default_value not in (None, ""): + # 添加默认值(文件类型不需要默认值) + if default_value not in (None, "") and param_type not in ("file", "fileList"): if param_type == "number": try: property_schema["default"] = int(default_value) if str(default_value).isdigit() else float(default_value) diff --git a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/utils/__pycache__/__init__.cpython-312.pyc b/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/utils/__pycache__/__init__.cpython-312.pyc index 2000b8d..074d8be 100644 Binary files a/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/utils/__pycache__/__init__.cpython-312.pyc and b/lzwcai_workflow_to_mcp/lzwcai_workflow_to_mcp/utils/__pycache__/__init__.cpython-312.pyc differ diff --git a/lzwcai_workflow_to_mcp/main.py b/lzwcai_workflow_to_mcp/main.py index d1197e0..7e44bdf 100644 --- a/lzwcai_workflow_to_mcp/main.py +++ b/lzwcai_workflow_to_mcp/main.py @@ -7,8 +7,8 @@ import os if __name__ == "__main__": # 设置环境变量 - os.environ["workflowId"] = "2019984063311556609" - os.environ["workflowExecuteKey"] = "wf_45bd630402664485a2ef5cd3ede5aa53" + os.environ["workflowId"] = "2020107946473074690" + os.environ["workflowExecuteKey"] = "wf_20170f33487d41459c180c6a277991a4" os.environ["backendBaseUrl"] = "http://192.168.2.236:8088" # Import and run the actual MCP server diff --git a/lzwcai_workflow_to_mcp/pyproject.toml b/lzwcai_workflow_to_mcp/pyproject.toml index 4fbafb3..d864806 100644 --- a/lzwcai_workflow_to_mcp/pyproject.toml +++ b/lzwcai_workflow_to_mcp/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "lzwcai-workflow-to-mcp" -version = "0.1.3" +version = "0.1.5" description = "MCP server for executing business SQL queries with dynamic tool generation" readme = "README.md" requires-python = ">=3.10"