feat(mfg-data-agent): 添加制造业数据智能体v2版本
新增基于MCP协议的制造业数据智能体服务器,支持从JSON配置文件动态生成查询工具, 具备灵活配置、完整日志、中文支持等功能特性,专注于制造业数据分析与智能决策场景。 包含详细的README文档、依赖配置和使用示例。
This commit is contained in:
138
lzwcai_mcpskills_mfg_data_agentv2/README.md
Normal file
138
lzwcai_mcpskills_mfg_data_agentv2/README.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# lzwcai-mcpskills-mfg-data-agent (制造业数据智能体)
|
||||
|
||||
一个基于 MCP (Model Context Protocol) 的制造业数据智能体服务器,支持从 JSON 配置文件动态生成查询工具。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 🚀 动态工具生成:从 `businessQueries.json` 自动生成 MCP 工具
|
||||
- 🔧 灵活配置:支持自定义业务查询和参数验证
|
||||
- 📝 完整日志:详细的操作日志记录
|
||||
- 🌐 中文支持:工具名称自动转换为拼音
|
||||
- 🏭 制造业场景:专注于制造业数据分析与智能决策
|
||||
|
||||
## 安装
|
||||
|
||||
### 使用 pip 安装
|
||||
|
||||
```bash
|
||||
pip install lzwcai-mcpskills-mfg-data-agent
|
||||
```
|
||||
|
||||
### 从源码安装
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd lzwcai_mcpskills_mfg_data_agent
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
### 使用 uv 安装(推荐)
|
||||
|
||||
```bash
|
||||
uv pip install lzwcai-mcpskills-mfg-data-agent
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 命令行启动
|
||||
|
||||
安装后,可以直接通过命令启动:
|
||||
|
||||
```bash
|
||||
lzwcai-mcpskills-mfg-data-agent
|
||||
```
|
||||
|
||||
### 作为 Python 模块运行
|
||||
|
||||
```bash
|
||||
python -m lzwcai_mcpskills_mfg_data_agent.main
|
||||
```
|
||||
|
||||
### 配置到 MCP 客户端
|
||||
|
||||
在你的 MCP 客户端配置文件中添加:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mfg-data-agent": {
|
||||
"command": "lzwcai-mcpskills-mfg-data-agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### businessQueries.json
|
||||
|
||||
在 `businessQueries.json` 中定义你的业务查询:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "query-001",
|
||||
"businessName": "生产订单查询",
|
||||
"businessDescription": "根据订单ID查询生产订单信息",
|
||||
"sqlTemplate": "SELECT * FROM production_orders WHERE order_id = {{orderId}}",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"required": ["orderId"],
|
||||
"properties": {
|
||||
"orderId": {
|
||||
"type": "string",
|
||||
"description": "生产订单的唯一标识符",
|
||||
"examples": ["PO-2024-001"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 开发
|
||||
|
||||
### 依赖项
|
||||
|
||||
- Python >= 3.13
|
||||
- httpx >= 0.28.1
|
||||
- mcp[cli] >= 1.10.1
|
||||
- pypinyin >= 0.53.0
|
||||
|
||||
### 本地开发
|
||||
|
||||
```bash
|
||||
# 克隆仓库
|
||||
git clone <repository-url>
|
||||
cd lzwcai_mcpskills_mfg_data_agent
|
||||
|
||||
# 安装开发依赖
|
||||
pip install -e .
|
||||
|
||||
# 运行服务器
|
||||
python -m lzwcai_mcpskills_mfg_data_agent.main
|
||||
```
|
||||
|
||||
## 构建与发布
|
||||
|
||||
### 使用 build 构建
|
||||
|
||||
```bash
|
||||
pip install build
|
||||
python -m build
|
||||
```
|
||||
|
||||
### 发布到 PyPI
|
||||
|
||||
```bash
|
||||
pip install twine
|
||||
twine upload dist/*
|
||||
```
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
|
||||
## 作者
|
||||
|
||||
lzwcai
|
||||
10
lzwcai_mcpskills_mfg_data_agentv2/lzwcai_mcpskills_mfg_data_agentv2/.gitignore
vendored
Normal file
10
lzwcai_mcpskills_mfg_data_agentv2/lzwcai_mcpskills_mfg_data_agentv2/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Python-generated files
|
||||
__pycache__/
|
||||
*.py[oc]
|
||||
build/
|
||||
dist/
|
||||
wheels/
|
||||
*.egg-info
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
@@ -0,0 +1 @@
|
||||
3.13
|
||||
@@ -0,0 +1,154 @@
|
||||
# lzwcai-mcpskills-analyzeWorkOrder
|
||||
|
||||
一个基于 MCP (Model Context Protocol) 的 SQL 查询执行服务器,支持从 JSON 配置文件动态生成查询工具。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 🚀 动态工具生成:从 `businessQueries.json` 自动生成 MCP 工具
|
||||
- 🔧 灵活配置:支持自定义业务查询和参数验证
|
||||
- 📝 完整日志:详细的操作日志记录(仅输出到文件,不干扰MCP通信)
|
||||
- 🌐 中文支持:工具名称自动转换为拼音
|
||||
|
||||
## 安装
|
||||
|
||||
### 使用 pip 安装
|
||||
|
||||
```bash
|
||||
pip install lzwcai-mcpskills-analyzeWorkOrder
|
||||
```
|
||||
|
||||
### 从源码安装
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
cd lzwcai_mcp_sqlexecutor
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
### 使用 uv 安装(推荐)
|
||||
|
||||
```bash
|
||||
uv pip install lzwcai-mcpskills-analyzeWorkOrder
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 命令行启动
|
||||
|
||||
安装后,可以直接通过命令启动:
|
||||
|
||||
```bash
|
||||
lzwcai-mcpskills-analyzeWorkOrder
|
||||
```
|
||||
|
||||
### 作为 Python 模块运行
|
||||
|
||||
```bash
|
||||
python -m lzwcai_mcp_sqlexecutor.main
|
||||
```
|
||||
|
||||
### 配置到 MCP 客户端
|
||||
|
||||
在你的 MCP 客户端配置文件中添加:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"lzwcai-sqlexecutor": {
|
||||
"command": "lzwcai-mcpskills-analyzeWorkOrder"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### businessQueries.json
|
||||
|
||||
在 `businessQueries.json` 中定义你的业务查询:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "query-001",
|
||||
"businessName": "用户订单查询",
|
||||
"businessDescription": "根据用户ID查询订单信息",
|
||||
"sqlTemplate": "SELECT * FROM orders WHERE user_id = {{userId}}",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"required": ["userId"],
|
||||
"properties": {
|
||||
"userId": {
|
||||
"type": "integer",
|
||||
"description": "用户的唯一标识符",
|
||||
"examples": [10086]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 开发
|
||||
|
||||
### 依赖项
|
||||
|
||||
- Python >= 3.13
|
||||
- httpx >= 0.28.1
|
||||
- mcp[cli] >= 1.10.1
|
||||
- pypinyin >= 0.53.0
|
||||
|
||||
### 本地开发
|
||||
|
||||
```bash
|
||||
# 克隆仓库
|
||||
git clone <repository-url>
|
||||
cd lzwcai_mcp_sqlexecutor
|
||||
|
||||
# 安装开发依赖
|
||||
pip install -e .
|
||||
|
||||
# 运行服务器
|
||||
python -m lzwcai_mcp_sqlexecutor.main
|
||||
```
|
||||
|
||||
## 构建与发布
|
||||
|
||||
### 使用 build 构建
|
||||
|
||||
```bash
|
||||
pip install build
|
||||
python -m build
|
||||
```
|
||||
|
||||
### 发布到 PyPI
|
||||
|
||||
```bash
|
||||
pip install twine
|
||||
twine upload dist/*
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### MCP Inspector 显示 JSON 解析错误
|
||||
|
||||
如果在使用 MCP Inspector 测试时遇到 `SyntaxError: Unexpected non-whitespace character after JSON` 错误,这是因为:
|
||||
|
||||
1. **原因**:MCP 协议使用 stdio(标准输入输出)进行 JSON-RPC 通信,任何输出到 stdout 的内容(如 print 语句或控制台日志)都会破坏 JSON 格式。
|
||||
|
||||
2. **解决方案**:本服务器已将所有日志输出配置为仅写入文件(位于 `logs/` 目录),不输出到控制台。日志文件包括:
|
||||
- `lzwcai_mcp_sqlexecutor.log` - 主日志文件
|
||||
- `lzwcai_mcp_sqlexecutor_error.log` - 错误日志
|
||||
- `lzwcai_mcp_sqlexecutor_daily.log` - 按日期滚动的日志
|
||||
- `mcp_services.log` - MCP 服务专用日志
|
||||
|
||||
3. **查看日志**:如果需要调试,请查看 `logs/` 目录下的日志文件。
|
||||
|
||||
## 许可证
|
||||
|
||||
MIT License
|
||||
|
||||
## 作者
|
||||
|
||||
lzwcai
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
lzwcai-mcpskills-mfg-data-agentv2 - MCP server for manufacturing data intelligence
|
||||
"""
|
||||
|
||||
__version__ = "0.1.2"
|
||||
__author__ = "lzwcai"
|
||||
|
||||
__all__ = []
|
||||
|
||||
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
@@ -0,0 +1,48 @@
|
||||
2026-01-09 18:27:40 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - ERROR - [api_client.py:168] - 接口业务错误: Multiple ResultSets were returned by the query.
|
||||
2026-01-09 18:27:40 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - ERROR - [api_client.py:192] - 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 169, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: Multiple ResultSets were returned by the query.
|
||||
2026-01-09 18:27:40 - mcp_services - ERROR - [main.py:238] - 调用测试SQL API失败: 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 169, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: Multiple ResultSets were returned by the query.
|
||||
|
||||
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_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\main.py", line 226, in handle_call_tool
|
||||
api_response = test_sql_with_schema(request_data)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 251, in test_sql_with_schema
|
||||
return default_client.test_sql_with_schema(request_data)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 193, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
2026-01-09 18:27:46 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - ERROR - [api_client.py:168] - 接口业务错误: Multiple ResultSets were returned by the query.
|
||||
2026-01-09 18:27:46 - lzwcai_mcpskills_mfg_data_agentv2.utils.api_client - ERROR - [api_client.py:192] - 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 169, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: Multiple ResultSets were returned by the query.
|
||||
2026-01-09 18:27:46 - mcp_services - ERROR - [main.py:238] - 调用测试SQL API失败: 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 169, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: Multiple ResultSets were returned by the query.
|
||||
|
||||
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_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\main.py", line 226, in handle_call_tool
|
||||
api_response = test_sql_with_schema(request_data)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 251, in test_sql_with_schema
|
||||
return default_client.test_sql_with_schema(request_data)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 193, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
@@ -0,0 +1,215 @@
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:313] - ============================================================
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:316] - ============================================================
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID:
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:324] - ============================================================
|
||||
2026-01-08 00:15:16 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动,等待客户端连接...
|
||||
2026-01-08 00:15:17 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
|
||||
2026-01-08 00:15:17 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)...
|
||||
2026-01-08 00:15:17 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
|
||||
2026-01-08 00:15:17 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
|
||||
2026-01-08 00:15:17 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
|
||||
2026-01-08 00:15:19 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OrderDelayWarningAnalysis
|
||||
2026-01-08 00:15:19 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:15:19 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:15:27 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: WorkOrderProgressAndAnomalyNodes
|
||||
2026-01-08 00:15:27 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:15:28 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:15:37 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OnePageDecisionBrief
|
||||
2026-01-08 00:15:37 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:15:38 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:15:58 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: EfficiencyOutputLossDashboard
|
||||
2026-01-08 00:15:58 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:15:59 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:16:07 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplyChainRiskWarning
|
||||
2026-01-08 00:16:07 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:16:07 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:16:13 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: WorkOrderProgressAndAnomalyNodes
|
||||
2026-01-08 00:16:13 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:16:13 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:313] - ============================================================
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:316] - ============================================================
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID:
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:324] - ============================================================
|
||||
2026-01-08 00:30:22 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动,等待客户端连接...
|
||||
2026-01-08 00:30:26 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
|
||||
2026-01-08 00:30:26 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)...
|
||||
2026-01-08 00:30:26 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
|
||||
2026-01-08 00:30:26 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
|
||||
2026-01-08 00:30:26 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
|
||||
2026-01-08 00:30:27 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OrderDelayWarningAnalysis
|
||||
2026-01-08 00:30:27 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:30:27 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:30:32 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: WorkOrderProgressAndAnomalyNodes
|
||||
2026-01-08 00:30:32 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:30:32 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:30:34 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplyChainRiskWarning
|
||||
2026-01-08 00:30:34 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:30:34 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:30:35 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: EfficiencyOutputLossDashboard
|
||||
2026-01-08 00:30:35 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:30:35 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:30:37 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OnePageDecisionBrief
|
||||
2026-01-08 00:30:37 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:30:38 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:30:39 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: MetricTrendAndTurningPointWarning
|
||||
2026-01-08 00:30:39 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:30:39 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:30:44 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: MetricTrendAndTurningPointWarning
|
||||
2026-01-08 00:30:44 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:30:44 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:313] - ============================================================
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:316] - ============================================================
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID:
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:324] - ============================================================
|
||||
2026-01-08 00:38:55 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动,等待客户端连接...
|
||||
2026-01-08 00:38:57 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
|
||||
2026-01-08 00:38:57 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)...
|
||||
2026-01-08 00:38:57 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
|
||||
2026-01-08 00:38:57 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
|
||||
2026-01-08 00:38:57 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
|
||||
2026-01-08 00:38:59 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OrderDelayWarningAnalysis
|
||||
2026-01-08 00:38:59 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:38:59 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:313] - ============================================================
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:316] - ============================================================
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID:
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:324] - ============================================================
|
||||
2026-01-08 00:52:34 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动,等待客户端连接...
|
||||
2026-01-08 00:52:36 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
|
||||
2026-01-08 00:52:36 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)...
|
||||
2026-01-08 00:52:36 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
|
||||
2026-01-08 00:52:36 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
|
||||
2026-01-08 00:52:36 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
|
||||
2026-01-08 00:52:37 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: WorkOrderProgressAndAnomalyNodes
|
||||
2026-01-08 00:52:37 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:52:37 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:53:21 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OnePageDecisionBrief
|
||||
2026-01-08 00:53:21 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:53:21 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 00:56:21 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OnePageDecisionBrief
|
||||
2026-01-08 00:56:21 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 00:56:21 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 09:52:27 - mcp_services - INFO - [main.py:344] - MCP 服务器已关闭
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:313] - ============================================================
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:316] - ============================================================
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID:
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:324] - ============================================================
|
||||
2026-01-08 10:00:42 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动,等待客户端连接...
|
||||
2026-01-08 10:00:45 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
|
||||
2026-01-08 10:00:45 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)...
|
||||
2026-01-08 10:00:45 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
|
||||
2026-01-08 10:00:45 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
|
||||
2026-01-08 10:00:45 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
|
||||
2026-01-08 10:02:28 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OrderDelayWarningAnalysis
|
||||
2026-01-08 10:02:28 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 10:02:28 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 10:02:30 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: WorkOrderProgressAndAnomalyNodes
|
||||
2026-01-08 10:02:30 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 10:02:30 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 10:02:35 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: MetricTrendAndTurningPointWarning
|
||||
2026-01-08 10:02:35 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 10:02:35 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 10:22:23 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OrderDelayWarningAnalysis
|
||||
2026-01-08 10:22:23 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 10:22:24 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 10:57:20 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: WorkOrderProgressAndAnomalyNodes
|
||||
2026-01-08 10:57:20 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 10:57:20 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 11:05:47 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplyChainRiskWarning
|
||||
2026-01-08 11:05:47 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 11:05:48 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 11:13:21 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: EfficiencyOutputLossDashboard
|
||||
2026-01-08 11:13:21 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 11:13:22 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 11:34:55 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: OnePageDecisionBrief
|
||||
2026-01-08 11:34:55 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 11:34:56 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-08 11:59:37 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: MetricTrendAndTurningPointWarning
|
||||
2026-01-08 11:59:37 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-08 11:59:37 - mcp_services - INFO - [main.py:227] - 测试SQL API调用成功
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:362] - 开始运行 MCP SQL Executor 服务器
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:313] - ============================================================
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:314] - 正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:315] - 版本: 0.1.0
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:316] - ============================================================
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:320] - 环境配置 - Database ID: 19
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:321] - 环境配置 - Datasource ID: 19
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:322] - 环境配置 - Skill ID:
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:323] - 环境配置 - Backend Base URL: http://192.168.11.24:8088
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:324] - ============================================================
|
||||
2026-01-09 18:27:37 - mcp_services - INFO - [main.py:329] - MCP 服务器已启动,等待客户端连接...
|
||||
2026-01-09 18:27:38 - mcp_services - INFO - [main.py:156] - 收到列出工具请求
|
||||
2026-01-09 18:27:38 - mcp_services - INFO - [main.py:119] - 初始化查询配置(数据源: local)...
|
||||
2026-01-09 18:27:38 - mcp_services - INFO - [main.py:55] - 成功加载 6 个业务查询配置
|
||||
2026-01-09 18:27:38 - mcp_services - INFO - [main.py:123] - 本地配置: 6 条
|
||||
2026-01-09 18:27:38 - mcp_services - INFO - [main.py:165] - 成功生成 6 个 MCP 工具
|
||||
2026-01-09 18:27:39 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SupplierEvaluationAndSmartReplenishment
|
||||
2026-01-09 18:27:39 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-09 18:27:40 - mcp_services - ERROR - [main.py:238] - 调用测试SQL API失败: 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 169, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: Multiple ResultSets were returned by the query.
|
||||
|
||||
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_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\main.py", line 226, in handle_call_tool
|
||||
api_response = test_sql_with_schema(request_data)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 251, in test_sql_with_schema
|
||||
return default_client.test_sql_with_schema(request_data)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 193, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
2026-01-09 18:27:46 - mcp_services - INFO - [main.py:190] - 收到工具调用请求: SalesBIIntelligentAnalyticsPlatform
|
||||
2026-01-09 18:27:46 - mcp_services - INFO - [main.py:225] - 正在调用测试SQL API...
|
||||
2026-01-09 18:27:46 - mcp_services - ERROR - [main.py:238] - 调用测试SQL API失败: 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
Traceback (most recent call last):
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 169, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: Multiple ResultSets were returned by the query.
|
||||
|
||||
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_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\main.py", line 226, in handle_call_tool
|
||||
api_response = test_sql_with_schema(request_data)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 251, in test_sql_with_schema
|
||||
return default_client.test_sql_with_schema(request_data)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "E:\yh-ai\project\lzwcai-szyg\lzwcai-mcp-server-package\lzwcai_mcpskills_mfg_data_agentv2\lzwcai_mcpskills_mfg_data_agentv2\utils\api_client.py", line 193, in test_sql_with_schema
|
||||
raise Exception(error_msg)
|
||||
Exception: 处理测试SQL API响应时出错: Multiple ResultSets were returned by the query.
|
||||
@@ -0,0 +1,373 @@
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
# 支持直接运行和模块导入两种方式
|
||||
try:
|
||||
from .utils import load_json, generate_tool_name, generate_input_schema
|
||||
from .utils import get_skill_by_id, DataSourceAPIClient, process_skill_response, test_sql_with_schema
|
||||
from .utils import get_database_id, get_datasource_id, get_skill_id, get_env_config
|
||||
from .utils.logger_config import logger_config
|
||||
except ImportError:
|
||||
from utils import load_json, generate_tool_name, generate_input_schema
|
||||
from utils import get_skill_by_id, DataSourceAPIClient, process_skill_response, test_sql_with_schema
|
||||
from utils import get_database_id, get_datasource_id, get_skill_id, get_env_config
|
||||
from utils.logger_config import logger_config
|
||||
|
||||
from mcp.server.models import InitializationOptions
|
||||
from mcp.server import NotificationOptions, Server
|
||||
import mcp.types as types
|
||||
|
||||
# 初始化 MCP 专用日志器
|
||||
mcp_logger = logger_config.setup_mcp_logging()
|
||||
|
||||
# ========== 数据源配置 ==========
|
||||
# 数据源类型常量
|
||||
DATA_SOURCE_API = "api" # 仅使用API数据
|
||||
DATA_SOURCE_LOCAL = "local" # 仅使用本地JSON数据
|
||||
DATA_SOURCE_BOTH = "both" # 合并本地和API数据
|
||||
|
||||
# 默认数据源(可修改)
|
||||
DEFAULT_DATA_SOURCE = DATA_SOURCE_LOCAL
|
||||
# ================================
|
||||
|
||||
|
||||
def get_queries():
|
||||
"""
|
||||
获取业务查询配置
|
||||
|
||||
Returns:
|
||||
list: 包含所有业务查询配置的列表
|
||||
"""
|
||||
try:
|
||||
# 获取当前文件所在目录
|
||||
current_dir = Path(__file__).parent
|
||||
|
||||
# 构建 businessQueries.json 的路径
|
||||
json_path = current_dir / "businessQueries.json"
|
||||
|
||||
mcp_logger.debug(f"正在读取业务查询配置文件: {json_path}")
|
||||
|
||||
# 使用 load_json 方法读取 JSON 文件
|
||||
queries = load_json(json_path)
|
||||
|
||||
mcp_logger.info(f"成功加载 {len(queries)} 个业务查询配置")
|
||||
|
||||
return queries
|
||||
except Exception as e:
|
||||
mcp_logger.error(f"加载业务查询配置失败: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def generate_tool_schema_from_query(query: dict) -> types.Tool:
|
||||
"""
|
||||
根据查询配置生成 MCP 工具模式
|
||||
|
||||
Args:
|
||||
query: 单个查询配置字典
|
||||
|
||||
Returns:
|
||||
types.Tool: MCP 工具对象
|
||||
"""
|
||||
try:
|
||||
# 获取参数定义并生成 inputSchema
|
||||
parameters = query.get('parameters', {})
|
||||
input_schema = generate_input_schema(parameters)
|
||||
|
||||
# 生成工具名称(格式: tool_拼音_id)
|
||||
# tool_name = generate_tool_name(query['businessName'], query['id'])
|
||||
tool_name = query['businessName']
|
||||
# 构建工具描述,包含业务名称和业务描述
|
||||
description = f"{query['businessName']}: {query['businessDescription']}"
|
||||
|
||||
mcp_logger.debug(f"生成工具模式: {tool_name} - {query['businessName']}")
|
||||
|
||||
return types.Tool(
|
||||
name=tool_name,
|
||||
description=description,
|
||||
inputSchema=input_schema
|
||||
)
|
||||
except Exception as e:
|
||||
mcp_logger.error(f"生成工具模式失败: {query.get('id', 'unknown')}, 错误: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
# 创建 MCP 服务器实例
|
||||
server = Server("lzwcai-mcpskills-mfg-data-agentv2")
|
||||
|
||||
# 缓存查询配置,避免重复加载
|
||||
_queries_cache = None
|
||||
|
||||
|
||||
async def get_queries_cache(source: str = None):
|
||||
"""
|
||||
获取或初始化查询配置缓存
|
||||
|
||||
Args:
|
||||
source: 数据源类型(默认使用 DEFAULT_DATA_SOURCE)
|
||||
- "api": 仅使用API数据
|
||||
- "local": 仅使用本地JSON数据
|
||||
- "both": 合并本地和API数据
|
||||
|
||||
Returns:
|
||||
查询配置列表
|
||||
"""
|
||||
global _queries_cache
|
||||
if _queries_cache is None:
|
||||
source = source or DEFAULT_DATA_SOURCE
|
||||
mcp_logger.info(f"初始化查询配置(数据源: {source})...")
|
||||
|
||||
if source == DATA_SOURCE_LOCAL:
|
||||
_queries_cache = get_queries()
|
||||
mcp_logger.info(f"本地配置: {len(_queries_cache)} 条")
|
||||
|
||||
elif source == DATA_SOURCE_API:
|
||||
try:
|
||||
_queries_cache = await call_third_party_api()
|
||||
mcp_logger.info(f"API配置: {len(_queries_cache)} 条")
|
||||
mcp_logger.info(f"API配置数组: {_queries_cache}")
|
||||
except Exception as e:
|
||||
mcp_logger.warning(f"API获取失败,降级使用本地配置: {e}")
|
||||
_queries_cache = get_queries()
|
||||
|
||||
else: # DATA_SOURCE_BOTH
|
||||
local = get_queries()
|
||||
try:
|
||||
api = await call_third_party_api()
|
||||
except Exception as e:
|
||||
mcp_logger.warning(f"API获取失败: {e}")
|
||||
api = []
|
||||
_queries_cache = local + api
|
||||
mcp_logger.info(f"配置总数: {len(_queries_cache)} 条(本地{len(local)}+API{len(api)})")
|
||||
|
||||
return _queries_cache
|
||||
|
||||
|
||||
@server.list_tools()
|
||||
async def handle_list_tools() -> list[types.Tool]:
|
||||
"""
|
||||
列出所有动态生成的 MCP 工具
|
||||
|
||||
Returns:
|
||||
list[types.Tool]: 所有可用的工具列表
|
||||
"""
|
||||
try:
|
||||
mcp_logger.info("收到列出工具请求")
|
||||
|
||||
queries = await get_queries_cache()
|
||||
tools = []
|
||||
|
||||
for query in queries:
|
||||
tool = generate_tool_schema_from_query(query)
|
||||
tools.append(tool)
|
||||
|
||||
mcp_logger.info(f"成功生成 {len(tools)} 个 MCP 工具")
|
||||
mcp_logger.debug(f"工具列表: {[tool.name for tool in tools]}")
|
||||
|
||||
return tools
|
||||
except Exception as e:
|
||||
mcp_logger.error(f"列出工具失败: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
@server.call_tool()
|
||||
async def handle_call_tool(
|
||||
name: str,
|
||||
arguments: dict[str, Any] | None
|
||||
) -> list[types.TextContent]:
|
||||
"""
|
||||
处理工具调用请求
|
||||
|
||||
Args:
|
||||
name: 工具名称
|
||||
arguments: 工具参数
|
||||
|
||||
Returns:
|
||||
list[types.TextContent]: 工具执行结果(返回参数和对应的接口配置)
|
||||
"""
|
||||
try:
|
||||
mcp_logger.info(f"收到工具调用请求: {name}")
|
||||
mcp_logger.debug(f"工具参数: {arguments}")
|
||||
|
||||
# 获取查询配置缓存
|
||||
queries = await get_queries_cache()
|
||||
|
||||
# 根据工具名称查找对应的 item(接口配置)
|
||||
tool_item = None
|
||||
for query in queries:
|
||||
# tool_name = generate_tool_name(query['businessName'], query['id'])
|
||||
tool_name = query['businessName']
|
||||
if tool_name == name:
|
||||
tool_item = query
|
||||
break
|
||||
|
||||
# 构建返回结果
|
||||
import json
|
||||
|
||||
if tool_item:
|
||||
request_data = {
|
||||
"datasourceId": get_datasource_id(),
|
||||
"businessName": tool_item.get("businessName"),
|
||||
"businessDescription": tool_item.get("businessDescription"),
|
||||
"sqlTemplate": tool_item.get("sqlTemplate"),
|
||||
"parameters": tool_item.get("parameters"),
|
||||
"testParams": arguments or {}
|
||||
}
|
||||
|
||||
# 如果 arguments 中有 targetDatabaseName 且有值,添加到 request_data
|
||||
if arguments and arguments.get("targetDatabaseName"):
|
||||
request_data["targetDatabaseName"] = arguments["targetDatabaseName"]
|
||||
mcp_logger.debug(f"添加目标数据库名称: {arguments['targetDatabaseName']}")
|
||||
|
||||
# 调用测试SQL API
|
||||
try:
|
||||
mcp_logger.info("正在调用测试SQL API...")
|
||||
api_response = test_sql_with_schema(request_data)
|
||||
mcp_logger.info("测试SQL API调用成功")
|
||||
|
||||
# 返回包含 data 字段的结果
|
||||
result = {
|
||||
"success": True,
|
||||
"data": api_response
|
||||
}
|
||||
result_text = json.dumps(result, ensure_ascii=False, indent=2)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"调用测试SQL API失败: {str(e)}"
|
||||
mcp_logger.error(error_msg, exc_info=True)
|
||||
result = {
|
||||
"success": False,
|
||||
"error": error_msg,
|
||||
"data": None
|
||||
}
|
||||
result_text = json.dumps(result, ensure_ascii=False, indent=2)
|
||||
else:
|
||||
error_msg = f"未找到工具 {name} 对应的配置"
|
||||
result = {
|
||||
"success": False,
|
||||
"error": error_msg,
|
||||
"data": None
|
||||
}
|
||||
result_text = json.dumps(result, ensure_ascii=False, indent=2)
|
||||
|
||||
mcp_logger.debug(f"工具调用结果: {result_text}")
|
||||
|
||||
return [
|
||||
types.TextContent(
|
||||
type="text",
|
||||
text=result_text
|
||||
)
|
||||
]
|
||||
except Exception as e:
|
||||
error_msg = f"工具调用失败: {name}, 错误: {e}"
|
||||
mcp_logger.error(error_msg, exc_info=True)
|
||||
return [
|
||||
types.TextContent(
|
||||
type="text",
|
||||
text=f"错误: {error_msg}"
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
async def call_third_party_api(skill_id: str = None) -> list:
|
||||
"""
|
||||
调用第三方API获取技能信息并返回处理后的数据
|
||||
|
||||
Args:
|
||||
skill_id: 技能ID(默认从环境变量 SKILL_ID 读取,如果未设置则使用 1981000305474482178)
|
||||
|
||||
Returns:
|
||||
处理后的查询配置列表(businessQueries格式)
|
||||
|
||||
Example:
|
||||
queries = await call_third_party_api()
|
||||
# 返回: [{"id": "...", "businessName": "...", ...}, ...]
|
||||
"""
|
||||
try:
|
||||
# 如果没有传入 skill_id,则从环境变量读取
|
||||
if skill_id is None:
|
||||
skill_id = get_skill_id()
|
||||
|
||||
mcp_logger.info(f"调用第三方API,skill_id: {skill_id}")
|
||||
|
||||
# 获取原始数据
|
||||
raw_result = get_skill_by_id(skill_id)
|
||||
|
||||
mcp_logger.info(f"成功{raw_result}")
|
||||
|
||||
# 处理并返回
|
||||
processed_queries = process_skill_response(raw_result)
|
||||
|
||||
mcp_logger.info(f"成功获取并处理 {len(processed_queries)} 条数据")
|
||||
return processed_queries
|
||||
|
||||
except Exception as e:
|
||||
mcp_logger.error(f"API调用失败: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
async def async_main():
|
||||
"""MCP 服务器异步主函数"""
|
||||
try:
|
||||
mcp_logger.info("=" * 60)
|
||||
mcp_logger.info("正在启动 MCP 服务器: lzwcai-mcpskills-analyzeOrder")
|
||||
mcp_logger.info("版本: 0.1.0")
|
||||
mcp_logger.info("=" * 60)
|
||||
|
||||
# 输出环境配置信息
|
||||
env_config = get_env_config()
|
||||
mcp_logger.info(f"环境配置 - Database ID: {env_config['database_id']}")
|
||||
mcp_logger.info(f"环境配置 - Datasource ID: {env_config['datasource_id']}")
|
||||
mcp_logger.info(f"环境配置 - Skill ID: {env_config['skill_id']}")
|
||||
mcp_logger.info(f"环境配置 - Backend Base URL: {env_config['backend_base_url']}")
|
||||
mcp_logger.info("=" * 60)
|
||||
|
||||
from mcp.server.stdio import stdio_server
|
||||
|
||||
async with stdio_server() as (read_stream, write_stream):
|
||||
mcp_logger.info("MCP 服务器已启动,等待客户端连接...")
|
||||
|
||||
await server.run(
|
||||
read_stream,
|
||||
write_stream,
|
||||
InitializationOptions(
|
||||
server_name="lzwcai-mcpskills-analyzeOrder",
|
||||
server_version="0.1.0",
|
||||
capabilities=server.get_capabilities(
|
||||
notification_options=NotificationOptions(),
|
||||
experimental_capabilities={},
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
mcp_logger.info("MCP 服务器已关闭")
|
||||
|
||||
except Exception as e:
|
||||
mcp_logger.error(f"MCP 服务器运行失败: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
def main():
|
||||
"""入口点函数(用于 console_scripts)"""
|
||||
try:
|
||||
# 初始化系统日志
|
||||
# MCP协议使用stdio通信,必须禁用控制台输出以避免干扰JSON-RPC通信
|
||||
logger_config.setup_logging(
|
||||
app_name="lzwcai_mcp_sqlexecutor",
|
||||
log_level=logging.INFO,
|
||||
console_output=False # 禁用控制台输出
|
||||
)
|
||||
|
||||
mcp_logger.info("开始运行 MCP SQL Executor 服务器")
|
||||
asyncio.run(async_main())
|
||||
|
||||
except KeyboardInterrupt:
|
||||
mcp_logger.info("收到中断信号,正在关闭服务器...")
|
||||
except Exception as e:
|
||||
mcp_logger.error(f"程序运行失败: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,35 @@
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai-mcpskills-mfg-data-agentv2"
|
||||
version = "0.1.1"
|
||||
description = "制造业数据智能体 - MCP server for manufacturing data intelligence with dynamic tool generation"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
license = {text = "MIT"}
|
||||
authors = [
|
||||
{name = "lzwcai", email = "your-email@example.com"},
|
||||
]
|
||||
keywords = ["mcp", "sql", "manufacturing", "data", "agent", "智能体"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
dependencies = [
|
||||
"httpx>=0.28.1",
|
||||
"mcp[cli]>=1.10.1",
|
||||
"pypinyin>=0.53.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
lzwcai-mcpskills-mfg-data-agentv2 = "lzwcai_mcpskills_mfg_data_agentv2.main:main"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["lzwcai_mcpskills_mfg_data_agentv2"]
|
||||
|
||||
[tool.hatch.build.targets.wheel.force-include]
|
||||
"lzwcai_mcpskills_mfg_data_agentv2/businessQueries.json" = "lzwcai_mcpskills_mfg_data_agentv2/businessQueries.json"
|
||||
@@ -0,0 +1,169 @@
|
||||
-- =====================================================
|
||||
-- 交付风险预测:延迟概率与红/黄/绿预警等级
|
||||
-- 基于历史订单的生产周期、物流延误、设备故障等特征
|
||||
-- =====================================================
|
||||
|
||||
WITH
|
||||
-- 1. 全局生产特征(汇总所有工单)
|
||||
global_production AS (
|
||||
SELECT
|
||||
COUNT(*) AS total_wo_count,
|
||||
AVG(CASE WHEN planned_qty > 0 THEN completed_qty / planned_qty ELSE 0 END) AS avg_completion_rate,
|
||||
SUM(CASE WHEN status IN ('OPEN', 'STARTED') THEN 1 ELSE 0 END) AS pending_wo_count,
|
||||
SUM(CASE WHEN status = 'CLOSED' THEN 1 ELSE 0 END) AS closed_wo_count
|
||||
FROM fact_work_order
|
||||
),
|
||||
|
||||
-- 2. 全局质检特征
|
||||
global_quality AS (
|
||||
SELECT
|
||||
COUNT(*) AS total_inspection_count,
|
||||
SUM(COALESCE(pass_qty, 0)) AS total_pass_qty,
|
||||
SUM(COALESCE(fail_qty, 0)) AS total_fail_qty,
|
||||
CASE WHEN SUM(COALESCE(pass_qty, 0) + COALESCE(fail_qty, 0)) > 0
|
||||
THEN SUM(COALESCE(pass_qty, 0))::FLOAT / SUM(COALESCE(pass_qty, 0) + COALESCE(fail_qty, 0))
|
||||
ELSE 1 END AS qc_pass_rate
|
||||
FROM fact_quality_inspection
|
||||
),
|
||||
|
||||
-- 3. 全局工序不良特征
|
||||
global_operation AS (
|
||||
SELECT
|
||||
COUNT(*) AS total_task_count,
|
||||
SUM(COALESCE(good_qty, 0)) AS total_good_qty,
|
||||
SUM(COALESCE(bad_qty, 0)) AS total_bad_qty,
|
||||
CASE WHEN SUM(COALESCE(good_qty, 0) + COALESCE(bad_qty, 0)) > 0
|
||||
THEN SUM(COALESCE(bad_qty, 0))::FLOAT / SUM(COALESCE(good_qty, 0) + COALESCE(bad_qty, 0))
|
||||
ELSE 0 END AS operation_defect_rate
|
||||
FROM fact_operation_task
|
||||
),
|
||||
|
||||
-- 4. 客户级别发货统计
|
||||
customer_shipment AS (
|
||||
SELECT
|
||||
customer_id,
|
||||
COUNT(*) AS shipment_count,
|
||||
SUM(COALESCE(amount, 0)) AS total_shipment_amount
|
||||
FROM fact_sales_shipment
|
||||
GROUP BY customer_id
|
||||
),
|
||||
|
||||
-- 5. 客户级别退货统计
|
||||
customer_return AS (
|
||||
SELECT
|
||||
customer_id,
|
||||
COUNT(*) AS return_count,
|
||||
SUM(COALESCE(amount, 0)) AS total_return_amount
|
||||
FROM fact_sales_return
|
||||
GROUP BY customer_id
|
||||
),
|
||||
|
||||
-- 6. 订单风险评估
|
||||
order_risk AS (
|
||||
SELECT
|
||||
so.sales_order_id,
|
||||
so.sales_order_number,
|
||||
c.customer_name,
|
||||
so.order_date_utc,
|
||||
so.deal_amount,
|
||||
so.payment_status,
|
||||
|
||||
-- 全局生产指标
|
||||
gp.avg_completion_rate AS production_completion_rate,
|
||||
gp.pending_wo_count,
|
||||
gp.total_wo_count AS work_order_count,
|
||||
|
||||
-- 全局质检指标
|
||||
gq.qc_pass_rate,
|
||||
gq.total_fail_qty,
|
||||
|
||||
-- 全局工序指标
|
||||
go.operation_defect_rate,
|
||||
|
||||
-- 客户级别指标
|
||||
COALESCE(cs.shipment_count, 0) AS shipment_count,
|
||||
COALESCE(cr.return_count, 0) AS return_count,
|
||||
CASE WHEN COALESCE(cs.shipment_count, 0) > 0
|
||||
THEN COALESCE(cr.return_count, 0)::FLOAT / cs.shipment_count
|
||||
ELSE 0 END AS return_rate
|
||||
|
||||
FROM fact_sales_order so
|
||||
LEFT JOIN dim_customer c ON so.customer_id = c.customer_id AND c.is_current = true
|
||||
CROSS JOIN global_production gp
|
||||
CROSS JOIN global_quality gq
|
||||
CROSS JOIN global_operation go
|
||||
LEFT JOIN customer_shipment cs ON so.customer_id = cs.customer_id
|
||||
LEFT JOIN customer_return cr ON so.customer_id = cr.customer_id
|
||||
)
|
||||
|
||||
-- 7. 最终输出
|
||||
SELECT
|
||||
sales_order_id,
|
||||
sales_order_number,
|
||||
customer_name,
|
||||
order_date_utc,
|
||||
deal_amount,
|
||||
payment_status,
|
||||
|
||||
-- 风险特征
|
||||
work_order_count,
|
||||
ROUND(production_completion_rate::NUMERIC, 2) AS production_completion_rate,
|
||||
pending_wo_count,
|
||||
ROUND(qc_pass_rate::NUMERIC, 2) AS qc_pass_rate,
|
||||
ROUND(operation_defect_rate::NUMERIC, 4) AS operation_defect_rate,
|
||||
return_count,
|
||||
ROUND(return_rate::NUMERIC, 4) AS return_rate,
|
||||
|
||||
-- 延迟概率
|
||||
ROUND((
|
||||
CASE WHEN production_completion_rate < 0.3 THEN 0.30
|
||||
WHEN production_completion_rate < 0.5 THEN 0.20
|
||||
WHEN production_completion_rate < 0.8 THEN 0.10
|
||||
ELSE 0 END
|
||||
+ CASE WHEN qc_pass_rate < 0.8 THEN 0.25
|
||||
WHEN qc_pass_rate < 0.9 THEN 0.15
|
||||
WHEN qc_pass_rate < 0.95 THEN 0.08
|
||||
ELSE 0 END
|
||||
+ CASE WHEN operation_defect_rate > 0.1 THEN 0.20
|
||||
WHEN operation_defect_rate > 0.05 THEN 0.12
|
||||
WHEN operation_defect_rate > 0.02 THEN 0.05
|
||||
ELSE 0 END
|
||||
+ CASE WHEN return_rate > 0.1 THEN 0.15
|
||||
WHEN return_rate > 0.05 THEN 0.08
|
||||
WHEN return_rate > 0.02 THEN 0.03
|
||||
ELSE 0 END
|
||||
+ CASE WHEN payment_status = 'UNPAID' THEN 0.10
|
||||
WHEN payment_status = 'PARTIAL' THEN 0.05
|
||||
ELSE 0 END
|
||||
)::NUMERIC, 2) AS delay_probability,
|
||||
|
||||
-- 红/黄/绿预警
|
||||
CASE
|
||||
WHEN (
|
||||
CASE WHEN production_completion_rate < 0.3 THEN 0.30 WHEN production_completion_rate < 0.5 THEN 0.20 WHEN production_completion_rate < 0.8 THEN 0.10 ELSE 0 END
|
||||
+ CASE WHEN qc_pass_rate < 0.8 THEN 0.25 WHEN qc_pass_rate < 0.9 THEN 0.15 WHEN qc_pass_rate < 0.95 THEN 0.08 ELSE 0 END
|
||||
+ CASE WHEN operation_defect_rate > 0.1 THEN 0.20 WHEN operation_defect_rate > 0.05 THEN 0.12 WHEN operation_defect_rate > 0.02 THEN 0.05 ELSE 0 END
|
||||
+ CASE WHEN return_rate > 0.1 THEN 0.15 WHEN return_rate > 0.05 THEN 0.08 WHEN return_rate > 0.02 THEN 0.03 ELSE 0 END
|
||||
+ CASE WHEN payment_status = 'UNPAID' THEN 0.10 WHEN payment_status = 'PARTIAL' THEN 0.05 ELSE 0 END
|
||||
) >= 0.50 THEN 'RED'
|
||||
WHEN (
|
||||
CASE WHEN production_completion_rate < 0.3 THEN 0.30 WHEN production_completion_rate < 0.5 THEN 0.20 WHEN production_completion_rate < 0.8 THEN 0.10 ELSE 0 END
|
||||
+ CASE WHEN qc_pass_rate < 0.8 THEN 0.25 WHEN qc_pass_rate < 0.9 THEN 0.15 WHEN qc_pass_rate < 0.95 THEN 0.08 ELSE 0 END
|
||||
+ CASE WHEN operation_defect_rate > 0.1 THEN 0.20 WHEN operation_defect_rate > 0.05 THEN 0.12 WHEN operation_defect_rate > 0.02 THEN 0.05 ELSE 0 END
|
||||
+ CASE WHEN return_rate > 0.1 THEN 0.15 WHEN return_rate > 0.05 THEN 0.08 WHEN return_rate > 0.02 THEN 0.03 ELSE 0 END
|
||||
+ CASE WHEN payment_status = 'UNPAID' THEN 0.10 WHEN payment_status = 'PARTIAL' THEN 0.05 ELSE 0 END
|
||||
) >= 0.25 THEN 'YELLOW'
|
||||
ELSE 'GREEN'
|
||||
END AS risk_level,
|
||||
|
||||
-- 风险原因
|
||||
CONCAT_WS(' | ',
|
||||
CASE WHEN production_completion_rate < 0.5 THEN '生产进度滞后' END,
|
||||
CASE WHEN qc_pass_rate < 0.9 THEN '质检通过率低' END,
|
||||
CASE WHEN operation_defect_rate > 0.05 THEN '工序不良率高' END,
|
||||
CASE WHEN return_rate > 0.05 THEN '历史退货率高' END,
|
||||
CASE WHEN payment_status = 'UNPAID' THEN '未付款' END
|
||||
) AS risk_reasons
|
||||
|
||||
FROM order_risk
|
||||
ORDER BY delay_probability DESC, deal_amount DESC;
|
||||
@@ -0,0 +1,25 @@
|
||||
"""Utils package for lzwcai_mcp_sqlexecutor"""
|
||||
|
||||
from .json_helper import load_json
|
||||
from .name_helper import generate_tool_name
|
||||
from .schema_helper import generate_input_schema, validate_input_schema
|
||||
from .api_client import DataSourceAPIClient, get_skill_by_id, process_skill_response, test_sql_with_schema
|
||||
from .env_config import get_database_id, get_datasource_id, get_skill_id, get_backend_base_url, get_env_config, set_env_variable
|
||||
|
||||
__all__ = [
|
||||
'load_json',
|
||||
'generate_tool_name',
|
||||
'generate_input_schema',
|
||||
'validate_input_schema',
|
||||
'DataSourceAPIClient',
|
||||
'get_skill_by_id',
|
||||
'process_skill_response',
|
||||
'test_sql_with_schema',
|
||||
'get_database_id',
|
||||
'get_datasource_id',
|
||||
'get_skill_id',
|
||||
'get_backend_base_url',
|
||||
'get_env_config',
|
||||
'set_env_variable'
|
||||
]
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
"""
|
||||
第三方API调用客户端
|
||||
用于调用外部数据源接口
|
||||
"""
|
||||
|
||||
import httpx
|
||||
import logging
|
||||
import json
|
||||
from typing import Dict, Any, Optional, List
|
||||
|
||||
# 支持直接运行和模块导入两种方式
|
||||
try:
|
||||
from .env_config import get_backend_base_url
|
||||
except ImportError:
|
||||
from env_config import get_backend_base_url
|
||||
|
||||
# 获取日志记录器
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DataSourceAPIClient:
|
||||
"""数据源API客户端"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
base_url: Optional[str] = None,
|
||||
token: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
初始化API客户端
|
||||
|
||||
Args:
|
||||
base_url: API基础URL(默认从环境变量 BACKEND_BASE_URL 读取,如果未设置则使用 http://192.168.2.236:8088)
|
||||
token: 认证令牌(Bearer Token)
|
||||
"""
|
||||
# 如果没有传入 base_url,则从环境变量读取
|
||||
if base_url is None:
|
||||
base_url = get_backend_base_url()
|
||||
|
||||
self.base_url = base_url.rstrip('/')
|
||||
self.token = token or "eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjJiYTk4ODllLWM2ZGItNDQ5YS1iZmFjLTQ2YzMxODFlODg5NCJ9.dvi8zm0LsWvJ_h9zD5blnHFRxa4z4_WBm1R487ekE7HlHzrN6dnvqhK8askqT5b1EcE8myHwRzLVMoI8UOjOrw"
|
||||
self.client = httpx.Client(timeout=30.0)
|
||||
|
||||
def _get_headers(self) -> Dict[str, str]:
|
||||
"""
|
||||
获取请求头
|
||||
|
||||
Returns:
|
||||
请求头字典
|
||||
"""
|
||||
return {
|
||||
'Authorization': f'Bearer {self.token}',
|
||||
}
|
||||
|
||||
def get_skill_by_id(self, skill_id: str) -> Dict[str, Any]:
|
||||
"""
|
||||
根据技能ID获取技能信息
|
||||
|
||||
Args:
|
||||
skill_id: 技能ID
|
||||
|
||||
Returns:
|
||||
API响应数据
|
||||
|
||||
Raises:
|
||||
Exception: 请求失败时抛出
|
||||
"""
|
||||
try:
|
||||
url = f"{self.base_url}/datasource/skill/getBySkillId/{skill_id}"
|
||||
|
||||
logger.info(f"正在调用API: {url}")
|
||||
logger.info(f"请求参数 - skill_id: {skill_id}")
|
||||
|
||||
response = self.client.get(
|
||||
url,
|
||||
headers=self._get_headers()
|
||||
)
|
||||
|
||||
# 检查HTTP状态码
|
||||
response.raise_for_status()
|
||||
|
||||
# 解析JSON响应
|
||||
data = response.json()
|
||||
|
||||
logger.info(f"API调用成功: {url}")
|
||||
logger.debug(f"响应数据: {data}")
|
||||
|
||||
return data
|
||||
|
||||
except httpx.TimeoutException:
|
||||
error_msg = f"API请求超时: {url}"
|
||||
logger.error(error_msg)
|
||||
raise Exception(error_msg)
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_msg = f"API请求失败 (HTTP {e.response.status_code}): {url}"
|
||||
logger.error(error_msg)
|
||||
logger.error(f"错误响应: {e.response.text}")
|
||||
raise Exception(error_msg)
|
||||
|
||||
except httpx.RequestError as e:
|
||||
error_msg = f"API请求异常: {url}, 错误: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
raise Exception(error_msg)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"处理API响应时出错: {str(e)}"
|
||||
logger.error(error_msg, exc_info=True)
|
||||
raise Exception(error_msg)
|
||||
|
||||
def test_sql_with_schema(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
测试SQL语句并返回执行结果
|
||||
|
||||
Args:
|
||||
request_data: 请求数据,包含以下字段:
|
||||
- datasourceId: 数据源ID
|
||||
- businessName: 业务名称
|
||||
- businessDescription: 业务描述
|
||||
- sqlTemplate: SQL模板
|
||||
- parameters: 参数定义
|
||||
- testParams: 测试参数
|
||||
|
||||
Returns:
|
||||
API响应数据
|
||||
|
||||
Raises:
|
||||
Exception: 请求失败时抛出
|
||||
"""
|
||||
try:
|
||||
url = f"{self.base_url}/datasource/sqlExecutionLog/testBatchSqlWithSchema"
|
||||
|
||||
# 构建请求头(包含Content-Type)
|
||||
headers = self._get_headers()
|
||||
headers['Content-Type'] = 'application/json'
|
||||
headers['Accept'] = '*/*'
|
||||
|
||||
logger.info(f"正在调用测试SQL API: {url}")
|
||||
logger.info(f"请求参数: {json.dumps(request_data, ensure_ascii=False, indent=2)}")
|
||||
|
||||
# 发送POST请求
|
||||
response = self.client.post(
|
||||
url,
|
||||
headers=headers,
|
||||
json=request_data
|
||||
)
|
||||
|
||||
# 检查HTTP状态码
|
||||
response.raise_for_status()
|
||||
|
||||
# 解析JSON响应
|
||||
result = response.json()
|
||||
|
||||
logger.info(f"测试SQL API调用成功")
|
||||
logger.debug(f"响应数据: {json.dumps(result, ensure_ascii=False, indent=2)}")
|
||||
|
||||
# 处理返回数据结构: {code, data: [{errorMessage, data}, ...], msg}
|
||||
# 检查外层 code
|
||||
if result.get("code") != 200:
|
||||
error_msg = result.get("msg", "接口返回错误")
|
||||
logger.error(f"接口返回错误: code={result.get('code')}, msg={error_msg}")
|
||||
raise Exception(error_msg)
|
||||
|
||||
# data 是一个数组,每个元素包含 errorMessage 和 data
|
||||
data_list = result.get("data", [])
|
||||
|
||||
# 如果不是数组,兼容旧格式
|
||||
if isinstance(data_list, dict):
|
||||
if data_list.get("errorMessage"):
|
||||
error_msg = data_list.get("errorMessage")
|
||||
logger.error(f"接口业务错误: {error_msg}")
|
||||
raise Exception(error_msg)
|
||||
return data_list.get("data")
|
||||
|
||||
# 处理数组格式,提取每个 item 的 data 并组合
|
||||
combined_data = []
|
||||
for item in data_list:
|
||||
if item.get("errorMessage"):
|
||||
error_msg = item.get("errorMessage")
|
||||
logger.error(f"接口业务错误: {error_msg}")
|
||||
raise Exception(error_msg)
|
||||
item_data = item.get("data", [])
|
||||
combined_data.append(item_data)
|
||||
|
||||
# 返回组合后的数据 [data1, data2, ...]
|
||||
return combined_data
|
||||
|
||||
except httpx.TimeoutException:
|
||||
error_msg = f"测试SQL API请求超时: {url}"
|
||||
logger.error(error_msg)
|
||||
raise Exception(error_msg)
|
||||
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_msg = f"测试SQL API请求失败 (HTTP {e.response.status_code}): {url}"
|
||||
logger.error(error_msg)
|
||||
logger.error(f"错误响应: {e.response.text}")
|
||||
raise Exception(error_msg)
|
||||
|
||||
except httpx.RequestError as e:
|
||||
error_msg = f"测试SQL API请求异常: {url}, 错误: {str(e)}"
|
||||
logger.error(error_msg)
|
||||
raise Exception(error_msg)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"处理测试SQL API响应时出错: {str(e)}"
|
||||
logger.error(error_msg, exc_info=True)
|
||||
raise Exception(error_msg)
|
||||
|
||||
def close(self):
|
||||
"""关闭HTTP客户端"""
|
||||
self.client.close()
|
||||
|
||||
|
||||
# 创建默认客户端实例
|
||||
default_client = DataSourceAPIClient()
|
||||
|
||||
|
||||
def get_skill_by_id(skill_id: str, base_url: Optional[str] = None, token: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
便捷函数:根据技能ID获取技能信息
|
||||
|
||||
Args:
|
||||
skill_id: 技能ID
|
||||
base_url: API基础URL(可选,默认从环境变量 BACKEND_BASE_URL 读取)
|
||||
token: 认证令牌(可选,使用默认值)
|
||||
|
||||
Returns:
|
||||
API响应数据
|
||||
"""
|
||||
if base_url or token:
|
||||
client = DataSourceAPIClient(
|
||||
base_url=base_url,
|
||||
token=token
|
||||
)
|
||||
return client.get_skill_by_id(skill_id)
|
||||
else:
|
||||
return default_client.get_skill_by_id(skill_id)
|
||||
|
||||
|
||||
def test_sql_with_schema(request_data: Dict[str, Any], base_url: Optional[str] = None, token: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
便捷函数:测试SQL语句并返回执行结果
|
||||
|
||||
Args:
|
||||
request_data: 请求数据,包含以下字段:
|
||||
- datasourceId: 数据源ID
|
||||
- businessName: 业务名称
|
||||
- businessDescription: 业务描述
|
||||
- sqlTemplate: SQL模板
|
||||
- parameters: 参数定义
|
||||
- testParams: 测试参数
|
||||
base_url: API基础URL(可选,默认从环境变量 BACKEND_BASE_URL 读取)
|
||||
token: 认证令牌(可选,使用默认值)
|
||||
|
||||
Returns:
|
||||
API响应数据
|
||||
"""
|
||||
if base_url or token:
|
||||
client = DataSourceAPIClient(
|
||||
base_url=base_url,
|
||||
token=token
|
||||
)
|
||||
return client.test_sql_with_schema(request_data)
|
||||
else:
|
||||
return default_client.test_sql_with_schema(request_data)
|
||||
|
||||
|
||||
def process_skill_response(response: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
处理API响应数据,映射为businessQueries格式
|
||||
|
||||
Args:
|
||||
response: API原始响应数据
|
||||
|
||||
Returns:
|
||||
处理后的查询配置列表
|
||||
"""
|
||||
try:
|
||||
# 提取data数组
|
||||
data_list = response.get("data", [])
|
||||
|
||||
# 默认的员工ID参数schema
|
||||
default_employee_schema = {
|
||||
"type": "object",
|
||||
"required": ["employeeId"],
|
||||
"properties": {
|
||||
"employeeId": {
|
||||
"type": "number",
|
||||
"description": "员工ID,用于标识员工的唯一数字标识符",
|
||||
"examples": [1001, 2002]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 映射每个skill为businessQuery格式
|
||||
queries = []
|
||||
for skill in data_list:
|
||||
# 解析sqlParams字符串为JSON对象
|
||||
sql_params = json.loads(skill.get("sqlParams", "{}"))
|
||||
|
||||
# 判断sqlParams是否为空对象
|
||||
is_empty_params = (
|
||||
not sql_params.get("properties") or
|
||||
len(sql_params.get("properties", {})) == 0
|
||||
) and (
|
||||
not sql_params.get("required") or
|
||||
len(sql_params.get("required", [])) == 0
|
||||
)
|
||||
|
||||
# 如果是空对象,使用默认的员工ID参数
|
||||
if is_empty_params:
|
||||
logger.info(f"技能 {skill.get('name')} (ID: {skill.get('id')}) 的sqlParams为空,使用默认员工ID参数")
|
||||
sql_params = default_employee_schema
|
||||
|
||||
# 映射字段
|
||||
query = {
|
||||
"id": skill.get("id"),
|
||||
"businessName": skill.get("name"),
|
||||
"businessDescription": skill.get("description"),
|
||||
"sqlTemplate": skill.get("sqlTemplate"),
|
||||
"parameters": sql_params,
|
||||
"datasourceId": skill.get("datasourceId")
|
||||
}
|
||||
queries.append(query)
|
||||
|
||||
logger.info(f"成功处理 {len(queries)} 条技能数据")
|
||||
return queries
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"处理API响应数据失败: {e}", exc_info=True)
|
||||
raise
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
"""环境变量配置模块"""
|
||||
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def get_database_id(default: str = "29") -> str:
|
||||
"""
|
||||
获取数据库ID环境变量
|
||||
|
||||
Args:
|
||||
default: 默认值(默认为 "29")
|
||||
|
||||
Returns:
|
||||
str: 数据库ID
|
||||
|
||||
Environment Variables:
|
||||
databaseId: 数据库ID
|
||||
"""
|
||||
return os.environ.get("databaseId", default)
|
||||
|
||||
|
||||
def get_datasource_id(default: str = "") -> str:
|
||||
"""
|
||||
获取数据源ID环境变量
|
||||
|
||||
Args:
|
||||
default: 默认值(默认为 "")
|
||||
|
||||
Returns:
|
||||
str: 数据源ID
|
||||
|
||||
Environment Variables:
|
||||
datasourceId: 数据源ID
|
||||
"""
|
||||
return os.environ.get("datasourceId", default)
|
||||
|
||||
|
||||
def get_skill_id(default: str = "") -> str:
|
||||
"""
|
||||
获取技能ID环境变量
|
||||
|
||||
Args:
|
||||
default: 默认值(默认为 "")
|
||||
|
||||
Returns:
|
||||
str: 技能ID
|
||||
|
||||
Environment Variables:
|
||||
skillId: 技能ID
|
||||
"""
|
||||
return os.environ.get("skillId", default)
|
||||
|
||||
|
||||
def get_backend_base_url(default: str = "http://lzwcai-demp-corp-manager:8086") -> str:
|
||||
"""
|
||||
获取后端API基础URL环境变量
|
||||
|
||||
Args:
|
||||
default: 默认值(默认为 "http://lzwcai-demp-corp-manager:8086")
|
||||
|
||||
Returns:
|
||||
str: 后端API基础URL
|
||||
|
||||
Environment Variables:
|
||||
backendBaseUrl: 后端API基础URL
|
||||
"""
|
||||
return os.environ.get("backendBaseUrl", default)
|
||||
|
||||
|
||||
def get_env_config() -> dict:
|
||||
"""
|
||||
获取所有环境配置
|
||||
|
||||
Returns:
|
||||
dict: 包含所有配置的字典
|
||||
|
||||
Example:
|
||||
config = get_env_config()
|
||||
print(config['database_id']) # 输出: "29"
|
||||
print(config['datasource_id']) # 输出: ""
|
||||
print(config['skill_id']) # 输出: ""
|
||||
print(config['backend_base_url']) # 输出: "http://lzwcai-demp-corp-manager:8086"
|
||||
"""
|
||||
return {
|
||||
"database_id": get_database_id(),
|
||||
"datasource_id": get_datasource_id(),
|
||||
"skill_id": get_skill_id(),
|
||||
"backend_base_url": get_backend_base_url()
|
||||
}
|
||||
|
||||
|
||||
def set_env_variable(key: str, value: str) -> None:
|
||||
"""
|
||||
设置环境变量(仅在当前进程中有效)
|
||||
|
||||
Args:
|
||||
key: 环境变量名
|
||||
value: 环境变量值
|
||||
|
||||
Example:
|
||||
set_env_variable("databaseId", "30")
|
||||
set_env_variable("skillId", "1234567890")
|
||||
"""
|
||||
os.environ[key] = value
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
"""JSON 文件读取工具"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Union
|
||||
|
||||
|
||||
def load_json(json_path: Union[str, Path]) -> Any:
|
||||
"""
|
||||
读取 JSON 文件并返回其内容
|
||||
|
||||
Args:
|
||||
json_path: JSON 文件的路径(支持字符串或 Path 对象)
|
||||
|
||||
Returns:
|
||||
JSON 文件中解析后的数据(可以是字典、列表或其他 JSON 类型)
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: 当文件不存在时
|
||||
json.JSONDecodeError: 当 JSON 格式无效时
|
||||
Exception: 其他读取错误
|
||||
|
||||
Example:
|
||||
>>> data = load_json('config.json')
|
||||
>>> print(data)
|
||||
{'key': 'value'}
|
||||
|
||||
>>> data = load_json(Path('data/users.json'))
|
||||
>>> print(data)
|
||||
[{'id': 1, 'name': 'Alice'}]
|
||||
"""
|
||||
try:
|
||||
# 转换为 Path 对象
|
||||
path = Path(json_path)
|
||||
|
||||
# 检查文件是否存在
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(f"JSON 文件不存在: {json_path}")
|
||||
|
||||
# 检查是否为文件
|
||||
if not path.is_file():
|
||||
raise ValueError(f"路径不是一个文件: {json_path}")
|
||||
|
||||
# 读取并解析 JSON 文件
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
return data
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
raise json.JSONDecodeError(
|
||||
f"JSON 格式错误: {e.msg}",
|
||||
e.doc,
|
||||
e.pos
|
||||
)
|
||||
except FileNotFoundError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise Exception(f"读取 JSON 文件时发生错误: {str(e)}")
|
||||
|
||||
@@ -0,0 +1,489 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
统一日志配置模块
|
||||
提供系统级别的日志配置和管理
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class LoggerConfig:
|
||||
"""日志配置管理类"""
|
||||
|
||||
def __init__(self, logs_dir: str = None):
|
||||
"""初始化日志配置
|
||||
|
||||
Args:
|
||||
logs_dir: 日志目录路径,默认为项目根目录下的logs文件夹
|
||||
"""
|
||||
# 确定日志目录
|
||||
if logs_dir:
|
||||
self.logs_dir = Path(logs_dir)
|
||||
else:
|
||||
# 获取项目根目录(logger_config.py 在 utils 目录下,需要上升两层到达项目根目录)
|
||||
project_root = Path(__file__).parent.parent
|
||||
self.logs_dir = project_root / "logs"
|
||||
|
||||
# 创建日志目录
|
||||
self.logs_dir.mkdir(exist_ok=True)
|
||||
|
||||
# 日志格式
|
||||
self.log_format = '%(asctime)s - %(name)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s'
|
||||
self.date_format = '%Y-%m-%d %H:%M:%S'
|
||||
|
||||
# 从环境变量获取日志级别,默认为INFO
|
||||
self.log_level = self._get_log_level_from_env()
|
||||
|
||||
# 是否已初始化
|
||||
self._initialized = False
|
||||
|
||||
def _get_log_level_from_env(self) -> int:
|
||||
"""从环境变量获取日志级别
|
||||
|
||||
Returns:
|
||||
int: 日志级别
|
||||
"""
|
||||
log_level_str = os.getenv('LOG_LEVEL', 'INFO').upper()
|
||||
|
||||
# 日志级别映射
|
||||
level_mapping = {
|
||||
'DEBUG': logging.DEBUG,
|
||||
'INFO': logging.INFO,
|
||||
'WARNING': logging.WARNING,
|
||||
'WARN': logging.WARNING, # 兼容性别名
|
||||
'ERROR': logging.ERROR,
|
||||
'CRITICAL': logging.CRITICAL,
|
||||
'FATAL': logging.CRITICAL # 兼容性别名
|
||||
}
|
||||
|
||||
return level_mapping.get(log_level_str, logging.INFO)
|
||||
|
||||
def setup_logging(self,
|
||||
app_name: str = "lzwcai_mcp_sqlexecutor",
|
||||
log_level: int = logging.INFO,
|
||||
max_file_size: int = 10 * 1024 * 1024, # 10MB
|
||||
backup_count: int = 5,
|
||||
console_output: bool = True) -> logging.Logger:
|
||||
"""设置系统日志配置
|
||||
|
||||
Args:
|
||||
app_name: 应用名称,用于日志文件命名
|
||||
log_level: 日志级别
|
||||
max_file_size: 单个日志文件最大大小(字节)
|
||||
backup_count: 保留的备份文件数量
|
||||
console_output: 是否输出到控制台
|
||||
|
||||
Returns:
|
||||
logging.Logger: 配置好的根日志器
|
||||
"""
|
||||
if self._initialized:
|
||||
return logging.getLogger()
|
||||
|
||||
# 设置根日志器
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(log_level)
|
||||
|
||||
# 清除现有的处理器
|
||||
for handler in root_logger.handlers[:]:
|
||||
root_logger.removeHandler(handler)
|
||||
|
||||
# 创建格式化器
|
||||
formatter = logging.Formatter(self.log_format, self.date_format)
|
||||
|
||||
# 1. 主日志文件 - 按大小滚动
|
||||
main_log_file = self.logs_dir / f"{app_name}.log"
|
||||
file_handler = RotatingFileHandler(
|
||||
main_log_file,
|
||||
maxBytes=max_file_size,
|
||||
backupCount=backup_count,
|
||||
encoding='utf-8'
|
||||
)
|
||||
file_handler.setLevel(log_level)
|
||||
file_handler.setFormatter(formatter)
|
||||
root_logger.addHandler(file_handler)
|
||||
|
||||
# 2. 错误日志文件 - 只记录ERROR及以上级别
|
||||
error_log_file = self.logs_dir / f"{app_name}_error.log"
|
||||
error_handler = RotatingFileHandler(
|
||||
error_log_file,
|
||||
maxBytes=max_file_size,
|
||||
backupCount=backup_count,
|
||||
encoding='utf-8'
|
||||
)
|
||||
error_handler.setLevel(logging.ERROR)
|
||||
error_handler.setFormatter(formatter)
|
||||
root_logger.addHandler(error_handler)
|
||||
|
||||
# 3. 按日期滚动的日志文件
|
||||
daily_log_file = self.logs_dir / f"{app_name}_daily.log"
|
||||
daily_handler = TimedRotatingFileHandler(
|
||||
daily_log_file,
|
||||
when='midnight',
|
||||
interval=1,
|
||||
backupCount=30, # 保留30天
|
||||
encoding='utf-8'
|
||||
)
|
||||
daily_handler.setLevel(log_level)
|
||||
daily_handler.setFormatter(formatter)
|
||||
daily_handler.suffix = "%Y-%m-%d"
|
||||
root_logger.addHandler(daily_handler)
|
||||
|
||||
# 4. 控制台输出
|
||||
# 重要:MCP协议使用stdio时,必须将日志输出到stderr,stdout仅用于JSON-RPC通信
|
||||
if console_output:
|
||||
console_handler = logging.StreamHandler(sys.stderr)
|
||||
console_handler.setLevel(log_level)
|
||||
console_formatter = logging.Formatter(
|
||||
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
self.date_format
|
||||
)
|
||||
console_handler.setFormatter(console_formatter)
|
||||
root_logger.addHandler(console_handler)
|
||||
|
||||
self._initialized = True
|
||||
|
||||
# 记录初始化信息
|
||||
root_logger.info(f"日志系统初始化完成 - 日志目录: {self.logs_dir}")
|
||||
root_logger.info(f"日志配置 - 级别: {logging.getLevelName(log_level)}, 文件大小限制: {max_file_size//1024//1024}MB, 备份数量: {backup_count}")
|
||||
|
||||
return root_logger
|
||||
|
||||
def get_module_logger(self, module_name: str) -> logging.Logger:
|
||||
"""获取模块专用日志器
|
||||
|
||||
Args:
|
||||
module_name: 模块名称
|
||||
|
||||
Returns:
|
||||
logging.Logger: 模块日志器
|
||||
"""
|
||||
return logging.getLogger(module_name)
|
||||
|
||||
def create_component_logger(self,
|
||||
component_name: str,
|
||||
log_file: str = None,
|
||||
log_level: int = None) -> logging.Logger:
|
||||
"""为特定组件创建独立的日志器
|
||||
|
||||
Args:
|
||||
component_name: 组件名称
|
||||
log_file: 独立日志文件名(可选)
|
||||
log_level: 日志级别(可选)
|
||||
|
||||
Returns:
|
||||
logging.Logger: 组件日志器
|
||||
"""
|
||||
logger = logging.getLogger(component_name)
|
||||
|
||||
if log_file:
|
||||
# 为组件创建独立的日志文件
|
||||
component_log_file = self.logs_dir / log_file
|
||||
handler = RotatingFileHandler(
|
||||
component_log_file,
|
||||
maxBytes=5 * 1024 * 1024, # 5MB
|
||||
backupCount=3,
|
||||
encoding='utf-8'
|
||||
)
|
||||
|
||||
formatter = logging.Formatter(self.log_format, self.date_format)
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
if log_level:
|
||||
handler.setLevel(log_level)
|
||||
|
||||
logger.addHandler(handler)
|
||||
logger.info(f"组件日志器创建完成: {component_name} -> {component_log_file}")
|
||||
|
||||
return logger
|
||||
|
||||
def setup_mqtt_logging(self) -> logging.Logger:
|
||||
"""设置MQTT专用日志
|
||||
|
||||
Returns:
|
||||
logging.Logger: MQTT日志器
|
||||
"""
|
||||
return self.create_component_logger(
|
||||
"mqtt_communication",
|
||||
"mqtt_communication.log",
|
||||
logging.DEBUG
|
||||
)
|
||||
|
||||
def setup_mcp_logging(self) -> logging.Logger:
|
||||
"""设置MCP专用日志
|
||||
|
||||
Returns:
|
||||
logging.Logger: MCP日志器
|
||||
"""
|
||||
return self.create_component_logger(
|
||||
"mcp_services",
|
||||
"mcp_services.log",
|
||||
logging.DEBUG
|
||||
)
|
||||
|
||||
def setup_api_logging(self) -> logging.Logger:
|
||||
"""设置API专用日志
|
||||
|
||||
Returns:
|
||||
logging.Logger: API日志器
|
||||
"""
|
||||
return self.create_component_logger(
|
||||
"api_requests",
|
||||
"api_requests.log",
|
||||
logging.INFO
|
||||
)
|
||||
|
||||
def get_logs_info(self) -> dict:
|
||||
"""获取日志系统信息
|
||||
|
||||
Returns:
|
||||
dict: 日志系统信息
|
||||
"""
|
||||
log_files = []
|
||||
if self.logs_dir.exists():
|
||||
for log_file in self.logs_dir.glob("*.log*"):
|
||||
stat = log_file.stat()
|
||||
log_files.append({
|
||||
"name": log_file.name,
|
||||
"size": stat.st_size,
|
||||
"modified": datetime.fromtimestamp(stat.st_mtime).isoformat()
|
||||
})
|
||||
|
||||
return {
|
||||
"logs_directory": str(self.logs_dir),
|
||||
"initialized": self._initialized,
|
||||
"log_files": log_files,
|
||||
"total_files": len(log_files)
|
||||
}
|
||||
|
||||
def cleanup_old_logs(self, days: int = 30):
|
||||
"""清理旧日志文件
|
||||
|
||||
Args:
|
||||
days: 保留天数
|
||||
"""
|
||||
if not self.logs_dir.exists():
|
||||
return
|
||||
|
||||
from datetime import timedelta
|
||||
cutoff_time = datetime.now() - timedelta(days=days)
|
||||
|
||||
cleaned_files = []
|
||||
for log_file in self.logs_dir.glob("*.log*"):
|
||||
if log_file.stat().st_mtime < cutoff_time.timestamp():
|
||||
try:
|
||||
log_file.unlink()
|
||||
cleaned_files.append(log_file.name)
|
||||
except Exception as e:
|
||||
logging.error(f"清理日志文件失败: {log_file.name}, 错误: {e}")
|
||||
|
||||
if cleaned_files:
|
||||
logging.info(f"清理了 {len(cleaned_files)} 个旧日志文件: {cleaned_files}")
|
||||
|
||||
def set_log_level(self, level: int, logger_name: str = None):
|
||||
"""动态调整日志级别
|
||||
|
||||
Args:
|
||||
level: 新的日志级别 (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
|
||||
logger_name: 指定日志器名称,None表示调整根日志器
|
||||
"""
|
||||
if logger_name:
|
||||
logger = logging.getLogger(logger_name)
|
||||
else:
|
||||
logger = logging.getLogger()
|
||||
|
||||
old_level = logger.level
|
||||
logger.setLevel(level)
|
||||
|
||||
# 同时调整所有处理器的级别
|
||||
for handler in logger.handlers:
|
||||
if not isinstance(handler, logging.StreamHandler) or handler.stream not in (sys.stdout, sys.stderr):
|
||||
# 不调整控制台处理器的级别,保持原有设置
|
||||
handler.setLevel(level)
|
||||
|
||||
level_name = logging.getLevelName(level)
|
||||
old_level_name = logging.getLevelName(old_level)
|
||||
target = logger_name or "根日志器"
|
||||
|
||||
logger.info(f"日志级别已调整: {target} {old_level_name} -> {level_name}")
|
||||
|
||||
def set_temporary_log_level(self, level: int, logger_name: str = None):
|
||||
"""临时调整日志级别(会保存原始级别用于恢复)
|
||||
|
||||
Args:
|
||||
level: 临时日志级别
|
||||
logger_name: 指定日志器名称,None表示调整根日志器
|
||||
"""
|
||||
if not hasattr(self, '_original_levels'):
|
||||
self._original_levels = {}
|
||||
|
||||
target_name = logger_name or 'root'
|
||||
|
||||
if logger_name:
|
||||
logger = logging.getLogger(logger_name)
|
||||
else:
|
||||
logger = logging.getLogger()
|
||||
|
||||
# 保存原始级别
|
||||
if target_name not in self._original_levels:
|
||||
self._original_levels[target_name] = logger.level
|
||||
|
||||
# 设置新级别
|
||||
self.set_log_level(level, logger_name)
|
||||
|
||||
level_name = logging.getLevelName(level)
|
||||
target = logger_name or "根日志器"
|
||||
logger.info(f"临时调整日志级别: {target} -> {level_name} (可通过restore_log_level恢复)")
|
||||
|
||||
def restore_log_level(self, logger_name: str = None):
|
||||
"""恢复日志级别到调整前的状态
|
||||
|
||||
Args:
|
||||
logger_name: 指定日志器名称,None表示恢复根日志器
|
||||
"""
|
||||
if not hasattr(self, '_original_levels'):
|
||||
logging.warning("没有找到保存的原始日志级别")
|
||||
return
|
||||
|
||||
target_name = logger_name or 'root'
|
||||
|
||||
if target_name not in self._original_levels:
|
||||
logging.warning(f"没有找到 {target_name} 的原始日志级别")
|
||||
return
|
||||
|
||||
original_level = self._original_levels[target_name]
|
||||
self.set_log_level(original_level, logger_name)
|
||||
|
||||
# 清除保存的级别
|
||||
del self._original_levels[target_name]
|
||||
|
||||
target = logger_name or "根日志器"
|
||||
level_name = logging.getLevelName(original_level)
|
||||
logging.info(f"已恢复日志级别: {target} -> {level_name}")
|
||||
|
||||
def get_current_log_levels(self) -> dict:
|
||||
"""获取当前所有日志器的级别信息
|
||||
|
||||
Returns:
|
||||
dict: 日志器级别信息
|
||||
"""
|
||||
levels_info = {}
|
||||
|
||||
# 根日志器
|
||||
root_logger = logging.getLogger()
|
||||
levels_info['root'] = {
|
||||
'level': root_logger.level,
|
||||
'level_name': logging.getLevelName(root_logger.level),
|
||||
'handlers_count': len(root_logger.handlers)
|
||||
}
|
||||
|
||||
# 其他已创建的日志器
|
||||
for name, logger in logging.Logger.manager.loggerDict.items():
|
||||
if isinstance(logger, logging.Logger):
|
||||
levels_info[name] = {
|
||||
'level': logger.level,
|
||||
'level_name': logging.getLevelName(logger.level),
|
||||
'handlers_count': len(logger.handlers)
|
||||
}
|
||||
|
||||
return levels_info
|
||||
|
||||
|
||||
# 全局日志配置实例
|
||||
logger_config = LoggerConfig()
|
||||
|
||||
|
||||
def setup_system_logging(app_name: str = "lzwcai_mcp_sqlexecutor",
|
||||
log_level: int = logging.INFO) -> logging.Logger:
|
||||
"""系统日志初始化快捷函数
|
||||
|
||||
Args:
|
||||
app_name: 应用名称
|
||||
log_level: 日志级别
|
||||
|
||||
Returns:
|
||||
logging.Logger: 根日志器
|
||||
"""
|
||||
return logger_config.setup_logging(app_name, log_level)
|
||||
|
||||
|
||||
def get_logger(name: str) -> logging.Logger:
|
||||
"""获取日志器的快捷函数
|
||||
|
||||
Args:
|
||||
name: 日志器名称
|
||||
|
||||
Returns:
|
||||
logging.Logger: 日志器实例
|
||||
"""
|
||||
return logger_config.get_module_logger(name)
|
||||
|
||||
|
||||
def set_log_level(level: int, logger_name: str = None):
|
||||
"""动态调整日志级别的快捷函数
|
||||
|
||||
Args:
|
||||
level: 新的日志级别 (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
|
||||
logger_name: 指定日志器名称,None表示调整根日志器
|
||||
|
||||
Examples:
|
||||
# 调整根日志器为DEBUG级别
|
||||
set_log_level(logging.DEBUG)
|
||||
|
||||
# 调整特定模块日志器为WARNING级别
|
||||
set_log_level(logging.WARNING, "agent_ontology.core")
|
||||
"""
|
||||
logger_config.set_log_level(level, logger_name)
|
||||
|
||||
|
||||
def set_temporary_log_level(level: int, logger_name: str = None):
|
||||
"""临时调整日志级别的快捷函数
|
||||
|
||||
Args:
|
||||
level: 临时日志级别
|
||||
logger_name: 指定日志器名称,None表示调整根日志器
|
||||
|
||||
Examples:
|
||||
# 临时调整为DEBUG级别进行调试
|
||||
set_temporary_log_level(logging.DEBUG)
|
||||
# ... 进行调试 ...
|
||||
# 恢复原始级别
|
||||
restore_log_level()
|
||||
"""
|
||||
logger_config.set_temporary_log_level(level, logger_name)
|
||||
|
||||
|
||||
def restore_log_level(logger_name: str = None):
|
||||
"""恢复日志级别的快捷函数
|
||||
|
||||
Args:
|
||||
logger_name: 指定日志器名称,None表示恢复根日志器
|
||||
"""
|
||||
logger_config.restore_log_level(logger_name)
|
||||
|
||||
|
||||
def get_current_log_levels() -> dict:
|
||||
"""获取当前日志级别信息的快捷函数
|
||||
|
||||
Returns:
|
||||
dict: 日志器级别信息
|
||||
|
||||
Examples:
|
||||
levels = get_current_log_levels()
|
||||
print(f"根日志器级别: {levels['root']['level_name']}")
|
||||
"""
|
||||
return logger_config.get_current_log_levels()
|
||||
|
||||
|
||||
# 便捷的日志级别常量
|
||||
class LogLevel:
|
||||
"""日志级别常量类"""
|
||||
DEBUG = logging.DEBUG
|
||||
INFO = logging.INFO
|
||||
WARNING = logging.WARNING
|
||||
ERROR = logging.ERROR
|
||||
CRITICAL = logging.CRITICAL
|
||||
@@ -0,0 +1,41 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
名称生成工具模块
|
||||
"""
|
||||
|
||||
from pypinyin import lazy_pinyin, Style
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def generate_tool_name(business_name: str, tool_id: str) -> str:
|
||||
"""
|
||||
根据业务名称和ID生成工具名称
|
||||
格式: tool_拼音_id
|
||||
|
||||
Args:
|
||||
business_name: 业务名称(中文)
|
||||
tool_id: 工具ID
|
||||
|
||||
Returns:
|
||||
str: 格式化的工具名称
|
||||
"""
|
||||
try:
|
||||
# 将中文转换为拼音(无音调,小写)
|
||||
pinyin_list = lazy_pinyin(business_name, style=Style.NORMAL)
|
||||
# 拼接拼音
|
||||
pinyin_str = ''.join(pinyin_list)
|
||||
|
||||
# 将 ID 中的 '-' 替换为 '_'
|
||||
formatted_id = tool_id.replace('-', '_')
|
||||
|
||||
# 组合成最终的工具名称
|
||||
tool_name = f"tool_{pinyin_str}_{formatted_id}"
|
||||
|
||||
return tool_name
|
||||
except Exception as e:
|
||||
logger.error(f"生成工具名称失败: {business_name}, {tool_id}, 错误: {e}", exc_info=True)
|
||||
# 降级处理:如果拼音转换失败,使用 ID
|
||||
return f"tool_{tool_id.replace('-', '_')}"
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Schema 生成工具模块
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
def generate_input_schema(parameters: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
从查询配置的参数定义生成 MCP 工具的 inputSchema
|
||||
|
||||
此函数会保留完整的 JSON Schema 信息,包括:
|
||||
- type: Schema 类型(通常是 "object")
|
||||
- required: 必填字段列表
|
||||
- properties: 属性定义(包括每个属性的 type, description, format, examples 等)
|
||||
- description: Schema 的整体描述(如果有)
|
||||
- 以及其他任何 JSON Schema 标准字段
|
||||
|
||||
此函数还会自动添加以下字段(如果原始 parameters 中未定义):
|
||||
- targetDatabaseName: 目标数据库名称(非必填,默认为空字符串)
|
||||
|
||||
Args:
|
||||
parameters: 查询配置中的参数定义字典,应该是一个完整的 JSON Schema 对象
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: 符合 JSON Schema 规范的 inputSchema 对象
|
||||
|
||||
Example:
|
||||
>>> params = {
|
||||
... "type": "object",
|
||||
... "required": ["userId", "startTime"],
|
||||
... "properties": {
|
||||
... "userId": {
|
||||
... "type": "integer",
|
||||
... "description": "用户的唯一标识符",
|
||||
... "examples": [10086]
|
||||
... },
|
||||
... "startTime": {
|
||||
... "type": "string",
|
||||
... "format": "date-time",
|
||||
... "description": "查询的起始时间",
|
||||
... "examples": ["2023-01-01 00:00:00"]
|
||||
... }
|
||||
... }
|
||||
... }
|
||||
>>> schema = generate_input_schema(params)
|
||||
>>> # schema 将包含所有原始信息,包括 format 和 examples
|
||||
>>> # 同时会自动添加 targetDatabaseName 字段
|
||||
"""
|
||||
# 如果 parameters 本身就是一个完整的 JSON Schema 对象,直接使用
|
||||
# 但确保至少包含 type 和 properties
|
||||
if not parameters:
|
||||
# 如果 parameters 为空,返回一个空的 object schema
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": []
|
||||
}
|
||||
|
||||
# 检查 parameters 是否已经是完整的 JSON Schema 格式
|
||||
# 完整格式应该有 "type": "object" 和 "properties" 字段
|
||||
if "type" in parameters and parameters.get("type") == "object" and "properties" in parameters:
|
||||
# 已经是完整的 JSON Schema 格式,直接使用
|
||||
input_schema = dict(parameters)
|
||||
else:
|
||||
# parameters 是简化格式(直接是参数定义),需要转换为 JSON Schema 格式
|
||||
# 例如: {"workOrderNumber": {"type": "string", "description": "...", "required": true}}
|
||||
properties = {}
|
||||
required = []
|
||||
|
||||
for param_name, param_def in parameters.items():
|
||||
if isinstance(param_def, dict):
|
||||
# 提取 required 标记
|
||||
if param_def.get("required", False):
|
||||
required.append(param_name)
|
||||
|
||||
# 复制参数定义,但移除 required 字段(它应该在顶层的 required 数组中)
|
||||
prop_def = {k: v for k, v in param_def.items() if k != "required"}
|
||||
properties[param_name] = prop_def
|
||||
|
||||
input_schema = {
|
||||
"type": "object",
|
||||
"properties": properties,
|
||||
"required": required
|
||||
}
|
||||
|
||||
# 确保必需的字段存在
|
||||
if "type" not in input_schema:
|
||||
input_schema["type"] = "object"
|
||||
|
||||
if "properties" not in input_schema:
|
||||
input_schema["properties"] = {}
|
||||
|
||||
if "required" not in input_schema:
|
||||
input_schema["required"] = []
|
||||
|
||||
# 添加 targetDatabaseName 字段(如果不存在)
|
||||
if "targetDatabaseName" not in input_schema["properties"]:
|
||||
input_schema["properties"]["targetDatabaseName"] = {
|
||||
"type": "string",
|
||||
"description": "目标数据库名称",
|
||||
"default": ""
|
||||
}
|
||||
|
||||
# 保留所有其他字段,如 description, examples, format 等
|
||||
# JSON Schema 标准支持的字段都会被保留:
|
||||
# - additionalProperties
|
||||
# - patternProperties
|
||||
# - minProperties / maxProperties
|
||||
# - dependencies
|
||||
# - 等等
|
||||
|
||||
return input_schema
|
||||
|
||||
|
||||
def validate_input_schema(schema: Dict[str, Any]) -> tuple[bool, str]:
|
||||
"""
|
||||
验证 inputSchema 是否符合基本的 JSON Schema 规范
|
||||
|
||||
Args:
|
||||
schema: 要验证的 schema 对象
|
||||
|
||||
Returns:
|
||||
tuple[bool, str]: (是否有效, 错误消息或成功消息)
|
||||
|
||||
Example:
|
||||
>>> schema = {"type": "object", "properties": {"id": {"type": "string"}}}
|
||||
>>> is_valid, msg = validate_input_schema(schema)
|
||||
>>> print(is_valid, msg)
|
||||
True, "Schema 验证通过"
|
||||
"""
|
||||
if not isinstance(schema, dict):
|
||||
return False, "Schema 必须是一个字典对象"
|
||||
|
||||
if schema.get("type") != "object":
|
||||
return False, "Schema 的 type 字段必须是 'object'"
|
||||
|
||||
if "properties" not in schema:
|
||||
return False, "Schema 必须包含 properties 字段"
|
||||
|
||||
if not isinstance(schema.get("properties"), dict):
|
||||
return False, "Schema 的 properties 字段必须是一个字典对象"
|
||||
|
||||
# 验证 required 字段(如果存在)
|
||||
if "required" in schema:
|
||||
required = schema["required"]
|
||||
if not isinstance(required, list):
|
||||
return False, "Schema 的 required 字段必须是一个列表"
|
||||
|
||||
# 验证所有 required 的字段都在 properties 中定义
|
||||
properties = schema["properties"]
|
||||
for field in required:
|
||||
if field not in properties:
|
||||
return False, f"必填字段 '{field}' 未在 properties 中定义"
|
||||
|
||||
# 验证 properties 中每个字段的定义
|
||||
for prop_name, prop_def in schema["properties"].items():
|
||||
if not isinstance(prop_def, dict):
|
||||
return False, f"属性 '{prop_name}' 的定义必须是一个字典对象"
|
||||
|
||||
if "type" not in prop_def:
|
||||
return False, f"属性 '{prop_name}' 必须包含 type 字段"
|
||||
|
||||
return True, "Schema 验证通过"
|
||||
|
||||
497
lzwcai_mcpskills_mfg_data_agentv2/lzwcai_mcpskills_mfg_data_agentv2/uv.lock
generated
Normal file
497
lzwcai_mcpskills_mfg_data_agentv2/lzwcai_mcpskills_mfg_data_agentv2/uv.lock
generated
Normal file
@@ -0,0 +1,497 @@
|
||||
version = 1
|
||||
revision = 2
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/aff/07c09a53a08bc/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/1f0/2e8b43a8fbbc3/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.11.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/82a/8d0b81e318cc5/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/028/7e96f4d26d414/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "25.4.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/16d/5969b87f0859e/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/adc/f7e2a1fb3b36a/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.10.5"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/47c/09d31ccf2acf0/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/0f2/12c2744a9bb6d/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.3.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/e7b/8232224eba16f/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/9b9/f285302c6e306/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/086/95f5cb7ed6e05/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/4f1/d9991f5acc0ca/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
version = "0.16.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/4e3/5b956cf45792e/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/63c/f8bbe7522de3b/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.9"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/6e3/4463af53fd2ab/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/2d4/00746a40668fc/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.28.1"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "certifi" },
|
||||
{ name = "httpcore" },
|
||||
{ name = "idna" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/75e/98c5f16b0f35b/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d90/9fcccc110f8c7/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx-sse"
|
||||
version = "0.4.3"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/9b1/ed0127459a660/httpx_sse-0.4.3.tar.gz", hash = "sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/0ac/1c9fe3c0afad2/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.11"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/795/dafcc9c04ed0c/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/771/a87f49d9defaf/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonschema"
|
||||
version = "4.25.1"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "attrs" },
|
||||
{ name = "jsonschema-specifications" },
|
||||
{ name = "referencing" },
|
||||
{ name = "rpds-py" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/e4a/9655ce0da0c0b/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/3fb/a0169e345c717/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonschema-specifications"
|
||||
version = "2025.9.1"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "referencing" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/b54/0987f239e7456/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/988/02fee3a11ee76/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lzwcai-mcpskills-analyzeWorkOrder"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
{ name = "mcp", extra = ["cli"] },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "httpx", specifier = ">=0.28.1" },
|
||||
{ name = "mcp", extras = ["cli"], specifier = ">=1.10.1" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "4.0.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "mdurl" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/cb0/a2b4aa34f932c/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/873/27c59b172c501/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mcp"
|
||||
version = "1.10.1"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "httpx" },
|
||||
{ name = "httpx-sse" },
|
||||
{ name = "jsonschema" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
{ name = "python-multipart" },
|
||||
{ name = "sse-starlette" },
|
||||
{ name = "starlette" },
|
||||
{ name = "uvicorn", marker = "sys_platform != 'emscripten'" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/aaa/0957d8307feef/mcp-1.10.1.tar.gz", hash = "sha256:aaa0957d8307feeff180da2d9d359f2b801f35c0c67f1882136239055ef034c2" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/4d0/8301aefe906dc/mcp-1.10.1-py3-none-any.whl", hash = "sha256:4d08301aefe906dce0fa482289db55ce1db831e3e67212e65b5e23ad8454b3c5" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
cli = [
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "typer" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/bb4/13d29f5eea38f/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/840/08a41e51615a4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.12.2"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "annotated-types" },
|
||||
{ name = "pydantic-core" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/7b8/fa15b831a4bbd/pydantic-2.12.2.tar.gz", hash = "sha256:7b8fa15b831a4bbde9d5b84028641ac3080a4ca2cbd4a621a661687e741624fd" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/25f/f718ee909acd8/pydantic-2.12.2-py3-none-any.whl", hash = "sha256:25ff718ee909acd82f1ff9b1a4acfd781bb23ab3739adaa7144f19a6a4e231ae" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.41.4"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/70e/47929a9d4a190/pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/85e/050ad9e5f6fe1/pydantic_core-2.41.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:85e050ad9e5f6fe1004eec65c914332e52f429bc0ae12d6fa2092407a462c746" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/e73/93f1d64792763/pydantic_core-2.41.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7393f1d64792763a48924ba31d1e44c2cfbc05e3b1c2c9abb4ceeadd912cced" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/94d/ab0940b0d1fb2/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94dab0940b0d1fb28bcab847adf887c66a27a40291eedf0b473be58761c9799a" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/de7/c42f897e689ee/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de7c42f897e689ee6f9e93c4bec72b99ae3b32a2ade1c7e4798e690ff5246e02" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/664/b319919326227/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:664b3199193262277b8b3cd1e754fb07f2c6023289c815a1e1e8fb415cb247b1" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d95/b253b88f7d308/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95b253b88f7d308b1c0b417c4624f44553ba4762816f94e6986819b9c273fb2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/a13/51f5bbdbbabc6/pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1351f5bbdbbabc689727cb91649a00cb9ee7203e0a6e54e9f5ba9e22e384b84" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/1af/fa4798520b148/pydantic_core-2.41.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1affa4798520b148d7182da0615d648e752de4ab1a9566b7471bc803d88a062d" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/7b7/4e18052fea4aa/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7b74e18052fea4aa8dea2fb7dbc23d15439695da6cbe6cfc1b694af1115df09d" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/285/b643d75c0e30a/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:285b643d75c0e30abda9dc1077395624f314a37e3c09ca402d4015ef5979f1a2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/f52/679ff4218d713/pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:f52679ff4218d713b3b33f88c89ccbf3a5c2c12ba665fb80ccc4192b4608dbab" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/ecd/e6dedd6fff127/pydantic_core-2.41.4-cp313-cp313-win32.whl", hash = "sha256:ecde6dedd6fff127c273c76821bb754d793be1024bc33314a120f83a3c69460c" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d08/1a1f3800f0540/pydantic_core-2.41.4-cp313-cp313-win_amd64.whl", hash = "sha256:d081a1f3800f05409ed868ebb2d74ac39dd0c1ff6c035b5162356d76030736d4" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/f8e/49c9c364a7edc/pydantic_core-2.41.4-cp313-cp313-win_arm64.whl", hash = "sha256:f8e49c9c364a7edcbe2a310f12733aad95b022495ef2a8d653f645e5d20c1564" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/ed9/7fd56a561f5eb/pydantic_core-2.41.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ed97fd56a561f5eb5706cebe94f1ad7c13b84d98312a05546f2ad036bafe87f4" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/a87/0c307bf1ee91f/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a870c307bf1ee91fc58a9a61338ff780d01bfae45922624816878dce784095d2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d25/e97bc1f5f8f79/pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25e97bc1f5f8f7985bdc2335ef9e73843bb561eb1fa6831fdfc295c1c2061cf" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d40/5d14bea042f16/pydantic_core-2.41.4-cp313-cp313t-win_amd64.whl", hash = "sha256:d405d14bea042f166512add3091c1af40437c2e7f86988f3915fabd27b1e9cd2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/19f/3684868309db5/pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/e92/05d97ed08a82e/pydantic_core-2.41.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e9205d97ed08a82ebb9a307e92914bb30e18cdf6f6b12ca4bedadb1588a0bfe1" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/82d/f1f432b37d832/pydantic_core-2.41.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82df1f432b37d832709fbcc0e24394bba04a01b6ecf1ee87578145c19cde12ac" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/fc3/b4cc4539e055c/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3b4cc4539e055cfa39a3763c939f9d409eb40e85813257dcd761985a108554" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/b1e/b1754fce47c63/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1eb1754fce47c63d2ff57fdb88c351a6c0150995890088b33767a10218eaa4e" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/e6a/b5ab30ef325b4/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6ab5ab30ef325b443f379ddb575a34969c333004fca5a1daa0133a6ffaad616" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/31a/41030b1d9ca49/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31a41030b1d9ca497634092b46481b937ff9397a86f9f51bd41c4767b6fc04af" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/a44/ac1738591472c/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a44ac1738591472c3d020f61c6df1e4015180d6262ebd39bf2aeb52571b60f12" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d72/f2b5e6e82ab8f/pydantic_core-2.41.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d72f2b5e6e82ab8f94ea7d0d42f83c487dc159c5240d8f83beae684472864e2d" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/c4d/1e854aaf04448/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c4d1e854aaf044487d31143f541f7aafe7b482ae72a022c664b2de2e466ed0ad" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/b56/8af94267729d7/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b568af94267729d76e6ee5ececda4e283d07bbb28e8148bb17adad93d025d25a" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/6d5/5fb8b1e8929b3/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6d55fb8b1e8929b341cc313a81a26e0d48aa3b519c1dbaadec3a6a2b4fcad025" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/5b6/6584e549e2e32/pydantic_core-2.41.4-cp314-cp314-win32.whl", hash = "sha256:5b66584e549e2e32a1398df11da2e0a7eff45d5c2d9db9d5667c5e6ac764d77e" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/557/a0aab88664cc5/pydantic_core-2.41.4-cp314-cp314-win_amd64.whl", hash = "sha256:557a0aab88664cc552285316809cab897716a372afaf8efdbef756f8b890e894" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/3f1/ea6f48a045745/pydantic_core-2.41.4-cp314-cp314-win_arm64.whl", hash = "sha256:3f1ea6f48a045745d0d9f325989d8abd3f1eaf47dd00485912d1a3a63c623a8d" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/6c1/fe4c5404c448b/pydantic_core-2.41.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6c1fe4c5404c448b13188dd8bd2ebc2bdd7e6727fa61ff481bcc2cca894018da" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/523/e7da4d43b113b/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:523e7da4d43b113bf8e7b49fa4ec0c35bf4fe66b2230bfc5c13cc498f12c6c3e" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/572/9225de81fb65b/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5729225de81fb65b70fdb1907fcf08c75d498f4a6f15af005aabb1fdadc19dfa" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/de2/cfbb09e88f0f7/pydantic_core-2.41.4-cp314-cp314t-win_amd64.whl", hash = "sha256:de2cfbb09e88f0f795fd90cf955858fc2c691df65b1f21f0aa00b99f3fbc661d" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d34/f950ae05a83e0/pydantic_core-2.41.4-cp314-cp314t-win_arm64.whl", hash = "sha256:d34f950ae05a83e0ede899c595f312ca976023ea1db100cd5aa188f7005e3ab0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-settings"
|
||||
version = "2.11.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "pydantic" },
|
||||
{ name = "python-dotenv" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/d0e/87a1c7d33593b/pydantic_settings-2.11.0.tar.gz", hash = "sha256:d0e87a1c7d33593beb7194adb8470fc426e95ba02af83a0f23474a04c9a08180" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/fe2/cea3413b9530d/pydantic_settings-2.11.0-py3-none-any.whl", hash = "sha256:fe2cea3413b9530d10f3a5875adffb17ada5c1e1bab0b2885546d7310415207c" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.19.2"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/636/cb2477cec7f89/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/865/40386c03d588b/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.1.1"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/a8a/6399716257f45/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/31f/23644fe2602f8/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-multipart"
|
||||
version = "0.0.20"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/8dd/0cab45b8e2306/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/8a6/2d3a8335e0658/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "referencing"
|
||||
version = "0.37.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "attrs" },
|
||||
{ name = "rpds-py" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/44a/efc3142c5b842/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/381/329a9f99628c9/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "14.2.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/73f/f50c7c0c1c77c/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/76b/c51fe2e57d2b1/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rpds-py"
|
||||
version = "0.27.1"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/26a/1c73171d10b7a/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/e4b/9fcfbc0216338/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/144/1811a96eadca9/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/552/66dafa22e672f/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d78/827d7ac08627e/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/ae9/2443798a40a92/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/c46/c9dd2403b66a2/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/2ef/e4eb1d01b7f5f/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/15d/3b4d83582d10c/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/4ed/2e16abbc982a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/a75/f305c9b013289/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/67c/e762070474588/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/9d9/92ac10eb86d9b/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/4f7/5e4bd8ab8db62/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/f90/25faafc62ed0b/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/ed1/0dc32829e7d22/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/920/22bbbad0d4426/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/471/62fdab9407ec3/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/fb8/9bec23fddc489/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/e48/af21883ded2b3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/6f5/b7bd8e219ed50/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/08f/1e20bccf73b08/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/0dc/5dceeaefcc96d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d76/f9cc8665acdc0/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/134/fae0e36022eda/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/eb1/1a4f1b2b63337/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/13e/608ac9f50a0ed/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/dd2/135527aa40f06/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/302/0724ade63fe32/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/8ee/50c3e41739886/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/acb/9aafccaae278f/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/b7f/b801aa7f845dd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/fe0/dd05afb46597b/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/b6d/fb0e058adb12d/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/ed0/90ccd235f6fa8/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/bf8/76e79763eecf3/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/12e/d005216a51b1d/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/ee4/308f409a40e50/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/0b0/8d152555acf1f/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/dce/51c828941973a/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/c14/76d6f29eb81aa/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/3ce/0cac322b0d69b/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/dfb/fac137d2a3d07/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/a6e/57b0abfe7cc51/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/faf/8d146f3d476ab/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/ba8/1d2b56b6d4911/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/84f/7d509870098de/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/a9e/960fc78fecd11/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/62f/85b665cedab1a/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/fed/467af29776f65/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/f27/29615f9d430af/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/1b2/07d881a9aef7b/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/639/fd5efec029f99/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/fec/c80cb2a90e28a/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/42a/89282d711711d/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/cf9/931f14223de59/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/f39/f58a27cc6e59f/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/d5f/a0ee122dc09e2/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a" },
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/656/7d2bb951e2123/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/8db/ca0739d487e5b/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/7ec/fff8f2fd72616/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/f43/24edc670a0f49/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/2f6/da418d1f1e0fd/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sse-starlette"
|
||||
version = "3.0.2"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/ccd/60b5765ebb358/sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/16b/7cbfddbcd4eac/sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.48.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/7e8/cee469a8ab235/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/076/4ca97b0975825/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.19.2"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "rich" },
|
||||
{ name = "shellingham" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/9ad/824308ded0ad0/typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/755/e7e19670ffad8/typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/0ce/a48d173cc12fa/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/f0f/a19c6845758ab/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-inspection"
|
||||
version = "0.4.2"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/ba5/61c48a67c5958/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/4ed/1cacbdc298c22/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.37.0"
|
||||
source = { registry = "http://devpi.iepai.fun/lzwc/dev/+simple/" }
|
||||
dependencies = [
|
||||
{ name = "click" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "http://devpi.iepai.fun/root/pypi/+f/411/5c8add6d3fd53/uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13" }
|
||||
wheels = [
|
||||
{ url = "http://devpi.iepai.fun/root/pypi/+f/913/b2b8867234373/uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c" },
|
||||
]
|
||||
File diff suppressed because one or more lines are too long
13
lzwcai_mcpskills_mfg_data_agentv2/main.py
Normal file
13
lzwcai_mcpskills_mfg_data_agentv2/main.py
Normal file
@@ -0,0 +1,13 @@
|
||||
"""
|
||||
Entry point for lzwcai-mcpskills-mfg-data-agentv2 (制造业数据智能体)
|
||||
Runs the MCP server for manufacturing data intelligence
|
||||
"""
|
||||
import os
|
||||
|
||||
os.environ["databaseId"] = "19"
|
||||
os.environ["datasourceId"] = "19"
|
||||
os.environ["backendBaseUrl"] = "http://192.168.11.24:8088"
|
||||
if __name__ == "__main__":
|
||||
# Import and run the actual MCP server
|
||||
from lzwcai_mcpskills_mfg_data_agentv2.main import main
|
||||
main()
|
||||
1094
lzwcai_mcpskills_mfg_data_agentv2/manufacturing_data_model_v1.0.0.md
Normal file
1094
lzwcai_mcpskills_mfg_data_agentv2/manufacturing_data_model_v1.0.0.md
Normal file
File diff suppressed because it is too large
Load Diff
35
lzwcai_mcpskills_mfg_data_agentv2/pyproject.toml
Normal file
35
lzwcai_mcpskills_mfg_data_agentv2/pyproject.toml
Normal file
@@ -0,0 +1,35 @@
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lzwcai-mcpskills-mfg-data-agentv2"
|
||||
version = "0.1.1"
|
||||
description = "制造业数据智能体 - MCP server for manufacturing data intelligence with dynamic tool generation"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
license = {text = "MIT"}
|
||||
authors = [
|
||||
{name = "lzwcai", email = "your-email@example.com"},
|
||||
]
|
||||
keywords = ["mcp", "sql", "manufacturing", "data", "agent", "智能体"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
]
|
||||
dependencies = [
|
||||
"httpx>=0.28.1",
|
||||
"mcp[cli]>=1.10.1",
|
||||
"pypinyin>=0.53.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
lzwcai-mcpskills-mfg-data-agentv2 = "lzwcai_mcpskills_mfg_data_agentv2.main:main"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["lzwcai_mcpskills_mfg_data_agentv2"]
|
||||
|
||||
[tool.hatch.build.targets.wheel.force-include]
|
||||
"lzwcai_mcpskills_mfg_data_agentv2/businessQueries.json" = "lzwcai_mcpskills_mfg_data_agentv2/businessQueries.json"
|
||||
Reference in New Issue
Block a user