From 384a1fbcb23aa669a4c4b0f8a9ef8e62d1137c83 Mon Sep 17 00:00:00 2001 From: yuanzhipeng <2501363769@qq.com> Date: Sun, 4 Jan 2026 10:14:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(create=5Fmcp):=20=E6=B7=BB=E5=8A=A0MCP?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E8=BE=93=E5=87=BASchema=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加了固定的输出Schema定义,包含code、message和data字段, 用于规范MCP工具的返回格式,提高API响应的一致性。 - 定义了标准的输出Schema结构 - 包含响应状态码、消息和数据字段 - code和message为必需字段 --- .../lzwcai_mcp_api_converter.log | 37 ++ .../__pycache__/create_mcp.cpython-312.pyc | Bin 31996 -> 32268 bytes .../get_business_api.cpython-312.pyc | Bin 8430 -> 8473 bytes .../core/__pycache__/get_auth.cpython-312.pyc | Bin 12348 -> 12391 bytes .../src/create_mcp.py | 12 + .../logs/lzwcai_mcp_sqlexecutor.log | 223 ++++++++ .../logs/lzwcai_mcp_sqlexecutor_daily.log | 274 ++++++++-- .../logs/lzwcai_mcp_sqlexecutor_error.log | 158 ++++++ .../logs/mcp_services.log | 205 ++++++++ lzwcai_mcpskills_analyzeWorkOrder/README.md | 138 +++++ .../.gitignore | 10 + .../.python-version | 1 + .../README.md | 154 ++++++ .../__init__.py | 9 + .../businessQueries.json | 35 ++ .../lzwcai_mcpskills_analyzeWorkOrder/main.py | 358 +++++++++++++ .../pyproject.toml | 35 ++ .../utils/__init__.py | 24 + .../utils/api_client.py | 318 +++++++++++ .../utils/env_config.py | 88 ++++ .../utils/json_helper.py | 60 +++ .../utils/logger_config.py | 489 +++++++++++++++++ .../utils/name_helper.py | 41 ++ .../utils/schema_helper.py | 166 ++++++ .../lzwcai_mcpskills_analyzeWorkOrder/uv.lock | 497 ++++++++++++++++++ lzwcai_mcpskills_analyzeWorkOrder/main.py | 12 + .../pyproject.toml | 35 ++ tools_config.json | 80 +++ 28 files changed, 3408 insertions(+), 51 deletions(-) create mode 100644 lzwcai_mcp_api_converter/lzwcai_mcp_api_converter.log create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/README.md create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/.gitignore create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/.python-version create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/README.md create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/__init__.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/businessQueries.json create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/main.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/pyproject.toml create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/__init__.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/api_client.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/env_config.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/json_helper.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/logger_config.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/name_helper.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/schema_helper.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/uv.lock create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/main.py create mode 100644 lzwcai_mcpskills_analyzeWorkOrder/pyproject.toml create mode 100644 tools_config.json diff --git a/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter.log b/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter.log new file mode 100644 index 0000000..e322619 --- /dev/null +++ b/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter.log @@ -0,0 +1,37 @@ +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================ +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2025-12-30 11:48:23 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:218] - 日志文件: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_api_converter\lzwcai_mcp_api_converter.log +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================ +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:277] - 开始初始化 MCP 服务器 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:116] - 配置模式: memory +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:124] - 使用内存模式加载配置(多租户支持) +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:135] - 使用环境变量提供的businessUuid: u9ua9ss2l8c +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:139] - 租户配置变量名: businessu9ua9ss2l8c +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:147] - 内存中没有租户 u9ua9ss2l8c 的配置,开始从业务平台获取... +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:168] - 从环境变量bizSysApiIds获取到API IDs: [1970386761072058369, 1970386761185304578, 1970386761583763457, 1970386761420185602] +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:175] - 调用get_business_api_config获取配置,API IDs: [1970386761072058369, 1970386761185304578, 1970386761583763457, 1970386761420185602] +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.business.get_business_api - INFO - [get_business_api.py:193] - 开始获取 4 个API的详情... +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.business.get_business_api - INFO - [get_business_api.py:93] - 成功获取 4 个API详情 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.business.get_business_api - INFO - [get_business_api.py:197] - 开始映射为配置格式... +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.business.get_business_api - INFO - [get_business_api.py:158] - 成功映射 4 个API到配置格式 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.business.get_business_api - INFO - [get_business_api.py:159] - 服务名称: lzwcai_mcp_api_converter +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.business.get_business_api - INFO - [get_business_api.py:160] - 域名URL: https://erp.166bg.com/api +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.business.get_business_api - INFO - [get_business_api.py:161] - 描述: 定时任务列表、定时任务详情、任务列表、任务统计列表(按状态) +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.business.get_business_api - INFO - [get_business_api.py:200] - [SUCCESS] 成功生成API配置!包含 4 个API +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:177] - 成功获取业务API配置,包含 4 个API配置 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:181] - 配置已存储到内存变量: businessu9ua9ss2l8c +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:182] - 当前内存中共有 1 个租户配置 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:292] - 服务器配置 - 名称: lzwcai-mcp-dyntoolapi, 版本: 1.0.0 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.core.api_base - INFO - [api_base.py:262] - 开始处理 4 个API配置 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.core.api_base - INFO - [api_base.py:317] - API配置处理完成,成功处理 4 个配置 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.core.api_base - INFO - [api_base.py:389] - ApiBase初始化完成,共处理 4 个API配置 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:307] - API 基础服务初始化完成,共 4 个API配置 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:506] - 注册API工具插件 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:509] - API工具插件注册完成 +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:779] - 配置文件监控功能已禁用(如需启用,请设置环境变量ENABLE_CONFIG_WATCH=true) +2025-12-30 11:48:23 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:578] - 启动STDIO传输模式 +2025-12-30 11:48:24 - lzwcai_mcp_api_converter.src.create_mcp - INFO - [create_mcp.py:391] - 返回工具列表,共 4 个工具 diff --git a/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/__pycache__/create_mcp.cpython-312.pyc b/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/__pycache__/create_mcp.cpython-312.pyc index 3e4cf82b9b0d752436068f98075bc3a0696e2461..1718742b144e53e3ff1ec341e8023a05d5b5376f 100644 GIT binary patch delta 1268 zcmYk5YfKbZ6vyYzYag(|DOMx zbI+Z7=ked<*kh7+-Q#g{>^aleqW^YyGVgX3Ny5FV=d2gj1iT~#{ecjXU@EYIMB$gf z=C!J*N~)|nMtRk#y0W9Fy0c@>sG#Pmo-SU^8x;C8_mu8D<#Ej54St9LbPz0)DMR%OWSanm^4BJVy0|}jKs$F1o?$>%E z9V#@0mY0gO71OdEO5gU5V{sbLMs|X4BVMmLW6vp)kCS z+=2FR9r3|%xO|h7E3N!VshxRAP5ZUEbsMK&OIPfgQ);HG)BffM4zZ#rB zuY0h}SynLY$rOPVE-##`tX*(PD~kRQ9Qg&AGM}elp%&)DYlLTCthc=N_Z^Px#^?aZ zTN=p$t9c70IVScWMkL_o)_rmcWgpZujFBNL-C*d_}bGH8~veX*529 zKX(U+-`cQ8A>=%~+WIm%Wu0qXAincxe~Or3PWK>CV_b}Jfv#z98lq#lrNut3V1)z>@84G<`mW?5j;O47@cyx1Xx`l@{x zwIyuFq^p^xm56B=>LfQTYm82)kA h_r%mhx3-x+w7iF!N&Wy&B4oI6fy;`_b{S}D=wGHkh#mj{ delta 1021 zcmYL{ZETBC6vv;__IcW_I;)qm#g^HaG?;j6m$eooGpUh^4<=JnYeTEry3aGT8x|jk zZOJyryT~ji-aqgx5+WE92|`4KJYK>F5hP1P#cRSnYclu4@BZ)qoO|xMxwqpF{P_vF z53JT4fsb#sBf@K%FXg^0gZ=oaY@TYJvOEub*x;%J10HqFfLgros)80AFptH>6{V$y ze7>zk7Zho}Af4A!89_J?*%^e6W!P0QafVT`WgVV996crkO~>{Bb6bQJ!bSa7aG2G% z6>-3yl@mtlSsmZVR&r>Ta13X;n?S@f?rAw}E%#)R0|(tTa2lPS*0IB(Es(hN#65n?jhtG%#64OBC*M0hpkCTzqv zi~Q1Nk}+IR(*rxycQu;Mmf((Nh=yf_ZKPlnA9@R5D}M0KmMF$rv3N;^vy00gtwP!^ zk7^JeUti{PN#ZPPfBKG1it>N7jg=RBIzo%bICJ+-56Rr7aps} zmUijj6;AWDTlP@py@YnW?VD*zfw&mHY}2d1eMX~nhywf3ROf;*>ijwfKo3S%ErV|L z>Z%Nk>!I)oLNA9y$4-(yhj;58;KsrFuSEyAq1k06z@i~V36%#DiDNA+{yN%4H=Oj$bsP7}wO>hTC%S?R8jZX zq<$1OiEB2Qa0NS)mEvnI-{GTVzrB;peh$q{x2JC<^AB`5HC=i^p?mls)ejxm+B`n* z1{pUAw+I7xrn#_w=!N{WZXnbXZWD&yeGaLq1iBrgyD;jXQFn~mVD#PCI>HK$Unb9{ gc(5rNs$w72;+ExLV>$>xmp3B}iF885UEACK0hCiISpWb4 diff --git a/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/business/__pycache__/get_business_api.cpython-312.pyc b/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/business/__pycache__/get_business_api.cpython-312.pyc index f5849edd4a65f44f06bbd3bc676afd0c2e0a9383..eb2aa08f68b16f98d62ed8b2fa0b2b279ae72e3a 100644 GIT binary patch delta 384 zcmaFoIMa#mG%qg~0}z-d`(-l7Zsfbn$kf6zd5WOYWL730y%d(!OdweXhFX>ymSXM_ zRtS%QA%%4{BZS?=n8H@eTEmjXJvotCSe_jwUc*`i(#Mv3)gVXW=Ij4 zyq{T}QFQWiW^YEZ$;K?^k`g8IF!$B)z)S_Il$_kmk~!IrRco>ss|BO19RI_tSgFdUU|wD+)QJ}xfduFrg2UlYha UA)(}9#eBkw)x&;so?rt%0MRg0^I1C_CAdO;u2=mbZ?#oUxptf;p0*oKaJ5b2i&%=FKi#pI8`; zCY$ryGGFF5-dx51n^8r>SV*mgE diff --git a/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/core/__pycache__/get_auth.cpython-312.pyc b/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/core/__pycache__/get_auth.cpython-312.pyc index cded94361504df0e3520d1d7d2ad9b1f9dcfd846..a9d721efae1a6e57ff01f60b55fac2b4e095a52a 100644 GIT binary patch delta 186 zcmdm!@H~O{G%qg~0}xmw`(@79$h(h)>mQIeouP)YL3uK#yqsJLQwsBHCXf;ahFZoN z#$xUgRtS%QA%$f!KdT}m>tsXLR&llz_7sj3&N&ZsU3CC6iZQDI delta 130 zcmaE!uqT1{G%qg~0}vdI_scBY$h(h)>kp7OouP)YL22?;7KO=j>KsC~j5UnK+$F3a zg&>f^JXw%caWbzk=VWWvT5;ACwiNahjycS$86onF43&(UoRiP99$+o?2MSGgWK-RI XpRJdXv0!p8hdA?PaqG=p9Cy_LKpr3f diff --git a/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/create_mcp.py b/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/create_mcp.py index 18c9d55..3809e6a 100644 --- a/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/create_mcp.py +++ b/lzwcai_mcp_api_converter/lzwcai_mcp_api_converter/src/create_mcp.py @@ -367,12 +367,24 @@ class ApiToolPlugin(ToolPlugin): tool_name = tool_config["interfaceName"] # 工具名称(拼音格式) logger.debug(f"注册工具: {tool_name}") + # 定义输出 Schema(先写死一个测试) + output_schema = { + "type": "object", + "properties": { + "code": {"type": "integer", "description": "响应状态码,0表示成功"}, + "message": {"type": "string", "description": "响应消息"}, + "data": {"type": "object", "description": "响应数据"} + }, + "required": ["code", "message"] + } + # 创建MCP工具定义 tools.append( types.Tool( name=tool_name, # 工具名称 description=tool_config["schema_description"], # 工具描述(包含参数说明) inputSchema=tool_config["schema"], # 输入参数的JSON Schema + outputSchema=output_schema, # 输出参数的JSON Schema ) ) diff --git a/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor.log b/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor.log index e3c00dd..5d46ebb 100644 --- a/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor.log +++ b/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor.log @@ -49,3 +49,226 @@ 2025-10-23 15:08:31 - mcp_services - INFO - [main.py:128] - API配置: 1 条 2025-10-23 15:08:31 - mcp_services - INFO - [main.py:129] - API配置数组: [{'id': '1981245768769118209', 'businessName': '数字员工列表查询', 'businessDescription': '查询系统中的所有数字员工信息,包括员工ID、名称、类型、状态等核心信息,用于展示数字员工管理列表', 'sqlTemplate': 'SELECT id, employee_id, name, employee_type, status, created_at, updated_at, description FROM digital_employees WHERE is_deleted = 0 ORDER BY created_at DESC', 'parameters': {'type': 'object', 'required': ['employeeId'], 'properties': {'employeeId': {'type': 'number', 'description': '员工ID,用于标识员工的唯一数字标识符', 'examples': [1001, 2002]}}}, 'datasourceId': '32'}] 2025-10-23 15:08:31 - mcp_services - INFO - [main.py:165] - 成功生成 1 个 MCP 工具 +2025-12-31 12:57:27 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\logs +2025-12-31 12:57:27 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 16 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://192.168.11.24:8088 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 12:57:28 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: api)... +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:278] - 调用第三方API,skill_id: +2025-12-31 12:57:28 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:71] - 正在调用API: http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - httpx - INFO - [_client.py:1025] - HTTP Request: GET http://192.168.11.24:8088/datasource/skill/getBySkillId/ "HTTP/1.1 404 " +2025-12-31 12:57:29 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:97] - API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:98] - 错误响应: {"timestamp":"2025-12-31T12:57:30.248+08:00","status":404,"error":"Not Found","path":"/datasource/skill/getBySkillId/"} +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:292] - API调用失败: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 80, in get_skill_by_id + response.raise_for_status() + File "D:\anaconda3\Lib\site-packages\httpx\_models.py", line 829, in raise_for_status + raise HTTPStatusError(message, request=request, response=self) +httpx.HTTPStatusError: Client error '404 ' for url 'http://192.168.11.24:8088/datasource/skill/getBySkillId/' +For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404 + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 281, in call_third_party_api + raw_result = get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 208, in get_skill_by_id + return default_client.get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 99, in get_skill_by_id + raise Exception(error_msg) +Exception: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - mcp_services - WARNING - [main.py:131] - API获取失败,降级使用本地配置: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - mcp_services - INFO - [main.py:55] - 成功加载 3 个业务查询配置 +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 12:57:29 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:54 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\logs +2025-12-31 12:57:54 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 16 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://192.168.11.24:8088 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 12:57:54 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)... +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:55] - 成功加载 3 个业务查询配置 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:123] - 本地配置: 3 条 +2025-12-31 12:57:54 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:54 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:31 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 15:00:31 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:31 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:31 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:34 - mcp_services - INFO - [main.py:329] - MCP 服务器已关闭 +2025-12-31 15:00:53 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\logs +2025-12-31 15:00:53 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 29 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://lzwcai-demp-corp-manager:8086 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 15:00:54 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: api)... +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:278] - 调用第三方API,skill_id: +2025-12-31 15:00:54 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:71] - 正在调用API: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/ +2025-12-31 15:00:56 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:103] - API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - ERROR - [main.py:292] - API调用失败: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +Traceback (most recent call last): + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 101, in map_httpcore_exceptions + yield + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 250, in handle_request + resp = self._pool.handle_request(req) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection_pool.py", line 216, in handle_request + raise exc from None + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection_pool.py", line 196, in handle_request + response = connection.handle_request( + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 99, in handle_request + raise exc + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 76, in handle_request + stream = self._connect(request) + ^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 122, in _connect + stream = self._network_backend.connect_tcp(**kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_backends\sync.py", line 205, in connect_tcp + with map_exceptions(exc_map): + ^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "D:\anaconda3\Lib\site-packages\httpcore\_exceptions.py", line 14, in map_exceptions + raise to_exc(exc) from exc +httpcore.ConnectError: [Errno 11001] getaddrinfo failed + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 74, in get_skill_by_id + response = self.client.get( + ^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 1053, in get + return self.request( + ^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 825, in request + return self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 914, in send + response = self._send_handling_auth( + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 942, in _send_handling_auth + response = self._send_handling_redirects( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 979, in _send_handling_redirects + response = self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 1014, in _send_single_request + response = transport.handle_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 249, in handle_request + with map_httpcore_exceptions(): + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 118, in map_httpcore_exceptions + raise mapped_exc(message) from exc +httpx.ConnectError: [Errno 11001] getaddrinfo failed + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 281, in call_third_party_api + raw_result = get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 208, in get_skill_by_id + return default_client.get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 104, in get_skill_by_id + raise Exception(error_msg) +Exception: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - WARNING - [main.py:131] - API获取失败,降级使用本地配置: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:55] - 成功加载 0 个业务查询配置 +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:165] - 成功生成 0 个 MCP 工具 +2025-12-31 15:00:56 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:165] - 成功生成 0 个 MCP 工具 diff --git a/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor_daily.log b/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor_daily.log index e3c00dd..bb8c9e3 100644 --- a/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor_daily.log +++ b/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor_daily.log @@ -1,51 +1,223 @@ -2025-10-23 15:05:51 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\logs -2025-10-23 15:05:51 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5 -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:341] - 开始运行 MCP SQL Executor 服务器 -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:293] - ============================================================ -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:294] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:295] - 版本: 0.1.0 -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:296] - ============================================================ -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:300] - 环境配置 - Database ID: 29 -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:301] - 环境配置 - Skill ID: 1981195682443014146 -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:302] - 环境配置 - Backend Base URL: http://192.168.2.236:8088 -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:303] - ============================================================ -2025-10-23 15:05:51 - mcp_services - INFO - [main.py:308] - MCP 服务器已启动,等待客户端连接... -2025-10-23 15:05:52 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest -2025-10-23 15:05:52 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 -2025-10-23 15:05:52 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: api)... -2025-10-23 15:05:52 - mcp_services - INFO - [main.py:272] - 调用第三方API,skill_id: 1981195682443014146 -2025-10-23 15:05:52 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:71] - 正在调用API: http://192.168.2.236:8088/datasource/skill/getBySkillId/1981195682443014146 -2025-10-23 15:05:52 - httpx - INFO - [_client.py:1025] - HTTP Request: GET http://192.168.2.236:8088/datasource/skill/getBySkillId/1981195682443014146 "HTTP/1.1 200 " -2025-10-23 15:05:52 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:85] - API调用成功: http://192.168.2.236:8088/datasource/skill/getBySkillId/1981195682443014146 -2025-10-23 15:05:52 - mcp_services - INFO - [main.py:277] - 成功{'msg': '查询失败: 技能不存在: 1981195682443014146', 'code': 500} -2025-10-23 15:05:52 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:297] - 成功处理 0 条技能数据 -2025-10-23 15:05:52 - mcp_services - INFO - [main.py:282] - 成功获取并处理 0 条数据 -2025-10-23 15:05:52 - mcp_services - INFO - [main.py:128] - API配置: 0 条 -2025-10-23 15:05:52 - mcp_services - INFO - [main.py:129] - API配置数组: [] -2025-10-23 15:05:52 - mcp_services - INFO - [main.py:165] - 成功生成 0 个 MCP 工具 -2025-10-23 15:08:30 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\logs -2025-10-23 15:08:30 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5 -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:341] - 开始运行 MCP SQL Executor 服务器 -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:293] - ============================================================ -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:294] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:295] - 版本: 0.1.0 -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:296] - ============================================================ -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:300] - 环境配置 - Database ID: 29 -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:301] - 环境配置 - Skill ID: 1981245768471322626 -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:302] - 环境配置 - Backend Base URL: http://192.168.2.236:8088 -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:303] - ============================================================ -2025-10-23 15:08:30 - mcp_services - INFO - [main.py:308] - MCP 服务器已启动,等待客户端连接... -2025-10-23 15:08:31 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest -2025-10-23 15:08:31 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 -2025-10-23 15:08:31 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: api)... -2025-10-23 15:08:31 - mcp_services - INFO - [main.py:272] - 调用第三方API,skill_id: 1981245768471322626 -2025-10-23 15:08:31 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:71] - 正在调用API: http://192.168.2.236:8088/datasource/skill/getBySkillId/1981245768471322626 -2025-10-23 15:08:31 - httpx - INFO - [_client.py:1025] - HTTP Request: GET http://192.168.2.236:8088/datasource/skill/getBySkillId/1981245768471322626 "HTTP/1.1 200 " -2025-10-23 15:08:31 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:85] - API调用成功: http://192.168.2.236:8088/datasource/skill/getBySkillId/1981245768471322626 -2025-10-23 15:08:31 - mcp_services - INFO - [main.py:277] - 成功{'msg': '查询成功', 'code': 200, 'data': [{'id': '1981245768769118209', 'createBy': 'yy8z6', 'createTime': '2025-10-23 14:26:16', 'updateBy': None, 'updateTime': None, 'serviceId': '1981245768475516930', 'uniqueName': '数字员工技能描述-SQL服务_数字员工列表查询', 'name': '数字员工列表查询', 'description': '查询系统中的所有数字员工信息,包括员工ID、名称、类型、状态等核心信息,用于展示数字员工管理列表', 'visualizable': 1, 'toolPrompt': '查询数字员工列表', 'toolType': 'sql', 'datasourceId': '32', 'sqlTemplate': 'SELECT id, employee_id, name, employee_type, status, created_at, updated_at, description FROM digital_employees WHERE is_deleted = 0 ORDER BY created_at DESC', 'sqlParams': '{"type":"object","required":[],"properties":{}}', 'resultType': 'list', 'sourceType': 'ai', 'trainingTaskId': None, 'tableMetadataIds': '889,890,891,892,893,894,895,896', 'executionCount': 0, 'visualizationConfigs': None, 'inputJsonSchema': '{}', 'outputJsonSchema': '{"type":"object","properties":{"data":{"type":"array"}}}', 'lastExecutionTime': None}]} -2025-10-23 15:08:31 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:283] - 技能 数字员工列表查询 (ID: 1981245768769118209) 的sqlParams为空,使用默认员工ID参数 -2025-10-23 15:08:31 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:297] - 成功处理 1 条技能数据 -2025-10-23 15:08:31 - mcp_services - INFO - [main.py:282] - 成功获取并处理 1 条数据 -2025-10-23 15:08:31 - mcp_services - INFO - [main.py:128] - API配置: 1 条 -2025-10-23 15:08:31 - mcp_services - INFO - [main.py:129] - API配置数组: [{'id': '1981245768769118209', 'businessName': '数字员工列表查询', 'businessDescription': '查询系统中的所有数字员工信息,包括员工ID、名称、类型、状态等核心信息,用于展示数字员工管理列表', 'sqlTemplate': 'SELECT id, employee_id, name, employee_type, status, created_at, updated_at, description FROM digital_employees WHERE is_deleted = 0 ORDER BY created_at DESC', 'parameters': {'type': 'object', 'required': ['employeeId'], 'properties': {'employeeId': {'type': 'number', 'description': '员工ID,用于标识员工的唯一数字标识符', 'examples': [1001, 2002]}}}, 'datasourceId': '32'}] -2025-10-23 15:08:31 - mcp_services - INFO - [main.py:165] - 成功生成 1 个 MCP 工具 +2025-12-31 12:57:27 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\logs +2025-12-31 12:57:27 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 16 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://192.168.11.24:8088 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 12:57:28 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: api)... +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:278] - 调用第三方API,skill_id: +2025-12-31 12:57:28 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:71] - 正在调用API: http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - httpx - INFO - [_client.py:1025] - HTTP Request: GET http://192.168.11.24:8088/datasource/skill/getBySkillId/ "HTTP/1.1 404 " +2025-12-31 12:57:29 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:97] - API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:98] - 错误响应: {"timestamp":"2025-12-31T12:57:30.248+08:00","status":404,"error":"Not Found","path":"/datasource/skill/getBySkillId/"} +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:292] - API调用失败: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 80, in get_skill_by_id + response.raise_for_status() + File "D:\anaconda3\Lib\site-packages\httpx\_models.py", line 829, in raise_for_status + raise HTTPStatusError(message, request=request, response=self) +httpx.HTTPStatusError: Client error '404 ' for url 'http://192.168.11.24:8088/datasource/skill/getBySkillId/' +For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404 + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 281, in call_third_party_api + raw_result = get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 208, in get_skill_by_id + return default_client.get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 99, in get_skill_by_id + raise Exception(error_msg) +Exception: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - mcp_services - WARNING - [main.py:131] - API获取失败,降级使用本地配置: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - mcp_services - INFO - [main.py:55] - 成功加载 3 个业务查询配置 +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 12:57:29 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:54 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\logs +2025-12-31 12:57:54 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 16 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://192.168.11.24:8088 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 12:57:54 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)... +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:55] - 成功加载 3 个业务查询配置 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:123] - 本地配置: 3 条 +2025-12-31 12:57:54 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:54 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:31 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 15:00:31 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:31 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:31 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:34 - mcp_services - INFO - [main.py:329] - MCP 服务器已关闭 +2025-12-31 15:00:53 - root - INFO - [logger_config.py:151] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\logs +2025-12-31 15:00:53 - root - INFO - [logger_config.py:152] - 日志配置 - 级别: INFO, 文件大小限制: 10MB, 备份数量: 5 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 29 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://lzwcai-demp-corp-manager:8086 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 15:00:54 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: api)... +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:278] - 调用第三方API,skill_id: +2025-12-31 15:00:54 - lzwcai_mcp_sqlexecutor.utils.api_client - INFO - [api_client.py:71] - 正在调用API: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/ +2025-12-31 15:00:56 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:103] - API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - ERROR - [main.py:292] - API调用失败: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +Traceback (most recent call last): + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 101, in map_httpcore_exceptions + yield + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 250, in handle_request + resp = self._pool.handle_request(req) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection_pool.py", line 216, in handle_request + raise exc from None + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection_pool.py", line 196, in handle_request + response = connection.handle_request( + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 99, in handle_request + raise exc + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 76, in handle_request + stream = self._connect(request) + ^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 122, in _connect + stream = self._network_backend.connect_tcp(**kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_backends\sync.py", line 205, in connect_tcp + with map_exceptions(exc_map): + ^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "D:\anaconda3\Lib\site-packages\httpcore\_exceptions.py", line 14, in map_exceptions + raise to_exc(exc) from exc +httpcore.ConnectError: [Errno 11001] getaddrinfo failed + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 74, in get_skill_by_id + response = self.client.get( + ^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 1053, in get + return self.request( + ^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 825, in request + return self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 914, in send + response = self._send_handling_auth( + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 942, in _send_handling_auth + response = self._send_handling_redirects( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 979, in _send_handling_redirects + response = self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 1014, in _send_single_request + response = transport.handle_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 249, in handle_request + with map_httpcore_exceptions(): + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 118, in map_httpcore_exceptions + raise mapped_exc(message) from exc +httpx.ConnectError: [Errno 11001] getaddrinfo failed + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 281, in call_third_party_api + raw_result = get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 208, in get_skill_by_id + return default_client.get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 104, in get_skill_by_id + raise Exception(error_msg) +Exception: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - WARNING - [main.py:131] - API获取失败,降级使用本地配置: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:55] - 成功加载 0 个业务查询配置 +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:165] - 成功生成 0 个 MCP 工具 +2025-12-31 15:00:56 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:165] - 成功生成 0 个 MCP 工具 diff --git a/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor_error.log b/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor_error.log index e69de29..7858e72 100644 --- a/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor_error.log +++ b/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/lzwcai_mcp_sqlexecutor_error.log @@ -0,0 +1,158 @@ +2025-12-31 12:57:29 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:97] - API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:98] - 错误响应: {"timestamp":"2025-12-31T12:57:30.248+08:00","status":404,"error":"Not Found","path":"/datasource/skill/getBySkillId/"} +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:292] - API调用失败: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 80, in get_skill_by_id + response.raise_for_status() + File "D:\anaconda3\Lib\site-packages\httpx\_models.py", line 829, in raise_for_status + raise HTTPStatusError(message, request=request, response=self) +httpx.HTTPStatusError: Client error '404 ' for url 'http://192.168.11.24:8088/datasource/skill/getBySkillId/' +For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404 + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 281, in call_third_party_api + raw_result = get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 208, in get_skill_by_id + return default_client.get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 99, in get_skill_by_id + raise Exception(error_msg) +Exception: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:54 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:54 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:31 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:31 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:56 - lzwcai_mcp_sqlexecutor.utils.api_client - ERROR - [api_client.py:103] - API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - ERROR - [main.py:292] - API调用失败: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +Traceback (most recent call last): + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 101, in map_httpcore_exceptions + yield + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 250, in handle_request + resp = self._pool.handle_request(req) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection_pool.py", line 216, in handle_request + raise exc from None + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection_pool.py", line 196, in handle_request + response = connection.handle_request( + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 99, in handle_request + raise exc + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 76, in handle_request + stream = self._connect(request) + ^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 122, in _connect + stream = self._network_backend.connect_tcp(**kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_backends\sync.py", line 205, in connect_tcp + with map_exceptions(exc_map): + ^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "D:\anaconda3\Lib\site-packages\httpcore\_exceptions.py", line 14, in map_exceptions + raise to_exc(exc) from exc +httpcore.ConnectError: [Errno 11001] getaddrinfo failed + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 74, in get_skill_by_id + response = self.client.get( + ^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 1053, in get + return self.request( + ^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 825, in request + return self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 914, in send + response = self._send_handling_auth( + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 942, in _send_handling_auth + response = self._send_handling_redirects( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 979, in _send_handling_redirects + response = self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 1014, in _send_single_request + response = transport.handle_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 249, in handle_request + with map_httpcore_exceptions(): + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 118, in map_httpcore_exceptions + raise mapped_exc(message) from exc +httpx.ConnectError: [Errno 11001] getaddrinfo failed + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 281, in call_third_party_api + raw_result = get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 208, in get_skill_by_id + return default_client.get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 104, in get_skill_by_id + raise Exception(error_msg) +Exception: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed diff --git a/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/mcp_services.log b/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/mcp_services.log index dedb405..c945346 100644 --- a/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/mcp_services.log +++ b/lzwcai_mcp_sqlexecutor/lzwcai_mcp_sqlexecutor/logs/mcp_services.log @@ -34,3 +34,208 @@ 2025-10-23 15:08:31 - mcp_services - INFO - [main.py:128] - API配置: 1 条 2025-10-23 15:08:31 - mcp_services - INFO - [main.py:129] - API配置数组: [{'id': '1981245768769118209', 'businessName': '数字员工列表查询', 'businessDescription': '查询系统中的所有数字员工信息,包括员工ID、名称、类型、状态等核心信息,用于展示数字员工管理列表', 'sqlTemplate': 'SELECT id, employee_id, name, employee_type, status, created_at, updated_at, description FROM digital_employees WHERE is_deleted = 0 ORDER BY created_at DESC', 'parameters': {'type': 'object', 'required': ['employeeId'], 'properties': {'employeeId': {'type': 'number', 'description': '员工ID,用于标识员工的唯一数字标识符', 'examples': [1001, 2002]}}}, 'datasourceId': '32'}] 2025-10-23 15:08:31 - mcp_services - INFO - [main.py:165] - 成功生成 1 个 MCP 工具 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 16 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://192.168.11.24:8088 +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 12:57:27 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: api)... +2025-12-31 12:57:28 - mcp_services - INFO - [main.py:278] - 调用第三方API,skill_id: +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:292] - API调用失败: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 80, in get_skill_by_id + response.raise_for_status() + File "D:\anaconda3\Lib\site-packages\httpx\_models.py", line 829, in raise_for_status + raise HTTPStatusError(message, request=request, response=self) +httpx.HTTPStatusError: Client error '404 ' for url 'http://192.168.11.24:8088/datasource/skill/getBySkillId/' +For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404 + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 281, in call_third_party_api + raw_result = get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 208, in get_skill_by_id + return default_client.get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 99, in get_skill_by_id + raise Exception(error_msg) +Exception: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - mcp_services - WARNING - [main.py:131] - API获取失败,降级使用本地配置: API请求失败 (HTTP 404): http://192.168.11.24:8088/datasource/skill/getBySkillId/ +2025-12-31 12:57:29 - mcp_services - INFO - [main.py:55] - 成功加载 3 个业务查询配置 +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:29 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 16 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://192.168.11.24:8088 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)... +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:55] - 成功加载 3 个业务查询配置 +2025-12-31 12:57:54 - mcp_services - INFO - [main.py:123] - 本地配置: 3 条 +2025-12-31 12:57:54 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 12:57:54 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:31 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:31 - mcp_services - ERROR - [main.py:92] - 生成工具模式失败: 2006300000000000001, 错误: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:31 - mcp_services - ERROR - [main.py:170] - 列出工具失败: 'businessName' +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 162, in handle_list_tools + tool = generate_tool_schema_from_query(query) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 80, in generate_tool_schema_from_query + tool_name = query['businessName'] + ~~~~~^^^^^^^^^^^^^^^^ +KeyError: 'businessName' +2025-12-31 15:00:34 - mcp_services - INFO - [main.py:329] - MCP 服务器已关闭 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:347] - 开始运行 MCP SQL Executor 服务器 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:299] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:300] - 正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:301] - 版本: 0.1.0 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:302] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:306] - 环境配置 - Database ID: 29 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:307] - 环境配置 - Skill ID: +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:308] - 环境配置 - Backend Base URL: http://lzwcai-demp-corp-manager:8086 +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:309] - ============================================================ +2025-12-31 15:00:53 - mcp_services - INFO - [main.py:314] - MCP 服务器已启动,等待客户端连接... +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: api)... +2025-12-31 15:00:54 - mcp_services - INFO - [main.py:278] - 调用第三方API,skill_id: +2025-12-31 15:00:56 - mcp_services - ERROR - [main.py:292] - API调用失败: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +Traceback (most recent call last): + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 101, in map_httpcore_exceptions + yield + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 250, in handle_request + resp = self._pool.handle_request(req) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection_pool.py", line 216, in handle_request + raise exc from None + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection_pool.py", line 196, in handle_request + response = connection.handle_request( + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 99, in handle_request + raise exc + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 76, in handle_request + stream = self._connect(request) + ^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_sync\connection.py", line 122, in _connect + stream = self._network_backend.connect_tcp(**kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpcore\_backends\sync.py", line 205, in connect_tcp + with map_exceptions(exc_map): + ^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "D:\anaconda3\Lib\site-packages\httpcore\_exceptions.py", line 14, in map_exceptions + raise to_exc(exc) from exc +httpcore.ConnectError: [Errno 11001] getaddrinfo failed + +The above exception was the direct cause of the following exception: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 74, in get_skill_by_id + response = self.client.get( + ^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 1053, in get + return self.request( + ^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 825, in request + return self.send(request, auth=auth, follow_redirects=follow_redirects) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 914, in send + response = self._send_handling_auth( + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 942, in _send_handling_auth + response = self._send_handling_redirects( + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 979, in _send_handling_redirects + response = self._send_single_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_client.py", line 1014, in _send_single_request + response = transport.handle_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 249, in handle_request + with map_httpcore_exceptions(): + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "D:\anaconda3\Lib\contextlib.py", line 158, in __exit__ + self.gen.throw(value) + File "D:\anaconda3\Lib\site-packages\httpx\_transports\default.py", line 118, in map_httpcore_exceptions + raise mapped_exc(message) from exc +httpx.ConnectError: [Errno 11001] getaddrinfo failed + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\main.py", line 281, in call_third_party_api + raw_result = get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 208, in get_skill_by_id + return default_client.get_skill_by_id(skill_id) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcp_sqlexecutor\lzwcai_mcp_sqlexecutor\utils\api_client.py", line 104, in get_skill_by_id + raise Exception(error_msg) +Exception: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - WARNING - [main.py:131] - API获取失败,降级使用本地配置: API请求异常: http://lzwcai-demp-corp-manager:8086/datasource/skill/getBySkillId/, 错误: [Errno 11001] getaddrinfo failed +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:55] - 成功加载 0 个业务查询配置 +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:165] - 成功生成 0 个 MCP 工具 +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:156] - 收到列出工具请求 +2025-12-31 15:00:56 - mcp_services - INFO - [main.py:165] - 成功生成 0 个 MCP 工具 diff --git a/lzwcai_mcpskills_analyzeWorkOrder/README.md b/lzwcai_mcpskills_analyzeWorkOrder/README.md new file mode 100644 index 0000000..44ee71d --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/README.md @@ -0,0 +1,138 @@ +# lzwcai-mcp-sqlexecutor + +一个基于 MCP (Model Context Protocol) 的 SQL 查询执行服务器,支持从 JSON 配置文件动态生成查询工具。 + +## 功能特性 + +- 🚀 动态工具生成:从 `businessQueries.json` 自动生成 MCP 工具 +- 🔧 灵活配置:支持自定义业务查询和参数验证 +- 📝 完整日志:详细的操作日志记录 +- 🌐 中文支持:工具名称自动转换为拼音 + +## 安装 + +### 使用 pip 安装 + +```bash +pip install lzwcai-mcp-sqlexecutor +``` + +### 从源码安装 + +```bash +git clone +cd lzwcai_mcp_sqlexecutor +pip install -e . +``` + +### 使用 uv 安装(推荐) + +```bash +uv pip install lzwcai-mcp-sqlexecutor +``` + +## 使用方法 + +### 命令行启动 + +安装后,可以直接通过命令启动: + +```bash +lzwcai-mcp-sqlexecutor +``` + +### 作为 Python 模块运行 + +```bash +python -m lzwcai_mcp_sqlexecutor.main +``` + +### 配置到 MCP 客户端 + +在你的 MCP 客户端配置文件中添加: + +```json +{ + "mcpServers": { + "lzwcai-sqlexecutor": { + "command": "lzwcai-mcp-sqlexecutor" + } + } +} +``` + +## 配置说明 + +### businessQueries.json + +在 `businessQueries.json` 中定义你的业务查询: + +```json +[ + { + "id": "query-001", + "businessName": "用户订单查询", + "businessDescription": "根据用户ID查询订单信息", + "sqlTemplate": "SELECT * FROM orders WHERE user_id = {{userId}}", + "parameters": { + "type": "object", + "required": ["userId"], + "properties": { + "userId": { + "type": "integer", + "description": "用户的唯一标识符", + "examples": [10086] + } + } + } + } +] +``` + +## 开发 + +### 依赖项 + +- Python >= 3.13 +- httpx >= 0.28.1 +- mcp[cli] >= 1.10.1 +- pypinyin >= 0.53.0 + +### 本地开发 + +```bash +# 克隆仓库 +git clone +cd lzwcai_mcp_sqlexecutor + +# 安装开发依赖 +pip install -e . + +# 运行服务器 +python -m lzwcai_mcp_sqlexecutor.main +``` + +## 构建与发布 + +### 使用 build 构建 + +```bash +pip install build +python -m build +``` + +### 发布到 PyPI + +```bash +pip install twine +twine upload dist/* +``` + +## 许可证 + +MIT License + +## 作者 + +lzwcai + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/.gitignore b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/.gitignore new file mode 100644 index 0000000..505a3b1 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/.gitignore @@ -0,0 +1,10 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/.python-version b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/README.md b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/README.md new file mode 100644 index 0000000..7352630 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/README.md @@ -0,0 +1,154 @@ +# lzwcai-mcp-sqlexecutor + +一个基于 MCP (Model Context Protocol) 的 SQL 查询执行服务器,支持从 JSON 配置文件动态生成查询工具。 + +## 功能特性 + +- 🚀 动态工具生成:从 `businessQueries.json` 自动生成 MCP 工具 +- 🔧 灵活配置:支持自定义业务查询和参数验证 +- 📝 完整日志:详细的操作日志记录(仅输出到文件,不干扰MCP通信) +- 🌐 中文支持:工具名称自动转换为拼音 + +## 安装 + +### 使用 pip 安装 + +```bash +pip install lzwcai-mcp-sqlexecutor +``` + +### 从源码安装 + +```bash +git clone +cd lzwcai_mcp_sqlexecutor +pip install -e . +``` + +### 使用 uv 安装(推荐) + +```bash +uv pip install lzwcai-mcp-sqlexecutor +``` + +## 使用方法 + +### 命令行启动 + +安装后,可以直接通过命令启动: + +```bash +lzwcai-mcp-sqlexecutor +``` + +### 作为 Python 模块运行 + +```bash +python -m lzwcai_mcp_sqlexecutor.main +``` + +### 配置到 MCP 客户端 + +在你的 MCP 客户端配置文件中添加: + +```json +{ + "mcpServers": { + "lzwcai-sqlexecutor": { + "command": "lzwcai-mcp-sqlexecutor" + } + } +} +``` + +## 配置说明 + +### businessQueries.json + +在 `businessQueries.json` 中定义你的业务查询: + +```json +[ + { + "id": "query-001", + "businessName": "用户订单查询", + "businessDescription": "根据用户ID查询订单信息", + "sqlTemplate": "SELECT * FROM orders WHERE user_id = {{userId}}", + "parameters": { + "type": "object", + "required": ["userId"], + "properties": { + "userId": { + "type": "integer", + "description": "用户的唯一标识符", + "examples": [10086] + } + } + } + } +] +``` + +## 开发 + +### 依赖项 + +- Python >= 3.13 +- httpx >= 0.28.1 +- mcp[cli] >= 1.10.1 +- pypinyin >= 0.53.0 + +### 本地开发 + +```bash +# 克隆仓库 +git clone +cd lzwcai_mcp_sqlexecutor + +# 安装开发依赖 +pip install -e . + +# 运行服务器 +python -m lzwcai_mcp_sqlexecutor.main +``` + +## 构建与发布 + +### 使用 build 构建 + +```bash +pip install build +python -m build +``` + +### 发布到 PyPI + +```bash +pip install twine +twine upload dist/* +``` + +## 常见问题 + +### MCP Inspector 显示 JSON 解析错误 + +如果在使用 MCP Inspector 测试时遇到 `SyntaxError: Unexpected non-whitespace character after JSON` 错误,这是因为: + +1. **原因**:MCP 协议使用 stdio(标准输入输出)进行 JSON-RPC 通信,任何输出到 stdout 的内容(如 print 语句或控制台日志)都会破坏 JSON 格式。 + +2. **解决方案**:本服务器已将所有日志输出配置为仅写入文件(位于 `logs/` 目录),不输出到控制台。日志文件包括: + - `lzwcai_mcp_sqlexecutor.log` - 主日志文件 + - `lzwcai_mcp_sqlexecutor_error.log` - 错误日志 + - `lzwcai_mcp_sqlexecutor_daily.log` - 按日期滚动的日志 + - `mcp_services.log` - MCP 服务专用日志 + +3. **查看日志**:如果需要调试,请查看 `logs/` 目录下的日志文件。 + +## 许可证 + +MIT License + +## 作者 + +lzwcai + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/__init__.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/__init__.py new file mode 100644 index 0000000..5df6d9c --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/__init__.py @@ -0,0 +1,9 @@ +""" +lzwcai-mcp-sqlexecutor - MCP server for executing business SQL queries +""" + +__version__ = "0.1.2" +__author__ = "lzwcai" + +__all__ = [] + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/businessQueries.json b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/businessQueries.json new file mode 100644 index 0000000..9065654 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/businessQueries.json @@ -0,0 +1,35 @@ +[ + { + "id": "2006300000000000000", + "businessName": "查询列表", + "businessDescription": "查询所有工单列表,返回fact_work_order表的全部数据", + "datasourceId": "19", + "sqlTemplate": "SELECT * FROM fact_work_order", + "parameters": {} + }, + { + "id": "2006300000000000004", + "businessName": "工单详情", + "businessDescription": "根据工单编号查询工单详情,包括工单基本信息、产品信息、委外供应商、工艺路线等", + "datasourceId": "19", + "sqlTemplate": "SELECT wo.work_order_id, wo.work_order_number AS 工单编号, wo.status AS 工单状态, wo.planned_qty AS 计划数量, wo.completed_qty AS 完成数量, wo.operation_good_qty AS 工序良品数, wo.operation_bad_qty AS 工序不良品数, wo.qc_good_qty AS 质检良品数, wo.qc_bad_qty AS 质检不良品数, wo.source_doc_number AS 来源单据编号, wo.event_time_utc AS 事件时间, p.product_code AS 产品编码, p.product_name AS 产品名称, p.product_spec AS 产品规格, s.supplier_name AS 委外供应商, r.routing_name AS 工艺路线 FROM fact_work_order wo LEFT JOIN dim_product p ON wo.product_id = p.product_id AND p.is_current = true LEFT JOIN dim_supplier s ON wo.supplier_id = s.supplier_id AND s.is_current = true LEFT JOIN dim_routing r ON wo.routing_id = r.routing_id AND r.is_current = true WHERE wo.work_order_number = '{workOrderNumber}'", + "parameters": { + "workOrderNumber": { + "type": "string", + "description": "工单编号", + "required": true, + "examples": [ + "WO1311343859" + ] + } + } + }, + { + "id": "2006300000000000005", + "businessName": "工单执行进度与异常节点看板", + "businessDescription": "工单执行进度与异常节点看板,展示工单完工进度、工序良率、质检良率、异常标识等关键监控指标", + "datasourceId": "19", + "sqlTemplate": "WITH work_order_progress AS (SELECT wo.work_order_number, wo.status AS work_order_status, wo.planned_qty, wo.completed_qty, wo.operation_good_qty, wo.operation_bad_qty, wo.qc_good_qty, wo.qc_bad_qty, wo.source_doc_number AS sales_order_number, wo.event_time_utc, p.product_code, p.product_name, CASE WHEN wo.planned_qty > 0 THEN ROUND(wo.completed_qty * 100.0 / wo.planned_qty, 2) ELSE 0 END AS completion_pct, CASE WHEN (wo.operation_good_qty + wo.operation_bad_qty) > 0 THEN ROUND(wo.operation_good_qty * 100.0 / (wo.operation_good_qty + wo.operation_bad_qty), 2) ELSE NULL END AS operation_yield_pct, CASE WHEN (wo.qc_good_qty + wo.qc_bad_qty) > 0 THEN ROUND(wo.qc_good_qty * 100.0 / (wo.qc_good_qty + wo.qc_bad_qty), 2) ELSE NULL END AS qc_yield_pct FROM fact_work_order wo LEFT JOIN dim_product p ON wo.product_id = p.product_id AND p.is_current = true), task_summary AS (SELECT work_order_number, COUNT(*) AS total_tasks, SUM(CASE WHEN actual_end_time_utc IS NOT NULL THEN 1 ELSE 0 END) AS completed_tasks, SUM(CASE WHEN actual_start_time_utc IS NOT NULL AND actual_end_time_utc IS NULL THEN 1 ELSE 0 END) AS in_progress_tasks, SUM(CASE WHEN actual_start_time_utc IS NULL THEN 1 ELSE 0 END) AS pending_tasks, SUM(bad_qty) AS total_bad_qty FROM fact_operation_task GROUP BY work_order_number), labor_summary AS (SELECT work_order_number, SUM(report_qty) AS total_report_qty, SUM(good_qty) AS total_good_qty, SUM(bad_qty) AS total_bad_qty, SUM(duration_minutes) AS total_work_minutes FROM fact_labor_report GROUP BY work_order_number), qc_summary AS (SELECT work_order_number, COUNT(*) AS qc_record_count, SUM(pass_qty) AS total_pass_qty, SUM(fail_qty) AS total_fail_qty FROM fact_quality_inspection WHERE work_order_number IS NOT NULL GROUP BY work_order_number) SELECT wp.work_order_number AS 工单编号, wp.product_code AS 产品编码, wp.product_name AS 产品名称, wp.sales_order_number AS 关联销售订单, wp.work_order_status AS 工单状态, wp.planned_qty AS 计划数量, wp.completed_qty AS 完成数量, wp.completion_pct AS 完工进度百分比, COALESCE(ts.total_tasks, 0) AS 工序总数, COALESCE(ts.completed_tasks, 0) AS 已完成工序, COALESCE(ts.in_progress_tasks, 0) AS 进行中工序, COALESCE(ts.pending_tasks, 0) AS 待开始工序, COALESCE(ls.total_report_qty, 0) AS 累计报工数, COALESCE(ls.total_work_minutes, 0) AS 累计工时_分钟, wp.operation_yield_pct AS 工序良率, wp.qc_yield_pct AS 质检良率, COALESCE(qc.total_pass_qty, 0) AS 质检通过数, COALESCE(qc.total_fail_qty, 0) AS 质检不通过数, CASE WHEN wp.completion_pct < 50 AND wp.work_order_status = 'STARTED' THEN '进度滞后' WHEN wp.operation_yield_pct < 90 THEN '工序良率异常' WHEN wp.qc_yield_pct < 95 THEN '质检良率异常' WHEN ts.total_bad_qty > 0 THEN '存在不良品' ELSE '正常' END AS 异常标识, wp.event_time_utc AS 最后更新时间 FROM work_order_progress wp LEFT JOIN task_summary ts ON wp.work_order_number = ts.work_order_number LEFT JOIN labor_summary ls ON wp.work_order_number = ls.work_order_number LEFT JOIN qc_summary qc ON wp.work_order_number = qc.work_order_number ORDER BY CASE wp.work_order_status WHEN 'STARTED' THEN 1 WHEN 'RELEASED' THEN 2 WHEN 'PLANNED' THEN 3 ELSE 4 END, wp.event_time_utc DESC", + "parameters": {} + } +] \ No newline at end of file diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/main.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/main.py new file mode 100644 index 0000000..efc904c --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/main.py @@ -0,0 +1,358 @@ +from pathlib import Path +from typing import Any +import asyncio +import logging + +# 支持直接运行和模块导入两种方式 +try: + from .utils import load_json, generate_tool_name, generate_input_schema + from .utils import get_skill_by_id, DataSourceAPIClient, process_skill_response, test_sql_with_schema + from .utils import get_database_id, get_skill_id, get_env_config + from .utils.logger_config import logger_config +except ImportError: + from utils import load_json, generate_tool_name, generate_input_schema + from utils import get_skill_by_id, DataSourceAPIClient, process_skill_response, test_sql_with_schema + from utils import get_database_id, get_skill_id, get_env_config + from utils.logger_config import logger_config + +from mcp.server.models import InitializationOptions +from mcp.server import NotificationOptions, Server +import mcp.types as types + +# 初始化 MCP 专用日志器 +mcp_logger = logger_config.setup_mcp_logging() + +# ========== 数据源配置 ========== +# 数据源类型常量 +DATA_SOURCE_API = "api" # 仅使用API数据 +DATA_SOURCE_LOCAL = "local" # 仅使用本地JSON数据 +DATA_SOURCE_BOTH = "both" # 合并本地和API数据 + +# 默认数据源(可修改) +DEFAULT_DATA_SOURCE = DATA_SOURCE_LOCAL +# ================================ + + +def get_queries(): + """ + 获取业务查询配置 + + Returns: + list: 包含所有业务查询配置的列表 + """ + try: + # 获取当前文件所在目录 + current_dir = Path(__file__).parent + + # 构建 businessQueries.json 的路径 + json_path = current_dir / "businessQueries.json" + + mcp_logger.debug(f"正在读取业务查询配置文件: {json_path}") + + # 使用 load_json 方法读取 JSON 文件 + queries = load_json(json_path) + + mcp_logger.info(f"成功加载 {len(queries)} 个业务查询配置") + + return queries + except Exception as e: + mcp_logger.error(f"加载业务查询配置失败: {e}", exc_info=True) + raise + + +def generate_tool_schema_from_query(query: dict) -> types.Tool: + """ + 根据查询配置生成 MCP 工具模式 + + Args: + query: 单个查询配置字典 + + Returns: + types.Tool: MCP 工具对象 + """ + try: + # 获取参数定义并生成 inputSchema + parameters = query.get('parameters', {}) + input_schema = generate_input_schema(parameters) + + # 生成工具名称(格式: tool_拼音_id) + # tool_name = generate_tool_name(query['businessName'], query['id']) + tool_name = query['businessName'] + # 构建工具描述,包含业务名称和业务描述 + description = f"{query['businessName']}: {query['businessDescription']}" + + mcp_logger.debug(f"生成工具模式: {tool_name} - {query['businessName']}") + + return types.Tool( + name=tool_name, + description=description, + inputSchema=input_schema + ) + except Exception as e: + mcp_logger.error(f"生成工具模式失败: {query.get('id', 'unknown')}, 错误: {e}", exc_info=True) + raise + + +# 创建 MCP 服务器实例 +server = Server("lzwcai-mcp-sqlexecutor") + +# 缓存查询配置,避免重复加载 +_queries_cache = None + + +async def get_queries_cache(source: str = None): + """ + 获取或初始化查询配置缓存 + + Args: + source: 数据源类型(默认使用 DEFAULT_DATA_SOURCE) + - "api": 仅使用API数据 + - "local": 仅使用本地JSON数据 + - "both": 合并本地和API数据 + + Returns: + 查询配置列表 + """ + global _queries_cache + if _queries_cache is None: + source = source or DEFAULT_DATA_SOURCE + mcp_logger.info(f"初始化查询配置(数据源: {source})...") + + if source == DATA_SOURCE_LOCAL: + _queries_cache = get_queries() + mcp_logger.info(f"本地配置: {len(_queries_cache)} 条") + + elif source == DATA_SOURCE_API: + try: + _queries_cache = await call_third_party_api() + mcp_logger.info(f"API配置: {len(_queries_cache)} 条") + mcp_logger.info(f"API配置数组: {_queries_cache}") + except Exception as e: + mcp_logger.warning(f"API获取失败,降级使用本地配置: {e}") + _queries_cache = get_queries() + + else: # DATA_SOURCE_BOTH + local = get_queries() + try: + api = await call_third_party_api() + except Exception as e: + mcp_logger.warning(f"API获取失败: {e}") + api = [] + _queries_cache = local + api + mcp_logger.info(f"配置总数: {len(_queries_cache)} 条(本地{len(local)}+API{len(api)})") + + return _queries_cache + + +@server.list_tools() +async def handle_list_tools() -> list[types.Tool]: + """ + 列出所有动态生成的 MCP 工具 + + Returns: + list[types.Tool]: 所有可用的工具列表 + """ + try: + mcp_logger.info("收到列出工具请求") + + queries = await get_queries_cache() + tools = [] + + for query in queries: + tool = generate_tool_schema_from_query(query) + tools.append(tool) + + mcp_logger.info(f"成功生成 {len(tools)} 个 MCP 工具") + mcp_logger.debug(f"工具列表: {[tool.name for tool in tools]}") + + return tools + except Exception as e: + mcp_logger.error(f"列出工具失败: {e}", exc_info=True) + raise + + +@server.call_tool() +async def handle_call_tool( + name: str, + arguments: dict[str, Any] | None +) -> list[types.TextContent]: + """ + 处理工具调用请求 + + Args: + name: 工具名称 + arguments: 工具参数 + + Returns: + list[types.TextContent]: 工具执行结果(返回参数和对应的接口配置) + """ + try: + mcp_logger.info(f"收到工具调用请求: {name}") + mcp_logger.debug(f"工具参数: {arguments}") + + # 获取查询配置缓存 + queries = await get_queries_cache() + + # 根据工具名称查找对应的 item(接口配置) + tool_item = None + for query in queries: + # tool_name = generate_tool_name(query['businessName'], query['id']) + tool_name = query['businessName'] + if tool_name == name: + tool_item = query + break + + # 构建返回结果 + import json + + if tool_item: + request_data = { + "datasourceId": tool_item.get("datasourceId"), + "businessName": tool_item.get("businessName"), + "businessDescription": tool_item.get("businessDescription"), + "sqlTemplate": tool_item.get("sqlTemplate"), + "parameters": tool_item.get("parameters"), + "testParams": arguments or {} + } + + # 如果 arguments 中有 targetDatabaseName 且有值,添加到 request_data + if arguments and arguments.get("targetDatabaseName"): + request_data["targetDatabaseName"] = arguments["targetDatabaseName"] + mcp_logger.debug(f"添加目标数据库名称: {arguments['targetDatabaseName']}") + + # 调用测试SQL API + try: + mcp_logger.info("正在调用测试SQL API...") + api_response = test_sql_with_schema(request_data) + mcp_logger.info("测试SQL API调用成功") + + # 只返回 API 响应结果 + result_text = json.dumps(api_response, ensure_ascii=False, indent=2) + + except Exception as e: + error_msg = f"调用测试SQL API失败: {str(e)}" + mcp_logger.error(error_msg, exc_info=True) + result_text = json.dumps({"error": error_msg}, ensure_ascii=False, indent=2) + else: + error_msg = f"未找到工具 {name} 对应的配置" + result_text = json.dumps({"error": error_msg}, ensure_ascii=False, indent=2) + + mcp_logger.debug(f"工具调用结果: {result_text}") + + return [ + types.TextContent( + type="text", + text=result_text + ) + ] + except Exception as e: + error_msg = f"工具调用失败: {name}, 错误: {e}" + mcp_logger.error(error_msg, exc_info=True) + return [ + types.TextContent( + type="text", + text=f"错误: {error_msg}" + ) + ] + + +async def call_third_party_api(skill_id: str = None) -> list: + """ + 调用第三方API获取技能信息并返回处理后的数据 + + Args: + skill_id: 技能ID(默认从环境变量 SKILL_ID 读取,如果未设置则使用 1981000305474482178) + + Returns: + 处理后的查询配置列表(businessQueries格式) + + Example: + queries = await call_third_party_api() + # 返回: [{"id": "...", "businessName": "...", ...}, ...] + """ + try: + # 如果没有传入 skill_id,则从环境变量读取 + if skill_id is None: + skill_id = get_skill_id() + + mcp_logger.info(f"调用第三方API,skill_id: {skill_id}") + + # 获取原始数据 + raw_result = get_skill_by_id(skill_id) + + mcp_logger.info(f"成功{raw_result}") + + # 处理并返回 + processed_queries = process_skill_response(raw_result) + + mcp_logger.info(f"成功获取并处理 {len(processed_queries)} 条数据") + return processed_queries + + except Exception as e: + mcp_logger.error(f"API调用失败: {e}", exc_info=True) + raise + + +async def async_main(): + """MCP 服务器异步主函数""" + try: + mcp_logger.info("=" * 60) + mcp_logger.info("正在启动 MCP 服务器: lzwcai-mcp-sqlexecutor") + mcp_logger.info("版本: 0.1.0") + mcp_logger.info("=" * 60) + + # 输出环境配置信息 + env_config = get_env_config() + mcp_logger.info(f"环境配置 - Database ID: {env_config['database_id']}") + mcp_logger.info(f"环境配置 - Skill ID: {env_config['skill_id']}") + mcp_logger.info(f"环境配置 - Backend Base URL: {env_config['backend_base_url']}") + mcp_logger.info("=" * 60) + + from mcp.server.stdio import stdio_server + + async with stdio_server() as (read_stream, write_stream): + mcp_logger.info("MCP 服务器已启动,等待客户端连接...") + + await server.run( + read_stream, + write_stream, + InitializationOptions( + server_name="lzwcai-mcp-sqlexecutor", + server_version="0.1.0", + capabilities=server.get_capabilities( + notification_options=NotificationOptions(), + experimental_capabilities={}, + ), + ), + ) + + mcp_logger.info("MCP 服务器已关闭") + + except Exception as e: + mcp_logger.error(f"MCP 服务器运行失败: {e}", exc_info=True) + raise + + +def main(): + """入口点函数(用于 console_scripts)""" + try: + # 初始化系统日志 + # MCP协议使用stdio通信,必须禁用控制台输出以避免干扰JSON-RPC通信 + logger_config.setup_logging( + app_name="lzwcai_mcp_sqlexecutor", + log_level=logging.INFO, + console_output=False # 禁用控制台输出 + ) + + mcp_logger.info("开始运行 MCP SQL Executor 服务器") + asyncio.run(async_main()) + + except KeyboardInterrupt: + mcp_logger.info("收到中断信号,正在关闭服务器...") + except Exception as e: + mcp_logger.error(f"程序运行失败: {e}", exc_info=True) + raise + + +if __name__ == "__main__": + main() diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/pyproject.toml b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/pyproject.toml new file mode 100644 index 0000000..33d9c30 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/pyproject.toml @@ -0,0 +1,35 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "lzwcai-mcp-sqlexecutor" +version = "0.1.6" +description = "MCP server for executing business SQL queries with dynamic tool generation" +readme = "README.md" +requires-python = ">=3.13" +license = {text = "MIT"} +authors = [ + {name = "lzwcai", email = "your-email@example.com"}, +] +keywords = ["mcp", "sql", "executor", "server"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.13", +] +dependencies = [ + "httpx>=0.28.1", + "mcp[cli]>=1.10.1", + "pypinyin>=0.53.0", +] + +[project.scripts] +lzwcai-mcp-sqlexecutor = "lzwcai_mcp_sqlexecutor.main:main" + +[tool.hatch.build.targets.wheel] +packages = ["lzwcai_mcp_sqlexecutor"] + +[tool.hatch.build.targets.wheel.force-include] +"lzwcai_mcp_sqlexecutor/businessQueries.json" = "lzwcai_mcp_sqlexecutor/businessQueries.json" diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/__init__.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/__init__.py new file mode 100644 index 0000000..4fdc6f7 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/__init__.py @@ -0,0 +1,24 @@ +"""Utils package for lzwcai_mcp_sqlexecutor""" + +from .json_helper import load_json +from .name_helper import generate_tool_name +from .schema_helper import generate_input_schema, validate_input_schema +from .api_client import DataSourceAPIClient, get_skill_by_id, process_skill_response, test_sql_with_schema +from .env_config import get_database_id, get_skill_id, get_backend_base_url, get_env_config, set_env_variable + +__all__ = [ + 'load_json', + 'generate_tool_name', + 'generate_input_schema', + 'validate_input_schema', + 'DataSourceAPIClient', + 'get_skill_by_id', + 'process_skill_response', + 'test_sql_with_schema', + 'get_database_id', + 'get_skill_id', + 'get_backend_base_url', + 'get_env_config', + 'set_env_variable' +] + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/api_client.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/api_client.py new file mode 100644 index 0000000..cf49a0a --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/api_client.py @@ -0,0 +1,318 @@ +""" +第三方API调用客户端 +用于调用外部数据源接口 +""" + +import httpx +import logging +import json +from typing import Dict, Any, Optional, List + +# 支持直接运行和模块导入两种方式 +try: + from .env_config import get_backend_base_url +except ImportError: + from env_config import get_backend_base_url + +# 获取日志记录器 +logger = logging.getLogger(__name__) + + +class DataSourceAPIClient: + """数据源API客户端""" + + def __init__( + self, + base_url: Optional[str] = None, + token: Optional[str] = None + ): + """ + 初始化API客户端 + + Args: + base_url: API基础URL(默认从环境变量 BACKEND_BASE_URL 读取,如果未设置则使用 http://192.168.2.236:8088) + token: 认证令牌(Bearer Token) + """ + # 如果没有传入 base_url,则从环境变量读取 + if base_url is None: + base_url = get_backend_base_url() + + self.base_url = base_url.rstrip('/') + self.token = token or "eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjJiYTk4ODllLWM2ZGItNDQ5YS1iZmFjLTQ2YzMxODFlODg5NCJ9.dvi8zm0LsWvJ_h9zD5blnHFRxa4z4_WBm1R487ekE7HlHzrN6dnvqhK8askqT5b1EcE8myHwRzLVMoI8UOjOrw" + self.client = httpx.Client(timeout=30.0) + + def _get_headers(self) -> Dict[str, str]: + """ + 获取请求头 + + Returns: + 请求头字典 + """ + return { + 'Authorization': f'Bearer {self.token}', + } + + def get_skill_by_id(self, skill_id: str) -> Dict[str, Any]: + """ + 根据技能ID获取技能信息 + + Args: + skill_id: 技能ID + + Returns: + API响应数据 + + Raises: + Exception: 请求失败时抛出 + """ + try: + url = f"{self.base_url}/datasource/skill/getBySkillId/{skill_id}" + + logger.info(f"正在调用API: {url}") + logger.info(f"请求参数 - skill_id: {skill_id}") + + response = self.client.get( + url, + headers=self._get_headers() + ) + + # 检查HTTP状态码 + response.raise_for_status() + + # 解析JSON响应 + data = response.json() + + logger.info(f"API调用成功: {url}") + logger.debug(f"响应数据: {data}") + + return data + + except httpx.TimeoutException: + error_msg = f"API请求超时: {url}" + logger.error(error_msg) + raise Exception(error_msg) + + except httpx.HTTPStatusError as e: + error_msg = f"API请求失败 (HTTP {e.response.status_code}): {url}" + logger.error(error_msg) + logger.error(f"错误响应: {e.response.text}") + raise Exception(error_msg) + + except httpx.RequestError as e: + error_msg = f"API请求异常: {url}, 错误: {str(e)}" + logger.error(error_msg) + raise Exception(error_msg) + + except Exception as e: + error_msg = f"处理API响应时出错: {str(e)}" + logger.error(error_msg, exc_info=True) + raise Exception(error_msg) + + def test_sql_with_schema(self, request_data: Dict[str, Any]) -> Dict[str, Any]: + """ + 测试SQL语句并返回执行结果 + + Args: + request_data: 请求数据,包含以下字段: + - datasourceId: 数据源ID + - businessName: 业务名称 + - businessDescription: 业务描述 + - sqlTemplate: SQL模板 + - parameters: 参数定义 + - testParams: 测试参数 + + Returns: + API响应数据 + + Raises: + Exception: 请求失败时抛出 + """ + try: + url = f"{self.base_url}/datasource/sqlExecutionLog/testSqlWithSchema" + + # 构建请求头(包含Content-Type) + headers = self._get_headers() + headers['Content-Type'] = 'application/json' + headers['Accept'] = '*/*' + + logger.info(f"正在调用测试SQL API: {url}") + logger.info(f"请求参数: {json.dumps(request_data, ensure_ascii=False, indent=2)}") + + # 发送POST请求 + response = self.client.post( + url, + headers=headers, + json=request_data + ) + + # 检查HTTP状态码 + response.raise_for_status() + + # 解析JSON响应 + result = response.json() + + logger.info(f"测试SQL API调用成功") + logger.debug(f"响应数据: {json.dumps(result, ensure_ascii=False, indent=2)}") + + # 处理返回数据结构: {code, data: {errorMessage, data}, msg} + # 检查外层 code + if result.get("code") != 200: + error_msg = result.get("msg", "接口返回错误") + logger.error(f"接口返回错误: code={result.get('code')}, msg={error_msg}") + raise Exception(error_msg) + + # 检查内层 errorMessage + inner_data = result.get("data", {}) + if inner_data.get("errorMessage"): + error_msg = inner_data.get("errorMessage") + logger.error(f"接口业务错误: {error_msg}") + raise Exception(error_msg) + + # 返回 data.data + return inner_data.get("data") + + except httpx.TimeoutException: + error_msg = f"测试SQL API请求超时: {url}" + logger.error(error_msg) + raise Exception(error_msg) + + except httpx.HTTPStatusError as e: + error_msg = f"测试SQL API请求失败 (HTTP {e.response.status_code}): {url}" + logger.error(error_msg) + logger.error(f"错误响应: {e.response.text}") + raise Exception(error_msg) + + except httpx.RequestError as e: + error_msg = f"测试SQL API请求异常: {url}, 错误: {str(e)}" + logger.error(error_msg) + raise Exception(error_msg) + + except Exception as e: + error_msg = f"处理测试SQL API响应时出错: {str(e)}" + logger.error(error_msg, exc_info=True) + raise Exception(error_msg) + + def close(self): + """关闭HTTP客户端""" + self.client.close() + + +# 创建默认客户端实例 +default_client = DataSourceAPIClient() + + +def get_skill_by_id(skill_id: str, base_url: Optional[str] = None, token: Optional[str] = None) -> Dict[str, Any]: + """ + 便捷函数:根据技能ID获取技能信息 + + Args: + skill_id: 技能ID + base_url: API基础URL(可选,默认从环境变量 BACKEND_BASE_URL 读取) + token: 认证令牌(可选,使用默认值) + + Returns: + API响应数据 + """ + if base_url or token: + client = DataSourceAPIClient( + base_url=base_url, + token=token + ) + return client.get_skill_by_id(skill_id) + else: + return default_client.get_skill_by_id(skill_id) + + +def test_sql_with_schema(request_data: Dict[str, Any], base_url: Optional[str] = None, token: Optional[str] = None) -> Dict[str, Any]: + """ + 便捷函数:测试SQL语句并返回执行结果 + + Args: + request_data: 请求数据,包含以下字段: + - datasourceId: 数据源ID + - businessName: 业务名称 + - businessDescription: 业务描述 + - sqlTemplate: SQL模板 + - parameters: 参数定义 + - testParams: 测试参数 + base_url: API基础URL(可选,默认从环境变量 BACKEND_BASE_URL 读取) + token: 认证令牌(可选,使用默认值) + + Returns: + API响应数据 + """ + if base_url or token: + client = DataSourceAPIClient( + base_url=base_url, + token=token + ) + return client.test_sql_with_schema(request_data) + else: + return default_client.test_sql_with_schema(request_data) + + +def process_skill_response(response: Dict[str, Any]) -> List[Dict[str, Any]]: + """ + 处理API响应数据,映射为businessQueries格式 + + Args: + response: API原始响应数据 + + Returns: + 处理后的查询配置列表 + """ + try: + # 提取data数组 + data_list = response.get("data", []) + + # 默认的员工ID参数schema + default_employee_schema = { + "type": "object", + "required": ["employeeId"], + "properties": { + "employeeId": { + "type": "number", + "description": "员工ID,用于标识员工的唯一数字标识符", + "examples": [1001, 2002] + } + } + } + + # 映射每个skill为businessQuery格式 + queries = [] + for skill in data_list: + # 解析sqlParams字符串为JSON对象 + sql_params = json.loads(skill.get("sqlParams", "{}")) + + # 判断sqlParams是否为空对象 + is_empty_params = ( + not sql_params.get("properties") or + len(sql_params.get("properties", {})) == 0 + ) and ( + not sql_params.get("required") or + len(sql_params.get("required", [])) == 0 + ) + + # 如果是空对象,使用默认的员工ID参数 + if is_empty_params: + logger.info(f"技能 {skill.get('name')} (ID: {skill.get('id')}) 的sqlParams为空,使用默认员工ID参数") + sql_params = default_employee_schema + + # 映射字段 + query = { + "id": skill.get("id"), + "businessName": skill.get("name"), + "businessDescription": skill.get("description"), + "sqlTemplate": skill.get("sqlTemplate"), + "parameters": sql_params, + "datasourceId": skill.get("datasourceId") + } + queries.append(query) + + logger.info(f"成功处理 {len(queries)} 条技能数据") + return queries + + except Exception as e: + logger.error(f"处理API响应数据失败: {e}", exc_info=True) + raise + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/env_config.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/env_config.py new file mode 100644 index 0000000..2b87425 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/env_config.py @@ -0,0 +1,88 @@ +"""环境变量配置模块""" + +import os +from typing import Optional + + +def get_database_id(default: str = "29") -> str: + """ + 获取数据库ID环境变量 + + Args: + default: 默认值(默认为 "29") + + Returns: + str: 数据库ID + + Environment Variables: + databaseId: 数据库ID + """ + return os.environ.get("databaseId", default) + + +def get_skill_id(default: str = "") -> str: + """ + 获取技能ID环境变量 + + Args: + default: 默认值(默认为 "") + + Returns: + str: 技能ID + + Environment Variables: + skillId: 技能ID + """ + return os.environ.get("skillId", default) + + +def get_backend_base_url(default: str = "http://lzwcai-demp-corp-manager:8086") -> str: + """ + 获取后端API基础URL环境变量 + + Args: + default: 默认值(默认为 "http://lzwcai-demp-corp-manager:8086") + + Returns: + str: 后端API基础URL + + Environment Variables: + backendBaseUrl: 后端API基础URL + """ + return os.environ.get("backendBaseUrl", default) + + +def get_env_config() -> dict: + """ + 获取所有环境配置 + + Returns: + dict: 包含所有配置的字典 + + Example: + config = get_env_config() + print(config['database_id']) # 输出: "29" + print(config['skill_id']) # 输出: "" + print(config['backend_base_url']) # 输出: "http://lzwcai-demp-corp-manager:8086" + """ + return { + "database_id": get_database_id(), + "skill_id": get_skill_id(), + "backend_base_url": get_backend_base_url() + } + + +def set_env_variable(key: str, value: str) -> None: + """ + 设置环境变量(仅在当前进程中有效) + + Args: + key: 环境变量名 + value: 环境变量值 + + Example: + set_env_variable("databaseId", "30") + set_env_variable("skillId", "1234567890") + """ + os.environ[key] = value + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/json_helper.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/json_helper.py new file mode 100644 index 0000000..1a6fc95 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/json_helper.py @@ -0,0 +1,60 @@ +"""JSON 文件读取工具""" + +import json +from pathlib import Path +from typing import Any, Union + + +def load_json(json_path: Union[str, Path]) -> Any: + """ + 读取 JSON 文件并返回其内容 + + Args: + json_path: JSON 文件的路径(支持字符串或 Path 对象) + + Returns: + JSON 文件中解析后的数据(可以是字典、列表或其他 JSON 类型) + + Raises: + FileNotFoundError: 当文件不存在时 + json.JSONDecodeError: 当 JSON 格式无效时 + Exception: 其他读取错误 + + Example: + >>> data = load_json('config.json') + >>> print(data) + {'key': 'value'} + + >>> data = load_json(Path('data/users.json')) + >>> print(data) + [{'id': 1, 'name': 'Alice'}] + """ + try: + # 转换为 Path 对象 + path = Path(json_path) + + # 检查文件是否存在 + if not path.exists(): + raise FileNotFoundError(f"JSON 文件不存在: {json_path}") + + # 检查是否为文件 + if not path.is_file(): + raise ValueError(f"路径不是一个文件: {json_path}") + + # 读取并解析 JSON 文件 + with open(path, 'r', encoding='utf-8') as f: + data = json.load(f) + + return data + + except json.JSONDecodeError as e: + raise json.JSONDecodeError( + f"JSON 格式错误: {e.msg}", + e.doc, + e.pos + ) + except FileNotFoundError: + raise + except Exception as e: + raise Exception(f"读取 JSON 文件时发生错误: {str(e)}") + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/logger_config.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/logger_config.py new file mode 100644 index 0000000..290964f --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/logger_config.py @@ -0,0 +1,489 @@ +# -*- coding: utf-8 -*- +""" +统一日志配置模块 +提供系统级别的日志配置和管理 +""" + +import os +import sys +import logging +from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler +from datetime import datetime +from pathlib import Path + + +class LoggerConfig: + """日志配置管理类""" + + def __init__(self, logs_dir: str = None): + """初始化日志配置 + + Args: + logs_dir: 日志目录路径,默认为项目根目录下的logs文件夹 + """ + # 确定日志目录 + if logs_dir: + self.logs_dir = Path(logs_dir) + else: + # 获取项目根目录(logger_config.py 在 utils 目录下,需要上升两层到达项目根目录) + project_root = Path(__file__).parent.parent + self.logs_dir = project_root / "logs" + + # 创建日志目录 + self.logs_dir.mkdir(exist_ok=True) + + # 日志格式 + self.log_format = '%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s' + self.date_format = '%Y-%m-%d %H:%M:%S' + + # 从环境变量获取日志级别,默认为INFO + self.log_level = self._get_log_level_from_env() + + # 是否已初始化 + self._initialized = False + + def _get_log_level_from_env(self) -> int: + """从环境变量获取日志级别 + + Returns: + int: 日志级别 + """ + log_level_str = os.getenv('LOG_LEVEL', 'INFO').upper() + + # 日志级别映射 + level_mapping = { + 'DEBUG': logging.DEBUG, + 'INFO': logging.INFO, + 'WARNING': logging.WARNING, + 'WARN': logging.WARNING, # 兼容性别名 + 'ERROR': logging.ERROR, + 'CRITICAL': logging.CRITICAL, + 'FATAL': logging.CRITICAL # 兼容性别名 + } + + return level_mapping.get(log_level_str, logging.INFO) + + def setup_logging(self, + app_name: str = "lzwcai_mcp_sqlexecutor", + log_level: int = logging.INFO, + max_file_size: int = 10 * 1024 * 1024, # 10MB + backup_count: int = 5, + console_output: bool = True) -> logging.Logger: + """设置系统日志配置 + + Args: + app_name: 应用名称,用于日志文件命名 + log_level: 日志级别 + max_file_size: 单个日志文件最大大小(字节) + backup_count: 保留的备份文件数量 + console_output: 是否输出到控制台 + + Returns: + logging.Logger: 配置好的根日志器 + """ + if self._initialized: + return logging.getLogger() + + # 设置根日志器 + root_logger = logging.getLogger() + root_logger.setLevel(log_level) + + # 清除现有的处理器 + for handler in root_logger.handlers[:]: + root_logger.removeHandler(handler) + + # 创建格式化器 + formatter = logging.Formatter(self.log_format, self.date_format) + + # 1. 主日志文件 - 按大小滚动 + main_log_file = self.logs_dir / f"{app_name}.log" + file_handler = RotatingFileHandler( + main_log_file, + maxBytes=max_file_size, + backupCount=backup_count, + encoding='utf-8' + ) + file_handler.setLevel(log_level) + file_handler.setFormatter(formatter) + root_logger.addHandler(file_handler) + + # 2. 错误日志文件 - 只记录ERROR及以上级别 + error_log_file = self.logs_dir / f"{app_name}_error.log" + error_handler = RotatingFileHandler( + error_log_file, + maxBytes=max_file_size, + backupCount=backup_count, + encoding='utf-8' + ) + error_handler.setLevel(logging.ERROR) + error_handler.setFormatter(formatter) + root_logger.addHandler(error_handler) + + # 3. 按日期滚动的日志文件 + daily_log_file = self.logs_dir / f"{app_name}_daily.log" + daily_handler = TimedRotatingFileHandler( + daily_log_file, + when='midnight', + interval=1, + backupCount=30, # 保留30天 + encoding='utf-8' + ) + daily_handler.setLevel(log_level) + daily_handler.setFormatter(formatter) + daily_handler.suffix = "%Y-%m-%d" + root_logger.addHandler(daily_handler) + + # 4. 控制台输出 + # 重要:MCP协议使用stdio时,必须将日志输出到stderr,stdout仅用于JSON-RPC通信 + if console_output: + console_handler = logging.StreamHandler(sys.stderr) + console_handler.setLevel(log_level) + console_formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s', + self.date_format + ) + console_handler.setFormatter(console_formatter) + root_logger.addHandler(console_handler) + + self._initialized = True + + # 记录初始化信息 + root_logger.info(f"日志系统初始化完成 - 日志目录: {self.logs_dir}") + root_logger.info(f"日志配置 - 级别: {logging.getLevelName(log_level)}, 文件大小限制: {max_file_size//1024//1024}MB, 备份数量: {backup_count}") + + return root_logger + + def get_module_logger(self, module_name: str) -> logging.Logger: + """获取模块专用日志器 + + Args: + module_name: 模块名称 + + Returns: + logging.Logger: 模块日志器 + """ + return logging.getLogger(module_name) + + def create_component_logger(self, + component_name: str, + log_file: str = None, + log_level: int = None) -> logging.Logger: + """为特定组件创建独立的日志器 + + Args: + component_name: 组件名称 + log_file: 独立日志文件名(可选) + log_level: 日志级别(可选) + + Returns: + logging.Logger: 组件日志器 + """ + logger = logging.getLogger(component_name) + + if log_file: + # 为组件创建独立的日志文件 + component_log_file = self.logs_dir / log_file + handler = RotatingFileHandler( + component_log_file, + maxBytes=5 * 1024 * 1024, # 5MB + backupCount=3, + encoding='utf-8' + ) + + formatter = logging.Formatter(self.log_format, self.date_format) + handler.setFormatter(formatter) + + if log_level: + handler.setLevel(log_level) + + logger.addHandler(handler) + logger.info(f"组件日志器创建完成: {component_name} -> {component_log_file}") + + return logger + + def setup_mqtt_logging(self) -> logging.Logger: + """设置MQTT专用日志 + + Returns: + logging.Logger: MQTT日志器 + """ + return self.create_component_logger( + "mqtt_communication", + "mqtt_communication.log", + logging.DEBUG + ) + + def setup_mcp_logging(self) -> logging.Logger: + """设置MCP专用日志 + + Returns: + logging.Logger: MCP日志器 + """ + return self.create_component_logger( + "mcp_services", + "mcp_services.log", + logging.DEBUG + ) + + def setup_api_logging(self) -> logging.Logger: + """设置API专用日志 + + Returns: + logging.Logger: API日志器 + """ + return self.create_component_logger( + "api_requests", + "api_requests.log", + logging.INFO + ) + + def get_logs_info(self) -> dict: + """获取日志系统信息 + + Returns: + dict: 日志系统信息 + """ + log_files = [] + if self.logs_dir.exists(): + for log_file in self.logs_dir.glob("*.log*"): + stat = log_file.stat() + log_files.append({ + "name": log_file.name, + "size": stat.st_size, + "modified": datetime.fromtimestamp(stat.st_mtime).isoformat() + }) + + return { + "logs_directory": str(self.logs_dir), + "initialized": self._initialized, + "log_files": log_files, + "total_files": len(log_files) + } + + def cleanup_old_logs(self, days: int = 30): + """清理旧日志文件 + + Args: + days: 保留天数 + """ + if not self.logs_dir.exists(): + return + + from datetime import timedelta + cutoff_time = datetime.now() - timedelta(days=days) + + cleaned_files = [] + for log_file in self.logs_dir.glob("*.log*"): + if log_file.stat().st_mtime < cutoff_time.timestamp(): + try: + log_file.unlink() + cleaned_files.append(log_file.name) + except Exception as e: + logging.error(f"清理日志文件失败: {log_file.name}, 错误: {e}") + + if cleaned_files: + logging.info(f"清理了 {len(cleaned_files)} 个旧日志文件: {cleaned_files}") + + def set_log_level(self, level: int, logger_name: str = None): + """动态调整日志级别 + + Args: + level: 新的日志级别 (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) + logger_name: 指定日志器名称,None表示调整根日志器 + """ + if logger_name: + logger = logging.getLogger(logger_name) + else: + logger = logging.getLogger() + + old_level = logger.level + logger.setLevel(level) + + # 同时调整所有处理器的级别 + for handler in logger.handlers: + if not isinstance(handler, logging.StreamHandler) or handler.stream not in (sys.stdout, sys.stderr): + # 不调整控制台处理器的级别,保持原有设置 + handler.setLevel(level) + + level_name = logging.getLevelName(level) + old_level_name = logging.getLevelName(old_level) + target = logger_name or "根日志器" + + logger.info(f"日志级别已调整: {target} {old_level_name} -> {level_name}") + + def set_temporary_log_level(self, level: int, logger_name: str = None): + """临时调整日志级别(会保存原始级别用于恢复) + + Args: + level: 临时日志级别 + logger_name: 指定日志器名称,None表示调整根日志器 + """ + if not hasattr(self, '_original_levels'): + self._original_levels = {} + + target_name = logger_name or 'root' + + if logger_name: + logger = logging.getLogger(logger_name) + else: + logger = logging.getLogger() + + # 保存原始级别 + if target_name not in self._original_levels: + self._original_levels[target_name] = logger.level + + # 设置新级别 + self.set_log_level(level, logger_name) + + level_name = logging.getLevelName(level) + target = logger_name or "根日志器" + logger.info(f"临时调整日志级别: {target} -> {level_name} (可通过restore_log_level恢复)") + + def restore_log_level(self, logger_name: str = None): + """恢复日志级别到调整前的状态 + + Args: + logger_name: 指定日志器名称,None表示恢复根日志器 + """ + if not hasattr(self, '_original_levels'): + logging.warning("没有找到保存的原始日志级别") + return + + target_name = logger_name or 'root' + + if target_name not in self._original_levels: + logging.warning(f"没有找到 {target_name} 的原始日志级别") + return + + original_level = self._original_levels[target_name] + self.set_log_level(original_level, logger_name) + + # 清除保存的级别 + del self._original_levels[target_name] + + target = logger_name or "根日志器" + level_name = logging.getLevelName(original_level) + logging.info(f"已恢复日志级别: {target} -> {level_name}") + + def get_current_log_levels(self) -> dict: + """获取当前所有日志器的级别信息 + + Returns: + dict: 日志器级别信息 + """ + levels_info = {} + + # 根日志器 + root_logger = logging.getLogger() + levels_info['root'] = { + 'level': root_logger.level, + 'level_name': logging.getLevelName(root_logger.level), + 'handlers_count': len(root_logger.handlers) + } + + # 其他已创建的日志器 + for name, logger in logging.Logger.manager.loggerDict.items(): + if isinstance(logger, logging.Logger): + levels_info[name] = { + 'level': logger.level, + 'level_name': logging.getLevelName(logger.level), + 'handlers_count': len(logger.handlers) + } + + return levels_info + + +# 全局日志配置实例 +logger_config = LoggerConfig() + + +def setup_system_logging(app_name: str = "lzwcai_mcp_sqlexecutor", + log_level: int = logging.INFO) -> logging.Logger: + """系统日志初始化快捷函数 + + Args: + app_name: 应用名称 + log_level: 日志级别 + + Returns: + logging.Logger: 根日志器 + """ + return logger_config.setup_logging(app_name, log_level) + + +def get_logger(name: str) -> logging.Logger: + """获取日志器的快捷函数 + + Args: + name: 日志器名称 + + Returns: + logging.Logger: 日志器实例 + """ + return logger_config.get_module_logger(name) + + +def set_log_level(level: int, logger_name: str = None): + """动态调整日志级别的快捷函数 + + Args: + level: 新的日志级别 (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) + logger_name: 指定日志器名称,None表示调整根日志器 + + Examples: + # 调整根日志器为DEBUG级别 + set_log_level(logging.DEBUG) + + # 调整特定模块日志器为WARNING级别 + set_log_level(logging.WARNING, "agent_ontology.core") + """ + logger_config.set_log_level(level, logger_name) + + +def set_temporary_log_level(level: int, logger_name: str = None): + """临时调整日志级别的快捷函数 + + Args: + level: 临时日志级别 + logger_name: 指定日志器名称,None表示调整根日志器 + + Examples: + # 临时调整为DEBUG级别进行调试 + set_temporary_log_level(logging.DEBUG) + # ... 进行调试 ... + # 恢复原始级别 + restore_log_level() + """ + logger_config.set_temporary_log_level(level, logger_name) + + +def restore_log_level(logger_name: str = None): + """恢复日志级别的快捷函数 + + Args: + logger_name: 指定日志器名称,None表示恢复根日志器 + """ + logger_config.restore_log_level(logger_name) + + +def get_current_log_levels() -> dict: + """获取当前日志级别信息的快捷函数 + + Returns: + dict: 日志器级别信息 + + Examples: + levels = get_current_log_levels() + print(f"根日志器级别: {levels['root']['level_name']}") + """ + return logger_config.get_current_log_levels() + + +# 便捷的日志级别常量 +class LogLevel: + """日志级别常量类""" + DEBUG = logging.DEBUG + INFO = logging.INFO + WARNING = logging.WARNING + ERROR = logging.ERROR + CRITICAL = logging.CRITICAL \ No newline at end of file diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/name_helper.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/name_helper.py new file mode 100644 index 0000000..d66cf32 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/name_helper.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +名称生成工具模块 +""" + +from pypinyin import lazy_pinyin, Style +import logging + +logger = logging.getLogger(__name__) + + +def generate_tool_name(business_name: str, tool_id: str) -> str: + """ + 根据业务名称和ID生成工具名称 + 格式: tool_拼音_id + + Args: + business_name: 业务名称(中文) + tool_id: 工具ID + + Returns: + str: 格式化的工具名称 + """ + try: + # 将中文转换为拼音(无音调,小写) + pinyin_list = lazy_pinyin(business_name, style=Style.NORMAL) + # 拼接拼音 + pinyin_str = ''.join(pinyin_list) + + # 将 ID 中的 '-' 替换为 '_' + formatted_id = tool_id.replace('-', '_') + + # 组合成最终的工具名称 + tool_name = f"tool_{pinyin_str}_{formatted_id}" + + return tool_name + except Exception as e: + logger.error(f"生成工具名称失败: {business_name}, {tool_id}, 错误: {e}", exc_info=True) + # 降级处理:如果拼音转换失败,使用 ID + return f"tool_{tool_id.replace('-', '_')}" + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/schema_helper.py b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/schema_helper.py new file mode 100644 index 0000000..626559f --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/utils/schema_helper.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- +""" +Schema 生成工具模块 +""" + +from typing import Any, Dict, List + + +def generate_input_schema(parameters: Dict[str, Any]) -> Dict[str, Any]: + """ + 从查询配置的参数定义生成 MCP 工具的 inputSchema + + 此函数会保留完整的 JSON Schema 信息,包括: + - type: Schema 类型(通常是 "object") + - required: 必填字段列表 + - properties: 属性定义(包括每个属性的 type, description, format, examples 等) + - description: Schema 的整体描述(如果有) + - 以及其他任何 JSON Schema 标准字段 + + 此函数还会自动添加以下字段(如果原始 parameters 中未定义): + - targetDatabaseName: 目标数据库名称(非必填,默认为空字符串) + + Args: + parameters: 查询配置中的参数定义字典,应该是一个完整的 JSON Schema 对象 + + Returns: + Dict[str, Any]: 符合 JSON Schema 规范的 inputSchema 对象 + + Example: + >>> params = { + ... "type": "object", + ... "required": ["userId", "startTime"], + ... "properties": { + ... "userId": { + ... "type": "integer", + ... "description": "用户的唯一标识符", + ... "examples": [10086] + ... }, + ... "startTime": { + ... "type": "string", + ... "format": "date-time", + ... "description": "查询的起始时间", + ... "examples": ["2023-01-01 00:00:00"] + ... } + ... } + ... } + >>> schema = generate_input_schema(params) + >>> # schema 将包含所有原始信息,包括 format 和 examples + >>> # 同时会自动添加 targetDatabaseName 字段 + """ + # 如果 parameters 本身就是一个完整的 JSON Schema 对象,直接使用 + # 但确保至少包含 type 和 properties + if not parameters: + # 如果 parameters 为空,返回一个空的 object schema + return { + "type": "object", + "properties": {}, + "required": [] + } + + # 检查 parameters 是否已经是完整的 JSON Schema 格式 + # 完整格式应该有 "type": "object" 和 "properties" 字段 + if "type" in parameters and parameters.get("type") == "object" and "properties" in parameters: + # 已经是完整的 JSON Schema 格式,直接使用 + input_schema = dict(parameters) + else: + # parameters 是简化格式(直接是参数定义),需要转换为 JSON Schema 格式 + # 例如: {"workOrderNumber": {"type": "string", "description": "...", "required": true}} + properties = {} + required = [] + + for param_name, param_def in parameters.items(): + if isinstance(param_def, dict): + # 提取 required 标记 + if param_def.get("required", False): + required.append(param_name) + + # 复制参数定义,但移除 required 字段(它应该在顶层的 required 数组中) + prop_def = {k: v for k, v in param_def.items() if k != "required"} + properties[param_name] = prop_def + + input_schema = { + "type": "object", + "properties": properties, + "required": required + } + + # 确保必需的字段存在 + if "type" not in input_schema: + input_schema["type"] = "object" + + if "properties" not in input_schema: + input_schema["properties"] = {} + + if "required" not in input_schema: + input_schema["required"] = [] + + # 添加 targetDatabaseName 字段(如果不存在) + if "targetDatabaseName" not in input_schema["properties"]: + input_schema["properties"]["targetDatabaseName"] = { + "type": "string", + "description": "目标数据库名称", + "default": "" + } + + # 保留所有其他字段,如 description, examples, format 等 + # JSON Schema 标准支持的字段都会被保留: + # - additionalProperties + # - patternProperties + # - minProperties / maxProperties + # - dependencies + # - 等等 + + return input_schema + + +def validate_input_schema(schema: Dict[str, Any]) -> tuple[bool, str]: + """ + 验证 inputSchema 是否符合基本的 JSON Schema 规范 + + Args: + schema: 要验证的 schema 对象 + + Returns: + tuple[bool, str]: (是否有效, 错误消息或成功消息) + + Example: + >>> schema = {"type": "object", "properties": {"id": {"type": "string"}}} + >>> is_valid, msg = validate_input_schema(schema) + >>> print(is_valid, msg) + True, "Schema 验证通过" + """ + if not isinstance(schema, dict): + return False, "Schema 必须是一个字典对象" + + if schema.get("type") != "object": + return False, "Schema 的 type 字段必须是 'object'" + + if "properties" not in schema: + return False, "Schema 必须包含 properties 字段" + + if not isinstance(schema.get("properties"), dict): + return False, "Schema 的 properties 字段必须是一个字典对象" + + # 验证 required 字段(如果存在) + if "required" in schema: + required = schema["required"] + if not isinstance(required, list): + return False, "Schema 的 required 字段必须是一个列表" + + # 验证所有 required 的字段都在 properties 中定义 + properties = schema["properties"] + for field in required: + if field not in properties: + return False, f"必填字段 '{field}' 未在 properties 中定义" + + # 验证 properties 中每个字段的定义 + for prop_name, prop_def in schema["properties"].items(): + if not isinstance(prop_def, dict): + return False, f"属性 '{prop_name}' 的定义必须是一个字典对象" + + if "type" not in prop_def: + return False, f"属性 '{prop_name}' 必须包含 type 字段" + + return True, "Schema 验证通过" + diff --git a/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/uv.lock b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/uv.lock new file mode 100644 index 0000000..c541de4 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/lzwcai_mcpskills_analyzeWorkOrder/uv.lock @@ -0,0 +1,497 @@ +version = 1 +revision = 2 +requires-python = ">=3.13" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/aff/07c09a53a08bc/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/1f0/2e8b43a8fbbc3/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53" }, +] + +[[package]] +name = "anyio" +version = "4.11.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/82a/8d0b81e318cc5/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/028/7e96f4d26d414/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/16d/5969b87f0859e/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/adc/f7e2a1fb3b36a/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373" }, +] + +[[package]] +name = "certifi" +version = "2025.10.5" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/47c/09d31ccf2acf0/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/0f2/12c2744a9bb6d/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de" }, +] + +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/e7b/8232224eba16f/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/9b9/f285302c6e306/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/086/95f5cb7ed6e05/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/4f1/d9991f5acc0ca/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/4e3/5b956cf45792e/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/63c/f8bbe7522de3b/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/6e3/4463af53fd2ab/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/2d4/00746a40668fc/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/75e/98c5f16b0f35b/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/d90/9fcccc110f8c7/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.3" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/9b1/ed0127459a660/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/0ac/1c9fe3c0afad2/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/795/dafcc9c04ed0c/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/771/a87f49d9defaf/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/e4a/9655ce0da0c0b/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/3fb/a0169e345c717/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/b54/0987f239e7456/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/988/02fee3a11ee76/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe" }, +] + +[[package]] +name = "lzwcai-mcp-sqlexecutor" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "httpx" }, + { name = "mcp", extra = ["cli"] }, +] + +[package.metadata] +requires-dist = [ + { name = "httpx", specifier = ">=0.28.1" }, + { name = "mcp", extras = ["cli"], specifier = ">=1.10.1" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/cb0/a2b4aa34f932c/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/873/27c59b172c501/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147" }, +] + +[[package]] +name = "mcp" +version = "1.10.1" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/aaa/0957d8307feef/mcp-1.10.1.tar.gz", hash = "sha256:aaa0957d8307feeff180da2d9d359f2b801f35c0c67f1882136239055ef034c2" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/4d0/8301aefe906dc/mcp-1.10.1-py3-none-any.whl", hash = "sha256:4d08301aefe906dce0fa482289db55ce1db831e3e67212e65b5e23ad8454b3c5" }, +] + +[package.optional-dependencies] +cli = [ + { name = "python-dotenv" }, + { name = "typer" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/bb4/13d29f5eea38f/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/840/08a41e51615a4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" }, +] + +[[package]] +name = "pydantic" +version = "2.12.2" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/7b8/fa15b831a4bbd/pydantic-2.12.2.tar.gz", hash = "sha256:7b8fa15b831a4bbde9d5b84028641ac3080a4ca2cbd4a621a661687e741624fd" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/25f/f718ee909acd8/pydantic-2.12.2-py3-none-any.whl", hash = "sha256:25ff718ee909acd82f1ff9b1a4acfd781bb23ab3739adaa7144f19a6a4e231ae" }, +] + +[[package]] +name = "pydantic-core" +version = "2.41.4" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/70e/47929a9d4a190/pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/85e/050ad9e5f6fe1/pydantic_core-2.41.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:85e050ad9e5f6fe1004eec65c914332e52f429bc0ae12d6fa2092407a462c746" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/e73/93f1d64792763/pydantic_core-2.41.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7393f1d64792763a48924ba31d1e44c2cfbc05e3b1c2c9abb4ceeadd912cced" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/94d/ab0940b0d1fb2/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94dab0940b0d1fb28bcab847adf887c66a27a40291eedf0b473be58761c9799a" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/de7/c42f897e689ee/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de7c42f897e689ee6f9e93c4bec72b99ae3b32a2ade1c7e4798e690ff5246e02" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/664/b319919326227/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:664b3199193262277b8b3cd1e754fb07f2c6023289c815a1e1e8fb415cb247b1" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d95/b253b88f7d308/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95b253b88f7d308b1c0b417c4624f44553ba4762816f94e6986819b9c273fb2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/a13/51f5bbdbbabc6/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1351f5bbdbbabc689727cb91649a00cb9ee7203e0a6e54e9f5ba9e22e384b84" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/1af/fa4798520b148/pydantic_core-2.41.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1affa4798520b148d7182da0615d648e752de4ab1a9566b7471bc803d88a062d" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/7b7/4e18052fea4aa/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7b74e18052fea4aa8dea2fb7dbc23d15439695da6cbe6cfc1b694af1115df09d" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/285/b643d75c0e30a/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:285b643d75c0e30abda9dc1077395624f314a37e3c09ca402d4015ef5979f1a2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/f52/679ff4218d713/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:f52679ff4218d713b3b33f88c89ccbf3a5c2c12ba665fb80ccc4192b4608dbab" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/ecd/e6dedd6fff127/pydantic_core-2.41.4-cp313-cp313-win32.whl", hash = "sha256:ecde6dedd6fff127c273c76821bb754d793be1024bc33314a120f83a3c69460c" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d08/1a1f3800f0540/pydantic_core-2.41.4-cp313-cp313-win_amd64.whl", hash = "sha256:d081a1f3800f05409ed868ebb2d74ac39dd0c1ff6c035b5162356d76030736d4" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/f8e/49c9c364a7edc/pydantic_core-2.41.4-cp313-cp313-win_arm64.whl", hash = "sha256:f8e49c9c364a7edcbe2a310f12733aad95b022495ef2a8d653f645e5d20c1564" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/ed9/7fd56a561f5eb/pydantic_core-2.41.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ed97fd56a561f5eb5706cebe94f1ad7c13b84d98312a05546f2ad036bafe87f4" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/a87/0c307bf1ee91f/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a870c307bf1ee91fc58a9a61338ff780d01bfae45922624816878dce784095d2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d25/e97bc1f5f8f79/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25e97bc1f5f8f7985bdc2335ef9e73843bb561eb1fa6831fdfc295c1c2061cf" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d40/5d14bea042f16/pydantic_core-2.41.4-cp313-cp313t-win_amd64.whl", hash = "sha256:d405d14bea042f166512add3091c1af40437c2e7f86988f3915fabd27b1e9cd2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/19f/3684868309db5/pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/e92/05d97ed08a82e/pydantic_core-2.41.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e9205d97ed08a82ebb9a307e92914bb30e18cdf6f6b12ca4bedadb1588a0bfe1" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/82d/f1f432b37d832/pydantic_core-2.41.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82df1f432b37d832709fbcc0e24394bba04a01b6ecf1ee87578145c19cde12ac" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/fc3/b4cc4539e055c/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3b4cc4539e055cfa39a3763c939f9d409eb40e85813257dcd761985a108554" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/b1e/b1754fce47c63/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1eb1754fce47c63d2ff57fdb88c351a6c0150995890088b33767a10218eaa4e" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/e6a/b5ab30ef325b4/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6ab5ab30ef325b443f379ddb575a34969c333004fca5a1daa0133a6ffaad616" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/31a/41030b1d9ca49/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31a41030b1d9ca497634092b46481b937ff9397a86f9f51bd41c4767b6fc04af" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/a44/ac1738591472c/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a44ac1738591472c3d020f61c6df1e4015180d6262ebd39bf2aeb52571b60f12" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d72/f2b5e6e82ab8f/pydantic_core-2.41.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d72f2b5e6e82ab8f94ea7d0d42f83c487dc159c5240d8f83beae684472864e2d" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/c4d/1e854aaf04448/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c4d1e854aaf044487d31143f541f7aafe7b482ae72a022c664b2de2e466ed0ad" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/b56/8af94267729d7/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b568af94267729d76e6ee5ececda4e283d07bbb28e8148bb17adad93d025d25a" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/6d5/5fb8b1e8929b3/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6d55fb8b1e8929b341cc313a81a26e0d48aa3b519c1dbaadec3a6a2b4fcad025" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/5b6/6584e549e2e32/pydantic_core-2.41.4-cp314-cp314-win32.whl", hash = "sha256:5b66584e549e2e32a1398df11da2e0a7eff45d5c2d9db9d5667c5e6ac764d77e" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/557/a0aab88664cc5/pydantic_core-2.41.4-cp314-cp314-win_amd64.whl", hash = "sha256:557a0aab88664cc552285316809cab897716a372afaf8efdbef756f8b890e894" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/3f1/ea6f48a045745/pydantic_core-2.41.4-cp314-cp314-win_arm64.whl", hash = "sha256:3f1ea6f48a045745d0d9f325989d8abd3f1eaf47dd00485912d1a3a63c623a8d" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/6c1/fe4c5404c448b/pydantic_core-2.41.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6c1fe4c5404c448b13188dd8bd2ebc2bdd7e6727fa61ff481bcc2cca894018da" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/523/e7da4d43b113b/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:523e7da4d43b113bf8e7b49fa4ec0c35bf4fe66b2230bfc5c13cc498f12c6c3e" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/572/9225de81fb65b/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5729225de81fb65b70fdb1907fcf08c75d498f4a6f15af005aabb1fdadc19dfa" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/de2/cfbb09e88f0f7/pydantic_core-2.41.4-cp314-cp314t-win_amd64.whl", hash = "sha256:de2cfbb09e88f0f795fd90cf955858fc2c691df65b1f21f0aa00b99f3fbc661d" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d34/f950ae05a83e0/pydantic_core-2.41.4-cp314-cp314t-win_arm64.whl", hash = "sha256:d34f950ae05a83e0ede899c595f312ca976023ea1db100cd5aa188f7005e3ab0" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.11.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/d0e/87a1c7d33593b/pydantic_settings-2.11.0.tar.gz", hash = "sha256:d0e87a1c7d33593beb7194adb8470fc426e95ba02af83a0f23474a04c9a08180" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/fe2/cea3413b9530d/pydantic_settings-2.11.0-py3-none-any.whl", hash = "sha256:fe2cea3413b9530d10f3a5875adffb17ada5c1e1bab0b2885546d7310415207c" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/636/cb2477cec7f89/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/865/40386c03d588b/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/a8a/6399716257f45/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/31f/23644fe2602f8/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.20" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/8dd/0cab45b8e2306/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/8a6/2d3a8335e0658/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/44a/efc3142c5b842/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/381/329a9f99628c9/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231" }, +] + +[[package]] +name = "rich" +version = "14.2.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/73f/f50c7c0c1c77c/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/76b/c51fe2e57d2b1/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd" }, +] + +[[package]] +name = "rpds-py" +version = "0.27.1" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/26a/1c73171d10b7a/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/e4b/9fcfbc0216338/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/144/1811a96eadca9/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/552/66dafa22e672f/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d78/827d7ac08627e/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/ae9/2443798a40a92/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/c46/c9dd2403b66a2/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/2ef/e4eb1d01b7f5f/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/15d/3b4d83582d10c/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/4ed/2e16abbc982a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/a75/f305c9b013289/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/67c/e762070474588/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/9d9/92ac10eb86d9b/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/4f7/5e4bd8ab8db62/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/f90/25faafc62ed0b/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/ed1/0dc32829e7d22/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/920/22bbbad0d4426/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/471/62fdab9407ec3/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/fb8/9bec23fddc489/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/e48/af21883ded2b3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/6f5/b7bd8e219ed50/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/08f/1e20bccf73b08/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/0dc/5dceeaefcc96d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d76/f9cc8665acdc0/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/134/fae0e36022eda/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/eb1/1a4f1b2b63337/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/13e/608ac9f50a0ed/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/dd2/135527aa40f06/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/302/0724ade63fe32/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/8ee/50c3e41739886/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/acb/9aafccaae278f/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/b7f/b801aa7f845dd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/fe0/dd05afb46597b/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/b6d/fb0e058adb12d/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/ed0/90ccd235f6fa8/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/bf8/76e79763eecf3/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/12e/d005216a51b1d/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/ee4/308f409a40e50/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/0b0/8d152555acf1f/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/dce/51c828941973a/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/c14/76d6f29eb81aa/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/3ce/0cac322b0d69b/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/dfb/fac137d2a3d07/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/a6e/57b0abfe7cc51/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/faf/8d146f3d476ab/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/ba8/1d2b56b6d4911/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/84f/7d509870098de/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/a9e/960fc78fecd11/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/62f/85b665cedab1a/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/fed/467af29776f65/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/f27/29615f9d430af/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/1b2/07d881a9aef7b/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/639/fd5efec029f99/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/fec/c80cb2a90e28a/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/42a/89282d711711d/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/cf9/931f14223de59/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/f39/f58a27cc6e59f/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/d5f/a0ee122dc09e2/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a" }, + { url = "http://devpi.iepai.fun/root/pypi/+f/656/7d2bb951e2123/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/8db/ca0739d487e5b/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/7ec/fff8f2fd72616/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/f43/24edc670a0f49/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/2f6/da418d1f1e0fd/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" }, +] + +[[package]] +name = "sse-starlette" +version = "3.0.2" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/ccd/60b5765ebb358/sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/16b/7cbfddbcd4eac/sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a" }, +] + +[[package]] +name = "starlette" +version = "0.48.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/7e8/cee469a8ab235/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/076/4ca97b0975825/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659" }, +] + +[[package]] +name = "typer" +version = "0.19.2" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/9ad/824308ded0ad0/typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/755/e7e19670ffad8/typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/0ce/a48d173cc12fa/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/f0f/a19c6845758ab/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/ba5/61c48a67c5958/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/4ed/1cacbdc298c22/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7" }, +] + +[[package]] +name = "uvicorn" +version = "0.37.0" +source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/411/5c8add6d3fd53/uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13" } +wheels = [ + { url = "http://devpi.iepai.fun/root/pypi/+f/913/b2b8867234373/uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c" }, +] diff --git a/lzwcai_mcpskills_analyzeWorkOrder/main.py b/lzwcai_mcpskills_analyzeWorkOrder/main.py new file mode 100644 index 0000000..c1e4b6e --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/main.py @@ -0,0 +1,12 @@ +""" +Entry point for lzwcai-mcp-sqlexecutor +Runs the MCP server for SQL query execution +""" +import os + +os.environ["databaseId"] = "19" +os.environ["backendBaseUrl"] = "http://192.168.11.24:8088" +if __name__ == "__main__": + # Import and run the actual MCP server + from lzwcai_mcpskills_analyzeWorkOrder.main import main + main() diff --git a/lzwcai_mcpskills_analyzeWorkOrder/pyproject.toml b/lzwcai_mcpskills_analyzeWorkOrder/pyproject.toml new file mode 100644 index 0000000..0483906 --- /dev/null +++ b/lzwcai_mcpskills_analyzeWorkOrder/pyproject.toml @@ -0,0 +1,35 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "lzwcai-mcpskills-analyzeWorkOrder" +version = "0.1.8" +description = "MCP server for executing business SQL queries with dynamic tool generation" +readme = "README.md" +requires-python = ">=3.13" +license = {text = "MIT"} +authors = [ + {name = "lzwcai", email = "your-email@example.com"}, +] +keywords = ["mcp", "sql", "executor", "server"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.13", +] +dependencies = [ + "httpx>=0.28.1", + "mcp[cli]>=1.10.1", + "pypinyin>=0.53.0", +] + +[project.scripts] +lzwcai-mcpskills-analyzeWorkOrder = "lzwcai_mcpskills_analyzeWorkOrder.main:main" + +[tool.hatch.build.targets.wheel] +packages = ["lzwcai_mcpskills_analyzeWorkOrder"] + +[tool.hatch.build.targets.wheel.force-include] +"lzwcai_mcpskills_analyzeWorkOrder/businessQueries.json" = "lzwcai_mcpskills_analyzeWorkOrder/businessQueries.json" diff --git a/tools_config.json b/tools_config.json new file mode 100644 index 0000000..98e18fd --- /dev/null +++ b/tools_config.json @@ -0,0 +1,80 @@ +[ + { + "id": "2006300000000000000", + "createBy": "admin", + "createTime": "2026-01-02 10:00:00", + "updateBy": null, + "updateTime": null, + "serviceId": "2005848885546889218", + "uniqueName": "查询列表", + "name": "chaxunliebiao_x1y2z3w4", + "description": "查询所有工单列表,返回fact_work_order表的全部数据", + "visualizable": 1, + "toolPrompt": "查询所有工单列表数据", + "toolType": "sql", + "datasourceId": "16", + "sqlTemplate": "SELECT * FROM fact_work_order", + "sqlParams": "{\"type\":\"object\",\"required\":[],\"properties\":{}}", + "resultType": "list", + "sourceType": "manual", + "trainingTaskId": null, + "tableMetadataIds": "", + "executionCount": 0, + "visualizationConfigs": null, + "inputJsonSchema": "", + "outputJsonSchema": "", + "lastExecutionTime": null + }, + { + "id": "2006300000000000004", + "createBy": "admin", + "createTime": "2026-01-02 10:00:00", + "updateBy": null, + "updateTime": null, + "serviceId": "2005848885546889218", + "uniqueName": "工单详情", + "name": "gongdanxiangqing_m3n4o5p6", + "description": "根据工单编号查询工单详情,包括工单基本信息、产品信息、委外供应商、工艺路线等", + "visualizable": 1, + "toolPrompt": "输入工单编号查询工单详情,返回工单状态、数量、产品信息、供应商、工艺路线等", + "toolType": "sql", + "datasourceId": "16", + "sqlTemplate": "SELECT wo.work_order_id, wo.work_order_number AS 工单编号, wo.status AS 工单状态, wo.planned_qty AS 计划数量, wo.completed_qty AS 完成数量, wo.operation_good_qty AS 工序良品数, wo.operation_bad_qty AS 工序不良品数, wo.qc_good_qty AS 质检良品数, wo.qc_bad_qty AS 质检不良品数, wo.source_doc_number AS 来源单据编号, wo.event_time_utc AS 事件时间, p.product_code AS 产品编码, p.product_name AS 产品名称, p.product_spec AS 产品规格, s.supplier_name AS 委外供应商, r.routing_name AS 工艺路线 FROM fact_work_order wo LEFT JOIN dim_product p ON wo.product_id = p.product_id AND p.is_current = true LEFT JOIN dim_supplier s ON wo.supplier_id = s.supplier_id AND s.is_current = true LEFT JOIN dim_routing r ON wo.routing_id = r.routing_id AND r.is_current = true WHERE wo.work_order_number = {workOrderNumber}", + "sqlParams": "{\"type\":\"object\",\"required\":[\"workOrderNumber\"],\"properties\":{\"workOrderNumber\":{\"type\":\"string\",\"description\":\"工单编号\",\"examples\":[\"WO1311343859\"]}}}", + "resultType": "list", + "sourceType": "manual", + "trainingTaskId": null, + "tableMetadataIds": "", + "executionCount": 0, + "visualizationConfigs": null, + "inputJsonSchema": "", + "outputJsonSchema": "", + "lastExecutionTime": null + }, + { + "id": "2006300000000000005", + "createBy": "admin", + "createTime": "2026-01-02 10:00:00", + "updateBy": null, + "updateTime": null, + "serviceId": "2005848885546889218", + "uniqueName": "工单执行进度与异常节点看板", + "name": "gongdanzhixingjinduyuyichangjiediankanban_q7r8s9t0", + "description": "工单执行进度与异常节点看板,展示工单完工进度、工序良率、质检良率、异常标识等关键监控指标", + "visualizable": 1, + "toolPrompt": "查看工单执行进度与异常节点看板,展示完工进度百分比、工序状态、报工统计、良率分析和异常标识", + "toolType": "sql", + "datasourceId": "16", + "sqlTemplate": "WITH work_order_progress AS (SELECT wo.work_order_number, wo.status AS work_order_status, wo.planned_qty, wo.completed_qty, wo.operation_good_qty, wo.operation_bad_qty, wo.qc_good_qty, wo.qc_bad_qty, wo.source_doc_number AS sales_order_number, wo.event_time_utc, p.product_code, p.product_name, CASE WHEN wo.planned_qty > 0 THEN ROUND(wo.completed_qty * 100.0 / wo.planned_qty, 2) ELSE 0 END AS completion_pct, CASE WHEN (wo.operation_good_qty + wo.operation_bad_qty) > 0 THEN ROUND(wo.operation_good_qty * 100.0 / (wo.operation_good_qty + wo.operation_bad_qty), 2) ELSE NULL END AS operation_yield_pct, CASE WHEN (wo.qc_good_qty + wo.qc_bad_qty) > 0 THEN ROUND(wo.qc_good_qty * 100.0 / (wo.qc_good_qty + wo.qc_bad_qty), 2) ELSE NULL END AS qc_yield_pct FROM fact_work_order wo LEFT JOIN dim_product p ON wo.product_id = p.product_id AND p.is_current = true), task_summary AS (SELECT work_order_number, COUNT(*) AS total_tasks, SUM(CASE WHEN actual_end_time_utc IS NOT NULL THEN 1 ELSE 0 END) AS completed_tasks, SUM(CASE WHEN actual_start_time_utc IS NOT NULL AND actual_end_time_utc IS NULL THEN 1 ELSE 0 END) AS in_progress_tasks, SUM(CASE WHEN actual_start_time_utc IS NULL THEN 1 ELSE 0 END) AS pending_tasks, SUM(bad_qty) AS total_bad_qty FROM fact_operation_task GROUP BY work_order_number), labor_summary AS (SELECT work_order_number, SUM(report_qty) AS total_report_qty, SUM(good_qty) AS total_good_qty, SUM(bad_qty) AS total_bad_qty, SUM(duration_minutes) AS total_work_minutes FROM fact_labor_report GROUP BY work_order_number), qc_summary AS (SELECT work_order_number, COUNT(*) AS qc_record_count, SUM(pass_qty) AS total_pass_qty, SUM(fail_qty) AS total_fail_qty FROM fact_quality_inspection WHERE work_order_number IS NOT NULL GROUP BY work_order_number) SELECT wp.work_order_number AS 工单编号, wp.product_code AS 产品编码, wp.product_name AS 产品名称, wp.sales_order_number AS 关联销售订单, wp.work_order_status AS 工单状态, wp.planned_qty AS 计划数量, wp.completed_qty AS 完成数量, wp.completion_pct AS 完工进度百分比, COALESCE(ts.total_tasks, 0) AS 工序总数, COALESCE(ts.completed_tasks, 0) AS 已完成工序, COALESCE(ts.in_progress_tasks, 0) AS 进行中工序, COALESCE(ts.pending_tasks, 0) AS 待开始工序, COALESCE(ls.total_report_qty, 0) AS 累计报工数, COALESCE(ls.total_work_minutes, 0) AS 累计工时_分钟, wp.operation_yield_pct AS 工序良率, wp.qc_yield_pct AS 质检良率, COALESCE(qc.total_pass_qty, 0) AS 质检通过数, COALESCE(qc.total_fail_qty, 0) AS 质检不通过数, CASE WHEN wp.completion_pct < 50 AND wp.work_order_status = 'STARTED' THEN '进度滞后' WHEN wp.operation_yield_pct < 90 THEN '工序良率异常' WHEN wp.qc_yield_pct < 95 THEN '质检良率异常' WHEN ts.total_bad_qty > 0 THEN '存在不良品' ELSE '正常' END AS 异常标识, wp.event_time_utc AS 最后更新时间 FROM work_order_progress wp LEFT JOIN task_summary ts ON wp.work_order_number = ts.work_order_number LEFT JOIN labor_summary ls ON wp.work_order_number = ls.work_order_number LEFT JOIN qc_summary qc ON wp.work_order_number = qc.work_order_number ORDER BY CASE wp.work_order_status WHEN 'STARTED' THEN 1 WHEN 'RELEASED' THEN 2 WHEN 'PLANNED' THEN 3 ELSE 4 END, wp.event_time_utc DESC", + "sqlParams": "{\"type\":\"object\",\"required\":[],\"properties\":{}}", + "resultType": "list", + "sourceType": "manual", + "trainingTaskId": null, + "tableMetadataIds": "", + "executionCount": 0, + "visualizationConfigs": "{\"chartType\":\"table\",\"highlightRules\":[{\"field\":\"异常标识\",\"condition\":\"notEquals\",\"value\":\"正常\",\"style\":\"danger\"}]}", + "inputJsonSchema": "", + "outputJsonSchema": "", + "lastExecutionTime": null + } +] \ No newline at end of file