aigroup-econ-mcp 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of aigroup-econ-mcp might be problematic. Click here for more details.
- aigroup_econ_mcp-0.1.1/BUG_FIX_SUMMARY.md +122 -0
- aigroup_econ_mcp-0.1.1/CHANGELOG.md +34 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/PKG-INFO +1 -1
- aigroup_econ_mcp-0.1.1/final_test.py +110 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/pyproject.toml +1 -1
- aigroup_econ_mcp-0.1.1/quick_test.py +76 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/src/aigroup_econ_mcp/__init__.py +1 -1
- aigroup_econ_mcp-0.1.1/src/aigroup_econ_mcp/cli.py +82 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/src/aigroup_econ_mcp/server.py +5 -4
- aigroup_econ_mcp-0.1.1/test_error.txt +10 -0
- aigroup_econ_mcp-0.1.1/test_mcp_connection.py +75 -0
- aigroup_econ_mcp-0.1.1/test_mcp_features.py +251 -0
- aigroup_econ_mcp-0.1.1/test_output.txt +0 -0
- aigroup_econ_mcp-0.1.0/final_test.py +0 -117
- aigroup_econ_mcp-0.1.0/src/aigroup_econ_mcp/cli.py +0 -78
- aigroup_econ_mcp-0.1.0//350/257/264/346/230/216/346/226/207/346/241/243.md +0 -259
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/.gitignore +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/LICENSE +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/README.md +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/comprehensive_test.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/examples/README.md +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/examples/basic_usage.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/examples/mcp_client_example.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/simple_test.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/src/aigroup_econ_mcp/tools/__init__.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/src/aigroup_econ_mcp/tools/regression.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/src/aigroup_econ_mcp/tools/statistics.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/src/aigroup_econ_mcp/tools/time_series.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/test_mcp.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/tests/__init__.py +0 -0
- {aigroup_econ_mcp-0.1.0 → aigroup_econ_mcp-0.1.1}/tests/test_econometrics.py +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Bug 修复总结
|
|
2
|
+
|
|
3
|
+
## 问题描述
|
|
4
|
+
**错误信息**: `MCP error -32000: Connection closed`
|
|
5
|
+
|
|
6
|
+
## 问题根源
|
|
7
|
+
CLI入口点 ([`src/aigroup_econ_mcp/cli.py`](src/aigroup_econ_mcp/cli.py)) 的命令结构存在问题:
|
|
8
|
+
|
|
9
|
+
1. **混乱的Click命令结构**: 同时使用了 `@click.command()` 和 `@click.group()`,导致命令组织混乱
|
|
10
|
+
2. **默认行为错误**: 运行 `uvx aigroup-econ-mcp` 时显示帮助信息而不是启动MCP服务器
|
|
11
|
+
3. **MCP协议通信失败**: MCP客户端期望立即开始stdio协议通信,但收到的是帮助文本,导致连接关闭
|
|
12
|
+
|
|
13
|
+
## 修复方案
|
|
14
|
+
简化CLI结构,确保默认行为是启动stdio模式的MCP服务器:
|
|
15
|
+
|
|
16
|
+
### 主要修改
|
|
17
|
+
- **移除复杂的命令组结构**: 删除了 `@click.group()` 和重复的命令定义
|
|
18
|
+
- **简化为单一入口点**: 使用单一的 `@click.command()` 装饰器
|
|
19
|
+
- **正确的默认行为**: 无参数运行时默认以stdio模式启动MCP服务器
|
|
20
|
+
- **保留所有功能**: 保留了版本显示、调试模式、多传输协议支持等功能
|
|
21
|
+
|
|
22
|
+
### 修改文件
|
|
23
|
+
- `src/aigroup_econ_mcp/cli.py` - 完全重构CLI入口点
|
|
24
|
+
|
|
25
|
+
## 验证测试
|
|
26
|
+
创建了 `test_mcp_connection.py` 测试脚本验证修复:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
$ python test_mcp_connection.py
|
|
30
|
+
正在启动MCP服务器...
|
|
31
|
+
发送初始化请求...
|
|
32
|
+
等待响应...
|
|
33
|
+
✓ 收到响应
|
|
34
|
+
✓ MCP服务器初始化成功!
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 结果
|
|
38
|
+
✅ MCP服务器现在能够正确启动并响应初始化请求
|
|
39
|
+
✅ stdio协议通信正常
|
|
40
|
+
✅ 修复了 "Connection closed" 错误
|
|
41
|
+
|
|
42
|
+
## 使用方法
|
|
43
|
+
|
|
44
|
+
### 默认启动(stdio模式,用于MCP客户端)
|
|
45
|
+
```bash
|
|
46
|
+
uvx aigroup-econ-mcp
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 显示帮助
|
|
50
|
+
```bash
|
|
51
|
+
uvx aigroup-econ-mcp --help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 显示版本
|
|
55
|
+
```bash
|
|
56
|
+
uvx aigroup-econ-mcp --version
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### HTTP模式启动
|
|
60
|
+
```bash
|
|
61
|
+
uvx aigroup-econ-mcp --transport streamable-http --port 8000
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 功能测试结果
|
|
65
|
+
|
|
66
|
+
所有7项功能测试全部通过:
|
|
67
|
+
|
|
68
|
+
✅ **测试1**: 初始化服务器 - 成功
|
|
69
|
+
✅ **测试2**: 获取工具列表 - 找到5个计量经济学工具
|
|
70
|
+
✅ **测试3**: 获取资源列表 - 正常
|
|
71
|
+
✅ **测试4**: 获取提示词列表 - 找到1个提示词模板
|
|
72
|
+
✅ **测试5**: 描述性统计工具 - 计算成功
|
|
73
|
+
✅ **测试6**: 相关性分析工具 - 分析成功
|
|
74
|
+
✅ **测试7**: 获取示例数据集资源 - 获取成功
|
|
75
|
+
|
|
76
|
+
### 可用工具列表
|
|
77
|
+
|
|
78
|
+
1. **descriptive_statistics** - 计算描述性统计量
|
|
79
|
+
2. **ols_regression** - 执行OLS回归分析
|
|
80
|
+
3. **hypothesis_testing** - 执行假设检验
|
|
81
|
+
4. **time_series_analysis** - 时间序列分析
|
|
82
|
+
5. **correlation_analysis** - 相关性分析
|
|
83
|
+
|
|
84
|
+
### 测试示例输出
|
|
85
|
+
|
|
86
|
+
**描述性统计结果**:
|
|
87
|
+
```
|
|
88
|
+
均值: 0.0060
|
|
89
|
+
标准差: 0.0131
|
|
90
|
+
最小值: -0.0100
|
|
91
|
+
最大值: 0.0200
|
|
92
|
+
中位数: 0.0120
|
|
93
|
+
偏度: -0.2857
|
|
94
|
+
峰度: -2.4609
|
|
95
|
+
|
|
96
|
+
相关系数矩阵:
|
|
97
|
+
stock_returns market_returns
|
|
98
|
+
stock_returns 1.0000 0.9951
|
|
99
|
+
market_returns 0.9951 1.0000
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**相关性分析结果**:
|
|
103
|
+
```
|
|
104
|
+
Pearson相关系数矩阵:
|
|
105
|
+
GDP_Growth Inflation Unemployment
|
|
106
|
+
GDP_Growth 1.0000 -0.9492 -0.3322
|
|
107
|
+
Inflation -0.9492 1.0000 0.3514
|
|
108
|
+
Unemployment -0.3322 0.3514 1.0000
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## 修复时间
|
|
112
|
+
2025-10-25
|
|
113
|
+
|
|
114
|
+
## 修复人员
|
|
115
|
+
Roo (Debug Mode)
|
|
116
|
+
|
|
117
|
+
## 总结
|
|
118
|
+
|
|
119
|
+
✅ **Bug已完全修复**
|
|
120
|
+
✅ **MCP连接正常**
|
|
121
|
+
✅ **所有功能测试通过**
|
|
122
|
+
✅ **服务器可投入使用**
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
## [0.1.1] - 2025-10-25
|
|
4
|
+
|
|
5
|
+
### 修复
|
|
6
|
+
- 🐛 修复CLI入口点结构问题,导致MCP连接失败的bug
|
|
7
|
+
- 🔧 简化命令行接口,移除混乱的Click命令组结构
|
|
8
|
+
- ✅ 确保默认行为正确启动stdio模式的MCP服务器
|
|
9
|
+
- 🌐 修复Windows系统UTF-8编码问题
|
|
10
|
+
|
|
11
|
+
### 改进
|
|
12
|
+
- 📝 添加完整的功能测试套件
|
|
13
|
+
- 📊 验证所有5个计量经济学工具正常工作
|
|
14
|
+
- 📖 完善文档和使用说明
|
|
15
|
+
|
|
16
|
+
### 测试
|
|
17
|
+
- ✅ 初始化服务器测试通过
|
|
18
|
+
- ✅ 工具列表测试通过(5个工具)
|
|
19
|
+
- ✅ 资源列表测试通过
|
|
20
|
+
- ✅ 提示词列表测试通过
|
|
21
|
+
- ✅ 描述性统计工具测试通过
|
|
22
|
+
- ✅ 相关性分析工具测试通过
|
|
23
|
+
- ✅ 资源获取测试通过
|
|
24
|
+
|
|
25
|
+
## [0.1.0] - 2025-10-24
|
|
26
|
+
|
|
27
|
+
### 新增
|
|
28
|
+
- 🎉 首次发布
|
|
29
|
+
- 📊 描述性统计分析功能
|
|
30
|
+
- 📈 OLS回归分析功能
|
|
31
|
+
- 🧪 假设检验功能
|
|
32
|
+
- ⏰ 时间序列分析功能
|
|
33
|
+
- 🔄 结构化输出支持
|
|
34
|
+
- 🎯 完整的MCP协议实现
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
最终测试修复后的MCP服务器
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
import json
|
|
8
|
+
import time
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
def test_server_connection():
|
|
12
|
+
"""测试服务器连接"""
|
|
13
|
+
print("🧪 测试MCP服务器连接...")
|
|
14
|
+
|
|
15
|
+
# 启动服务器进程
|
|
16
|
+
process = subprocess.Popen(
|
|
17
|
+
["uv", "run", "aigroup-econ-mcp", "main", "--transport", "stdio"],
|
|
18
|
+
stdin=subprocess.PIPE,
|
|
19
|
+
stdout=subprocess.PIPE,
|
|
20
|
+
stderr=subprocess.PIPE,
|
|
21
|
+
text=True,
|
|
22
|
+
bufsize=1
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
# 等待服务器启动
|
|
27
|
+
time.sleep(1)
|
|
28
|
+
|
|
29
|
+
# 发送初始化请求
|
|
30
|
+
init_request = {
|
|
31
|
+
"jsonrpc": "2.0",
|
|
32
|
+
"id": 1,
|
|
33
|
+
"method": "initialize",
|
|
34
|
+
"params": {
|
|
35
|
+
"protocolVersion": "2024-11-05",
|
|
36
|
+
"capabilities": {},
|
|
37
|
+
"clientInfo": {
|
|
38
|
+
"name": "test-client",
|
|
39
|
+
"version": "1.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
print("📤 发送初始化请求...")
|
|
45
|
+
process.stdin.write(json.dumps(init_request) + "\n")
|
|
46
|
+
process.stdin.flush()
|
|
47
|
+
|
|
48
|
+
# 读取响应
|
|
49
|
+
time.sleep(1)
|
|
50
|
+
response_line = process.stdout.readline()
|
|
51
|
+
|
|
52
|
+
if response_line.strip():
|
|
53
|
+
try:
|
|
54
|
+
response = json.loads(response_line.strip())
|
|
55
|
+
if response.get("id") == 1:
|
|
56
|
+
print("✅ 服务器初始化成功!")
|
|
57
|
+
server_name = response.get('result', {}).get('serverInfo', {}).get('name', 'Unknown')
|
|
58
|
+
print(f" 服务器名称: {server_name}")
|
|
59
|
+
|
|
60
|
+
# 测试工具列表
|
|
61
|
+
tools_request = {
|
|
62
|
+
"jsonrpc": "2.0",
|
|
63
|
+
"id": 2,
|
|
64
|
+
"method": "tools/list",
|
|
65
|
+
"params": {}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
print("🔧 测试工具列表...")
|
|
69
|
+
process.stdin.write(json.dumps(tools_request) + "\n")
|
|
70
|
+
process.stdin.flush()
|
|
71
|
+
|
|
72
|
+
time.sleep(1)
|
|
73
|
+
tools_response = process.stdout.readline()
|
|
74
|
+
|
|
75
|
+
if tools_response.strip():
|
|
76
|
+
tools_data = json.loads(tools_response.strip())
|
|
77
|
+
tools = tools_data.get("result", {}).get("tools", [])
|
|
78
|
+
print(f"✅ 找到 {len(tools)} 个工具:")
|
|
79
|
+
for tool in tools:
|
|
80
|
+
print(f" - {tool.get('name', 'Unknown')}")
|
|
81
|
+
return True
|
|
82
|
+
else:
|
|
83
|
+
print("❌ 获取工具列表失败")
|
|
84
|
+
return False
|
|
85
|
+
except json.JSONDecodeError as e:
|
|
86
|
+
print(f"❌ JSON解析错误: {e}")
|
|
87
|
+
print(f" 响应内容: {response_line}")
|
|
88
|
+
else:
|
|
89
|
+
print("❌ 没有收到响应")
|
|
90
|
+
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f"❌ 测试出错: {e}")
|
|
95
|
+
return False
|
|
96
|
+
finally:
|
|
97
|
+
process.terminate()
|
|
98
|
+
process.wait()
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
print("=" * 50)
|
|
102
|
+
success = test_server_connection()
|
|
103
|
+
print("=" * 50)
|
|
104
|
+
|
|
105
|
+
if success:
|
|
106
|
+
print("🎉 服务器修复成功!现在可以使用 uvx aigroup-econ-mcp 了")
|
|
107
|
+
sys.exit(0)
|
|
108
|
+
else:
|
|
109
|
+
print("⚠️ 服务器仍有问题,需要进一步调试")
|
|
110
|
+
sys.exit(1)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
快速测试修复后的MCP服务器
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import subprocess
|
|
7
|
+
import json
|
|
8
|
+
import time
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
def test_server():
|
|
12
|
+
"""测试服务器功能"""
|
|
13
|
+
print("🧪 快速测试MCP服务器...")
|
|
14
|
+
|
|
15
|
+
# 启动服务器进程
|
|
16
|
+
process = subprocess.Popen(
|
|
17
|
+
["uv", "run", "aigroup-econ-mcp", "main", "--transport", "stdio"],
|
|
18
|
+
stdin=subprocess.PIPE,
|
|
19
|
+
stdout=subprocess.PIPE,
|
|
20
|
+
stderr=subprocess.PIPE,
|
|
21
|
+
text=True,
|
|
22
|
+
bufsize=1
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
# 等待服务器启动
|
|
27
|
+
time.sleep(2)
|
|
28
|
+
|
|
29
|
+
# 发送初始化请求
|
|
30
|
+
init_request = {
|
|
31
|
+
"jsonrpc": "2.0",
|
|
32
|
+
"id": 1,
|
|
33
|
+
"method": "initialize",
|
|
34
|
+
"params": {
|
|
35
|
+
"protocolVersion": "2024-11-05",
|
|
36
|
+
"capabilities": {},
|
|
37
|
+
"clientInfo": {
|
|
38
|
+
"name": "test-client",
|
|
39
|
+
"version": "1.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
print("📤 发送初始化请求...")
|
|
45
|
+
process.stdin.write(json.dumps(init_request) + "\n")
|
|
46
|
+
process.stdin.flush()
|
|
47
|
+
|
|
48
|
+
# 读取响应
|
|
49
|
+
time.sleep(1)
|
|
50
|
+
response_line = process.stdout.readline()
|
|
51
|
+
|
|
52
|
+
if response_line.strip():
|
|
53
|
+
try:
|
|
54
|
+
response = json.loads(response_line.strip())
|
|
55
|
+
if response.get("id") == 1:
|
|
56
|
+
print("✅ 服务器初始化成功!")
|
|
57
|
+
print(f" 服务器名称: {response.get('result', {}).get('serverInfo', {}).get('name', 'Unknown')}")
|
|
58
|
+
return True
|
|
59
|
+
except json.JSONDecodeError as e:
|
|
60
|
+
print(f"❌ JSON解析错误: {e}")
|
|
61
|
+
print(f" 响应内容: {response_line}")
|
|
62
|
+
else:
|
|
63
|
+
print("❌ 没有收到响应")
|
|
64
|
+
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
except Exception as e:
|
|
68
|
+
print(f"❌ 测试出错: {e}")
|
|
69
|
+
return False
|
|
70
|
+
finally:
|
|
71
|
+
process.terminate()
|
|
72
|
+
process.wait()
|
|
73
|
+
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
success = test_server()
|
|
76
|
+
sys.exit(0 if success else 1)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIGroup 计量经济学 MCP 服务命令行入口
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import click
|
|
7
|
+
from .server import create_mcp_server
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.command()
|
|
11
|
+
@click.option('--port', default=8000, help='服务器端口')
|
|
12
|
+
@click.option('--host', default='127.0.0.1', help='服务器地址')
|
|
13
|
+
@click.option('--transport', default='stdio',
|
|
14
|
+
type=click.Choice(['stdio', 'streamable-http', 'sse']),
|
|
15
|
+
help='传输协议 (默认: stdio)')
|
|
16
|
+
@click.option('--debug', is_flag=True, help='启用调试模式')
|
|
17
|
+
@click.option('--mount-path', default=None, help='挂载路径')
|
|
18
|
+
@click.option('--version', is_flag=True, help='显示版本信息')
|
|
19
|
+
def cli(port: int, host: str, transport: str, debug: bool, mount_path: str, version: bool):
|
|
20
|
+
"""AIGroup 计量经济学 MCP 工具
|
|
21
|
+
|
|
22
|
+
默认以stdio模式启动MCP服务器,适用于MCP客户端集成。
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# 处理版本标志
|
|
26
|
+
if version:
|
|
27
|
+
click.echo("aigroup-econ-mcp v0.1.0", err=True)
|
|
28
|
+
click.echo("Professional econometrics MCP tool", err=True)
|
|
29
|
+
click.echo("Author: AIGroup", err=True)
|
|
30
|
+
sys.exit(0)
|
|
31
|
+
|
|
32
|
+
# 创建MCP服务器
|
|
33
|
+
mcp_server = create_mcp_server()
|
|
34
|
+
|
|
35
|
+
# 设置调试模式
|
|
36
|
+
if debug:
|
|
37
|
+
mcp_server.settings.debug = True
|
|
38
|
+
click.echo(f"[DEBUG] 调试模式已启用", err=True)
|
|
39
|
+
|
|
40
|
+
# 根据传输协议启动服务器
|
|
41
|
+
if transport == 'stdio':
|
|
42
|
+
# stdio模式直接运行,不输出任何日志到stdout(MCP协议通信)
|
|
43
|
+
# 所有日志输出到stderr
|
|
44
|
+
if debug:
|
|
45
|
+
click.echo(f"[DEBUG] Starting in stdio mode", err=True)
|
|
46
|
+
mcp_server.run(transport='stdio')
|
|
47
|
+
|
|
48
|
+
elif transport == 'streamable-http':
|
|
49
|
+
# Streamable HTTP模式
|
|
50
|
+
click.echo(f"[INFO] Starting aigroup-econ-mcp server", err=True)
|
|
51
|
+
click.echo(f"[INFO] Professional econometrics MCP tool for AI data analysis", err=True)
|
|
52
|
+
click.echo(f"[INFO] Transport protocol: {transport}", err=True)
|
|
53
|
+
click.echo(f"[INFO] Service address: http://{host}:{port}", err=True)
|
|
54
|
+
if mount_path:
|
|
55
|
+
click.echo(f"[INFO] Mount path: {mount_path}", err=True)
|
|
56
|
+
|
|
57
|
+
mcp_server.run(
|
|
58
|
+
transport='streamable-http',
|
|
59
|
+
host=host,
|
|
60
|
+
port=port,
|
|
61
|
+
mount_path=mount_path or '/mcp'
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
elif transport == 'sse':
|
|
65
|
+
# SSE模式
|
|
66
|
+
click.echo(f"[INFO] Starting aigroup-econ-mcp server", err=True)
|
|
67
|
+
click.echo(f"[INFO] Professional econometrics MCP tool for AI data analysis", err=True)
|
|
68
|
+
click.echo(f"[INFO] Transport protocol: {transport}", err=True)
|
|
69
|
+
click.echo(f"[INFO] Service address: http://{host}:{port}", err=True)
|
|
70
|
+
if mount_path:
|
|
71
|
+
click.echo(f"[INFO] Mount path: {mount_path}", err=True)
|
|
72
|
+
|
|
73
|
+
mcp_server.run(
|
|
74
|
+
transport='sse',
|
|
75
|
+
host=host,
|
|
76
|
+
port=port,
|
|
77
|
+
mount_path=mount_path or '/sse'
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
cli()
|
|
@@ -11,6 +11,7 @@ from dataclasses import dataclass
|
|
|
11
11
|
import pandas as pd
|
|
12
12
|
import numpy as np
|
|
13
13
|
import statsmodels.api as sm
|
|
14
|
+
from statsmodels.tsa import stattools
|
|
14
15
|
from scipy import stats
|
|
15
16
|
from pydantic import BaseModel, Field
|
|
16
17
|
|
|
@@ -320,7 +321,7 @@ async def hypothesis_testing(
|
|
|
320
321
|
|
|
321
322
|
elif test_type == "adf":
|
|
322
323
|
# ADF单位根检验
|
|
323
|
-
result =
|
|
324
|
+
result = stattools.adfuller(data1)
|
|
324
325
|
test_result = HypothesisTestResult(
|
|
325
326
|
test_type="adf",
|
|
326
327
|
statistic=result[0],
|
|
@@ -370,11 +371,11 @@ async def time_series_analysis(
|
|
|
370
371
|
|
|
371
372
|
try:
|
|
372
373
|
# ADF单位根检验
|
|
373
|
-
adf_result =
|
|
374
|
+
adf_result = stattools.adfuller(data)
|
|
374
375
|
|
|
375
376
|
# 自相关和偏自相关函数
|
|
376
|
-
acf_values =
|
|
377
|
-
pacf_values =
|
|
377
|
+
acf_values = stattools.acf(data, nlags=min(20, len(data)-1))
|
|
378
|
+
pacf_values = stattools.pacf(data, nlags=min(20, len(data)-1))
|
|
378
379
|
|
|
379
380
|
result = TimeSeriesStatsResult(
|
|
380
381
|
adf_statistic=adf_result[0],
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""测试MCP连接是否正常"""
|
|
3
|
+
import subprocess
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
def test_mcp_stdio():
|
|
9
|
+
"""测试stdio模式的MCP通信"""
|
|
10
|
+
print("正在启动MCP服务器...")
|
|
11
|
+
|
|
12
|
+
# 启动MCP服务器进程
|
|
13
|
+
process = subprocess.Popen(
|
|
14
|
+
['uvx', '--from', '.', 'aigroup-econ-mcp'],
|
|
15
|
+
stdin=subprocess.PIPE,
|
|
16
|
+
stdout=subprocess.PIPE,
|
|
17
|
+
stderr=subprocess.PIPE,
|
|
18
|
+
text=True,
|
|
19
|
+
bufsize=0
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
# 发送初始化请求
|
|
24
|
+
init_request = {
|
|
25
|
+
"jsonrpc": "2.0",
|
|
26
|
+
"id": 1,
|
|
27
|
+
"method": "initialize",
|
|
28
|
+
"params": {
|
|
29
|
+
"protocolVersion": "2024-11-05",
|
|
30
|
+
"capabilities": {},
|
|
31
|
+
"clientInfo": {
|
|
32
|
+
"name": "test-client",
|
|
33
|
+
"version": "1.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
print("发送初始化请求...")
|
|
39
|
+
process.stdin.write(json.dumps(init_request) + "\n")
|
|
40
|
+
process.stdin.flush()
|
|
41
|
+
|
|
42
|
+
# 等待响应
|
|
43
|
+
print("等待响应...")
|
|
44
|
+
time.sleep(2)
|
|
45
|
+
|
|
46
|
+
# 读取响应
|
|
47
|
+
response_line = process.stdout.readline()
|
|
48
|
+
if response_line:
|
|
49
|
+
print("✓ 收到响应:")
|
|
50
|
+
print(response_line)
|
|
51
|
+
response = json.loads(response_line)
|
|
52
|
+
if "result" in response:
|
|
53
|
+
print("✓ MCP服务器初始化成功!")
|
|
54
|
+
return True
|
|
55
|
+
else:
|
|
56
|
+
print("✗ 未收到响应")
|
|
57
|
+
# 检查stderr
|
|
58
|
+
error = process.stderr.read()
|
|
59
|
+
if error:
|
|
60
|
+
print(f"错误输出: {error}")
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
print(f"✗ 测试失败: {e}")
|
|
65
|
+
stderr = process.stderr.read()
|
|
66
|
+
if stderr:
|
|
67
|
+
print(f"错误输出: {stderr}")
|
|
68
|
+
return False
|
|
69
|
+
finally:
|
|
70
|
+
process.terminate()
|
|
71
|
+
process.wait(timeout=5)
|
|
72
|
+
|
|
73
|
+
if __name__ == "__main__":
|
|
74
|
+
success = test_mcp_stdio()
|
|
75
|
+
sys.exit(0 if success else 1)
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""全面测试MCP服务器的所有功能"""
|
|
3
|
+
import subprocess
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
class MCPTester:
|
|
9
|
+
def __init__(self):
|
|
10
|
+
self.process = None
|
|
11
|
+
self.request_id = 0
|
|
12
|
+
|
|
13
|
+
def start_server(self):
|
|
14
|
+
"""启动MCP服务器"""
|
|
15
|
+
print("🚀 启动MCP服务器...")
|
|
16
|
+
self.process = subprocess.Popen(
|
|
17
|
+
['uvx', '--from', '.', 'aigroup-econ-mcp'],
|
|
18
|
+
stdin=subprocess.PIPE,
|
|
19
|
+
stdout=subprocess.PIPE,
|
|
20
|
+
stderr=subprocess.PIPE,
|
|
21
|
+
text=True,
|
|
22
|
+
encoding='utf-8',
|
|
23
|
+
errors='replace',
|
|
24
|
+
bufsize=0
|
|
25
|
+
)
|
|
26
|
+
time.sleep(1)
|
|
27
|
+
|
|
28
|
+
def send_request(self, method, params=None):
|
|
29
|
+
"""发送JSON-RPC请求"""
|
|
30
|
+
self.request_id += 1
|
|
31
|
+
request = {
|
|
32
|
+
"jsonrpc": "2.0",
|
|
33
|
+
"id": self.request_id,
|
|
34
|
+
"method": method,
|
|
35
|
+
"params": params or {}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
self.process.stdin.write(json.dumps(request) + "\n")
|
|
39
|
+
self.process.stdin.flush()
|
|
40
|
+
|
|
41
|
+
# 读取响应(可能有多行通知消息)
|
|
42
|
+
max_attempts = 10
|
|
43
|
+
for _ in range(max_attempts):
|
|
44
|
+
response_line = self.process.stdout.readline()
|
|
45
|
+
if response_line:
|
|
46
|
+
response = json.loads(response_line)
|
|
47
|
+
# 如果是通知消息,继续读取下一行
|
|
48
|
+
if "method" in response and response["method"].startswith("notifications/"):
|
|
49
|
+
continue
|
|
50
|
+
# 如果有id字段,说明这是我们请求的响应
|
|
51
|
+
if "id" in response:
|
|
52
|
+
return response
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
def test_initialize(self):
|
|
56
|
+
"""测试初始化"""
|
|
57
|
+
print("\n📋 测试1: 初始化服务器")
|
|
58
|
+
response = self.send_request("initialize", {
|
|
59
|
+
"protocolVersion": "2024-11-05",
|
|
60
|
+
"capabilities": {},
|
|
61
|
+
"clientInfo": {
|
|
62
|
+
"name": "test-client",
|
|
63
|
+
"version": "1.0.0"
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
if response and "result" in response:
|
|
68
|
+
print(" ✓ 初始化成功")
|
|
69
|
+
print(f" 服务器名称: {response['result']['serverInfo']['name']}")
|
|
70
|
+
print(f" 服务器版本: {response['result']['serverInfo']['version']}")
|
|
71
|
+
return True
|
|
72
|
+
else:
|
|
73
|
+
print(" ✗ 初始化失败")
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
def test_list_tools(self):
|
|
77
|
+
"""测试工具列表"""
|
|
78
|
+
print("\n📋 测试2: 获取工具列表")
|
|
79
|
+
response = self.send_request("tools/list")
|
|
80
|
+
|
|
81
|
+
if response and "result" in response:
|
|
82
|
+
tools = response['result'].get('tools', [])
|
|
83
|
+
print(f" ✓ 找到 {len(tools)} 个工具:")
|
|
84
|
+
for tool in tools:
|
|
85
|
+
print(f" - {tool['name']}: {tool.get('description', 'N/A')}")
|
|
86
|
+
return len(tools) > 0
|
|
87
|
+
else:
|
|
88
|
+
print(" ✗ 获取工具列表失败")
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
def test_list_resources(self):
|
|
92
|
+
"""测试资源列表"""
|
|
93
|
+
print("\n📋 测试3: 获取资源列表")
|
|
94
|
+
response = self.send_request("resources/list")
|
|
95
|
+
|
|
96
|
+
if response and "result" in response:
|
|
97
|
+
resources = response['result'].get('resources', [])
|
|
98
|
+
print(f" ✓ 找到 {len(resources)} 个资源:")
|
|
99
|
+
for resource in resources:
|
|
100
|
+
print(f" - {resource['uri']}: {resource.get('name', 'N/A')}")
|
|
101
|
+
return True
|
|
102
|
+
else:
|
|
103
|
+
print(" ✗ 获取资源列表失败")
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
def test_list_prompts(self):
|
|
107
|
+
"""测试提示词列表"""
|
|
108
|
+
print("\n📋 测试4: 获取提示词列表")
|
|
109
|
+
response = self.send_request("prompts/list")
|
|
110
|
+
|
|
111
|
+
if response and "result" in response:
|
|
112
|
+
prompts = response['result'].get('prompts', [])
|
|
113
|
+
print(f" ✓ 找到 {len(prompts)} 个提示词:")
|
|
114
|
+
for prompt in prompts:
|
|
115
|
+
print(f" - {prompt['name']}: {prompt.get('description', 'N/A')}")
|
|
116
|
+
return True
|
|
117
|
+
else:
|
|
118
|
+
print(" ✗ 获取提示词列表失败")
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
def test_descriptive_statistics(self):
|
|
122
|
+
"""测试描述性统计工具"""
|
|
123
|
+
print("\n📋 测试5: 描述性统计工具")
|
|
124
|
+
response = self.send_request("tools/call", {
|
|
125
|
+
"name": "descriptive_statistics",
|
|
126
|
+
"arguments": {
|
|
127
|
+
"data": {
|
|
128
|
+
"stock_returns": [0.02, -0.01, 0.015, -0.008, 0.012, 0.018, -0.005],
|
|
129
|
+
"market_returns": [0.018, -0.005, 0.012, -0.006, 0.010, 0.015, -0.003]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
print(f" 收到响应: {json.dumps(response, indent=2, ensure_ascii=False)[:500]}...")
|
|
135
|
+
|
|
136
|
+
if response and "result" in response:
|
|
137
|
+
content = response['result'].get('content', [])
|
|
138
|
+
if content and len(content) > 0:
|
|
139
|
+
print(" ✓ 描述性统计计算成功")
|
|
140
|
+
print(f" 结果预览: {content[0].get('text', '')[:200]}...")
|
|
141
|
+
return True
|
|
142
|
+
|
|
143
|
+
print(" ✗ 描述性统计计算失败")
|
|
144
|
+
if response and "error" in response:
|
|
145
|
+
print(f" 错误详情: {json.dumps(response['error'], indent=2, ensure_ascii=False)}")
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
def test_correlation_analysis(self):
|
|
149
|
+
"""测试相关性分析工具"""
|
|
150
|
+
print("\n📋 测试6: 相关性分析工具")
|
|
151
|
+
response = self.send_request("tools/call", {
|
|
152
|
+
"name": "correlation_analysis",
|
|
153
|
+
"arguments": {
|
|
154
|
+
"data": {
|
|
155
|
+
"GDP_Growth": [3.2, 2.8, 3.5, 2.9, 3.1],
|
|
156
|
+
"Inflation": [2.1, 2.3, 1.9, 2.4, 2.2],
|
|
157
|
+
"Unemployment": [4.5, 4.2, 4.0, 4.3, 4.1]
|
|
158
|
+
},
|
|
159
|
+
"method": "pearson"
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
print(f" 收到响应: {json.dumps(response, indent=2, ensure_ascii=False)[:500]}...")
|
|
164
|
+
|
|
165
|
+
if response and "result" in response:
|
|
166
|
+
content = response['result'].get('content', [])
|
|
167
|
+
if content and len(content) > 0:
|
|
168
|
+
print(" ✓ 相关性分析成功")
|
|
169
|
+
print(f" 结果预览: {content[0].get('text', '')[:200]}...")
|
|
170
|
+
return True
|
|
171
|
+
|
|
172
|
+
print(" ✗ 相关性分析失败")
|
|
173
|
+
if response and "error" in response:
|
|
174
|
+
print(f" 错误详情: {json.dumps(response['error'], indent=2, ensure_ascii=False)}")
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
def test_get_resource(self):
|
|
178
|
+
"""测试获取资源"""
|
|
179
|
+
print("\n📋 测试7: 获取示例数据集资源")
|
|
180
|
+
response = self.send_request("resources/read", {
|
|
181
|
+
"uri": "dataset://sample/economic_growth"
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
if response and "result" in response:
|
|
185
|
+
contents = response['result'].get('contents', [])
|
|
186
|
+
if contents and len(contents) > 0:
|
|
187
|
+
print(" ✓ 资源获取成功")
|
|
188
|
+
print(f" 数据预览: {contents[0].get('text', '')[:200]}...")
|
|
189
|
+
return True
|
|
190
|
+
|
|
191
|
+
print(" ✗ 资源获取失败")
|
|
192
|
+
if response and "error" in response:
|
|
193
|
+
print(f" 错误: {response['error']}")
|
|
194
|
+
return False
|
|
195
|
+
|
|
196
|
+
def cleanup(self):
|
|
197
|
+
"""清理资源"""
|
|
198
|
+
if self.process:
|
|
199
|
+
self.process.terminate()
|
|
200
|
+
self.process.wait(timeout=5)
|
|
201
|
+
|
|
202
|
+
def run_all_tests(self):
|
|
203
|
+
"""运行所有测试"""
|
|
204
|
+
print("="*60)
|
|
205
|
+
print("MCP服务器功能测试")
|
|
206
|
+
print("="*60)
|
|
207
|
+
|
|
208
|
+
try:
|
|
209
|
+
self.start_server()
|
|
210
|
+
|
|
211
|
+
results = []
|
|
212
|
+
results.append(("初始化", self.test_initialize()))
|
|
213
|
+
results.append(("工具列表", self.test_list_tools()))
|
|
214
|
+
results.append(("资源列表", self.test_list_resources()))
|
|
215
|
+
results.append(("提示词列表", self.test_list_prompts()))
|
|
216
|
+
results.append(("描述性统计", self.test_descriptive_statistics()))
|
|
217
|
+
results.append(("相关性分析", self.test_correlation_analysis()))
|
|
218
|
+
results.append(("获取资源", self.test_get_resource()))
|
|
219
|
+
|
|
220
|
+
print("\n" + "="*60)
|
|
221
|
+
print("测试总结")
|
|
222
|
+
print("="*60)
|
|
223
|
+
|
|
224
|
+
passed = sum(1 for _, result in results if result)
|
|
225
|
+
total = len(results)
|
|
226
|
+
|
|
227
|
+
for name, result in results:
|
|
228
|
+
status = "✓ 通过" if result else "✗ 失败"
|
|
229
|
+
print(f" {status} - {name}")
|
|
230
|
+
|
|
231
|
+
print(f"\n总计: {passed}/{total} 测试通过")
|
|
232
|
+
|
|
233
|
+
if passed == total:
|
|
234
|
+
print("\n🎉 所有测试通过!MCP服务器功能正常!")
|
|
235
|
+
return True
|
|
236
|
+
else:
|
|
237
|
+
print(f"\n⚠️ {total - passed} 个测试失败")
|
|
238
|
+
return False
|
|
239
|
+
|
|
240
|
+
except Exception as e:
|
|
241
|
+
print(f"\n❌ 测试过程中出现异常: {e}")
|
|
242
|
+
import traceback
|
|
243
|
+
traceback.print_exc()
|
|
244
|
+
return False
|
|
245
|
+
finally:
|
|
246
|
+
self.cleanup()
|
|
247
|
+
|
|
248
|
+
if __name__ == "__main__":
|
|
249
|
+
tester = MCPTester()
|
|
250
|
+
success = tester.run_all_tests()
|
|
251
|
+
sys.exit(0 if success else 1)
|
|
File without changes
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
最终验证测试 - 直接测试MCP服务器功能
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import subprocess
|
|
7
|
-
import json
|
|
8
|
-
import sys
|
|
9
|
-
|
|
10
|
-
def test_server_directly():
|
|
11
|
-
"""直接测试服务器功能"""
|
|
12
|
-
print("🚀 直接测试MCP服务器功能...")
|
|
13
|
-
|
|
14
|
-
# 测试1: 基本启动测试
|
|
15
|
-
print("\n1️⃣ 测试服务器启动...")
|
|
16
|
-
try:
|
|
17
|
-
process = subprocess.Popen(
|
|
18
|
-
["uv", "run", "aigroup-econ-mcp", "main", "--transport", "stdio"],
|
|
19
|
-
stdin=subprocess.PIPE,
|
|
20
|
-
stdout=subprocess.PIPE,
|
|
21
|
-
stderr=subprocess.PIPE,
|
|
22
|
-
text=True
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
import time
|
|
26
|
-
time.sleep(2)
|
|
27
|
-
|
|
28
|
-
# 读取启动消息
|
|
29
|
-
output = process.stdout.readline()
|
|
30
|
-
if "Starting aigroup-econ-mcp server" in output:
|
|
31
|
-
print(" ✅ 服务器启动成功")
|
|
32
|
-
else:
|
|
33
|
-
print(f" ⚠️ 启动消息: {output}")
|
|
34
|
-
|
|
35
|
-
process.terminate()
|
|
36
|
-
process.wait()
|
|
37
|
-
|
|
38
|
-
except Exception as e:
|
|
39
|
-
print(f" ❌ 启动测试失败: {e}")
|
|
40
|
-
return False
|
|
41
|
-
|
|
42
|
-
# 测试2: 版本信息
|
|
43
|
-
print("\n2️⃣ 测试版本信息...")
|
|
44
|
-
try:
|
|
45
|
-
result = subprocess.run(
|
|
46
|
-
["uv", "run", "aigroup-econ-mcp", "version"],
|
|
47
|
-
capture_output=True,
|
|
48
|
-
text=True
|
|
49
|
-
)
|
|
50
|
-
if result.returncode == 0 and "aigroup-econ-mcp v0.1.0" in result.stdout:
|
|
51
|
-
print(" ✅ 版本信息正确")
|
|
52
|
-
else:
|
|
53
|
-
print(f" ❌ 版本测试失败: {result.stdout}")
|
|
54
|
-
except Exception as e:
|
|
55
|
-
print(f" ❌ 版本测试失败: {e}")
|
|
56
|
-
return False
|
|
57
|
-
|
|
58
|
-
# 测试3: 帮助信息
|
|
59
|
-
print("\n3️⃣ 测试帮助信息...")
|
|
60
|
-
try:
|
|
61
|
-
result = subprocess.run(
|
|
62
|
-
["uv", "run", "aigroup-econ-mcp", "--help"],
|
|
63
|
-
capture_output=True,
|
|
64
|
-
text=True
|
|
65
|
-
)
|
|
66
|
-
if result.returncode == 0 and "AIGroup" in result.stdout:
|
|
67
|
-
print(" ✅ 帮助信息正确")
|
|
68
|
-
else:
|
|
69
|
-
print(f" ❌ 帮助测试失败: {result.stdout}")
|
|
70
|
-
except Exception as e:
|
|
71
|
-
print(f" ❌ 帮助测试失败: {e}")
|
|
72
|
-
return False
|
|
73
|
-
|
|
74
|
-
# 测试4: 验证mcp.json配置
|
|
75
|
-
print("\n4️⃣ 验证mcp.json配置...")
|
|
76
|
-
try:
|
|
77
|
-
import os
|
|
78
|
-
mcp_config_path = os.path.join(".roo", "mcp.json")
|
|
79
|
-
if os.path.exists(mcp_config_path):
|
|
80
|
-
with open(mcp_config_path, 'r', encoding='utf-8') as f:
|
|
81
|
-
config = json.load(f)
|
|
82
|
-
|
|
83
|
-
if "mcpServers" in config and "aigroup-econ-mcp" in config["mcpServers"]:
|
|
84
|
-
server_config = config["mcpServers"]["aigroup-econ-mcp"]
|
|
85
|
-
required_fields = ["command", "args", "transport"]
|
|
86
|
-
|
|
87
|
-
if all(field in server_config for field in required_fields):
|
|
88
|
-
print(" ✅ mcp.json配置正确")
|
|
89
|
-
print(f" 📋 配置详情: {server_config}")
|
|
90
|
-
else:
|
|
91
|
-
print(f" ❌ 配置缺少必要字段: {required_fields}")
|
|
92
|
-
return False
|
|
93
|
-
else:
|
|
94
|
-
print(" ❌ mcp.json中没有aigroup-econ-mcp配置")
|
|
95
|
-
return False
|
|
96
|
-
else:
|
|
97
|
-
print(" ❌ 找不到mcp.json文件")
|
|
98
|
-
return False
|
|
99
|
-
|
|
100
|
-
except Exception as e:
|
|
101
|
-
print(f" ❌ 配置验证失败: {e}")
|
|
102
|
-
return False
|
|
103
|
-
|
|
104
|
-
print("\n🎉 所有基础测试通过!")
|
|
105
|
-
print("\n📋 总结:")
|
|
106
|
-
print(" ✅ MCP服务器配置完成")
|
|
107
|
-
print(" ✅ 依赖包安装成功")
|
|
108
|
-
print(" ✅ 服务器能正常启动")
|
|
109
|
-
print(" ✅ CLI命令工作正常")
|
|
110
|
-
print(" ✅ mcp.json配置正确")
|
|
111
|
-
print("\n🚀 服务器已准备就绪,可以通过MCP客户端使用!")
|
|
112
|
-
|
|
113
|
-
return True
|
|
114
|
-
|
|
115
|
-
if __name__ == "__main__":
|
|
116
|
-
success = test_server_directly()
|
|
117
|
-
sys.exit(0 if success else 1)
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
AIGroup 计量经济学 MCP 服务命令行入口
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import click
|
|
6
|
-
import uvicorn
|
|
7
|
-
from .server import create_mcp_server
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@click.command()
|
|
11
|
-
@click.option('--port', default=8000, help='服务器端口')
|
|
12
|
-
@click.option('--host', default='127.0.0.1', help='服务器地址')
|
|
13
|
-
@click.option('--transport', default='streamable-http',
|
|
14
|
-
type=click.Choice(['stdio', 'streamable-http', 'sse']),
|
|
15
|
-
help='传输协议')
|
|
16
|
-
@click.option('--debug', is_flag=True, help='启用调试模式')
|
|
17
|
-
@click.option('--mount-path', default=None, help='挂载路径')
|
|
18
|
-
def main(port: int, host: str, transport: str, debug: bool, mount_path: str):
|
|
19
|
-
"""启动aigroup-econ-mcp服务器"""
|
|
20
|
-
|
|
21
|
-
# 创建MCP服务器
|
|
22
|
-
mcp_server = create_mcp_server()
|
|
23
|
-
|
|
24
|
-
# 设置调试模式
|
|
25
|
-
if debug:
|
|
26
|
-
mcp_server.settings.debug = True
|
|
27
|
-
click.echo(f"[DEBUG] 调试模式已启用")
|
|
28
|
-
|
|
29
|
-
click.echo(f"[INFO] Starting aigroup-econ-mcp server")
|
|
30
|
-
click.echo(f"[INFO] Professional econometrics MCP tool for AI data analysis")
|
|
31
|
-
click.echo(f"[INFO] Transport protocol: {transport}")
|
|
32
|
-
click.echo(f"[INFO] Service address: http://{host}:{port}")
|
|
33
|
-
if mount_path:
|
|
34
|
-
click.echo(f"[INFO] Mount path: {mount_path}")
|
|
35
|
-
|
|
36
|
-
# 根据传输协议启动服务器
|
|
37
|
-
if transport == 'stdio':
|
|
38
|
-
# stdio模式直接运行
|
|
39
|
-
mcp_server.run(transport='stdio')
|
|
40
|
-
elif transport == 'streamable-http':
|
|
41
|
-
# Streamable HTTP模式
|
|
42
|
-
mcp_server.run(
|
|
43
|
-
transport='streamable-http',
|
|
44
|
-
host=host,
|
|
45
|
-
port=port,
|
|
46
|
-
mount_path=mount_path or '/mcp'
|
|
47
|
-
)
|
|
48
|
-
elif transport == 'sse':
|
|
49
|
-
# SSE模式
|
|
50
|
-
mcp_server.run(
|
|
51
|
-
transport='sse',
|
|
52
|
-
host=host,
|
|
53
|
-
port=port,
|
|
54
|
-
mount_path=mount_path or '/sse'
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@click.command()
|
|
59
|
-
def version():
|
|
60
|
-
"""Show version information"""
|
|
61
|
-
click.echo("aigroup-econ-mcp v0.1.0")
|
|
62
|
-
click.echo("Professional econometrics MCP tool")
|
|
63
|
-
click.echo("Author: AIGroup")
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
@click.group()
|
|
67
|
-
def cli():
|
|
68
|
-
"""AIGroup 计量经济学 MCP 工具"""
|
|
69
|
-
pass
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# 添加子命令
|
|
73
|
-
cli.add_command(main)
|
|
74
|
-
cli.add_command(version)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if __name__ == "__main__":
|
|
78
|
-
cli()
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
你说得对!**使用 uvx 来安装和运行 MCP 服务是更简单快捷的方式**,特别适合开发和快速部署。让我重新设计这个方案:
|
|
2
|
-
|
|
3
|
-
## UVX 部署的优势
|
|
4
|
-
|
|
5
|
-
### 1. 极简安装和使用
|
|
6
|
-
```bash
|
|
7
|
-
# 一行命令安装和运行
|
|
8
|
-
uvx aigroup-econ-mcp
|
|
9
|
-
|
|
10
|
-
# 或者直接作为MCP服务器运行
|
|
11
|
-
uvx aigroup-econ-mcp --port 8000
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
### 2. 依赖管理自动化
|
|
15
|
-
```python
|
|
16
|
-
# pyproject.toml - 配置uvx兼容的依赖
|
|
17
|
-
[project]
|
|
18
|
-
name = "aigroup-econ-mcp"
|
|
19
|
-
dependencies = [
|
|
20
|
-
"pandas>=1.5.0",
|
|
21
|
-
"numpy>=1.21.0",
|
|
22
|
-
"statsmodels>=0.13.0",
|
|
23
|
-
"scipy>=1.7.0",
|
|
24
|
-
"matplotlib>=3.5.0",
|
|
25
|
-
"mcp>=1.0.0"
|
|
26
|
-
]
|
|
27
|
-
|
|
28
|
-
[project.scripts]
|
|
29
|
-
aigroup-econ-mcp = "aigroup_econ_mcp.cli:main"
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## MCP 服务器设计
|
|
33
|
-
|
|
34
|
-
### 核心服务器结构
|
|
35
|
-
```python
|
|
36
|
-
# cli.py - UVX可执行入口
|
|
37
|
-
import click
|
|
38
|
-
import uvicorn
|
|
39
|
-
from mcp.server.fastmcp import FastMCP
|
|
40
|
-
|
|
41
|
-
@click.command()
|
|
42
|
-
@click.option('--port', default=8000, help='服务器端口')
|
|
43
|
-
@click.option('--host', default='127.0.0.1', help='服务器地址')
|
|
44
|
-
def main(port: int, host: str):
|
|
45
|
-
"""启动aigroup-econ-mcp服务器"""
|
|
46
|
-
from aigroup_econ_mcp.server import create_mcp_server
|
|
47
|
-
|
|
48
|
-
server = create_mcp_server()
|
|
49
|
-
|
|
50
|
-
print(f"🚀 aigroup-econ-mcp 服务启动在 http://{host}:{port}")
|
|
51
|
-
print("📊 可用的计量经济学工具已就绪")
|
|
52
|
-
|
|
53
|
-
uvicorn.run(server, host=host, port=port)
|
|
54
|
-
|
|
55
|
-
if __name__ == "__main__":
|
|
56
|
-
main()
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### MCP 服务器实现
|
|
60
|
-
```python
|
|
61
|
-
# server.py
|
|
62
|
-
from mcp.server.fastmcp import FastMCP
|
|
63
|
-
import pandas as pd
|
|
64
|
-
import numpy as np
|
|
65
|
-
import statsmodels.api as sm
|
|
66
|
-
from typing import List, Dict, Any
|
|
67
|
-
|
|
68
|
-
# 创建MCP服务器实例
|
|
69
|
-
mcp = FastMCP("aigroup-econ-mcp")
|
|
70
|
-
|
|
71
|
-
@mcp.tool()
|
|
72
|
-
async def descriptive_stats(data: Dict[str, List[float]]) -> Dict[str, Any]:
|
|
73
|
-
"""计算描述性统计量"""
|
|
74
|
-
df = pd.DataFrame(data)
|
|
75
|
-
return {
|
|
76
|
-
"mean": df.mean().to_dict(),
|
|
77
|
-
"std": df.std().to_dict(),
|
|
78
|
-
"min": df.min().to_dict(),
|
|
79
|
-
"max": df.max().to_dict(),
|
|
80
|
-
"correlation": df.corr().to_dict()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@mcp.tool()
|
|
84
|
-
async def ols_regression(
|
|
85
|
-
y_data: List[float],
|
|
86
|
-
x_data: List[List[float]],
|
|
87
|
-
feature_names: List[str] = None
|
|
88
|
-
) -> Dict[str, Any]:
|
|
89
|
-
"""执行OLS回归分析"""
|
|
90
|
-
X = np.column_stack(x_data)
|
|
91
|
-
X = sm.add_constant(X) # 添加常数项
|
|
92
|
-
|
|
93
|
-
model = sm.OLS(y_data, X).fit()
|
|
94
|
-
|
|
95
|
-
result = {
|
|
96
|
-
"rsquared": model.rsquared,
|
|
97
|
-
"rsquared_adj": model.rsquared_adj,
|
|
98
|
-
"f_statistic": model.fvalue,
|
|
99
|
-
"f_pvalue": model.f_pvalue,
|
|
100
|
-
"aic": model.aic,
|
|
101
|
-
"bic": model.bic,
|
|
102
|
-
"coefficients": {}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
# 整理系数结果
|
|
106
|
-
for i, coef in enumerate(model.params):
|
|
107
|
-
var_name = "const" if i == 0 else feature_names[i-1] if feature_names else f"x{i}"
|
|
108
|
-
result["coefficients"][var_name] = {
|
|
109
|
-
"coef": coef,
|
|
110
|
-
"std_err": model.bse[i],
|
|
111
|
-
"t_value": model.tvalues[i],
|
|
112
|
-
"p_value": model.pvalues[i],
|
|
113
|
-
"ci_lower": model.conf_int()[0][i],
|
|
114
|
-
"ci_upper": model.conf_int()[1][i]
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return result
|
|
118
|
-
|
|
119
|
-
@mcp.tool()
|
|
120
|
-
async def hypothesis_test(
|
|
121
|
-
data1: List[float],
|
|
122
|
-
data2: List[float] = None,
|
|
123
|
-
test_type: str = "t_test"
|
|
124
|
-
) -> Dict[str, Any]:
|
|
125
|
-
"""执行假设检验"""
|
|
126
|
-
from scipy import stats
|
|
127
|
-
|
|
128
|
-
if test_type == "t_test":
|
|
129
|
-
if data2 is None:
|
|
130
|
-
# 单样本t检验
|
|
131
|
-
result = stats.ttest_1samp(data1, 0)
|
|
132
|
-
else:
|
|
133
|
-
# 双样本t检验
|
|
134
|
-
result = stats.ttest_ind(data1, data2)
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
"test_type": test_type,
|
|
138
|
-
"statistic": result.statistic,
|
|
139
|
-
"p_value": result.pvalue,
|
|
140
|
-
"significant": result.pvalue < 0.05
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
def create_mcp_server():
|
|
144
|
-
"""创建并返回MCP服务器实例"""
|
|
145
|
-
return mcp
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## 使用方式
|
|
149
|
-
|
|
150
|
-
### 1. 直接运行
|
|
151
|
-
```bash
|
|
152
|
-
# 安装并运行(uvx会自动处理依赖)
|
|
153
|
-
uvx aigroup-econ-mcp
|
|
154
|
-
|
|
155
|
-
# 指定端口运行
|
|
156
|
-
uvx aigroup-econ-mcp --port 8080
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### 2. 与 Claude Desktop 集成
|
|
160
|
-
```json
|
|
161
|
-
// Claude Desktop 配置
|
|
162
|
-
{
|
|
163
|
-
"mcpServers": {
|
|
164
|
-
"aigroup-econ-mcp": {
|
|
165
|
-
"command": "uvx",
|
|
166
|
-
"args": ["aigroup-econ-mcp"]
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### 3. 开发模式
|
|
173
|
-
```bash
|
|
174
|
-
# 克隆代码库
|
|
175
|
-
git clone https://github.com/aigroup/aigroup-econ-mcp
|
|
176
|
-
cd aigroup-econ-mcp
|
|
177
|
-
|
|
178
|
-
# 开发模式运行
|
|
179
|
-
uv run aigroup-econ-mcp --port 8000
|
|
180
|
-
|
|
181
|
-
# 或直接使用uvx
|
|
182
|
-
uvx -p . aigroup-econ-mcp
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
## 项目结构
|
|
186
|
-
```
|
|
187
|
-
aigroup-econ-mcp/
|
|
188
|
-
├── pyproject.toml # 项目配置和依赖
|
|
189
|
-
├── README.md
|
|
190
|
-
├── cli.py # UVX入口点
|
|
191
|
-
├── server.py # MCP服务器核心
|
|
192
|
-
├── tools/
|
|
193
|
-
│ ├── regression.py # 回归分析工具
|
|
194
|
-
│ ├── time_series.py # 时间序列工具
|
|
195
|
-
│ └── diagnostics.py # 模型诊断工具
|
|
196
|
-
└── examples/
|
|
197
|
-
└── basic_usage.py # 使用示例
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## 实际使用示例
|
|
201
|
-
|
|
202
|
-
用户可以通过自然语言直接调用:
|
|
203
|
-
|
|
204
|
-
```
|
|
205
|
-
用户:帮我分析一下广告投入和价格对销售额的影响
|
|
206
|
-
|
|
207
|
-
Claude调用MCP工具:
|
|
208
|
-
1. descriptive_stats - 查看数据基本情况
|
|
209
|
-
2. ols_regression - 运行回归分析
|
|
210
|
-
3. hypothesis_test - 检验系数显著性
|
|
211
|
-
|
|
212
|
-
返回:专业计量结果 + 自然语言解释
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
## 开发工作流
|
|
216
|
-
|
|
217
|
-
### 快速迭代
|
|
218
|
-
```bash
|
|
219
|
-
# 1. 开发时使用uv运行
|
|
220
|
-
uv run --with aigroup-econ-mcp python -m aigroup_econ_mcp.cli
|
|
221
|
-
|
|
222
|
-
# 2. 测试工具
|
|
223
|
-
uvx aigroup-econ-mcp --port 8000
|
|
224
|
-
|
|
225
|
-
# 3. 发布到PyPI后,用户直接使用
|
|
226
|
-
uvx aigroup-econ-mcp
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### 依赖管理的优势
|
|
230
|
-
- ✅ **自动环境隔离**:uvx自动创建虚拟环境
|
|
231
|
-
- ✅ **版本冲突解决**:uv的依赖解析能力
|
|
232
|
-
- ✅ **快速安装**:基于Rust的高性能包管理
|
|
233
|
-
- ✅ **无需配置**:用户不需要安装Python或管理虚拟环境
|
|
234
|
-
|
|
235
|
-
## 发布到PyPI
|
|
236
|
-
|
|
237
|
-
```toml
|
|
238
|
-
# pyproject.toml 发布配置
|
|
239
|
-
[build-system]
|
|
240
|
-
requires = ["hatchling"]
|
|
241
|
-
build-backend = "hatchling.build"
|
|
242
|
-
|
|
243
|
-
[project]
|
|
244
|
-
name = "aigroup-econ-mcp"
|
|
245
|
-
version = "0.1.0"
|
|
246
|
-
description = "专业计量经济学MCP工具 - 让大模型直接进行数据分析"
|
|
247
|
-
authors = [
|
|
248
|
-
{name = "AIGroup", email = "contact@aigroup.com"}
|
|
249
|
-
]
|
|
250
|
-
readme = "README.md"
|
|
251
|
-
requires-python = ">=3.8"
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
发布后用户只需要:
|
|
255
|
-
```bash
|
|
256
|
-
uvx aigroup-econ-mcp
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
这种基于 uvx 的方案确实比 Docker 更轻量、更便捷,特别适合MCP工具的快速部署和使用!你觉得这个架构设计如何?
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|