aigroup-econ-mcp 0.1.0__py3-none-any.whl

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.

@@ -0,0 +1,19 @@
1
+ """
2
+ AIGroup 计量经济学 MCP 服务
3
+ 专业计量经济学MCP工具 - 让大模型直接进行数据分析
4
+
5
+ 提供:
6
+ - 描述性统计分析
7
+ - OLS回归分析
8
+ - 时间序列分析
9
+ - 假设检验
10
+ - 模型诊断
11
+ """
12
+
13
+ __version__ = "0.1.0"
14
+ __author__ = "AIGroup"
15
+ __description__ = "专业计量经济学MCP工具 - 让大模型直接进行数据分析"
16
+
17
+ from .server import create_mcp_server
18
+
19
+ __all__ = ["create_mcp_server", "__version__", "__author__", "__description__"]
@@ -0,0 +1,78 @@
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()
@@ -0,0 +1,442 @@
1
+ """
2
+ AIGroup 计量经济学 MCP 服务器
3
+ 使用最新的MCP特性提供专业计量经济学分析工具
4
+ """
5
+
6
+ from typing import List, Dict, Any, Optional, Annotated
7
+ from collections.abc import AsyncIterator
8
+ from contextlib import asynccontextmanager
9
+ from dataclasses import dataclass
10
+
11
+ import pandas as pd
12
+ import numpy as np
13
+ import statsmodels.api as sm
14
+ from scipy import stats
15
+ from pydantic import BaseModel, Field
16
+
17
+ from mcp.server.fastmcp import FastMCP, Context, Icon
18
+ from mcp.server.session import ServerSession
19
+ from mcp.types import CallToolResult, TextContent
20
+
21
+
22
+ # 数据模型定义 - 使用Pydantic实现结构化输出
23
+ class DescriptiveStatsResult(BaseModel):
24
+ """描述性统计结果"""
25
+ count: int = Field(description="样本数量")
26
+ mean: float = Field(description="均值")
27
+ std: float = Field(description="标准差")
28
+ min: float = Field(description="最小值")
29
+ max: float = Field(description="最大值")
30
+ median: float = Field(description="中位数")
31
+ skewness: float = Field(description="偏度")
32
+ kurtosis: float = Field(description="峰度")
33
+
34
+
35
+ class OLSRegressionResult(BaseModel):
36
+ """OLS回归分析结果"""
37
+ rsquared: float = Field(description="R²")
38
+ rsquared_adj: float = Field(description="调整R²")
39
+ f_statistic: float = Field(description="F统计量")
40
+ f_pvalue: float = Field(description="F检验p值")
41
+ aic: float = Field(description="AIC信息准则")
42
+ bic: float = Field(description="BIC信息准则")
43
+ coefficients: Dict[str, Dict[str, float]] = Field(description="回归系数详情")
44
+
45
+
46
+ class HypothesisTestResult(BaseModel):
47
+ """假设检验结果"""
48
+ test_type: str = Field(description="检验类型")
49
+ statistic: float = Field(description="检验统计量")
50
+ p_value: float = Field(description="p值")
51
+ significant: bool = Field(description="是否显著(5%水平)")
52
+ confidence_interval: Optional[List[float]] = Field(default=None, description="置信区间")
53
+
54
+
55
+ class TimeSeriesStatsResult(BaseModel):
56
+ """时间序列统计结果"""
57
+ adf_statistic: float = Field(description="ADF检验统计量")
58
+ adf_pvalue: float = Field(description="ADF检验p值")
59
+ stationary: bool = Field(description="是否平稳")
60
+ acf: List[float] = Field(description="自相关函数")
61
+ pacf: List[float] = Field(description="偏自相关函数")
62
+
63
+
64
+ # 应用上下文
65
+ @dataclass
66
+ class AppContext:
67
+ """应用上下文,包含共享资源"""
68
+ config: Dict[str, Any]
69
+ version: str = "0.1.0"
70
+
71
+
72
+ # 服务器图标
73
+ server_icon = Icon(
74
+ src="https://img.icons8.com/fluency/48/bar-chart.png",
75
+ mimeType="image/png",
76
+ sizes=["48x48"]
77
+ )
78
+
79
+
80
+ @asynccontextmanager
81
+ async def lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
82
+ """服务器生命周期管理"""
83
+ # 启动时初始化资源
84
+ config = {
85
+ "max_sample_size": 10000,
86
+ "default_significance_level": 0.05,
87
+ "supported_tests": ["t_test", "f_test", "chi_square", "adf"],
88
+ "data_types": ["cross_section", "time_series", "panel"]
89
+ }
90
+
91
+ try:
92
+ yield AppContext(config=config, version="0.1.0")
93
+ finally:
94
+ # 清理资源
95
+ pass
96
+
97
+
98
+ # 创建MCP服务器实例
99
+ mcp = FastMCP(
100
+ name="aigroup-econ-mcp",
101
+ instructions="Econometrics MCP Server - Provides data analysis, regression analysis, hypothesis testing and more",
102
+ lifespan=lifespan
103
+ )
104
+
105
+
106
+ @mcp.resource("dataset://sample/{dataset_name}")
107
+ def get_sample_dataset(dataset_name: str) -> str:
108
+ """Get sample dataset"""
109
+ datasets = {
110
+ "economic_growth": """
111
+ GDP Growth,Inflation Rate,Unemployment Rate,Investment Rate
112
+ 3.2,2.1,4.5,15.2
113
+ 2.8,2.3,4.2,14.8
114
+ 3.5,1.9,4.0,16.1
115
+ 2.9,2.4,4.3,15.5
116
+ """,
117
+ "stock_returns": """
118
+ Stock A,Stock B,Stock C
119
+ 0.02,-0.01,0.015
120
+ -0.015,0.025,-0.008
121
+ 0.018,-0.005,0.012
122
+ """,
123
+ "time_series": """
124
+ Date,Sales,Advertising Expense
125
+ 2023-01,12000,800
126
+ 2023-02,13500,900
127
+ 2023-03,11800,750
128
+ 2023-04,14200,1000
129
+ """
130
+ }
131
+
132
+ if dataset_name not in datasets:
133
+ return f"Available datasets: {', '.join(datasets.keys())}"
134
+
135
+ return datasets[dataset_name]
136
+
137
+
138
+ @mcp.prompt(title="Economic Data Analysis")
139
+ def economic_analysis_prompt(data_description: str, analysis_type: str = "descriptive") -> str:
140
+ """Economic data analysis prompt template"""
141
+ prompts = {
142
+ "descriptive": "Please perform descriptive statistical analysis on the following economic data:",
143
+ "regression": "Please perform regression analysis on the following economic data to identify key factors:",
144
+ "hypothesis": "Please perform hypothesis testing on the following economic data to verify research assumptions:",
145
+ "time_series": "Please analyze the following time series data to check stationarity and correlation:"
146
+ }
147
+
148
+ return f"{prompts.get(analysis_type, prompts['descriptive'])}\n\nData description: {data_description}"
149
+
150
+
151
+ @mcp.tool()
152
+ async def descriptive_statistics(
153
+ ctx: Context[ServerSession, AppContext],
154
+ data: Dict[str, List[float]]
155
+ ) -> Annotated[CallToolResult, DescriptiveStatsResult]:
156
+ """计算描述性统计量
157
+
158
+ Args:
159
+ data: 字典格式的数据,键为变量名,值为数值列表
160
+ ctx: MCP上下文对象
161
+ """
162
+ await ctx.info(f"开始计算描述性统计,处理 {len(data)} 个变量")
163
+
164
+ try:
165
+ df = pd.DataFrame(data)
166
+
167
+ # 基础统计量
168
+ result = DescriptiveStatsResult(
169
+ count=len(df),
170
+ mean=df.mean().iloc[0], # 简化示例,实际应返回所有变量
171
+ std=df.std().iloc[0],
172
+ min=df.min().iloc[0],
173
+ max=df.max().iloc[0],
174
+ median=df.median().iloc[0],
175
+ skewness=df.skew().iloc[0],
176
+ kurtosis=df.kurtosis().iloc[0]
177
+ )
178
+
179
+ # 计算相关系数矩阵
180
+ correlation_matrix = df.corr().round(4)
181
+
182
+ await ctx.info(f"描述性统计计算完成,样本大小: {len(df)}")
183
+
184
+ return CallToolResult(
185
+ content=[
186
+ TextContent(
187
+ type="text",
188
+ text=f"描述性统计结果:\n"
189
+ f"均值: {result.mean:.4f}\n"
190
+ f"标准差: {result.std:.4f}\n"
191
+ f"最小值: {result.min:.4f}\n"
192
+ f"最大值: {result.max:.4f}\n"
193
+ f"中位数: {result.median:.4f}\n"
194
+ f"偏度: {result.skewness:.4f}\n"
195
+ f"峰度: {result.kurtosis:.4f}\n\n"
196
+ f"相关系数矩阵:\n{correlation_matrix.to_string()}"
197
+ )
198
+ ],
199
+ structuredContent=result.model_dump()
200
+ )
201
+
202
+ except Exception as e:
203
+ await ctx.error(f"计算描述性统计时出错: {str(e)}")
204
+ return CallToolResult(
205
+ content=[TextContent(type="text", text=f"错误: {str(e)}")],
206
+ isError=True
207
+ )
208
+
209
+
210
+ @mcp.tool()
211
+ async def ols_regression(
212
+ ctx: Context[ServerSession, AppContext],
213
+ y_data: List[float],
214
+ x_data: List[List[float]],
215
+ feature_names: Optional[List[str]] = None
216
+ ) -> Annotated[CallToolResult, OLSRegressionResult]:
217
+ """执行OLS回归分析
218
+
219
+ Args:
220
+ y_data: 因变量数据
221
+ x_data: 自变量数据,每行一个观测
222
+ feature_names: 自变量名称
223
+ ctx: MCP上下文对象
224
+ """
225
+ await ctx.info(f"开始OLS回归分析,样本大小: {len(y_data)},自变量数量: {len(x_data[0]) if x_data else 0}")
226
+
227
+ try:
228
+ # 准备数据
229
+ X = np.column_stack(x_data) if x_data else np.ones((len(y_data), 1))
230
+ if x_data: # 只有当有自变量时才添加常数项
231
+ X = sm.add_constant(X)
232
+
233
+ # 拟合模型
234
+ model = sm.OLS(y_data, X).fit()
235
+
236
+ # 构建结果
237
+ result = OLSRegressionResult(
238
+ rsquared=model.rsquared,
239
+ rsquared_adj=model.rsquared_adj,
240
+ f_statistic=model.fvalue,
241
+ f_pvalue=model.f_pvalue,
242
+ aic=model.aic,
243
+ bic=model.bic,
244
+ coefficients={}
245
+ )
246
+
247
+ # 添加系数详情
248
+ conf_int = model.conf_int()
249
+ for i, coef in enumerate(model.params):
250
+ var_name = "const" if i == 0 else feature_names[i-1] if feature_names else f"x{i}"
251
+ result.coefficients[var_name] = {
252
+ "coef": coef,
253
+ "std_err": model.bse[i],
254
+ "t_value": model.tvalues[i],
255
+ "p_value": model.pvalues[i],
256
+ "ci_lower": conf_int[i][0],
257
+ "ci_upper": conf_int[i][1]
258
+ }
259
+
260
+ await ctx.info("OLS回归分析完成")
261
+
262
+ return CallToolResult(
263
+ content=[
264
+ TextContent(
265
+ type="text",
266
+ text=f"OLS回归分析结果:\n"
267
+ f"R² = {result.rsquared:.4f}\n"
268
+ f"调整R² = {result.rsquared_adj:.4f}\n"
269
+ f"F统计量 = {result.f_statistic:.4f} (p = {result.f_pvalue:.4f})\n"
270
+ f"AIC = {result.aic:.2f}, BIC = {result.bic:.2f}\n\n"
271
+ f"回归系数:\n{model.summary().tables[1]}"
272
+ )
273
+ ],
274
+ structuredContent=result.model_dump()
275
+ )
276
+
277
+ except Exception as e:
278
+ await ctx.error(f"OLS回归分析出错: {str(e)}")
279
+ return CallToolResult(
280
+ content=[TextContent(type="text", text=f"错误: {str(e)}")],
281
+ isError=True
282
+ )
283
+
284
+
285
+ @mcp.tool()
286
+ async def hypothesis_testing(
287
+ ctx: Context[ServerSession, AppContext],
288
+ data1: List[float],
289
+ data2: Optional[List[float]] = None,
290
+ test_type: str = "t_test"
291
+ ) -> Annotated[CallToolResult, HypothesisTestResult]:
292
+ """执行假设检验
293
+
294
+ Args:
295
+ data1: 第一组数据
296
+ data2: 第二组数据(可选)
297
+ test_type: 检验类型
298
+ ctx: MCP上下文对象
299
+ """
300
+ await ctx.info(f"开始假设检验: {test_type}")
301
+
302
+ try:
303
+ if test_type == "t_test":
304
+ if data2 is None:
305
+ # 单样本t检验
306
+ result = stats.ttest_1samp(data1, 0)
307
+ ci = stats.t.interval(0.95, len(data1)-1, loc=np.mean(data1), scale=stats.sem(data1))
308
+ else:
309
+ # 双样本t检验
310
+ result = stats.ttest_ind(data1, data2)
311
+ ci = None # 双样本t检验不计算置信区间
312
+
313
+ test_result = HypothesisTestResult(
314
+ test_type=test_type,
315
+ statistic=result.statistic,
316
+ p_value=result.pvalue,
317
+ significant=result.pvalue < 0.05,
318
+ confidence_interval=list(ci) if ci else None
319
+ )
320
+
321
+ elif test_type == "adf":
322
+ # ADF单位根检验
323
+ result = statsmodels.tsa.stattools.adfuller(data1)
324
+ test_result = HypothesisTestResult(
325
+ test_type="adf",
326
+ statistic=result[0],
327
+ p_value=result[1],
328
+ significant=result[1] < 0.05,
329
+ confidence_interval=None
330
+ )
331
+ else:
332
+ raise ValueError(f"不支持的检验类型: {test_type}")
333
+
334
+ await ctx.info(f"假设检验完成: {test_type}")
335
+
336
+ return CallToolResult(
337
+ content=[
338
+ TextContent(
339
+ type="text",
340
+ text=f"{test_type.upper()}检验结果:\n"
341
+ f"检验统计量 = {test_result.statistic:.4f}\n"
342
+ f"p值 = {test_result.p_value:.4f}\n"
343
+ f"{'显著' if test_result.significant else '不显著'} (5%水平)\n"
344
+ f"{f'95%置信区间: [{test_result.confidence_interval[0]:.4f}, {test_result.confidence_interval[1]:.4f}]' if test_result.confidence_interval else ''}"
345
+ )
346
+ ],
347
+ structuredContent=test_result.model_dump()
348
+ )
349
+
350
+ except Exception as e:
351
+ await ctx.error(f"假设检验出错: {str(e)}")
352
+ return CallToolResult(
353
+ content=[TextContent(type="text", text=f"错误: {str(e)}")],
354
+ isError=True
355
+ )
356
+
357
+
358
+ @mcp.tool()
359
+ async def time_series_analysis(
360
+ ctx: Context[ServerSession, AppContext],
361
+ data: List[float]
362
+ ) -> Annotated[CallToolResult, TimeSeriesStatsResult]:
363
+ """时间序列分析
364
+
365
+ Args:
366
+ data: 时间序列数据
367
+ ctx: MCP上下文对象
368
+ """
369
+ await ctx.info(f"开始时间序列分析,数据点数量: {len(data)}")
370
+
371
+ try:
372
+ # ADF单位根检验
373
+ adf_result = statsmodels.tsa.stattools.adfuller(data)
374
+
375
+ # 自相关和偏自相关函数
376
+ acf_values = statsmodels.tsa.stattools.acf(data, nlags=min(20, len(data)-1))
377
+ pacf_values = statsmodels.tsa.stattools.pacf(data, nlags=min(20, len(data)-1))
378
+
379
+ result = TimeSeriesStatsResult(
380
+ adf_statistic=adf_result[0],
381
+ adf_pvalue=adf_result[1],
382
+ stationary=adf_result[1] < 0.05,
383
+ acf=acf_values.tolist(),
384
+ pacf=pacf_values.tolist()
385
+ )
386
+
387
+ await ctx.info("时间序列分析完成")
388
+
389
+ return CallToolResult(
390
+ content=[
391
+ TextContent(
392
+ type="text",
393
+ text=f"时间序列分析结果:\n"
394
+ f"ADF检验统计量 = {result.adf_statistic:.4f}\n"
395
+ f"ADF检验p值 = {result.adf_pvalue:.4f}\n"
396
+ f"{'平稳' if result.stationary else '非平稳'}序列\n"
397
+ f"ACF前5阶: {result.acf[:5]}\n"
398
+ f"PACF前5阶: {result.pacf[:5]}"
399
+ )
400
+ ],
401
+ structuredContent=result.model_dump()
402
+ )
403
+
404
+ except Exception as e:
405
+ await ctx.error(f"时间序列分析出错: {str(e)}")
406
+ return CallToolResult(
407
+ content=[TextContent(type="text", text=f"错误: {str(e)}")],
408
+ isError=True
409
+ )
410
+
411
+
412
+ @mcp.tool()
413
+ async def correlation_analysis(
414
+ ctx: Context[ServerSession, AppContext],
415
+ data: Dict[str, List[float]],
416
+ method: str = "pearson"
417
+ ) -> str:
418
+ """相关性分析
419
+
420
+ Args:
421
+ data: 变量数据
422
+ method: 相关系数类型
423
+ ctx: MCP上下文对象
424
+ """
425
+ await ctx.info(f"开始相关性分析: {method}")
426
+
427
+ try:
428
+ df = pd.DataFrame(data)
429
+ correlation_matrix = df.corr(method=method)
430
+
431
+ await ctx.info("相关性分析完成")
432
+
433
+ return f"{method.title()}相关系数矩阵:\n{correlation_matrix.round(4).to_string()}"
434
+
435
+ except Exception as e:
436
+ await ctx.error(f"相关性分析出错: {str(e)}")
437
+ return f"错误: {str(e)}"
438
+
439
+
440
+ def create_mcp_server() -> FastMCP:
441
+ """创建并返回MCP服务器实例"""
442
+ return mcp
@@ -0,0 +1,7 @@
1
+ """
2
+ 计量经济学工具模块
3
+ """
4
+
5
+ from . import regression, statistics, time_series
6
+
7
+ __all__ = ["regression", "statistics", "time_series"]