Compare commits
10 Commits
70d2606698
...
fb61ae27cf
| Author | SHA1 | Date | |
|---|---|---|---|
| fb61ae27cf | |||
| 992d97c0a4 | |||
| 8703a61198 | |||
| 3c9fba36e9 | |||
| 32bc05376f | |||
| 1b850913e7 | |||
| a50aa307ab | |||
| e18c661368 | |||
| 41c3d7a8fd | |||
| 5107fdb74c |
@@ -1,6 +1,6 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: lzwcai-mcp-api-converter
|
||||
Version: 0.2.0
|
||||
Version: 0.2.5
|
||||
Summary: 基于FastMCP框架的动态API工具服务器,自动将企业业务API配置转换为MCP协议工具,支持多种传输方式、企业认证和参数验证,为AI助手提供标准化的业务接口访问能力。
|
||||
Requires-Python: >=3.10
|
||||
Description-Content-Type: text/markdown
|
||||
|
||||
@@ -1,37 +1,96 @@
|
||||
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 个工具
|
||||
2026-03-18 17:57:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 17:57:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 17:57:40
|
||||
2026-03-18 17:57:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 17:57:40 - 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
|
||||
2026-03-18 17:57:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 17:57:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 17:57:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 17:57:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 17:57:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 17:57:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 17:57:52
|
||||
2026-03-18 17:57:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 17:57:52 - 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
|
||||
2026-03-18 17:57:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 17:57:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 17:57:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 17:57:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 17:58:11 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 17:58:11 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 17:58:11
|
||||
2026-03-18 17:58:11 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 17:58:11 - 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
|
||||
2026-03-18 17:58:11 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 17:58:11 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 17:58:11 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 17:58:11 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 17:58:59 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 17:58:59 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 17:58:59
|
||||
2026-03-18 17:58:59 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 17:58:59 - 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
|
||||
2026-03-18 17:58:59 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 17:58:59 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 17:58:59 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 17:58:59 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 17:59:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 17:59:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 17:59:12
|
||||
2026-03-18 17:59:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 17:59:12 - 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
|
||||
2026-03-18 17:59:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 17:59:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 17:59:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 17:59:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 18:04:50 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 18:04:50 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 18:04:50
|
||||
2026-03-18 18:04:50 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 18:04:50 - 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
|
||||
2026-03-18 18:04:50 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 18:04:50 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 18:04:50 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 18:04:50 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 18:06:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 18:06:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 18:06:12
|
||||
2026-03-18 18:06:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 18:06:12 - 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
|
||||
2026-03-18 18:06:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 18:06:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 18:06:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 18:06:12 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 18:10:29 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 18:10:29 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 18:10:29
|
||||
2026-03-18 18:10:29 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 18:10:29 - 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
|
||||
2026-03-18 18:10:29 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 18:10:29 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 18:10:29 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 18:10:29 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 18:10:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 18:10:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 18:10:40
|
||||
2026-03-18 18:10:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 18:10:40 - 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
|
||||
2026-03-18 18:10:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 18:10:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 18:10:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 18:10:40 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 18:11:20 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 18:11:20 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 18:11:20
|
||||
2026-03-18 18:11:20 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 18:11:20 - 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
|
||||
2026-03-18 18:11:20 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 18:11:20 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 18:11:20 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 18:11:20 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 18:13:17 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 18:13:17 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 18:13:17
|
||||
2026-03-18 18:13:17 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 18:13:17 - 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
|
||||
2026-03-18 18:13:17 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 18:13:17 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 18:13:17 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 18:13:17 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
2026-03-18 18:16:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:215] - ================================================================================
|
||||
2026-03-18 18:16:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:216] - 日志系统初始化完成 - 2026-03-18 18:16:52
|
||||
2026-03-18 18:16:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:217] - 日志级别: INFO
|
||||
2026-03-18 18:16:52 - 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
|
||||
2026-03-18 18:16:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:219] - 控制台输出: False
|
||||
2026-03-18 18:16:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:220] - 文件输出: True
|
||||
2026-03-18 18:16:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:221] - 文件轮转: 最大10MB, 保留5个备份
|
||||
2026-03-18 18:16:52 - lzwcai_mcp_api_converter.src.util.logger_config - INFO - [logger_config.py:222] - ================================================================================
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
lzwc19781970385781825785858token={"authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMTAwMDAwMDEiLCJsb2dpbl91c2VyX2tleSI6IjJmNmViMWVkYTk3MGRlNzI1OTM1YTczNzY5YWZmODJmZDE3MmFmMGIiLCJhYmJyIjoiXHU3MDc1XHU2Y2ZkXHU0ZTA3XHU1ZGRkIiwiYXVkIjoiIiwiZXhwIjoxNzY3MzQ4OTQxLCJpYXQiOjE3NjY3NDQxNDEsImlzcyI6IiIsImp0aSI6IjUyOTIyNzc0ZTdmZDA3MjZkNGEyY2FkMTgyYzEzNjM4IiwibmJmIjoxNzY2NzQ0MTQxLCJzdWIiOiIifQ.S8cvKtUfojJu0JvA1aPgd6H9y5ccd7XOa7UHMqZzn5w"}
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,219 @@
|
||||
{
|
||||
"serverName": "lzwcai_mcp_api_converter",
|
||||
"description": "登录、单据查询",
|
||||
"domainUrl": "http://39.108.116.74",
|
||||
"packageName": "lzwcai-mcp-dyntoolapi",
|
||||
"version": "1.0.0",
|
||||
"apiConfig": [
|
||||
{
|
||||
"id": "2029506334288154626",
|
||||
"enterpriseId": "1932095424144715777",
|
||||
"bizSysId": "2029468454441897985",
|
||||
"domainUrl": "http://39.108.116.74",
|
||||
"interfaceName": "登录",
|
||||
"businessPrompts": "登录",
|
||||
"returnType": "JSON",
|
||||
"returnConversion": "{\"success_param\": \"code==200\", \"status_param\": \"code\", \"msg_param\": \"msg\", \"data\": \"data\"}",
|
||||
"header": null,
|
||||
"apiUrl": "/K3Cloud/Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc",
|
||||
"parametersFormat": "2",
|
||||
"method": "POST",
|
||||
"status": 1,
|
||||
"version": "1.0.0",
|
||||
"authenticationRequired": 0,
|
||||
"responseExample": null,
|
||||
"crudType": "0",
|
||||
"isView": 0,
|
||||
"templateType": "markdown",
|
||||
"viewTemplates": null,
|
||||
"parameters": [
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 1,
|
||||
"paramName": "parameters",
|
||||
"paramType": "ARRAY",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334288154626",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "1",
|
||||
"tags": "2",
|
||||
"example": null
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "2029506334388817922",
|
||||
"enterpriseId": "1932095424144715777",
|
||||
"bizSysId": "2029468454441897985",
|
||||
"domainUrl": "http://39.108.116.74",
|
||||
"interfaceName": "单据查询",
|
||||
"businessPrompts": "单据查询",
|
||||
"returnType": "JSON",
|
||||
"returnConversion": "{\"success_param\": \"code==200\", \"status_param\": \"code\", \"msg_param\": \"msg\", \"data\": \"data\"}",
|
||||
"header": null,
|
||||
"apiUrl": "/k3cloud/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc",
|
||||
"parametersFormat": "2",
|
||||
"method": "POST",
|
||||
"status": 1,
|
||||
"version": "1.0.0",
|
||||
"authenticationRequired": 1,
|
||||
"responseExample": null,
|
||||
"crudType": "4",
|
||||
"isView": 0,
|
||||
"templateType": "markdown",
|
||||
"viewTemplates": null,
|
||||
"parameters": [
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 1,
|
||||
"paramName": "parameters",
|
||||
"paramType": "ARRAY",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334388817922",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "1",
|
||||
"tags": "2",
|
||||
"example": null
|
||||
},
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 0,
|
||||
"paramName": "parameters[].FormId",
|
||||
"paramType": "STRING",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334388817922",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "2",
|
||||
"tags": "2",
|
||||
"example": null
|
||||
},
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 0,
|
||||
"paramName": "parameters[].TopRowCount",
|
||||
"paramType": "INTEGER",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334388817922",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "3",
|
||||
"tags": "2",
|
||||
"example": null
|
||||
},
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 0,
|
||||
"paramName": "parameters[].Limit",
|
||||
"paramType": "INTEGER",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334388817922",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "4",
|
||||
"tags": "1",
|
||||
"example": null
|
||||
},
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 0,
|
||||
"paramName": "parameters[].StartRow",
|
||||
"paramType": "INTEGER",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334388817922",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "5",
|
||||
"tags": "2",
|
||||
"example": null
|
||||
},
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 0,
|
||||
"paramName": "parameters[].FilterString",
|
||||
"paramType": "STRING",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334388817922",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "6",
|
||||
"tags": "2",
|
||||
"example": null
|
||||
},
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 0,
|
||||
"paramName": "parameters[].OrderString",
|
||||
"paramType": "STRING",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334388817922",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "7",
|
||||
"tags": "3",
|
||||
"example": null
|
||||
},
|
||||
{
|
||||
"keyParam": null,
|
||||
"required": 0,
|
||||
"paramName": "parameters[].FieldKeys",
|
||||
"paramType": "STRING",
|
||||
"paramPrompts": "",
|
||||
"defaultValue": null,
|
||||
"assoKey": null,
|
||||
"assoApiId": null,
|
||||
"memory": 0,
|
||||
"apiId": "2029506334388817922",
|
||||
"requestType": "body",
|
||||
"dataFormat": null,
|
||||
"validity": null,
|
||||
"sort": "8",
|
||||
"tags": "0",
|
||||
"example": null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -687,7 +687,7 @@ class AuthService:
|
||||
self,
|
||||
user_id: Optional[str],
|
||||
biz_sys_id: Optional[str],
|
||||
persist_token: bool = True,
|
||||
persist_token: bool = False,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
完整的请求鉴权处理
|
||||
@@ -725,7 +725,7 @@ class AuthService:
|
||||
user_id: Optional[str],
|
||||
biz_sys_id: Optional[str],
|
||||
token: Optional[str] = None,
|
||||
persist_token: bool = True,
|
||||
persist_token: bool = False,
|
||||
) -> Optional[Union[str, Dict[str, Any]]]:
|
||||
"""
|
||||
检查用户Token是否有效,如无效则重新获取
|
||||
@@ -760,7 +760,7 @@ class AuthService:
|
||||
# 如果环境变量存在,直接返回值
|
||||
if exists:
|
||||
self.logger.info(
|
||||
f"从环境变量获取到用户{user_id}业务系统{biz_sys_id}的Token"
|
||||
f"从环境变量获取到用户{user_id}业务系统{biz_sys_id}的Token: {token_value}"
|
||||
)
|
||||
return token_value
|
||||
|
||||
@@ -774,7 +774,7 @@ class AuthService:
|
||||
return await self._refresh_user_token(user_id, biz_sys_id, token_name, persist_token)
|
||||
|
||||
async def _refresh_user_token(
|
||||
self, user_id: str, biz_sys_id: str, token_name: str, persist_token: bool = True
|
||||
self, user_id: str, biz_sys_id: str, token_name: str, persist_token: bool = False
|
||||
) -> Optional[Union[str, Dict[str, Any]]]:
|
||||
"""刷新用户Token"""
|
||||
# 获取鉴权类型和认证数据
|
||||
|
||||
@@ -667,7 +667,9 @@ class ApiClient:
|
||||
auth_result.get("error_response", {}).get("status_code"),
|
||||
)
|
||||
|
||||
return auth_result.get("tokenHeader", {})
|
||||
token_header = auth_result.get("tokenHeader", {})
|
||||
logger.info(f"API调用获取到Token - 用户ID: {user_id}, 业务系统ID: {biz_sys_id}, Token: {token_header}")
|
||||
return token_header
|
||||
|
||||
|
||||
def _contains_file(self, data: Dict[str, Any]) -> bool:
|
||||
@@ -938,10 +940,28 @@ class ApiClient:
|
||||
"status_code": response.status_code,
|
||||
}
|
||||
else:
|
||||
# 对于非JSON响应,记录前100个字符
|
||||
# 对于非JSON响应,尝试解析为JSON(某些API返回text/plain但内容是JSON)
|
||||
if not response.text:
|
||||
return {
|
||||
"status": "success",
|
||||
"data": "",
|
||||
"status_code": response.status_code,
|
||||
}
|
||||
|
||||
response_preview = response.text[:100] + "..." if len(response.text) > 100 else response.text
|
||||
logger.info(f"文本响应预览: {response_preview}")
|
||||
|
||||
# 尝试解析为JSON
|
||||
text = response.text.strip()
|
||||
if text and (text.startswith('{') or text.startswith('[')):
|
||||
try:
|
||||
json_response = json.loads(text)
|
||||
logger.info("文本响应成功解析为JSON")
|
||||
return json_response
|
||||
except (json.JSONDecodeError, ValueError) as e:
|
||||
logger.debug(f"文本响应JSON解析失败: {e}")
|
||||
|
||||
# 返回原始文本
|
||||
return {
|
||||
"status": "success",
|
||||
"data": response.text,
|
||||
|
||||
@@ -138,13 +138,11 @@ def load_api_configs():
|
||||
config_key = f"business{business_uuid}"
|
||||
logger.info(f"租户配置变量名: {config_key}")
|
||||
|
||||
# 检查内存中是否已有该租户的配置
|
||||
if config_key in business_configs:
|
||||
logger.info(f"从内存中获取租户 {business_uuid} 的配置")
|
||||
return business_configs[config_key]
|
||||
# 构建租户专属的配置文件路径
|
||||
memory_config_path = os.path.join(current_dir, f"api_config_{business_uuid}.json")
|
||||
|
||||
# 内存中没有,从业务平台获取
|
||||
logger.info(f"内存中没有租户 {business_uuid} 的配置,开始从业务平台获取...")
|
||||
# 本地文件不存在或加载失败,从业务平台获取
|
||||
logger.info(f"准备从业务平台获取租户 {business_uuid} 的最新配置(强制刷新)...")
|
||||
|
||||
try:
|
||||
# 从环境变量获取API ID列表
|
||||
@@ -181,11 +179,35 @@ def load_api_configs():
|
||||
logger.info(f"配置已存储到内存变量: {config_key}")
|
||||
logger.info(f"当前内存中共有 {len(business_configs)} 个租户配置")
|
||||
|
||||
# 保存到本地文件作为备份
|
||||
try:
|
||||
logger.info(f"保存配置到本地文件: {memory_config_path}")
|
||||
with open(memory_config_path, "w", encoding="utf-8") as f:
|
||||
json.dump(config, f, ensure_ascii=False, indent=2)
|
||||
logger.info("配置文件保存成功")
|
||||
except Exception as save_error:
|
||||
logger.warning(f"保存配置到本地文件失败(不影响运行): {str(save_error)}")
|
||||
|
||||
return config
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取业务API配置失败: {str(e)}")
|
||||
error_msg = f"内存模式下无法获取租户 {business_uuid} 的配置: {str(e)}"
|
||||
|
||||
# 网络获取失败,尝试降级使用本地缓存
|
||||
if os.path.exists(memory_config_path):
|
||||
try:
|
||||
logger.info(f"网络获取失败,尝试使用本地缓存文件: {memory_config_path}")
|
||||
with open(memory_config_path, "r", encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
logger.info(f"成功加载本地缓存配置,包含 {len(config.get('apiConfig', []))} 个API配置")
|
||||
|
||||
# 存储到内存中
|
||||
business_configs[config_key] = config
|
||||
return config
|
||||
except Exception as cache_error:
|
||||
logger.error(f"加载本地缓存也失败了: {str(cache_error)}")
|
||||
|
||||
error_msg = f"无法获取租户 {business_uuid} 的配置(网络和缓存均不可用): {str(e)}"
|
||||
raise Exception(error_msg)
|
||||
|
||||
# ==================== 模式二:文件模式(单租户) ====================
|
||||
@@ -367,24 +389,12 @@ 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
|
||||
name=tool_name,
|
||||
description=tool_config["schema_description"],
|
||||
inputSchema=tool_config["schema"],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -639,7 +649,7 @@ def refresh_api_configs():
|
||||
|
||||
这个函数实现了配置的热加载功能,支持两种模式:
|
||||
- 文件模式:当检测到配置文件变化时会被调用
|
||||
- 内存模式:强制重新从业务平台获取配置并更新内存
|
||||
- 内存模式:强制重新从业务平台获取配置并更新内存和本地文件
|
||||
|
||||
全局变量更新:
|
||||
- api_configs: 重新加载的API配置
|
||||
@@ -658,7 +668,7 @@ def refresh_api_configs():
|
||||
# 获取配置模式
|
||||
config_mode = os.getenv('configMode', 'memory').lower()
|
||||
|
||||
# 内存模式下需要清除当前租户的缓存配置,强制重新获取
|
||||
# 内存模式下需要清除当前租户的缓存配置和本地文件,强制重新获取
|
||||
if config_mode == 'memory':
|
||||
business_uuid = os.getenv('businessUuid')
|
||||
if business_uuid:
|
||||
@@ -667,6 +677,16 @@ def refresh_api_configs():
|
||||
logger.info(f"清除租户 {business_uuid} 的缓存配置")
|
||||
del business_configs[config_key]
|
||||
|
||||
# 删除本地配置文件,强制从业务平台重新获取
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
memory_config_path = os.path.join(current_dir, f"api_config_{business_uuid}.json")
|
||||
if os.path.exists(memory_config_path):
|
||||
try:
|
||||
os.remove(memory_config_path)
|
||||
logger.info(f"已删除本地配置文件: {memory_config_path}")
|
||||
except Exception as e:
|
||||
logger.warning(f"删除本地配置文件失败: {str(e)}")
|
||||
|
||||
# 重新加载API配置
|
||||
api_configs = load_api_configs()
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,9 +1,9 @@
|
||||
import os
|
||||
|
||||
os.environ["modelId"] = "1946471611735015425"
|
||||
os.environ["bizSysId"] = "1970385781825785858"
|
||||
os.environ["bizSysApiIds"] = "[\"1970386761072058369\",\"1970386761185304578\",\"1970386761583763457\",\"1970386761420185602\"]"
|
||||
os.environ["businessUuid"] = "u9ua9ss2l8c"
|
||||
os.environ["bizSysId"] = "2029468454441897985"
|
||||
os.environ["bizSysApiIds"] = "[\"2033382693160300546\"]"
|
||||
os.environ["businessUuid"] = "dcqwlucfo7h"
|
||||
os.environ["LZWCAI_CORP_MANAGER_URL"] = "http://192.168.2.236:8088"
|
||||
# 导入模块
|
||||
from lzwcai_mcp_api_converter.src.create_mcp import run_main
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "lzwcai-mcp-api-converter"
|
||||
version = "0.2.0"
|
||||
version = "0.2.5"
|
||||
description = "基于FastMCP框架的动态API工具服务器,自动将企业业务API配置转换为MCP协议工具,支持多种传输方式、企业认证和参数验证,为AI助手提供标准化的业务接口访问能力。"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,223 @@
|
||||
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 工具
|
||||
File diff suppressed because one or more lines are too long
@@ -7,7 +7,7 @@ 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"
|
||||
requires-python = ">=3.10"
|
||||
license = {text = "MIT"}
|
||||
authors = [
|
||||
{name = "lzwcai", email = "your-email@example.com"},
|
||||
@@ -17,7 +17,7 @@ classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
]
|
||||
dependencies = [
|
||||
"httpx>=0.28.1",
|
||||
|
||||
@@ -4,9 +4,9 @@ Runs the MCP server for SQL query execution
|
||||
"""
|
||||
import os
|
||||
|
||||
os.environ["databaseId"] = "12"
|
||||
os.environ["skillId"] = "2013848312313335809"
|
||||
os.environ["backendBaseUrl"] = "http://192.168.11.24:8088"
|
||||
os.environ["databaseId"] = "162"
|
||||
os.environ["skillId"] = "2008360664955854850"
|
||||
os.environ["backendBaseUrl"] = "http://192.168.2.236:8088"
|
||||
if __name__ == "__main__":
|
||||
# Import and run the actual MCP server
|
||||
from lzwcai_mcp_sqlexecutor.main import main
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai-mcp-sqlexecutor"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
description = "MCP server for executing business SQL queries with dynamic tool generation"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -240,3 +240,56 @@
|
||||
2026-01-16 12:39:34 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: MetricTrendAndTurningPointWarning
|
||||
2026-01-16 12:39:34 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-16 12:39:35 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:313] - ============================================================
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:316] - ============================================================
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 57
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 57
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID:
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.167.30.2:8088
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:324] - ============================================================
|
||||
2026-01-29 13:30:19 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动,等待客户端连接...
|
||||
2026-01-29 13:30:21 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
|
||||
2026-01-29 13:30:21 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)...
|
||||
2026-01-29 13:30:21 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
|
||||
2026-01-29 13:30:21 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
|
||||
2026-01-29 13:30:21 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
|
||||
2026-01-29 13:30:22 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OrderDelayWarningAnalysis
|
||||
2026-01-29 13:30:22 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-29 13:30:22 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-29 13:30:25 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: WorkOrderProgressAndAnomalyNodes
|
||||
2026-01-29 13:30:25 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-29 13:30:25 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:313] - ============================================================
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:316] - ============================================================
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 57
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 57
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID:
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.167.30.2:8088
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:324] - ============================================================
|
||||
2026-01-29 13:36:26 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动,等待客户端连接...
|
||||
2026-01-29 13:36:27 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
|
||||
2026-01-29 13:36:27 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)...
|
||||
2026-01-29 13:36:27 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
|
||||
2026-01-29 13:36:27 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
|
||||
2026-01-29 13:36:27 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
|
||||
2026-01-29 13:36:28 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OrderDelayWarningAnalysis
|
||||
2026-01-29 13:36:28 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-29 13:36:28 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-29 13:36:30 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: WorkOrderProgressAndAnomalyNodes
|
||||
2026-01-29 13:36:30 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-29 13:36:30 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-29 13:36:33 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplyChainRiskWarning
|
||||
2026-01-29 13:36:33 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-29 13:36:34 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-29 13:36:38 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: EfficiencyOutputLossDashboard
|
||||
2026-01-29 13:36:38 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-29 13:36:38 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-29 13:36:41 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: MetricTrendAndTurningPointWarning
|
||||
2026-01-29 13:36:41 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-29 13:36:41 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai-mcpskills-mfg-data-agent"
|
||||
version = "0.1.4"
|
||||
version = "0.1.6"
|
||||
description = "制造业数据智能体 - MCP server for manufacturing data intelligence with dynamic tool generation"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
111
lzwcai_mcpskills_mfg_data_agent/test.py
Normal file
111
lzwcai_mcpskills_mfg_data_agent/test.py
Normal file
@@ -0,0 +1,111 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
def main(**kwargs) -> dict:
|
||||
"""
|
||||
函数节点的入口函数
|
||||
|
||||
Args:
|
||||
**kwargs: 从前端配置的参数传入,可通过变量引用获取工作流上下文
|
||||
|
||||
Returns:
|
||||
dict: 返回结果将作为节点输出,可被后续节点引用
|
||||
"""
|
||||
# 从 kwargs 获取参数,如果没有提供则使用默认值
|
||||
url = kwargs.get('url', 'http://192.167.30.2:8088/datasource/sqlExecutionLog/testBatchSqlWithSchema')
|
||||
|
||||
# 请求头(从kwargs获取或使用默认值)
|
||||
authorization_token = kwargs.get('authorization_token', 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiTE9HSU4iLCJsb2dpbl91c2VyX2tleSI6IjAxNzZiNjEyLTc2YWItNDdhMS1iYTRiLTdjNWU2ZTMxNDlmZCJ9.w7aOfDJDHtA4bwNKIvUVK2cf1yO_2F27d_eYuos-p1-XGrSQOX0D4ny0b8Js36MhXwBnF4GDcy8V1VobEN6zBA')
|
||||
headers = {
|
||||
'Authorization': authorization_token
|
||||
}
|
||||
|
||||
# 请求体参数(从kwargs获取或使用默认值)
|
||||
payload_id = kwargs.get('id', '2006300000000000001')
|
||||
business_name = kwargs.get('businessName', 'OrderDelayWarningAnalysis')
|
||||
business_description = kwargs.get('businessDescription', '订单延迟预警分析:依据历史订单的生产周期、物流延误、设备故障等特征,输出延迟概率与红/黄/绿预警等级')
|
||||
datasource_id = kwargs.get('datasourceId', '57')
|
||||
sql_template = kwargs.get('sqlTemplate', 'WITH production_cycle_stats AS (SELECT COALESCE(AVG(GREATEST(0, EXTRACT(DAY FROM last_updated_utc - event_time_utc))), 0) AS avg_production_days FROM fact_work_order WHERE status = \'CLOSED\' AND last_updated_utc >= event_time_utc), logistics_delay_stats AS (SELECT customer_id, AVG(GREATEST(0, EXTRACT(DAY FROM event_time_utc - doc_date_utc))) AS avg_logistics_delay_days, SUM(CASE WHEN EXTRACT(DAY FROM event_time_utc - doc_date_utc) > 3 THEN 1 ELSE 0 END) AS delay_count FROM fact_sales_shipment WHERE doc_date_utc IS NOT NULL AND event_time_utc IS NOT NULL GROUP BY customer_id), quality_issue_stats AS (SELECT COALESCE(ROUND(SUM(fail_qty) * 100.0 / NULLIF(SUM(pass_qty + fail_qty), 0), 2), 0) AS defect_rate_pct FROM fact_quality_inspection WHERE pass_qty IS NOT NULL AND fail_qty IS NOT NULL), scrap_stats AS (SELECT COALESCE((SELECT COUNT(*) FROM fact_scrap) * 100.0 / NULLIF((SELECT COUNT(*) FROM fact_work_order WHERE status = \'CLOSED\'), 0), 0) AS scrap_rate_pct), active_work_order_risk AS (SELECT COUNT(*) AS active_wo_count, COALESCE(SUM(CASE WHEN planned_qty > 0 AND (completed_qty / planned_qty) 7 THEN 1 ELSE 0 END), 0) AS lagging_wo_count FROM fact_work_order WHERE status IN (\'OPEN\', \'STARTED\')), global_metrics AS (SELECT pcs.avg_production_days, qis.defect_rate_pct, ss.scrap_rate_pct, awr.active_wo_count, awr.lagging_wo_count FROM production_cycle_stats pcs, quality_issue_stats qis, scrap_stats ss, active_work_order_risk awr) SELECT so.sales_order_number AS order_number, c.customer_name, so.order_date_utc::DATE AS order_date, so.deal_amount AS order_amount, so.payment_status, ROUND(gm.avg_production_days::NUMERIC, 1) AS avg_production_days, ROUND(COALESCE(lds.avg_logistics_delay_days, 0)::NUMERIC, 1) AS avg_logistics_delay_days, COALESCE(lds.delay_count, 0)::INT AS historical_delay_count, ROUND(gm.defect_rate_pct::NUMERIC, 2) AS defect_rate_pct, ROUND(gm.scrap_rate_pct::NUMERIC, 2) AS scrap_rate_pct, gm.active_wo_count::INT AS active_work_order_count, gm.lagging_wo_count::INT AS lagging_work_order_count, ROUND(LEAST(100, GREATEST(0, LEAST(25, GREATEST(0, gm.avg_production_days - 10) * 2.5) + LEAST(30, COALESCE(lds.avg_logistics_delay_days, 0) * 6) + LEAST(25, gm.defect_rate_pct * 2.5) + LEAST(20, gm.lagging_wo_count * 10)))::NUMERIC, 1) AS delay_probability_pct, CASE WHEN (LEAST(25, GREATEST(0, gm.avg_production_days - 10) * 2.5) + LEAST(30, COALESCE(lds.avg_logistics_delay_days, 0) * 6) + LEAST(25, gm.defect_rate_pct * 2.5) + LEAST(20, gm.lagging_wo_count * 10)) >= 60 THEN \'RED\' WHEN (LEAST(25, GREATEST(0, gm.avg_production_days - 10) * 2.5) + LEAST(30, COALESCE(lds.avg_logistics_delay_days, 0) * 6) + LEAST(25, gm.defect_rate_pct * 2.5) + LEAST(20, gm.lagging_wo_count * 10)) >= 30 THEN \'YELLOW\' ELSE \'GREEN\' END AS warning_level, CASE WHEN gm.lagging_wo_count >= 2 THEN \'PRODUCTION_SEVERELY_DELAYED\' WHEN COALESCE(lds.avg_logistics_delay_days, 0) > 5 THEN \'HIGH_LOGISTICS_DELAY_RISK\' WHEN gm.avg_production_days > 15 THEN \'LONG_PRODUCTION_CYCLE\' WHEN gm.defect_rate_pct > 10 THEN \'QUALITY_ISSUES\' ELSE \'NORMAL\' END AS primary_risk_factor FROM fact_sales_order so LEFT JOIN dim_customer c ON so.customer_id = c.customer_id AND c.is_current = \'t\' CROSS JOIN global_metrics gm LEFT JOIN logistics_delay_stats lds ON so.customer_id = lds.customer_id WHERE EXTRACT(YEAR FROM so.order_date_utc) = 2025 ORDER BY delay_probability_pct DESC, so.order_date_utc DESC LIMIT 30')
|
||||
parameters = kwargs.get('parameters', {})
|
||||
|
||||
# 请求体(从kwargs获取或使用默认值)
|
||||
payload = {
|
||||
"id": payload_id,
|
||||
"businessName": business_name,
|
||||
"businessDescription": business_description,
|
||||
"datasourceId": datasource_id,
|
||||
"sqlTemplate": sql_template,
|
||||
"parameters": parameters
|
||||
}
|
||||
|
||||
# 超时时间(从kwargs获取或使用默认值)
|
||||
timeout = kwargs.get('timeout', 30)
|
||||
|
||||
try:
|
||||
# 发送POST请求
|
||||
response = requests.post(
|
||||
url=url,
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
# 检查HTTP响应状态码
|
||||
response.raise_for_status()
|
||||
|
||||
# 解析响应结果
|
||||
result = response.json()
|
||||
|
||||
# 返回接口调用结果
|
||||
return {
|
||||
"status": "success",
|
||||
"status_code": response.status_code,
|
||||
"result": result
|
||||
}
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
return {
|
||||
"status": "error",
|
||||
"error_type": "timeout",
|
||||
"message": f"接口调用超时({timeout}秒)",
|
||||
"result": None
|
||||
}
|
||||
|
||||
except requests.exceptions.ConnectionError:
|
||||
return {
|
||||
"status": "error",
|
||||
"error_type": "connection_error",
|
||||
"message": "无法连接到目标服务器",
|
||||
"result": None
|
||||
}
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
return {
|
||||
"status": "error",
|
||||
"error_type": "http_error",
|
||||
"status_code": response.status_code if 'response' in locals() else None,
|
||||
"message": f"HTTP请求错误: {str(e)}",
|
||||
"response_text": response.text if 'response' in locals() else "",
|
||||
"result": None
|
||||
}
|
||||
|
||||
except json.JSONDecodeError:
|
||||
return {
|
||||
"status": "error",
|
||||
"error_type": "json_decode_error",
|
||||
"message": "接口返回的不是有效的JSON格式",
|
||||
"response_text": response.text if 'response' in locals() else "",
|
||||
"result": None
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"status": "error",
|
||||
"error_type": "unknown_error",
|
||||
"message": f"接口调用失败: {str(e)}",
|
||||
"result": None
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = main()
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai-mcpskills-mfg-data-agentv2"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
description = "制造业数据智能体 - MCP server for manufacturing data intelligence with dynamic tool generation"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
65
lzwcai_mcpskills_template/README.md
Normal file
65
lzwcai_mcpskills_template/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# lzwcai-mcpskills-template
|
||||
|
||||
MCP Server 模板项目,用于快速创建新的 MCP 服务。
|
||||
|
||||
## 功能
|
||||
|
||||
- 提供 MCP Server 基础框架
|
||||
- 支持动态工具注册
|
||||
- 内置日志系统
|
||||
- 支持环境变量配置
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
pip install lzwcai-mcpskills-template
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
```bash
|
||||
# 设置环境变量
|
||||
export API_KEY="your-api-key"
|
||||
export BASE_URL="http://your-api-server"
|
||||
|
||||
# 运行
|
||||
lzwcai-mcpskills-template
|
||||
```
|
||||
|
||||
## 环境变量
|
||||
|
||||
| 变量名 | 说明 | 默认值 |
|
||||
|--------|------|--------|
|
||||
| API_KEY | API密钥 | - |
|
||||
| BASE_URL | 后端API地址 | http://localhost:8080 |
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
lzwcai_mcpskills_template/
|
||||
├── main.py # 入口文件
|
||||
├── pyproject.toml # 项目配置
|
||||
├── README.md # 说明文档
|
||||
└── lzwcai_mcpskills_template/ # 核心代码
|
||||
├── main.py # MCP Server 主逻辑
|
||||
├── schema_converter.py # Schema 转换器
|
||||
└── utils/ # 工具模块
|
||||
├── __init__.py
|
||||
├── api_client.py # API 客户端
|
||||
├── env_config.py # 环境变量配置
|
||||
├── json_helper.py # JSON 工具
|
||||
└── logger_config.py # 日志配置
|
||||
```
|
||||
|
||||
## 开发
|
||||
|
||||
基于此模板创建新项目:
|
||||
|
||||
1. 复制整个目录
|
||||
2. 修改 `pyproject.toml` 中的项目名称
|
||||
3. 修改 `lzwcai_mcpskills_template` 目录名
|
||||
4. 在 `main.py` 中实现你的工具逻辑
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1 @@
|
||||
3.13
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,89 @@
|
||||
2026-01-28 09:58:33 - root - INFO - [logger_config.py:112] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\logs
|
||||
2026-01-28 09:58:33 - mcp.server.lowlevel.server - DEBUG - [server.py:154] - Initializing server 'mcpskills_template_server'
|
||||
2026-01-28 09:58:33 - mcp.server.lowlevel.server - DEBUG - [server.py:380] - Registering handler for ListToolsRequest
|
||||
2026-01-28 09:58:33 - mcp.server.lowlevel.server - DEBUG - [server.py:441] - Registering handler for CallToolRequest
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:304] - ==================================================
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:305] - MCP Skills Template Server 启动
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:306] - ==================================================
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:311] - 命令行参数: {'mode': 'local', 'json_path': None}
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:314] - 使用模式: local
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:82] - 从本地加载 7 条配置: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\tools_config.json
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:136] - 已加载 7 个工具配置
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:321] - 开始运行 MCP Server (stdio 模式)
|
||||
2026-01-28 09:58:33 - asyncio - DEBUG - [proactor_events.py:634] - Using proactor: IocpProactor
|
||||
2026-01-28 09:58:33 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: root=InitializedNotification(method='notifications/initialized', params=None, jsonrpc='2.0')
|
||||
2026-01-28 09:58:34 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B64BFE0>
|
||||
2026-01-28 09:58:34 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest
|
||||
2026-01-28 09:58:34 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type ListToolsRequest
|
||||
2026-01-28 09:58:34 - lzwcai_mcpskills_template.main - INFO - [main.py:142] - 收到 ListTools 请求,当前配置数量: 7
|
||||
2026-01-28 09:58:34 - lzwcai_mcpskills_template.main - INFO - [main.py:161] - ListTools 响应: 返回 7 个工具
|
||||
2026-01-28 09:58:34 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:58:36 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B59CFE0>
|
||||
2026-01-28 09:58:36 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:58:36 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:58:36 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_mixed, arguments=None
|
||||
2026-01-28 09:58:36 - lzwcai_mcpskills_template.main - INFO - [main.py:187] - 工具执行成功: demo_mixed
|
||||
2026-01-28 09:58:36 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:58:55 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B39D7C0>
|
||||
2026-01-28 09:58:55 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:58:55 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:58:55 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_error, arguments=None
|
||||
2026-01-28 09:58:55 - lzwcai_mcpskills_template.main - ERROR - [main.py:190] - 工具执行失败: 这是一个演示用的模拟错误!执行被中断。
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\main.py", line 186, in handle_call_tool
|
||||
result_contents = execute_tool(name, arguments or {}, tool_config)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\main.py", line 259, in execute_tool
|
||||
raise ValueError("这是一个演示用的模拟错误!执行被中断。")
|
||||
ValueError: 这是一个演示用的模拟错误!执行被中断。
|
||||
2026-01-28 09:58:55 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:59:01 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B6164E0>
|
||||
2026-01-28 09:59:01 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:59:01 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:59:01 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_resource, arguments=None
|
||||
2026-01-28 09:59:01 - lzwcai_mcpskills_template.main - INFO - [main.py:187] - 工具执行成功: demo_resource
|
||||
2026-01-28 09:59:01 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:59:04 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B64BF80>
|
||||
2026-01-28 09:59:04 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:59:04 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:59:04 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_image, arguments=None
|
||||
2026-01-28 09:59:04 - lzwcai_mcpskills_template.main - INFO - [main.py:187] - 工具执行成功: demo_image
|
||||
2026-01-28 09:59:04 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:59:09 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B36DD90>
|
||||
2026-01-28 09:59:09 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:59:09 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:59:09 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_image, arguments=None
|
||||
2026-01-28 09:59:09 - lzwcai_mcpskills_template.main - INFO - [main.py:187] - 工具执行成功: demo_image
|
||||
2026-01-28 09:59:09 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 10:02:13 - root - INFO - [logger_config.py:112] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\logs
|
||||
2026-01-28 10:02:13 - mcp.server.lowlevel.server - DEBUG - [server.py:154] - Initializing server 'mcpskills_template_server'
|
||||
2026-01-28 10:02:13 - mcp.server.lowlevel.server - DEBUG - [server.py:380] - Registering handler for ListToolsRequest
|
||||
2026-01-28 10:02:13 - mcp.server.lowlevel.server - DEBUG - [server.py:441] - Registering handler for CallToolRequest
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:322] - ==================================================
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:323] - MCP Skills Template Server 启动
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:324] - ==================================================
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:329] - 命令行参数: {'mode': 'local', 'json_path': None}
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:332] - 使用模式: local
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:83] - 从本地加载 8 条配置: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\tools_config.json
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:137] - 已加载 8 个工具配置
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:339] - 开始运行 MCP Server (stdio 模式)
|
||||
2026-01-28 10:02:13 - asyncio - DEBUG - [proactor_events.py:634] - Using proactor: IocpProactor
|
||||
2026-01-28 10:02:13 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: root=InitializedNotification(method='notifications/initialized', params=None, jsonrpc='2.0')
|
||||
2026-01-28 10:02:40 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x000001407A58E3F0>
|
||||
2026-01-28 10:02:40 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest
|
||||
2026-01-28 10:02:40 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type ListToolsRequest
|
||||
2026-01-28 10:02:40 - lzwcai_mcpskills_template.main - INFO - [main.py:143] - 收到 ListTools 请求,当前配置数量: 8
|
||||
2026-01-28 10:02:40 - lzwcai_mcpskills_template.main - INFO - [main.py:162] - ListTools 响应: 返回 8 个工具
|
||||
2026-01-28 10:02:40 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 10:02:44 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x000001407A66FAD0>
|
||||
2026-01-28 10:02:44 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 10:02:44 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 10:02:44 - lzwcai_mcpskills_template.main - INFO - [main.py:172] - 收到 CallTool 请求: name=demo_complex, arguments={"user_info": {}}
|
||||
2026-01-28 10:02:44 - lzwcai_mcpskills_template.main - INFO - [main.py:189] - 工具执行成功: demo_complex
|
||||
2026-01-28 10:02:44 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 10:02:50 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x000001407A1DAF00>
|
||||
2026-01-28 10:02:50 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 10:02:50 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 10:02:50 - lzwcai_mcpskills_template.main - INFO - [main.py:172] - 收到 CallTool 请求: name=demo_mixed, arguments=None
|
||||
2026-01-28 10:02:50 - lzwcai_mcpskills_template.main - INFO - [main.py:189] - 工具执行成功: demo_mixed
|
||||
2026-01-28 10:02:50 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
@@ -0,0 +1,89 @@
|
||||
2026-01-28 09:58:33 - root - INFO - [logger_config.py:112] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\logs
|
||||
2026-01-28 09:58:33 - mcp.server.lowlevel.server - DEBUG - [server.py:154] - Initializing server 'mcpskills_template_server'
|
||||
2026-01-28 09:58:33 - mcp.server.lowlevel.server - DEBUG - [server.py:380] - Registering handler for ListToolsRequest
|
||||
2026-01-28 09:58:33 - mcp.server.lowlevel.server - DEBUG - [server.py:441] - Registering handler for CallToolRequest
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:304] - ==================================================
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:305] - MCP Skills Template Server 启动
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:306] - ==================================================
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:311] - 命令行参数: {'mode': 'local', 'json_path': None}
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:314] - 使用模式: local
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:82] - 从本地加载 7 条配置: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\tools_config.json
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:136] - 已加载 7 个工具配置
|
||||
2026-01-28 09:58:33 - lzwcai_mcpskills_template.main - INFO - [main.py:321] - 开始运行 MCP Server (stdio 模式)
|
||||
2026-01-28 09:58:33 - asyncio - DEBUG - [proactor_events.py:634] - Using proactor: IocpProactor
|
||||
2026-01-28 09:58:33 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: root=InitializedNotification(method='notifications/initialized', params=None, jsonrpc='2.0')
|
||||
2026-01-28 09:58:34 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B64BFE0>
|
||||
2026-01-28 09:58:34 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest
|
||||
2026-01-28 09:58:34 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type ListToolsRequest
|
||||
2026-01-28 09:58:34 - lzwcai_mcpskills_template.main - INFO - [main.py:142] - 收到 ListTools 请求,当前配置数量: 7
|
||||
2026-01-28 09:58:34 - lzwcai_mcpskills_template.main - INFO - [main.py:161] - ListTools 响应: 返回 7 个工具
|
||||
2026-01-28 09:58:34 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:58:36 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B59CFE0>
|
||||
2026-01-28 09:58:36 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:58:36 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:58:36 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_mixed, arguments=None
|
||||
2026-01-28 09:58:36 - lzwcai_mcpskills_template.main - INFO - [main.py:187] - 工具执行成功: demo_mixed
|
||||
2026-01-28 09:58:36 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:58:55 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B39D7C0>
|
||||
2026-01-28 09:58:55 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:58:55 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:58:55 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_error, arguments=None
|
||||
2026-01-28 09:58:55 - lzwcai_mcpskills_template.main - ERROR - [main.py:190] - 工具执行失败: 这是一个演示用的模拟错误!执行被中断。
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\main.py", line 186, in handle_call_tool
|
||||
result_contents = execute_tool(name, arguments or {}, tool_config)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\main.py", line 259, in execute_tool
|
||||
raise ValueError("这是一个演示用的模拟错误!执行被中断。")
|
||||
ValueError: 这是一个演示用的模拟错误!执行被中断。
|
||||
2026-01-28 09:58:55 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:59:01 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B6164E0>
|
||||
2026-01-28 09:59:01 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:59:01 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:59:01 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_resource, arguments=None
|
||||
2026-01-28 09:59:01 - lzwcai_mcpskills_template.main - INFO - [main.py:187] - 工具执行成功: demo_resource
|
||||
2026-01-28 09:59:01 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:59:04 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B64BF80>
|
||||
2026-01-28 09:59:04 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:59:04 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:59:04 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_image, arguments=None
|
||||
2026-01-28 09:59:04 - lzwcai_mcpskills_template.main - INFO - [main.py:187] - 工具执行成功: demo_image
|
||||
2026-01-28 09:59:04 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 09:59:09 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x0000029E6B36DD90>
|
||||
2026-01-28 09:59:09 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 09:59:09 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 09:59:09 - lzwcai_mcpskills_template.main - INFO - [main.py:171] - 收到 CallTool 请求: name=demo_image, arguments=None
|
||||
2026-01-28 09:59:09 - lzwcai_mcpskills_template.main - INFO - [main.py:187] - 工具执行成功: demo_image
|
||||
2026-01-28 09:59:09 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 10:02:13 - root - INFO - [logger_config.py:112] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\logs
|
||||
2026-01-28 10:02:13 - mcp.server.lowlevel.server - DEBUG - [server.py:154] - Initializing server 'mcpskills_template_server'
|
||||
2026-01-28 10:02:13 - mcp.server.lowlevel.server - DEBUG - [server.py:380] - Registering handler for ListToolsRequest
|
||||
2026-01-28 10:02:13 - mcp.server.lowlevel.server - DEBUG - [server.py:441] - Registering handler for CallToolRequest
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:322] - ==================================================
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:323] - MCP Skills Template Server 启动
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:324] - ==================================================
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:329] - 命令行参数: {'mode': 'local', 'json_path': None}
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:332] - 使用模式: local
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:83] - 从本地加载 8 条配置: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\tools_config.json
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:137] - 已加载 8 个工具配置
|
||||
2026-01-28 10:02:13 - lzwcai_mcpskills_template.main - INFO - [main.py:339] - 开始运行 MCP Server (stdio 模式)
|
||||
2026-01-28 10:02:13 - asyncio - DEBUG - [proactor_events.py:634] - Using proactor: IocpProactor
|
||||
2026-01-28 10:02:13 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: root=InitializedNotification(method='notifications/initialized', params=None, jsonrpc='2.0')
|
||||
2026-01-28 10:02:40 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x000001407A58E3F0>
|
||||
2026-01-28 10:02:40 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type ListToolsRequest
|
||||
2026-01-28 10:02:40 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type ListToolsRequest
|
||||
2026-01-28 10:02:40 - lzwcai_mcpskills_template.main - INFO - [main.py:143] - 收到 ListTools 请求,当前配置数量: 8
|
||||
2026-01-28 10:02:40 - lzwcai_mcpskills_template.main - INFO - [main.py:162] - ListTools 响应: 返回 8 个工具
|
||||
2026-01-28 10:02:40 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 10:02:44 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x000001407A66FAD0>
|
||||
2026-01-28 10:02:44 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 10:02:44 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 10:02:44 - lzwcai_mcpskills_template.main - INFO - [main.py:172] - 收到 CallTool 请求: name=demo_complex, arguments={"user_info": {}}
|
||||
2026-01-28 10:02:44 - lzwcai_mcpskills_template.main - INFO - [main.py:189] - 工具执行成功: demo_complex
|
||||
2026-01-28 10:02:44 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
2026-01-28 10:02:50 - mcp.server.lowlevel.server - DEBUG - [server.py:582] - Received message: <mcp.shared.session.RequestResponder object at 0x000001407A1DAF00>
|
||||
2026-01-28 10:02:50 - mcp.server.lowlevel.server - INFO - [server.py:619] - Processing request of type CallToolRequest
|
||||
2026-01-28 10:02:50 - mcp.server.lowlevel.server - DEBUG - [server.py:621] - Dispatching request of type CallToolRequest
|
||||
2026-01-28 10:02:50 - lzwcai_mcpskills_template.main - INFO - [main.py:172] - 收到 CallTool 请求: name=demo_mixed, arguments=None
|
||||
2026-01-28 10:02:50 - lzwcai_mcpskills_template.main - INFO - [main.py:189] - 工具执行成功: demo_mixed
|
||||
2026-01-28 10:02:50 - mcp.server.lowlevel.server - DEBUG - [server.py:662] - Response sent
|
||||
@@ -0,0 +1,8 @@
|
||||
2026-01-28 09:58:55 - lzwcai_mcpskills_template.main - ERROR - [main.py:190] - 工具执行失败: 这是一个演示用的模拟错误!执行被中断。
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\main.py", line 186, in handle_call_tool
|
||||
result_contents = execute_tool(name, arguments or {}, tool_config)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_template\lzwcai_mcpskills_template\main.py", line 259, in execute_tool
|
||||
raise ValueError("这是一个演示用的模拟错误!执行被中断。")
|
||||
ValueError: 这是一个演示用的模拟错误!执行被中断。
|
||||
345
lzwcai_mcpskills_template/lzwcai_mcpskills_template/main.py
Normal file
345
lzwcai_mcpskills_template/lzwcai_mcpskills_template/main.py
Normal file
@@ -0,0 +1,345 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
MCP Server 模板
|
||||
支持从本地 JSON 或 API 动态加载工具配置
|
||||
|
||||
使用方式:
|
||||
- local: 从本地 JSON 文件加载工具配置
|
||||
- api: 从远程 API 加载工具配置
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
import argparse
|
||||
import anyio
|
||||
import asyncio
|
||||
|
||||
import mcp.types as types
|
||||
from mcp.server import NotificationOptions, Server
|
||||
from mcp.server.models import InitializationOptions
|
||||
from mcp.server.stdio import stdio_server
|
||||
|
||||
try:
|
||||
from .schema_converter import convert_sql_params_to_input_schema
|
||||
from .utils.api_client import call_api
|
||||
from .utils.env_config import get_api_key, get_base_url
|
||||
from .utils.logger_config import setup_system_logging, get_logger
|
||||
except ImportError:
|
||||
from schema_converter import convert_sql_params_to_input_schema
|
||||
from utils.api_client import call_api
|
||||
from utils.env_config import get_api_key, get_base_url
|
||||
from utils.logger_config import setup_system_logging, get_logger
|
||||
|
||||
# 初始化日志系统
|
||||
setup_system_logging(app_name="lzwcai_mcpskills_template", log_level=logging.DEBUG)
|
||||
logger = get_logger(__name__)
|
||||
|
||||
# 初始化 MCP Server
|
||||
server = Server("mcpskills_template_server")
|
||||
|
||||
# 全局配置
|
||||
_tools_config: list[dict] = []
|
||||
_config: dict = {}
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
"""解析命令行参数"""
|
||||
parser = argparse.ArgumentParser(description="MCP Skills Template Server")
|
||||
parser.add_argument(
|
||||
"--mode",
|
||||
type=str,
|
||||
choices=["local", "api"],
|
||||
default="local",
|
||||
help="数据加载模式: local(本地JSON,默认) 或 api(远程API)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--json-path",
|
||||
type=str,
|
||||
default=None,
|
||||
help="本地 JSON 文件路径 (local 模式)"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
class DataLoader:
|
||||
"""数据加载器基类"""
|
||||
|
||||
def load(self) -> list[dict]:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class LocalLoader(DataLoader):
|
||||
"""本地 JSON 文件加载器"""
|
||||
|
||||
def __init__(self, json_path: str = None):
|
||||
if json_path is None:
|
||||
json_path = os.path.join(os.path.dirname(__file__), "tools_config.json")
|
||||
self.json_path = json_path
|
||||
|
||||
def load(self) -> list[dict]:
|
||||
try:
|
||||
with open(self.json_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
logger.info(f"从本地加载 {len(data)} 条配置: {self.json_path}")
|
||||
return data
|
||||
except FileNotFoundError:
|
||||
logger.error(f"配置文件不存在: {self.json_path}")
|
||||
return []
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"JSON 解析错误: {e}")
|
||||
return []
|
||||
|
||||
|
||||
class ApiLoader(DataLoader):
|
||||
"""API 远程加载器"""
|
||||
|
||||
def __init__(self):
|
||||
self.base_url = get_base_url()
|
||||
self.api_key = get_api_key()
|
||||
logger.debug(f"ApiLoader 初始化,base_url: {self.base_url}")
|
||||
|
||||
def load(self) -> list[dict]:
|
||||
try:
|
||||
# TODO: 根据实际 API 修改此处
|
||||
logger.info(f"开始从 API 加载工具配置")
|
||||
response = call_api("/api/tools", method="GET")
|
||||
|
||||
if response.get("code") != 200:
|
||||
logger.error(f"获取工具配置失败: {response.get('msg')}")
|
||||
return []
|
||||
|
||||
data = response.get("data", [])
|
||||
if isinstance(data, dict):
|
||||
data = [data]
|
||||
|
||||
logger.info(f"从 API 加载工具配置成功,数量: {len(data)}")
|
||||
return data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"API 请求失败: {e}", exc_info=True)
|
||||
return []
|
||||
|
||||
|
||||
def create_loader(mode: str, **kwargs) -> DataLoader:
|
||||
"""创建数据加载器"""
|
||||
if mode == "local":
|
||||
return LocalLoader(json_path=kwargs.get("json_path"))
|
||||
elif mode == "api":
|
||||
return ApiLoader()
|
||||
else:
|
||||
raise ValueError(f"不支持的模式: {mode}")
|
||||
|
||||
|
||||
def init_tools(loader: DataLoader):
|
||||
"""初始化工具配置"""
|
||||
global _tools_config
|
||||
_tools_config = loader.load()
|
||||
logger.info(f"已加载 {len(_tools_config)} 个工具配置")
|
||||
|
||||
|
||||
@server.list_tools()
|
||||
async def handle_list_tools() -> list[types.Tool]:
|
||||
"""列出所有可用工具"""
|
||||
logger.info(f"收到 ListTools 请求,当前配置数量: {len(_tools_config)}")
|
||||
tools = []
|
||||
|
||||
for tool in _tools_config:
|
||||
name = tool.get("name", "")
|
||||
description = tool.get("description") or tool.get("toolPrompt", "")
|
||||
sql_params = tool.get("sqlParams", "[]")
|
||||
|
||||
# 转换参数为 inputSchema
|
||||
input_schema = convert_sql_params_to_input_schema(sql_params)
|
||||
|
||||
tools.append(
|
||||
types.Tool(
|
||||
name=name,
|
||||
description=description,
|
||||
inputSchema=input_schema
|
||||
)
|
||||
)
|
||||
|
||||
logger.info(f"ListTools 响应: 返回 {len(tools)} 个工具")
|
||||
return tools
|
||||
|
||||
|
||||
@server.call_tool()
|
||||
async def handle_call_tool(
|
||||
name: str,
|
||||
arguments: dict | None
|
||||
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
|
||||
"""调用工具"""
|
||||
logger.info(f"收到 CallTool 请求: name={name}, arguments={json.dumps(arguments, ensure_ascii=False) if arguments else 'None'}")
|
||||
|
||||
# 查找对应的工具配置
|
||||
tool_config = None
|
||||
for tool in _tools_config:
|
||||
if tool.get("name") == name:
|
||||
tool_config = tool
|
||||
break
|
||||
|
||||
if tool_config is None:
|
||||
logger.error(f"未找到工具配置: {name}")
|
||||
raise ValueError(f"未知工具: {name}")
|
||||
|
||||
# TODO: 在这里实现你的工具逻辑
|
||||
try:
|
||||
# execute_tool 现在是 async 的
|
||||
result_contents = await execute_tool(name, arguments or {}, tool_config)
|
||||
logger.info(f"工具执行成功: {name}")
|
||||
return result_contents
|
||||
except Exception as e:
|
||||
logger.error(f"工具执行失败: {e}", exc_info=True)
|
||||
# 重新抛出异常,以便 MCP SDK 能够捕获并将其格式化为错误响应
|
||||
raise e
|
||||
|
||||
|
||||
async def execute_tool(name: str, arguments: dict, config: dict) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
|
||||
"""
|
||||
执行工具逻辑并返回 MCP 内容列表 (Async)
|
||||
"""
|
||||
# 1. 示例:Hello World (返回纯文本)
|
||||
if name == "example_hello_world":
|
||||
msg = f"Hello, {arguments.get('name', 'World')}!"
|
||||
return [types.TextContent(type="text", text=msg)]
|
||||
|
||||
# 2. 示例:计算器 (返回 JSON 格式的文本)
|
||||
elif name == "example_calculator":
|
||||
a = float(arguments.get("a", 0))
|
||||
b = float(arguments.get("b", 0))
|
||||
op = arguments.get("operation", "+")
|
||||
|
||||
if op == "+":
|
||||
result = a + b
|
||||
elif op == "-":
|
||||
result = a - b
|
||||
elif op == "*":
|
||||
result = a * b
|
||||
elif op == "/":
|
||||
result = a / b if b != 0 else "除数不能为0"
|
||||
else:
|
||||
result = "未知运算符"
|
||||
|
||||
output = {"result": result, "expression": f"{a} {op} {b}"}
|
||||
return [types.TextContent(type="text", text=json.dumps(output, ensure_ascii=False))]
|
||||
|
||||
# 3. 演示:纯文本
|
||||
elif name == "demo_text":
|
||||
return [types.TextContent(type="text", text="这是一个标准的纯文本输出示例。")]
|
||||
|
||||
# 4. 演示:图片输出
|
||||
elif name == "demo_image":
|
||||
# 这是一个 1x1 的红色像素点的 Base64
|
||||
red_dot_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
|
||||
return [
|
||||
types.ImageContent(
|
||||
type="image",
|
||||
data=red_dot_base64,
|
||||
mimeType="image/png"
|
||||
)
|
||||
]
|
||||
|
||||
# 5. 演示:资源输出
|
||||
elif name == "demo_resource":
|
||||
# 模拟返回一个嵌入式资源
|
||||
return [
|
||||
types.EmbeddedResource(
|
||||
type="resource",
|
||||
resource=types.TextResourceContents(
|
||||
uri="file:///logs/app.log",
|
||||
text="[INFO] System started\n[WARN] Low memory",
|
||||
mimeType="text/plain"
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
# 6. 演示:错误状态 (带 observation)
|
||||
elif name == "demo_error":
|
||||
# 尝试模拟用户要求的带 observation 的错误结构
|
||||
# 注意:标准 MCP 协议中 TextContent 可能不支持 observation 字段
|
||||
# 这里演示如何抛出异常,这是最标准的错误反馈方式
|
||||
raise ValueError("执行失败: 网络超时,请检查连接")
|
||||
|
||||
# 如果客户端支持非标准字段,可以尝试返回如下结构(需 SDK 支持):
|
||||
# return [
|
||||
# types.TextContent(type="text", text="执行失败") # 无法直接添加 observation
|
||||
# ]
|
||||
|
||||
# 7. 演示:混合输出 (文本 + 图片)
|
||||
elif name == "demo_mixed":
|
||||
red_dot_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
|
||||
return [
|
||||
types.TextContent(type="text", text="下面是一张图片:"),
|
||||
types.ImageContent(
|
||||
type="image",
|
||||
data=red_dot_base64,
|
||||
mimeType="image/png"
|
||||
),
|
||||
types.TextContent(type="text", text="图片展示完毕。")
|
||||
]
|
||||
|
||||
# 8. 演示:复杂参数
|
||||
elif name == "demo_complex":
|
||||
user_info = arguments.get("user_info", {})
|
||||
tags = arguments.get("tags", [])
|
||||
|
||||
# 模拟异步处理
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
result_text = f"接收到复杂参数:\n用户: {json.dumps(user_info, ensure_ascii=False)}\n标签: {tags}"
|
||||
return [types.TextContent(type="text", text=result_text)]
|
||||
|
||||
# 默认返回参数
|
||||
default_result = {
|
||||
"tool_name": name,
|
||||
"arguments": arguments,
|
||||
"message": "工具执行成功(默认实现)"
|
||||
}
|
||||
return [types.TextContent(type="text", text=json.dumps(default_result, ensure_ascii=False, indent=2))]
|
||||
|
||||
|
||||
async def run_server():
|
||||
"""运行 MCP Server (stdio 模式)"""
|
||||
async with stdio_server() as streams:
|
||||
await server.run(
|
||||
streams[0],
|
||||
streams[1],
|
||||
InitializationOptions(
|
||||
server_name="mcpskills_template_server",
|
||||
server_version="0.1.0",
|
||||
capabilities=server.get_capabilities(
|
||||
notification_options=NotificationOptions(),
|
||||
experimental_capabilities={},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
"""主入口"""
|
||||
global _config
|
||||
|
||||
logger.info("=" * 50)
|
||||
logger.info("MCP Skills Template Server 启动")
|
||||
logger.info("=" * 50)
|
||||
|
||||
# 解析命令行参数
|
||||
args = parse_arguments()
|
||||
_config = vars(args)
|
||||
logger.info(f"命令行参数: {_config}")
|
||||
|
||||
# 创建加载器并初始化工具
|
||||
logger.info(f"使用模式: {args.mode}")
|
||||
loader = create_loader(
|
||||
mode=args.mode,
|
||||
json_path=args.json_path
|
||||
)
|
||||
init_tools(loader)
|
||||
|
||||
logger.info("开始运行 MCP Server (stdio 模式)")
|
||||
# 运行服务器
|
||||
anyio.run(run_server)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,185 @@
|
||||
"""
|
||||
Schema 转换器
|
||||
将 sqlParams 数组格式转换为 MCP 工具需要的 JSON Schema 格式
|
||||
|
||||
支持的类型:
|
||||
- string: 文本输入
|
||||
- paragraph: 段落/多行文本
|
||||
- select: 下拉选项
|
||||
- number: 数字输入
|
||||
"""
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
|
||||
def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]:
|
||||
"""
|
||||
将单个参数转换为 JSON Schema property
|
||||
|
||||
Args:
|
||||
param: 参数配置,格式如:
|
||||
{
|
||||
"type": "string",
|
||||
"name": "param_name",
|
||||
"displayName": "参数显示名",
|
||||
"maxLength": 200,
|
||||
"defaultValue": "",
|
||||
"required": true,
|
||||
"options": ["选项1", "选项2"] # 仅 select 类型
|
||||
}
|
||||
|
||||
Returns:
|
||||
tuple: (property_name, property_schema, is_required)
|
||||
"""
|
||||
param_type = param.get("type", "string")
|
||||
param_name = param.get("name", "")
|
||||
display_name = param.get("displayName", param_name)
|
||||
default_value = param.get("defaultValue", "")
|
||||
max_length = param.get("maxLength")
|
||||
is_required = param.get("required", False)
|
||||
options = param.get("options", [])
|
||||
|
||||
property_schema = {
|
||||
"description": display_name
|
||||
}
|
||||
|
||||
if param_type == "string":
|
||||
property_schema["type"] = "string"
|
||||
if max_length:
|
||||
property_schema["maxLength"] = max_length
|
||||
|
||||
elif param_type == "paragraph":
|
||||
property_schema["type"] = "string"
|
||||
property_schema["format"] = "paragraph"
|
||||
if max_length:
|
||||
property_schema["maxLength"] = max_length
|
||||
|
||||
elif param_type == "select":
|
||||
property_schema["type"] = "string"
|
||||
if options:
|
||||
property_schema["enum"] = options
|
||||
|
||||
elif param_type == "number":
|
||||
property_schema["type"] = "number"
|
||||
|
||||
elif param_type == "boolean":
|
||||
property_schema["type"] = "boolean"
|
||||
# Boolean default handling
|
||||
if default_value is not None and str(default_value).lower() in ("true", "false", "1", "0"):
|
||||
property_schema["default"] = str(default_value).lower() in ("true", "1")
|
||||
|
||||
elif param_type == "array":
|
||||
property_schema["type"] = "array"
|
||||
# Simple array of strings by default if no item type specified
|
||||
# For more complex arrays, we might need extended config in sqlParams
|
||||
property_schema["items"] = {"type": "string"}
|
||||
|
||||
elif param_type == "object":
|
||||
property_schema["type"] = "object"
|
||||
# Allow any object structure by default
|
||||
property_schema["additionalProperties"] = True
|
||||
|
||||
else:
|
||||
# 默认当作 string 处理
|
||||
property_schema["type"] = "string"
|
||||
|
||||
# 添加默认值
|
||||
if default_value not in (None, ""):
|
||||
if param_type == "number":
|
||||
try:
|
||||
property_schema["default"] = int(default_value) if str(default_value).isdigit() else float(default_value)
|
||||
except (ValueError, TypeError):
|
||||
property_schema["default"] = default_value
|
||||
else:
|
||||
property_schema["default"] = default_value
|
||||
|
||||
return param_name, property_schema, is_required
|
||||
|
||||
|
||||
def convert_sql_params_to_input_schema(sql_params: str | list) -> dict:
|
||||
"""
|
||||
将 sqlParams 转换为 MCP 工具的 inputSchema
|
||||
|
||||
Args:
|
||||
sql_params: sqlParams 字段值,可以是 JSON 字符串或已解析的列表
|
||||
格式: [{"type": "string", "name": "xxx", ...}, ...]
|
||||
|
||||
Returns:
|
||||
dict: MCP 工具的 inputSchema,格式如:
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {...},
|
||||
"required": [...]
|
||||
}
|
||||
"""
|
||||
# 解析 JSON 字符串
|
||||
if isinstance(sql_params, str):
|
||||
try:
|
||||
params_list = json.loads(sql_params)
|
||||
except json.JSONDecodeError:
|
||||
return {"type": "object", "properties": {}, "required": []}
|
||||
else:
|
||||
params_list = sql_params
|
||||
|
||||
if not isinstance(params_list, list):
|
||||
return {"type": "object", "properties": {}, "required": []}
|
||||
|
||||
input_schema = {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
|
||||
for param in params_list:
|
||||
if not isinstance(param, dict):
|
||||
continue
|
||||
|
||||
name, schema, is_required = convert_param_to_schema_property(param)
|
||||
|
||||
if name:
|
||||
input_schema["properties"][name] = schema
|
||||
if is_required:
|
||||
input_schema["required"].append(name)
|
||||
|
||||
return input_schema
|
||||
|
||||
|
||||
def convert_tool_config_to_mcp_tool(config: dict) -> dict:
|
||||
"""
|
||||
将单个工具配置转换为 MCP Tool 配置
|
||||
|
||||
Args:
|
||||
config: 工具配置对象
|
||||
|
||||
Returns:
|
||||
dict: MCP Tool 配置
|
||||
"""
|
||||
name = config.get("name", "")
|
||||
description = config.get("description") or config.get("toolPrompt", "")
|
||||
sql_params = config.get("sqlParams", "[]")
|
||||
|
||||
input_schema = convert_sql_params_to_input_schema(sql_params)
|
||||
|
||||
return {
|
||||
"name": name,
|
||||
"description": description,
|
||||
"inputSchema": input_schema,
|
||||
"_raw": config # 保留原始数据
|
||||
}
|
||||
|
||||
|
||||
# 测试用
|
||||
if __name__ == "__main__":
|
||||
# 测试单个参数转换
|
||||
test_param = {
|
||||
"type": "select",
|
||||
"name": "operation",
|
||||
"displayName": "运算符",
|
||||
"required": True,
|
||||
"options": ["+", "-", "*", "/"]
|
||||
}
|
||||
|
||||
name, schema, required = convert_param_to_schema_property(test_param)
|
||||
print(f"参数名: {name}")
|
||||
print(f"Schema: {json.dumps(schema, ensure_ascii=False, indent=2)}")
|
||||
print(f"必填: {required}")
|
||||
@@ -0,0 +1,58 @@
|
||||
[
|
||||
{
|
||||
"id": "example_tool_001",
|
||||
"name": "example_hello_world2",
|
||||
"description": "示例工具 - Hello World2",
|
||||
"toolPrompt": "这是一个示例工具,用于演示 MCP 工具的基本结构",
|
||||
"sqlParams": "[{\"type\":\"string\",\"name\":\"name2\",\"displayName\":\"名称\",\"maxLength\":100,\"defaultValue\":\"World\",\"required\":true}]"
|
||||
},
|
||||
{
|
||||
"id": "example_tool_002",
|
||||
"name": "example_calculator",
|
||||
"description": "示例工具 - 简单计算器",
|
||||
"toolPrompt": "执行简单的数学计算",
|
||||
"sqlParams": "[{\"type\":\"number\",\"name\":\"a\",\"displayName\":\"数字A\",\"required\":true},{\"type\":\"number\",\"name\":\"b\",\"displayName\":\"数字B\",\"required\":true},{\"type\":\"select\",\"name\":\"operation\",\"displayName\":\"运算符\",\"required\":true,\"options\":[\"+\",\"-\",\"*\",\"/\"]}]"
|
||||
},
|
||||
{
|
||||
"id": "demo_001",
|
||||
"name": "demo_text",
|
||||
"description": "演示纯文本输出",
|
||||
"toolPrompt": "返回一段简单的文本信息",
|
||||
"sqlParams": "[]"
|
||||
},
|
||||
{
|
||||
"id": "demo_002",
|
||||
"name": "demo_image",
|
||||
"description": "演示图片输出",
|
||||
"toolPrompt": "返回一张 Base64 编码的图片",
|
||||
"sqlParams": "[]"
|
||||
},
|
||||
{
|
||||
"id": "demo_003",
|
||||
"name": "demo_resource",
|
||||
"description": "演示资源输出",
|
||||
"toolPrompt": "返回一个嵌入式资源",
|
||||
"sqlParams": "[]"
|
||||
},
|
||||
{
|
||||
"id": "demo_004",
|
||||
"name": "demo_error",
|
||||
"description": "演示错误状态",
|
||||
"toolPrompt": "触发一个执行错误",
|
||||
"sqlParams": "[]"
|
||||
},
|
||||
{
|
||||
"id": "demo_005",
|
||||
"name": "demo_mixed",
|
||||
"description": "演示混合输出",
|
||||
"toolPrompt": "同时返回文本和图片",
|
||||
"sqlParams": "[]"
|
||||
},
|
||||
{
|
||||
"id": "demo_006",
|
||||
"name": "demo_complex",
|
||||
"description": "演示复杂参数输入",
|
||||
"toolPrompt": "接受对象和数组类型的参数",
|
||||
"sqlParams": "[{\"type\":\"object\",\"name\":\"user_info\",\"displayName\":\"用户信息\",\"required\":true},{\"type\":\"array\",\"name\":\"tags\",\"displayName\":\"标签列表\",\"required\":false}]"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
"""Utils package for lzwcai_mcpskills_template"""
|
||||
|
||||
from .json_helper import load_json
|
||||
from .api_client import call_api, APIClient, get_default_client
|
||||
from .env_config import get_api_key, get_base_url, get_env_config, set_env_variable
|
||||
from .logger_config import setup_system_logging, get_logger
|
||||
|
||||
__all__ = [
|
||||
'load_json',
|
||||
'call_api',
|
||||
'APIClient',
|
||||
'get_default_client',
|
||||
'get_api_key',
|
||||
'get_base_url',
|
||||
'get_env_config',
|
||||
'set_env_variable',
|
||||
'setup_system_logging',
|
||||
'get_logger'
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,197 @@
|
||||
"""
|
||||
API 调用客户端
|
||||
通用的 HTTP API 客户端封装
|
||||
"""
|
||||
|
||||
import httpx
|
||||
import json
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
try:
|
||||
from .env_config import get_base_url, get_api_key
|
||||
from .logger_config import get_logger
|
||||
except ImportError:
|
||||
from env_config import get_base_url, get_api_key
|
||||
from logger_config import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
# 默认超时配置(秒)
|
||||
DEFAULT_TIMEOUT = 30.0
|
||||
LONG_TIMEOUT = 300.0
|
||||
|
||||
|
||||
class APIClient:
|
||||
"""通用 API 客户端"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
base_url: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
default_timeout: float = DEFAULT_TIMEOUT
|
||||
):
|
||||
"""
|
||||
初始化 API 客户端
|
||||
|
||||
Args:
|
||||
base_url: API 基础 URL(默认从环境变量读取)
|
||||
api_key: API 密钥(默认从环境变量读取)
|
||||
default_timeout: 默认超时时间(秒)
|
||||
"""
|
||||
self.base_url = (base_url or get_base_url()).rstrip('/')
|
||||
self.api_key = api_key or get_api_key()
|
||||
self.default_timeout = default_timeout
|
||||
self._client: Optional[httpx.Client] = None
|
||||
|
||||
logger.info(f"[客户端初始化] base_url={self.base_url}")
|
||||
|
||||
@property
|
||||
def client(self) -> httpx.Client:
|
||||
"""懒加载 HTTP 客户端"""
|
||||
if self._client is None:
|
||||
self._client = httpx.Client(timeout=self.default_timeout)
|
||||
return self._client
|
||||
|
||||
def _get_headers(self) -> Dict[str, str]:
|
||||
"""获取请求头"""
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
if self.api_key:
|
||||
headers['X-API-Key'] = self.api_key
|
||||
return headers
|
||||
|
||||
def request(
|
||||
self,
|
||||
endpoint: str,
|
||||
method: str = "GET",
|
||||
data: Optional[Dict[str, Any]] = None,
|
||||
params: Optional[Dict[str, Any]] = None,
|
||||
timeout: Optional[float] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
发送 HTTP 请求
|
||||
|
||||
Args:
|
||||
endpoint: API 端点路径
|
||||
method: HTTP 方法
|
||||
data: 请求体数据
|
||||
params: URL 查询参数
|
||||
timeout: 超时时间
|
||||
|
||||
Returns:
|
||||
API 响应数据
|
||||
"""
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
timeout = timeout or self.default_timeout
|
||||
|
||||
try:
|
||||
logger.info(f"[API请求] {method} {url}")
|
||||
|
||||
if method.upper() == "GET":
|
||||
response = self.client.get(
|
||||
url,
|
||||
headers=self._get_headers(),
|
||||
params=params,
|
||||
timeout=timeout
|
||||
)
|
||||
elif method.upper() == "POST":
|
||||
response = self.client.post(
|
||||
url,
|
||||
headers=self._get_headers(),
|
||||
json=data,
|
||||
params=params,
|
||||
timeout=timeout
|
||||
)
|
||||
elif method.upper() == "PUT":
|
||||
response = self.client.put(
|
||||
url,
|
||||
headers=self._get_headers(),
|
||||
json=data,
|
||||
params=params,
|
||||
timeout=timeout
|
||||
)
|
||||
elif method.upper() == "DELETE":
|
||||
response = self.client.delete(
|
||||
url,
|
||||
headers=self._get_headers(),
|
||||
params=params,
|
||||
timeout=timeout
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"不支持的 HTTP 方法: {method}")
|
||||
|
||||
logger.info(f"[API响应] HTTP {response.status_code}")
|
||||
response.raise_for_status()
|
||||
|
||||
return response.json()
|
||||
|
||||
except httpx.TimeoutException:
|
||||
error_msg = f"API 请求超时: {url}"
|
||||
logger.error(f"[API错误] {error_msg}")
|
||||
raise Exception(error_msg)
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_msg = f"API 请求失败 (HTTP {e.response.status_code}): {url}"
|
||||
logger.error(f"[API错误] {error_msg}")
|
||||
raise Exception(error_msg)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"API 请求异常: {str(e)}"
|
||||
logger.error(f"[API错误] {error_msg}", exc_info=True)
|
||||
raise Exception(error_msg)
|
||||
|
||||
def close(self):
|
||||
"""关闭 HTTP 客户端"""
|
||||
if self._client is not None:
|
||||
self._client.close()
|
||||
self._client = None
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.close()
|
||||
return False
|
||||
|
||||
|
||||
# 懒加载的默认客户端
|
||||
_default_client: Optional[APIClient] = None
|
||||
|
||||
|
||||
def get_default_client() -> APIClient:
|
||||
"""获取默认客户端(懒加载)"""
|
||||
global _default_client
|
||||
if _default_client is None:
|
||||
_default_client = APIClient()
|
||||
return _default_client
|
||||
|
||||
|
||||
def call_api(
|
||||
endpoint: str,
|
||||
method: str = "GET",
|
||||
data: Optional[Dict[str, Any]] = None,
|
||||
params: Optional[Dict[str, Any]] = None,
|
||||
timeout: Optional[float] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
便捷函数:调用 API
|
||||
|
||||
Args:
|
||||
endpoint: API 端点路径
|
||||
method: HTTP 方法
|
||||
data: 请求体数据
|
||||
params: URL 查询参数
|
||||
timeout: 超时时间
|
||||
|
||||
Returns:
|
||||
API 响应数据
|
||||
"""
|
||||
return get_default_client().request(
|
||||
endpoint=endpoint,
|
||||
method=method,
|
||||
data=data,
|
||||
params=params,
|
||||
timeout=timeout
|
||||
)
|
||||
@@ -0,0 +1,60 @@
|
||||
"""环境变量配置模块"""
|
||||
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def get_api_key(default: str = "") -> str:
|
||||
"""
|
||||
获取 API 密钥环境变量
|
||||
|
||||
Args:
|
||||
default: 默认值
|
||||
|
||||
Returns:
|
||||
str: API 密钥
|
||||
|
||||
Environment Variables:
|
||||
API_KEY: API 密钥
|
||||
"""
|
||||
return os.environ.get("API_KEY", default)
|
||||
|
||||
|
||||
def get_base_url(default: str = "http://localhost:8080") -> str:
|
||||
"""
|
||||
获取后端 API 基础 URL 环境变量
|
||||
|
||||
Args:
|
||||
default: 默认值
|
||||
|
||||
Returns:
|
||||
str: 后端 API 基础 URL
|
||||
|
||||
Environment Variables:
|
||||
BASE_URL: 后端 API 基础 URL
|
||||
"""
|
||||
return os.environ.get("BASE_URL", default)
|
||||
|
||||
|
||||
def get_env_config() -> dict:
|
||||
"""
|
||||
获取所有环境配置
|
||||
|
||||
Returns:
|
||||
dict: 包含所有配置的字典
|
||||
"""
|
||||
return {
|
||||
"api_key": get_api_key(),
|
||||
"base_url": get_base_url()
|
||||
}
|
||||
|
||||
|
||||
def set_env_variable(key: str, value: str) -> None:
|
||||
"""
|
||||
设置环境变量(仅在当前进程中有效)
|
||||
|
||||
Args:
|
||||
key: 环境变量名
|
||||
value: 环境变量值
|
||||
"""
|
||||
os.environ[key] = value
|
||||
@@ -0,0 +1,41 @@
|
||||
"""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 文件的路径
|
||||
|
||||
Returns:
|
||||
JSON 文件中解析后的数据
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: 当文件不存在时
|
||||
json.JSONDecodeError: 当 JSON 格式无效时
|
||||
"""
|
||||
try:
|
||||
path = Path(json_path)
|
||||
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(f"JSON 文件不存在: {json_path}")
|
||||
|
||||
if not path.is_file():
|
||||
raise ValueError(f"路径不是一个文件: {json_path}")
|
||||
|
||||
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)}")
|
||||
@@ -0,0 +1,130 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
统一日志配置模块
|
||||
提供系统级别的日志配置和管理
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class LoggerConfig:
|
||||
"""日志配置管理类"""
|
||||
|
||||
def __init__(self, logs_dir: str = None):
|
||||
"""初始化日志配置"""
|
||||
if logs_dir:
|
||||
self.logs_dir = Path(logs_dir)
|
||||
else:
|
||||
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'
|
||||
self.log_level = self._get_log_level_from_env()
|
||||
self._initialized = False
|
||||
|
||||
def _get_log_level_from_env(self) -> 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_mcpskills_template",
|
||||
log_level: int = logging.INFO,
|
||||
max_file_size: int = 10 * 1024 * 1024,
|
||||
backup_count: int = 5,
|
||||
console_output: bool = True) -> 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_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,
|
||||
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)
|
||||
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}")
|
||||
|
||||
return root_logger
|
||||
|
||||
def get_module_logger(self, module_name: str) -> logging.Logger:
|
||||
return logging.getLogger(module_name)
|
||||
|
||||
|
||||
# 全局日志配置实例
|
||||
logger_config = LoggerConfig()
|
||||
|
||||
|
||||
def setup_system_logging(app_name: str = "lzwcai_mcpskills_template",
|
||||
log_level: int = logging.INFO) -> logging.Logger:
|
||||
return logger_config.setup_logging(app_name, log_level)
|
||||
|
||||
|
||||
def get_logger(name: str) -> logging.Logger:
|
||||
return logger_config.get_module_logger(name)
|
||||
15
lzwcai_mcpskills_template/main.py
Normal file
15
lzwcai_mcpskills_template/main.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
Entry point for lzwcai-mcpskills-template
|
||||
MCP Server 模板项目入口
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 设置环境变量(根据实际需求修改)
|
||||
os.environ["API_KEY"] = "your-api-key"
|
||||
os.environ["BASE_URL"] = "http://localhost:8080"
|
||||
|
||||
# Import and run the actual MCP server
|
||||
from lzwcai_mcpskills_template.main import main
|
||||
main()
|
||||
31
lzwcai_mcpskills_template/pyproject.toml
Normal file
31
lzwcai_mcpskills_template/pyproject.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai_mcpskills_template"
|
||||
version = "0.1.3"
|
||||
description = "MCP Server 模板项目 - 用于快速创建新的 MCP 服务"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
license = {text = "MIT"}
|
||||
authors = [
|
||||
{name = "lzwcai", email = "your-email@example.com"},
|
||||
]
|
||||
keywords = ["mcp", "template", "server"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
]
|
||||
dependencies = [
|
||||
"httpx>=0.28.1",
|
||||
"mcp[cli]>=1.10.1",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
lzwcai_mcpskills_template = "lzwcai_mcpskills_template.main:main"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["lzwcai_mcpskills_template"]
|
||||
37
lzwcai_mcpskills_visual2url/README.md
Normal file
37
lzwcai_mcpskills_visual2url/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# lzwcai_mcpskills_visual2url
|
||||
|
||||
基于 FastMCP 的 MCP Server 项目。主要提供 HTML 转换为浏览器可访问 URL 的工具。
|
||||
|
||||
## 功能
|
||||
|
||||
提供以下两个工具(Tools):
|
||||
- `html_file_to_url`: 传入本地 HTML 文件路径,转换成 `file://` 协议的 URL,方便浏览器直接打开预览。
|
||||
- `html_code_to_url`: 传入 HTML 代码片段,将其保存为临时文件并返回可访问的 `file://` URL。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
pip install lzwcai_mcpskills_visual2url
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
```bash
|
||||
# 直接运行服务端
|
||||
lzwcai_mcpskills_visual2url
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
lzwcai_mcpskills_visual2url/
|
||||
├── main.py # 入口文件
|
||||
├── pyproject.toml # 项目配置
|
||||
├── README.md # 说明文档
|
||||
└── lzwcai_mcpskills_visual2url/ # 核心代码
|
||||
└── main.py # FastMCP Server 主逻辑
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1 @@
|
||||
3.13
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,72 @@
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
import os
|
||||
import requests
|
||||
|
||||
# 创建 FastMCP 实例
|
||||
mcp = FastMCP("Visual2URL")
|
||||
|
||||
UPLOAD_URL = "http://192.168.2.236:5002/api/html/upload"
|
||||
AUTHORIZATION = "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ0b2tlbl90eXBlIjoiTE9HSU4iLCJsb2dpbl91c2VyX2tleSI6IjM3OTAzNGIwLTg3OTQtNGU2OS05MzRiLTJkNTA3ZWIzODQyOCJ9.X5O0zez0_zm4Ejc9wTyj04Sf3GLT2L9ilIE6W0qbSgggdTvKcaboVm-A64U3SPxC8rpB1Gxc5p-XK7FXqAjgEg"
|
||||
|
||||
@mcp.tool()
|
||||
def html_file_to_url(file_path: str) -> str:
|
||||
"""
|
||||
将本地 HTML 文件上传至服务器并转换成可在浏览器中打开的 URL。
|
||||
|
||||
Args:
|
||||
file_path: 本地 HTML 文件的绝对路径
|
||||
"""
|
||||
if not os.path.exists(file_path):
|
||||
return f"Error: 文件不存在: {file_path}"
|
||||
|
||||
headers = {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)'
|
||||
}
|
||||
|
||||
try:
|
||||
with open(file_path, 'rb') as f:
|
||||
files = {
|
||||
'file': (os.path.basename(file_path), f, 'text/html')
|
||||
}
|
||||
response = requests.post(UPLOAD_URL, headers=headers, files=files)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if data.get('code') == 200 and 'data' in data and 'fileUrl' in data['data']:
|
||||
return data['data']['fileUrl']
|
||||
else:
|
||||
return f"上传失败: {data.get('msg', '未知错误')}"
|
||||
except Exception as e:
|
||||
return f"请求发生异常: {str(e)}"
|
||||
|
||||
@mcp.tool()
|
||||
def html_code_to_url(html_code: str) -> str:
|
||||
"""
|
||||
将 HTML 代码片段上传至服务器并转换成可在浏览器中打开的 URL。
|
||||
|
||||
Args:
|
||||
html_code: HTML 代码字符串
|
||||
"""
|
||||
headers = {
|
||||
'Authorization': AUTHORIZATION,
|
||||
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
|
||||
'Content-Type': 'text/html'
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(UPLOAD_URL, headers=headers, data=html_code.encode('utf-8'))
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
if data.get('code') == 200 and 'data' in data and 'fileUrl' in data['data']:
|
||||
return data['data']['fileUrl']
|
||||
else:
|
||||
return f"上传失败: {data.get('msg', '未知错误')}"
|
||||
except Exception as e:
|
||||
return f"请求发生异常: {str(e)}"
|
||||
|
||||
def main():
|
||||
# 运行 MCP Server
|
||||
mcp.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
9
lzwcai_mcpskills_visual2url/main.py
Normal file
9
lzwcai_mcpskills_visual2url/main.py
Normal file
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
Entry point for lzwcai_mcpskills_visual2url
|
||||
MCP Server 项目入口
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Import and run the actual MCP server
|
||||
from lzwcai_mcpskills_visual2url.main import main
|
||||
main()
|
||||
31
lzwcai_mcpskills_visual2url/pyproject.toml
Normal file
31
lzwcai_mcpskills_visual2url/pyproject.toml
Normal file
@@ -0,0 +1,31 @@
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai_mcpskills_visual2url"
|
||||
version = "0.1.1"
|
||||
description = "MCP Server 模板项目 - 用于快速创建新的 MCP 服务"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
license = {text = "MIT"}
|
||||
authors = [
|
||||
{name = "lzwcai", email = "your-email@example.com"},
|
||||
]
|
||||
keywords = ["mcp", "template", "server"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
]
|
||||
dependencies = [
|
||||
"mcp>=1.0.0",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
lzwcai_mcpskills_visual2url = "lzwcai_mcpskills_visual2url.main:main"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["lzwcai_mcpskills_visual2url"]
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,137 @@
|
||||
2026-03-28 12:30:33 - root - INFO - [logger_config.py:117] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_workflow_to_mcp\lzwcai_workflow_to_mcp\logs
|
||||
2026-03-28 12:30:33 - mcp.server.lowlevel.server - DEBUG - [server.py:162] - Initializing server 'workflow_mcp_server'
|
||||
2026-03-28 12:30:33 - mcp.server.lowlevel.server - DEBUG - [server.py:439] - Registering handler for ListToolsRequest
|
||||
2026-03-28 12:30:33 - mcp.server.lowlevel.server - DEBUG - [server.py:519] - Registering handler for CallToolRequest
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:334] - ==================================================
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:335] - Workflow MCP Server 启动
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:336] - ==================================================
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:341] - 命令行参数: {'mode': 'api', 'json_path': None, 'workflow_id': None}
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:344] - 使用模式: api
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:103] - ApiLoader 初始化,工作流ID: 2037527155235225601
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:111] - 开始从 API 加载工作流配置,工作流ID: 2037527155235225601
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:115] - [客户端初始化] base_url=http://192.168.2.236:8088
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:116] - [客户端初始化] token=wf_bd39a583670c42ceab48b3353bf2ba43
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:117] - [客户端初始化] execute_timeout=600.0s
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:148] - [API请求] GET http://192.168.2.236:8088/system/workflowManage/getByWorkflowId/2037527155235225601
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - DEBUG - [api_client.py:149] - [API请求] Headers: {'X-API-Key': 'wf_bd39a583670c42ceab48b3353bf2ba43'}
|
||||
2026-03-28 12:30:34 - httpcore.connection - DEBUG - [_trace.py:47] - connect_tcp.started host='192.168.2.236' port=8088 local_address=None timeout=30.0 socket_options=None
|
||||
2026-03-28 12:30:34 - httpcore.connection - DEBUG - [_trace.py:47] - connect_tcp.complete return_value=<httpcore._backends.sync.SyncStream object at 0x0000016702CF9970>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - send_request_headers.started request=<Request [b'GET']>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - send_request_headers.complete
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - send_request_body.started request=<Request [b'GET']>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - send_request_body.complete
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - receive_response_headers.started request=<Request [b'GET']>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'', [(b'Vary', b'Origin'), (b'Vary', b'Access-Control-Request-Method'), (b'Vary', b'Access-Control-Request-Headers'), (b'X-Content-Type-Options', b'nosniff'), (b'X-XSS-Protection', b'1; mode=block'), (b'X-Frame-Options', b'SAMEORIGIN'), (b'Content-Type', b'application/json'), (b'Transfer-Encoding', b'chunked'), (b'Date', b'Sat, 28 Mar 2026 04:30:30 GMT'), (b'Keep-Alive', b'timeout=60'), (b'Connection', b'keep-alive')])
|
||||
2026-03-28 12:30:34 - httpx - INFO - [_client.py:1025] - HTTP Request: GET http://192.168.2.236:8088/system/workflowManage/getByWorkflowId/2037527155235225601 "HTTP/1.1 200 "
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - receive_response_body.started request=<Request [b'GET']>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - receive_response_body.complete
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - response_closed.started
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - response_closed.complete
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:156] - [API响应] HTTP 200
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.utils.api_client - DEBUG - [api_client.py:157] - [API响应] Headers: {'vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'x-content-type-options': 'nosniff', 'x-xss-protection': '1; mode=block', 'x-frame-options': 'SAMEORIGIN', 'content-type': 'application/json', 'transfer-encoding': 'chunked', 'date': 'Sat, 28 Mar 2026 04:30:30 GMT', 'keep-alive': 'timeout=60', 'connection': 'keep-alive'}
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:162] - [API响应] 获取工作流配置成功: workflow_id=2037527155235225601
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.utils.api_client - DEBUG - [api_client.py:163] - [API响应] Body: {
|
||||
"msg": "查询成功",
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": "2037535460665982977",
|
||||
"createBy": "duchangyuan",
|
||||
"createTime": "2026-03-27 22:21:24",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2026-03-28 12:21:49",
|
||||
"serviceId": "2037535460632428546",
|
||||
"uniqueName": "银行流水状态检测",
|
||||
"name": "yinxingliushuizhuangtaijiance_7c4d9a63",
|
||||
"description": "用于检测流水导入状态,检查是否全部导入完成",
|
||||
"visualizable": 0,
|
||||
"toolPrompt": null,
|
||||
"toolType": "api",
|
||||
"datasourceId": null,
|
||||
"sqlTemplate": null,
|
||||
"sqlParams": "[]",
|
||||
"resultType": null,
|
||||
"sourceType": null,
|
||||
"trainingTaskId": null,
|
||||
"tableMetadataIds": null,
|
||||
"executionCount": 0,
|
||||
"visualizationConfigs": null,
|
||||
"inputJsonSchema": "{\"type\":\"object\",\"properties\":{\"workflow_extraContext\":{\"description\":\"工作流额外的上下文参数(如环境变量等),可以是任何类型,非必填\"}},\"required\":[]}",
|
||||
"outputJsonSchema": "{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"}},\"additionalProperties\":false}",
|
||||
"lastExecutionTime": null
|
||||
}
|
||||
]
|
||||
}
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:116] - API 响应原始数据: {
|
||||
"msg": "查询成功",
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": "2037535460665982977",
|
||||
"createBy": "duchangyuan",
|
||||
"createTime": "2026-03-27 22:21:24",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2026-03-28 12:21:49",
|
||||
"serviceId": "2037535460632428546",
|
||||
"uniqueName": "银行流水状态检测",
|
||||
"name": "yinxingliushuizhuangtaijiance_7c4d9a63",
|
||||
"description": "用于检测流水导入状态,检查是否全部导入完成",
|
||||
"visualizable": 0,
|
||||
"toolPrompt": null,
|
||||
"toolType": "api",
|
||||
"datasourceId": null,
|
||||
"sqlTemplate": null,
|
||||
"sqlParams": "[]",
|
||||
"resultType": null,
|
||||
"sourceType": null,
|
||||
"trainingTaskId": null,
|
||||
"tableMetadataIds": null,
|
||||
"executionCount": 0,
|
||||
"visualizationConfigs": null,
|
||||
"inputJsonSchema": "{\"type\":\"object\",\"properties\":{\"workflow_extraContext\":{\"description\":\"工作流额外的上下文参数(如环境变量等),可以是任何类型,非必填\"}},\"required\":[]}",
|
||||
"outputJsonSchema": "{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"}},\"additionalProperties\":false}",
|
||||
"lastExecutionTime": null
|
||||
}
|
||||
]
|
||||
}
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:124] - API 响应 data 字段: [
|
||||
{
|
||||
"id": "2037535460665982977",
|
||||
"createBy": "duchangyuan",
|
||||
"createTime": "2026-03-27 22:21:24",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2026-03-28 12:21:49",
|
||||
"serviceId": "2037535460632428546",
|
||||
"uniqueName": "银行流水状态检测",
|
||||
"name": "yinxingliushuizhuangtaijiance_7c4d9a63",
|
||||
"description": "用于检测流水导入状态,检查是否全部导入完成",
|
||||
"visualizable": 0,
|
||||
"toolPrompt": null,
|
||||
"toolType": "api",
|
||||
"datasourceId": null,
|
||||
"sqlTemplate": null,
|
||||
"sqlParams": "[]",
|
||||
"resultType": null,
|
||||
"sourceType": null,
|
||||
"trainingTaskId": null,
|
||||
"tableMetadataIds": null,
|
||||
"executionCount": 0,
|
||||
"visualizationConfigs": null,
|
||||
"inputJsonSchema": "{\"type\":\"object\",\"properties\":{\"workflow_extraContext\":{\"description\":\"工作流额外的上下文参数(如环境变量等),可以是任何类型,非必填\"}},\"required\":[]}",
|
||||
"outputJsonSchema": "{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"}},\"additionalProperties\":false}",
|
||||
"lastExecutionTime": null
|
||||
}
|
||||
]
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - INFO - [main.py:135] - 从 API 加载工作流配置成功,工作流ID: 2037527155235225601, 配置数量: 1
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - INFO - [main.py:165] - 已加载 1 个工具配置
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - INFO - [main.py:352] - 开始运行 MCP Server (stdio 模式)
|
||||
2026-03-28 12:30:34 - asyncio - DEBUG - [proactor_events.py:634] - Using proactor: IocpProactor
|
||||
2026-03-28 12:30:34 - mcp.server.lowlevel.server - DEBUG - [server.py:675] - Received message: root=InitializedNotification(method='notifications/initialized', params=None, jsonrpc='2.0')
|
||||
2026-03-28 12:30:40 - mcp.server.lowlevel.server - DEBUG - [server.py:675] - Received message: <mcp.shared.session.RequestResponder object at 0x0000016702D378C0>
|
||||
2026-03-28 12:30:40 - mcp.server.lowlevel.server - INFO - [server.py:720] - Processing request of type ListToolsRequest
|
||||
2026-03-28 12:30:40 - mcp.server.lowlevel.server - DEBUG - [server.py:723] - Dispatching request of type ListToolsRequest
|
||||
2026-03-28 12:30:40 - lzwcai_workflow_to_mcp.main - INFO - [main.py:171] - 收到 ListTools 请求,当前配置数量: 1
|
||||
2026-03-28 12:30:40 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:178] - 处理工具配置: name=yinxingliushuizhuangtaijiance_7c4d9a63, description=用于检测流水导入状态,检查是否全部导入完成...
|
||||
2026-03-28 12:30:40 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:185] - 从 sqlParams 转换的 inputSchema: {"type": "object", "properties": {}, "required": []}
|
||||
2026-03-28 12:30:40 - lzwcai_workflow_to_mcp.main - INFO - [main.py:237] - ListTools 响应: 返回 1 个工具
|
||||
2026-03-28 12:30:40 - mcp.server.lowlevel.server - DEBUG - [server.py:790] - Response sent
|
||||
@@ -0,0 +1,137 @@
|
||||
2026-03-28 12:30:33 - root - INFO - [logger_config.py:117] - 日志系统初始化完成 - 日志目录: E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_workflow_to_mcp\lzwcai_workflow_to_mcp\logs
|
||||
2026-03-28 12:30:33 - mcp.server.lowlevel.server - DEBUG - [server.py:162] - Initializing server 'workflow_mcp_server'
|
||||
2026-03-28 12:30:33 - mcp.server.lowlevel.server - DEBUG - [server.py:439] - Registering handler for ListToolsRequest
|
||||
2026-03-28 12:30:33 - mcp.server.lowlevel.server - DEBUG - [server.py:519] - Registering handler for CallToolRequest
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:334] - ==================================================
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:335] - Workflow MCP Server 启动
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:336] - ==================================================
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:341] - 命令行参数: {'mode': 'api', 'json_path': None, 'workflow_id': None}
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:344] - 使用模式: api
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:103] - ApiLoader 初始化,工作流ID: 2037527155235225601
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.main - INFO - [main.py:111] - 开始从 API 加载工作流配置,工作流ID: 2037527155235225601
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:115] - [客户端初始化] base_url=http://192.168.2.236:8088
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:116] - [客户端初始化] token=wf_bd39a583670c42ceab48b3353bf2ba43
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:117] - [客户端初始化] execute_timeout=600.0s
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:148] - [API请求] GET http://192.168.2.236:8088/system/workflowManage/getByWorkflowId/2037527155235225601
|
||||
2026-03-28 12:30:33 - lzwcai_workflow_to_mcp.utils.api_client - DEBUG - [api_client.py:149] - [API请求] Headers: {'X-API-Key': 'wf_bd39a583670c42ceab48b3353bf2ba43'}
|
||||
2026-03-28 12:30:34 - httpcore.connection - DEBUG - [_trace.py:47] - connect_tcp.started host='192.168.2.236' port=8088 local_address=None timeout=30.0 socket_options=None
|
||||
2026-03-28 12:30:34 - httpcore.connection - DEBUG - [_trace.py:47] - connect_tcp.complete return_value=<httpcore._backends.sync.SyncStream object at 0x0000016702CF9970>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - send_request_headers.started request=<Request [b'GET']>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - send_request_headers.complete
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - send_request_body.started request=<Request [b'GET']>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - send_request_body.complete
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - receive_response_headers.started request=<Request [b'GET']>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - receive_response_headers.complete return_value=(b'HTTP/1.1', 200, b'', [(b'Vary', b'Origin'), (b'Vary', b'Access-Control-Request-Method'), (b'Vary', b'Access-Control-Request-Headers'), (b'X-Content-Type-Options', b'nosniff'), (b'X-XSS-Protection', b'1; mode=block'), (b'X-Frame-Options', b'SAMEORIGIN'), (b'Content-Type', b'application/json'), (b'Transfer-Encoding', b'chunked'), (b'Date', b'Sat, 28 Mar 2026 04:30:30 GMT'), (b'Keep-Alive', b'timeout=60'), (b'Connection', b'keep-alive')])
|
||||
2026-03-28 12:30:34 - httpx - INFO - [_client.py:1025] - HTTP Request: GET http://192.168.2.236:8088/system/workflowManage/getByWorkflowId/2037527155235225601 "HTTP/1.1 200 "
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - receive_response_body.started request=<Request [b'GET']>
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - receive_response_body.complete
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - response_closed.started
|
||||
2026-03-28 12:30:34 - httpcore.http11 - DEBUG - [_trace.py:47] - response_closed.complete
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:156] - [API响应] HTTP 200
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.utils.api_client - DEBUG - [api_client.py:157] - [API响应] Headers: {'vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'x-content-type-options': 'nosniff', 'x-xss-protection': '1; mode=block', 'x-frame-options': 'SAMEORIGIN', 'content-type': 'application/json', 'transfer-encoding': 'chunked', 'date': 'Sat, 28 Mar 2026 04:30:30 GMT', 'keep-alive': 'timeout=60', 'connection': 'keep-alive'}
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.utils.api_client - INFO - [api_client.py:162] - [API响应] 获取工作流配置成功: workflow_id=2037527155235225601
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.utils.api_client - DEBUG - [api_client.py:163] - [API响应] Body: {
|
||||
"msg": "查询成功",
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": "2037535460665982977",
|
||||
"createBy": "duchangyuan",
|
||||
"createTime": "2026-03-27 22:21:24",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2026-03-28 12:21:49",
|
||||
"serviceId": "2037535460632428546",
|
||||
"uniqueName": "银行流水状态检测",
|
||||
"name": "yinxingliushuizhuangtaijiance_7c4d9a63",
|
||||
"description": "用于检测流水导入状态,检查是否全部导入完成",
|
||||
"visualizable": 0,
|
||||
"toolPrompt": null,
|
||||
"toolType": "api",
|
||||
"datasourceId": null,
|
||||
"sqlTemplate": null,
|
||||
"sqlParams": "[]",
|
||||
"resultType": null,
|
||||
"sourceType": null,
|
||||
"trainingTaskId": null,
|
||||
"tableMetadataIds": null,
|
||||
"executionCount": 0,
|
||||
"visualizationConfigs": null,
|
||||
"inputJsonSchema": "{\"type\":\"object\",\"properties\":{\"workflow_extraContext\":{\"description\":\"工作流额外的上下文参数(如环境变量等),可以是任何类型,非必填\"}},\"required\":[]}",
|
||||
"outputJsonSchema": "{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"}},\"additionalProperties\":false}",
|
||||
"lastExecutionTime": null
|
||||
}
|
||||
]
|
||||
}
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:116] - API 响应原始数据: {
|
||||
"msg": "查询成功",
|
||||
"code": 200,
|
||||
"data": [
|
||||
{
|
||||
"id": "2037535460665982977",
|
||||
"createBy": "duchangyuan",
|
||||
"createTime": "2026-03-27 22:21:24",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2026-03-28 12:21:49",
|
||||
"serviceId": "2037535460632428546",
|
||||
"uniqueName": "银行流水状态检测",
|
||||
"name": "yinxingliushuizhuangtaijiance_7c4d9a63",
|
||||
"description": "用于检测流水导入状态,检查是否全部导入完成",
|
||||
"visualizable": 0,
|
||||
"toolPrompt": null,
|
||||
"toolType": "api",
|
||||
"datasourceId": null,
|
||||
"sqlTemplate": null,
|
||||
"sqlParams": "[]",
|
||||
"resultType": null,
|
||||
"sourceType": null,
|
||||
"trainingTaskId": null,
|
||||
"tableMetadataIds": null,
|
||||
"executionCount": 0,
|
||||
"visualizationConfigs": null,
|
||||
"inputJsonSchema": "{\"type\":\"object\",\"properties\":{\"workflow_extraContext\":{\"description\":\"工作流额外的上下文参数(如环境变量等),可以是任何类型,非必填\"}},\"required\":[]}",
|
||||
"outputJsonSchema": "{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"}},\"additionalProperties\":false}",
|
||||
"lastExecutionTime": null
|
||||
}
|
||||
]
|
||||
}
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:124] - API 响应 data 字段: [
|
||||
{
|
||||
"id": "2037535460665982977",
|
||||
"createBy": "duchangyuan",
|
||||
"createTime": "2026-03-27 22:21:24",
|
||||
"updateBy": "admin",
|
||||
"updateTime": "2026-03-28 12:21:49",
|
||||
"serviceId": "2037535460632428546",
|
||||
"uniqueName": "银行流水状态检测",
|
||||
"name": "yinxingliushuizhuangtaijiance_7c4d9a63",
|
||||
"description": "用于检测流水导入状态,检查是否全部导入完成",
|
||||
"visualizable": 0,
|
||||
"toolPrompt": null,
|
||||
"toolType": "api",
|
||||
"datasourceId": null,
|
||||
"sqlTemplate": null,
|
||||
"sqlParams": "[]",
|
||||
"resultType": null,
|
||||
"sourceType": null,
|
||||
"trainingTaskId": null,
|
||||
"tableMetadataIds": null,
|
||||
"executionCount": 0,
|
||||
"visualizationConfigs": null,
|
||||
"inputJsonSchema": "{\"type\":\"object\",\"properties\":{\"workflow_extraContext\":{\"description\":\"工作流额外的上下文参数(如环境变量等),可以是任何类型,非必填\"}},\"required\":[]}",
|
||||
"outputJsonSchema": "{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"}},\"additionalProperties\":false}",
|
||||
"lastExecutionTime": null
|
||||
}
|
||||
]
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - INFO - [main.py:135] - 从 API 加载工作流配置成功,工作流ID: 2037527155235225601, 配置数量: 1
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - INFO - [main.py:165] - 已加载 1 个工具配置
|
||||
2026-03-28 12:30:34 - lzwcai_workflow_to_mcp.main - INFO - [main.py:352] - 开始运行 MCP Server (stdio 模式)
|
||||
2026-03-28 12:30:34 - asyncio - DEBUG - [proactor_events.py:634] - Using proactor: IocpProactor
|
||||
2026-03-28 12:30:34 - mcp.server.lowlevel.server - DEBUG - [server.py:675] - Received message: root=InitializedNotification(method='notifications/initialized', params=None, jsonrpc='2.0')
|
||||
2026-03-28 12:30:40 - mcp.server.lowlevel.server - DEBUG - [server.py:675] - Received message: <mcp.shared.session.RequestResponder object at 0x0000016702D378C0>
|
||||
2026-03-28 12:30:40 - mcp.server.lowlevel.server - INFO - [server.py:720] - Processing request of type ListToolsRequest
|
||||
2026-03-28 12:30:40 - mcp.server.lowlevel.server - DEBUG - [server.py:723] - Dispatching request of type ListToolsRequest
|
||||
2026-03-28 12:30:40 - lzwcai_workflow_to_mcp.main - INFO - [main.py:171] - 收到 ListTools 请求,当前配置数量: 1
|
||||
2026-03-28 12:30:40 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:178] - 处理工具配置: name=yinxingliushuizhuangtaijiance_7c4d9a63, description=用于检测流水导入状态,检查是否全部导入完成...
|
||||
2026-03-28 12:30:40 - lzwcai_workflow_to_mcp.main - DEBUG - [main.py:185] - 从 sqlParams 转换的 inputSchema: {"type": "object", "properties": {}, "required": []}
|
||||
2026-03-28 12:30:40 - lzwcai_workflow_to_mcp.main - INFO - [main.py:237] - ListTools 响应: 返回 1 个工具
|
||||
2026-03-28 12:30:40 - mcp.server.lowlevel.server - DEBUG - [server.py:790] - Response sent
|
||||
@@ -19,12 +19,12 @@ from mcp.server.models import InitializationOptions
|
||||
from mcp.server.stdio import stdio_server
|
||||
|
||||
try:
|
||||
from .schema_converter import convert_sql_params_to_input_schema
|
||||
from .schema_converter import convert_sql_params_to_input_schema, sanitize_json_schema
|
||||
from .utils.api_client import execute_workflow, get_workflow_by_id, extract_final_output
|
||||
from .utils.env_config import get_workflow_id
|
||||
from .utils.logger_config import setup_system_logging, get_logger
|
||||
except ImportError:
|
||||
from schema_converter import convert_sql_params_to_input_schema
|
||||
from schema_converter import convert_sql_params_to_input_schema, sanitize_json_schema
|
||||
from utils.api_client import execute_workflow, get_workflow_by_id, extract_final_output
|
||||
from utils.env_config import get_workflow_id
|
||||
from utils.logger_config import setup_system_logging, get_logger
|
||||
@@ -174,13 +174,57 @@ async def handle_list_tools() -> list[types.Tool]:
|
||||
for query in _tools_config:
|
||||
name = query.get("name", "")
|
||||
description = query.get("description") or query.get("toolPrompt") or query.get("uniqueName", "")
|
||||
sql_params = query.get("sqlParams", "[]")
|
||||
|
||||
logger.debug(f"处理工具配置: name={name}, description={description[:50] if description else 'None'}...")
|
||||
|
||||
# 转换参数为 inputSchema
|
||||
input_schema = convert_sql_params_to_input_schema(sql_params)
|
||||
logger.debug(f"工具 {name} 的 inputSchema: {json.dumps(input_schema, ensure_ascii=False)}")
|
||||
# 优先从 sqlParams 转换,因为它包含更详细的文件配置信息
|
||||
sql_params = query.get("sqlParams")
|
||||
if sql_params:
|
||||
try:
|
||||
input_schema = convert_sql_params_to_input_schema(sql_params)
|
||||
logger.debug(f"从 sqlParams 转换的 inputSchema: {json.dumps(input_schema, ensure_ascii=False)}")
|
||||
except Exception as e:
|
||||
logger.warning(f"从 sqlParams 转换失败: {e},尝试使用 inputJsonSchema")
|
||||
# 回退到 inputJsonSchema
|
||||
input_json_schema = query.get("inputJsonSchema")
|
||||
if input_json_schema:
|
||||
try:
|
||||
if isinstance(input_json_schema, str):
|
||||
input_schema = json.loads(input_json_schema)
|
||||
else:
|
||||
input_schema = input_json_schema
|
||||
input_schema = sanitize_json_schema(input_schema)
|
||||
logger.debug(f"使用 inputJsonSchema (已清理): {json.dumps(input_schema, ensure_ascii=False)}")
|
||||
except (json.JSONDecodeError, TypeError) as e2:
|
||||
logger.error(f"解析 inputJsonSchema 也失败: {e2},使用空 schema")
|
||||
input_schema = {"type": "object", "properties": {}, "required": []}
|
||||
else:
|
||||
logger.warning("sqlParams 和 inputJsonSchema 都不可用,使用空 schema")
|
||||
input_schema = {"type": "object", "properties": {}, "required": []}
|
||||
else:
|
||||
# 如果没有 sqlParams,尝试使用 inputJsonSchema
|
||||
input_json_schema = query.get("inputJsonSchema")
|
||||
if input_json_schema:
|
||||
try:
|
||||
if isinstance(input_json_schema, str):
|
||||
input_schema = json.loads(input_json_schema)
|
||||
else:
|
||||
input_schema = input_json_schema
|
||||
input_schema = sanitize_json_schema(input_schema)
|
||||
logger.debug(f"使用 inputJsonSchema (已清理): {json.dumps(input_schema, ensure_ascii=False)}")
|
||||
except (json.JSONDecodeError, TypeError) as e:
|
||||
logger.error(f"解析 inputJsonSchema 失败: {e},使用空 schema")
|
||||
input_schema = {"type": "object", "properties": {}, "required": []}
|
||||
else:
|
||||
logger.warning("sqlParams 和 inputJsonSchema 都不存在,使用空 schema")
|
||||
input_schema = {"type": "object", "properties": {}, "required": []}
|
||||
|
||||
# 添加 workflow_extraContext 字段到 schema,可以接收任何类型(非必填)
|
||||
if "properties" not in input_schema:
|
||||
input_schema["properties"] = {}
|
||||
input_schema["properties"]["workflow_extraContext"] = {
|
||||
"description": "工作流额外的上下文参数(如环境变量等),可以是任何类型,非必填"
|
||||
}
|
||||
|
||||
tools.append(
|
||||
types.Tool(
|
||||
@@ -197,7 +241,7 @@ async def handle_list_tools() -> list[types.Tool]:
|
||||
@server.call_tool()
|
||||
async def handle_call_tool(
|
||||
name: str,
|
||||
arguments: dict | None
|
||||
arguments: dict | None,
|
||||
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
|
||||
"""调用工具"""
|
||||
logger.info(f"收到 CallTool 请求: name={name}, arguments={json.dumps(arguments, ensure_ascii=False) if arguments else 'None'}")
|
||||
@@ -219,10 +263,25 @@ async def handle_call_tool(
|
||||
workflow_id = tool_config.get("workflowId") or get_workflow_id()
|
||||
logger.info(f"使用工作流ID: {workflow_id}")
|
||||
|
||||
# 提取 workflow_extraContext 字段并合并到 inputs
|
||||
inputs = arguments or {}
|
||||
workflow_extra_context = inputs.pop("workflow_extraContext", None)
|
||||
|
||||
# 如果 workflow_extraContext 存在,将其内容合并到 inputs
|
||||
if workflow_extra_context is not None:
|
||||
if isinstance(workflow_extra_context, dict):
|
||||
# 如果 workflow_extraContext 是字典,合并到 inputs
|
||||
inputs.update(workflow_extra_context)
|
||||
logger.info(f"workflow_extraContext 是字典类型,已合并到 inputs: {json.dumps(workflow_extra_context, ensure_ascii=False)}")
|
||||
else:
|
||||
# 如果 workflow_extraContext 不是字典,作为 workflow_extraContext 字段保留
|
||||
inputs["workflow_extraContext"] = workflow_extra_context
|
||||
logger.info(f"workflow_extraContext 是 {type(workflow_extra_context).__name__} 类型,保留为 workflow_extraContext 字段")
|
||||
|
||||
# 构建请求数据
|
||||
request_data = {
|
||||
"workflowId": workflow_id,
|
||||
"inputs": arguments or {}
|
||||
"inputs": inputs
|
||||
}
|
||||
|
||||
logger.info(f"执行工作流请求数据: {json.dumps(request_data, ensure_ascii=False, indent=2)}")
|
||||
|
||||
@@ -7,11 +7,48 @@ Schema 转换器
|
||||
- paragraph: 段落/多行文本
|
||||
- select: 下拉选项
|
||||
- number: 数字输入
|
||||
- file: 单文件上传
|
||||
- fileList: 多文件上传
|
||||
"""
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
|
||||
def sanitize_json_schema(schema: dict) -> dict:
|
||||
"""
|
||||
清理 JSON Schema,确保 enum 字段只包含字符串值
|
||||
|
||||
Args:
|
||||
schema: 原始 JSON Schema
|
||||
|
||||
Returns:
|
||||
dict: 清理后的 JSON Schema
|
||||
"""
|
||||
if not isinstance(schema, dict):
|
||||
return schema
|
||||
|
||||
# 递归处理 properties
|
||||
if "properties" in schema and isinstance(schema["properties"], dict):
|
||||
for prop_name, prop_schema in schema["properties"].items():
|
||||
if isinstance(prop_schema, dict) and "enum" in prop_schema:
|
||||
enum_values = prop_schema["enum"]
|
||||
if isinstance(enum_values, list) and len(enum_values) > 0:
|
||||
# 检查是否是对象数组
|
||||
if isinstance(enum_values[0], dict):
|
||||
# 提取 value 字段
|
||||
cleaned_enum = [
|
||||
item.get("value", item.get("label", ""))
|
||||
for item in enum_values
|
||||
if isinstance(item, dict)
|
||||
]
|
||||
# 过滤空值
|
||||
prop_schema["enum"] = [v for v in cleaned_enum if v]
|
||||
# 保留原始数据
|
||||
prop_schema["x-options"] = enum_values
|
||||
|
||||
return schema
|
||||
|
||||
|
||||
def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]:
|
||||
"""
|
||||
将单个参数转换为 JSON Schema property
|
||||
@@ -25,7 +62,13 @@ def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]:
|
||||
"maxLength": 200,
|
||||
"defaultValue": "",
|
||||
"required": true,
|
||||
"options": ["选项1", "选项2"] # 仅 select 类型
|
||||
"options": ["选项1", "选项2"], # 仅 select 类型
|
||||
"fileConfig": { # 仅 file/fileList 类型
|
||||
"uploadMode": "both",
|
||||
"typeCategories": ["image"],
|
||||
"customAccept": "",
|
||||
"accept": ".jpg,.jpeg,.png"
|
||||
}
|
||||
}
|
||||
|
||||
Returns:
|
||||
@@ -38,6 +81,7 @@ def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]:
|
||||
max_length = param.get("maxLength")
|
||||
is_required = param.get("required", False)
|
||||
options = param.get("options", [])
|
||||
file_config = param.get("fileConfig", {})
|
||||
|
||||
property_schema = {
|
||||
"description": display_name
|
||||
@@ -57,17 +101,69 @@ def convert_param_to_schema_property(param: dict) -> tuple[str, dict, bool]:
|
||||
elif param_type == "select":
|
||||
property_schema["type"] = "string"
|
||||
if options:
|
||||
property_schema["enum"] = options
|
||||
# 处理 options 可能是对象数组 [{label, value}] 或字符串数组的情况
|
||||
if isinstance(options, list) and len(options) > 0:
|
||||
if isinstance(options[0], dict):
|
||||
# 对象数组,提取 value 字段作为 enum,过滤空值
|
||||
enum_values = [
|
||||
opt.get("value", opt.get("label", ""))
|
||||
for opt in options
|
||||
if isinstance(opt, dict)
|
||||
]
|
||||
# 过滤掉空字符串
|
||||
property_schema["enum"] = [v for v in enum_values if v]
|
||||
# 保留原始 options 供前端使用(如果前端支持)
|
||||
property_schema["x-options"] = options
|
||||
else:
|
||||
# 字符串数组,直接使用,过滤空值
|
||||
property_schema["enum"] = [v for v in options if v]
|
||||
|
||||
elif param_type == "number":
|
||||
property_schema["type"] = "number"
|
||||
|
||||
elif param_type == "file":
|
||||
# 单文件上传
|
||||
property_schema["type"] = "string"
|
||||
property_schema["format"] = "url"
|
||||
property_schema["x-file-type"] = "single"
|
||||
|
||||
# 添加文件配置信息
|
||||
if file_config:
|
||||
if file_config.get("accept"):
|
||||
property_schema["x-accept"] = file_config["accept"]
|
||||
if file_config.get("typeCategories"):
|
||||
property_schema["x-type-categories"] = file_config["typeCategories"]
|
||||
if file_config.get("uploadMode"):
|
||||
property_schema["x-upload-mode"] = file_config["uploadMode"]
|
||||
# 保留完整配置
|
||||
property_schema["x-file-config"] = file_config
|
||||
|
||||
elif param_type == "fileList":
|
||||
# 多文件上传
|
||||
property_schema["type"] = "array"
|
||||
property_schema["items"] = {
|
||||
"type": "string",
|
||||
"format": "url"
|
||||
}
|
||||
property_schema["x-file-type"] = "multiple"
|
||||
|
||||
# 添加文件配置信息
|
||||
if file_config:
|
||||
if file_config.get("accept"):
|
||||
property_schema["x-accept"] = file_config["accept"]
|
||||
if file_config.get("typeCategories"):
|
||||
property_schema["x-type-categories"] = file_config["typeCategories"]
|
||||
if file_config.get("uploadMode"):
|
||||
property_schema["x-upload-mode"] = file_config["uploadMode"]
|
||||
# 保留完整配置
|
||||
property_schema["x-file-config"] = file_config
|
||||
|
||||
else:
|
||||
# 默认当作 string 处理
|
||||
property_schema["type"] = "string"
|
||||
|
||||
# 添加默认值
|
||||
if default_value not in (None, ""):
|
||||
# 添加默认值(文件类型不需要默认值)
|
||||
if default_value not in (None, "") and param_type not in ("file", "fileList"):
|
||||
if param_type == "number":
|
||||
try:
|
||||
property_schema["default"] = int(default_value) if str(default_value).isdigit() else float(default_value)
|
||||
|
||||
Binary file not shown.
@@ -7,8 +7,8 @@ import os
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 设置环境变量
|
||||
os.environ["workflowId"] = "2005892514011795457"
|
||||
os.environ["workflowExecuteKey"] = "wf_ce270212b2ee45ab9c81714a7c243c56"
|
||||
os.environ["workflowId"] = "2037527155235225601"
|
||||
os.environ["workflowExecuteKey"] = "wf_bd39a583670c42ceab48b3353bf2ba43"
|
||||
os.environ["backendBaseUrl"] = "http://192.168.2.236:8088"
|
||||
|
||||
# Import and run the actual MCP server
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai-workflow-to-mcp"
|
||||
version = "0.1.3"
|
||||
version = "0.1.8"
|
||||
description = "MCP server for executing business SQL queries with dynamic tool generation"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
Reference in New Issue
Block a user