@youhaozhao/cninfo-mcp 1.2.0 → 1.3.0
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.
- package/README.md +64 -54
- package/package.json +17 -4
- package/python/mcp_server.py +193 -268
- package/python/spider.py +351 -260
package/README.md
CHANGED
|
@@ -1,54 +1,64 @@
|
|
|
1
|
-
# cninfo-mcp
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@youhaozhao/cninfo-mcp)
|
|
4
|
-
|
|
5
|
-
通过 MCP
|
|
6
|
-
|
|
7
|
-
## 使用方法
|
|
8
|
-
|
|
9
|
-
在 Claude Desktop / Claude Code 配置文件中添加:
|
|
10
|
-
|
|
11
|
-
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
12
|
-
|
|
13
|
-
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
14
|
-
|
|
15
|
-
```json
|
|
16
|
-
{
|
|
17
|
-
"mcpServers": {
|
|
18
|
-
"cninfo": {
|
|
19
|
-
"command": "npx",
|
|
20
|
-
"args": ["-y", "@youhaozhao/cninfo-mcp"]
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
重启 Claude Desktop 后即可使用。
|
|
27
|
-
|
|
28
|
-
## 可用工具
|
|
29
|
-
|
|
30
|
-
- **`query_annual_reports_tool`** —
|
|
31
|
-
- **`download_annual_reports_tool`** —
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
1
|
+
# cninfo-mcp
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@youhaozhao/cninfo-mcp)
|
|
4
|
+
|
|
5
|
+
通过 MCP 协议查询和下载巨潮资讯网上市公司定期报告及招股书 PDF 的工具,适用于 Claude Desktop / Claude Code。
|
|
6
|
+
|
|
7
|
+
## 使用方法
|
|
8
|
+
|
|
9
|
+
在 Claude Desktop / Claude Code 配置文件中添加:
|
|
10
|
+
|
|
11
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
12
|
+
|
|
13
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"cninfo": {
|
|
19
|
+
"command": "npx",
|
|
20
|
+
"args": ["-y", "@youhaozhao/cninfo-mcp"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
重启 Claude Desktop 后即可使用。
|
|
27
|
+
|
|
28
|
+
## 可用工具
|
|
29
|
+
|
|
30
|
+
- **`query_annual_reports_tool`** — 查询报告列表,参数:股票代码(必填)、年份(可选)、报告类型(可选,默认 `annual`)
|
|
31
|
+
- **`download_annual_reports_tool`** — 下载报告 PDF,参数:股票代码(必填)、年份(可选)、保存路径(可选)、报告类型(可选,默认 `annual`)
|
|
32
|
+
|
|
33
|
+
支持的 `report_type`:
|
|
34
|
+
|
|
35
|
+
- `annual` — 年度报告 / 年报
|
|
36
|
+
- `semiannual` — 半年度报告 / 半年报 / 中报
|
|
37
|
+
- `q1` — 第一季度报告 / 一季报
|
|
38
|
+
- `q3` — 第三季度报告 / 三季报
|
|
39
|
+
- `prospectus` — 招股书 / 招股说明书 / 招股意向书(招股书无固定年份,省略年份参数即可)
|
|
40
|
+
|
|
41
|
+
示例对话:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
查询 000888 的 2024 年报
|
|
45
|
+
查询 000001 的 2024 半年报
|
|
46
|
+
查询 600519 的 2024 一季报
|
|
47
|
+
下载 300750 的 2023 三季报
|
|
48
|
+
下载 688777 的年报
|
|
49
|
+
查询 920185 的年报 # 北交所,新旧代码(如 835185)均可
|
|
50
|
+
查询 688777 的招股书
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 系统要求
|
|
54
|
+
|
|
55
|
+
- Node.js 18+
|
|
56
|
+
- Python 3.10+(Python 依赖会自动安装)
|
|
57
|
+
|
|
58
|
+
## 数据来源
|
|
59
|
+
|
|
60
|
+
[巨潮资讯网](https://www.cninfo.com.cn) — 支持沪深两市(主板、创业板、科创板)及北京证券交易所(北交所)
|
|
61
|
+
|
|
62
|
+
## Credits
|
|
63
|
+
|
|
64
|
+
爬虫逻辑基于 [gaodechen/cninfo_process](https://github.com/gaodechen/cninfo_process)。
|
package/package.json
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@youhaozhao/cninfo-mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "MCP Server for querying and downloading Chinese listed companies'
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "MCP Server for querying and downloading Chinese listed companies' periodic reports from CNINFO (巨潮资讯网)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
7
7
|
"mcp-server",
|
|
8
8
|
"cninfo",
|
|
9
9
|
"chinese-stock",
|
|
10
10
|
"annual-reports",
|
|
11
|
+
"quarterly-reports",
|
|
12
|
+
"semiannual-reports",
|
|
13
|
+
"periodic-reports",
|
|
11
14
|
"finance",
|
|
12
|
-
"python"
|
|
15
|
+
"python",
|
|
16
|
+
"巨潮",
|
|
17
|
+
"巨潮资讯",
|
|
18
|
+
"定期报告",
|
|
19
|
+
"年报",
|
|
20
|
+
"半年报",
|
|
21
|
+
"季报",
|
|
22
|
+
"招股书",
|
|
23
|
+
"A股",
|
|
24
|
+
"上市公司",
|
|
25
|
+
"财报"
|
|
13
26
|
],
|
|
14
27
|
"homepage": "https://github.com/youhaozhao/cninfo-mcp#readme",
|
|
15
28
|
"repository": {
|
|
@@ -27,7 +40,7 @@
|
|
|
27
40
|
"postinstall": "node scripts/install-python-deps.js",
|
|
28
41
|
"start": "node bin/cninfo-mcp.js",
|
|
29
42
|
"dev": "node bin/cninfo-mcp.js",
|
|
30
|
-
"test": "
|
|
43
|
+
"test": "python3 -m pytest python/test_spider.py -q"
|
|
31
44
|
},
|
|
32
45
|
"dependencies": {
|
|
33
46
|
"spawn-please": "^2.0.2"
|
package/python/mcp_server.py
CHANGED
|
@@ -1,268 +1,193 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
巨潮资讯 MCP 服务器
|
|
4
|
-
用于查询和下载 A
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
import sys
|
|
9
|
-
from typing import Optional
|
|
10
|
-
|
|
11
|
-
# 将当前目录加入模块搜索路径
|
|
12
|
-
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
13
|
-
|
|
14
|
-
from mcp.server import FastMCP
|
|
15
|
-
from spider import (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
"success":
|
|
89
|
-
"stock_code": stock_code,
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"
|
|
94
|
-
"message": f"
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"""
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
{
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
"count": 0,
|
|
195
|
-
"reports": [],
|
|
196
|
-
"error": str(e),
|
|
197
|
-
"message": f"Error querying prospectus: {str(e)}",
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
@mcp.tool()
|
|
202
|
-
def download_prospectus_tool(stock_code: str, save_path: Optional[str] = None) -> dict:
|
|
203
|
-
"""
|
|
204
|
-
Download prospectus documents for a Chinese listed company
|
|
205
|
-
|
|
206
|
-
Args:
|
|
207
|
-
stock_code: Stock code (e.g., '000888' for 峨眉山, '688777' for 中科德芯)
|
|
208
|
-
save_path: Optional directory to save files (e.g., '/Users/me/reports'). Defaults to pdf/ in package directory
|
|
209
|
-
|
|
210
|
-
Returns:
|
|
211
|
-
Dictionary containing:
|
|
212
|
-
- success: Boolean indicating if download was successful
|
|
213
|
-
- stock_code: The stock code
|
|
214
|
-
- downloaded: Number of files downloaded
|
|
215
|
-
- path: Directory where files were saved
|
|
216
|
-
- message: Status message
|
|
217
|
-
"""
|
|
218
|
-
try:
|
|
219
|
-
output_dir = save_path or saving_path
|
|
220
|
-
os.makedirs(output_dir, exist_ok=True)
|
|
221
|
-
|
|
222
|
-
result = download_prospectus(stock_code, save_path=output_dir)
|
|
223
|
-
result["stock_code"] = stock_code
|
|
224
|
-
|
|
225
|
-
return result
|
|
226
|
-
|
|
227
|
-
except Exception as e:
|
|
228
|
-
return {
|
|
229
|
-
"success": False,
|
|
230
|
-
"stock_code": stock_code,
|
|
231
|
-
"downloaded": 0,
|
|
232
|
-
"path": save_path or saving_path,
|
|
233
|
-
"error": str(e),
|
|
234
|
-
"message": f"Error downloading prospectus: {str(e)}",
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
@mcp.resource("annual-reports-list://{stock_code}")
|
|
239
|
-
def get_annual_reports_list(stock_code: str) -> str:
|
|
240
|
-
"""返回指定股票代码的年度报告格式化列表"""
|
|
241
|
-
try:
|
|
242
|
-
reports = query_annual_reports(stock_code)
|
|
243
|
-
|
|
244
|
-
if not reports:
|
|
245
|
-
return f"No annual reports found for stock {stock_code}"
|
|
246
|
-
|
|
247
|
-
output = [f"Annual Reports for {stock_code}:", "=" * 60]
|
|
248
|
-
|
|
249
|
-
for report in reports:
|
|
250
|
-
title = report.get("announcementTitle", "N/A")
|
|
251
|
-
time = report.get("announcementTime", "N/A")
|
|
252
|
-
name = report.get("secName", "N/A")
|
|
253
|
-
output.append(f"\n📄 {title}")
|
|
254
|
-
output.append(f" Company: {name}")
|
|
255
|
-
output.append(f" Date: {time}")
|
|
256
|
-
|
|
257
|
-
output.append("\n" + "=" * 60)
|
|
258
|
-
output.append(f"Total: {len(reports)} report(s)")
|
|
259
|
-
|
|
260
|
-
return "\n".join(output)
|
|
261
|
-
|
|
262
|
-
except Exception as e:
|
|
263
|
-
return f"Error retrieving annual reports: {str(e)}"
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if __name__ == "__main__":
|
|
267
|
-
# 以 stdio 方式运行服务器
|
|
268
|
-
mcp.run()
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
巨潮资讯 MCP 服务器
|
|
4
|
+
用于查询和下载 A 股定期报告、招股书的 MCP 工具服务
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
# 将当前目录加入模块搜索路径
|
|
12
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
13
|
+
|
|
14
|
+
from mcp.server import FastMCP
|
|
15
|
+
from spider import (
|
|
16
|
+
query_reports,
|
|
17
|
+
download_reports,
|
|
18
|
+
saving_path,
|
|
19
|
+
supported_report_types,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# 创建 MCP 服务器实例
|
|
23
|
+
mcp = FastMCP(
|
|
24
|
+
name="cninfo-server",
|
|
25
|
+
instructions="CNINFO reports server - Query and download Chinese listed companies' periodic reports from cninfo.com.cn",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _format_reports(reports: list) -> list:
|
|
30
|
+
"""提取 MCP 返回中稳定、有用的公告字段。"""
|
|
31
|
+
base_url = "https://static.cninfo.com.cn/"
|
|
32
|
+
report_details = []
|
|
33
|
+
for report in reports:
|
|
34
|
+
adj = report.get("adjunctUrl", "")
|
|
35
|
+
report_details.append(
|
|
36
|
+
{
|
|
37
|
+
"announcementTitle": report.get("announcementTitle", ""),
|
|
38
|
+
"announcementTime": report.get("announcementTime", ""),
|
|
39
|
+
"secCode": report.get("secCode", ""),
|
|
40
|
+
"secName": report.get("secName", ""),
|
|
41
|
+
"adjunctUrl": base_url + adj if adj else "",
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
return report_details
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _supported_report_types_text() -> str:
|
|
48
|
+
return ", ".join(supported_report_types().keys())
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@mcp.tool()
|
|
52
|
+
def query_annual_reports_tool(
|
|
53
|
+
stock_code: str, year: Optional[int] = None, report_type: str = "annual"
|
|
54
|
+
) -> dict:
|
|
55
|
+
"""
|
|
56
|
+
Query periodic reports for a Chinese listed company.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
stock_code: Stock code (e.g., '000888' for 峨眉山, '688777' for 中科德芯)
|
|
60
|
+
year: Optional year to filter (e.g., 2024). If not provided, returns all available years
|
|
61
|
+
report_type: Optional report type. Supported values: annual, semiannual, q1, q3, prospectus. Defaults to annual for backward compatibility.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Dictionary containing:
|
|
65
|
+
- success: Boolean indicating if the query was successful
|
|
66
|
+
- stock_code: The queried stock code
|
|
67
|
+
- report_type: The requested report type
|
|
68
|
+
- year: The filtered year (if any)
|
|
69
|
+
- count: Number of reports found
|
|
70
|
+
- reports: List of report details (announcementTitle, announcementTime, secCode, secName, adjunctUrl)
|
|
71
|
+
"""
|
|
72
|
+
try:
|
|
73
|
+
reports = query_reports(stock_code, report_type, year)
|
|
74
|
+
|
|
75
|
+
if not reports:
|
|
76
|
+
return {
|
|
77
|
+
"success": False,
|
|
78
|
+
"stock_code": stock_code,
|
|
79
|
+
"report_type": report_type,
|
|
80
|
+
"year": year,
|
|
81
|
+
"count": 0,
|
|
82
|
+
"reports": [],
|
|
83
|
+
"message": f"No {report_type} reports found for stock {stock_code}"
|
|
84
|
+
+ (f" in year {year}" if year else ""),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
"success": True,
|
|
89
|
+
"stock_code": stock_code,
|
|
90
|
+
"report_type": report_type,
|
|
91
|
+
"year": year,
|
|
92
|
+
"count": len(reports),
|
|
93
|
+
"reports": _format_reports(reports),
|
|
94
|
+
"message": f"Found {len(reports)} {report_type} report(s)"
|
|
95
|
+
+ (f" for year {year}" if year else ""),
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
except Exception as e:
|
|
99
|
+
return {
|
|
100
|
+
"success": False,
|
|
101
|
+
"stock_code": stock_code,
|
|
102
|
+
"report_type": report_type,
|
|
103
|
+
"year": year,
|
|
104
|
+
"count": 0,
|
|
105
|
+
"reports": [],
|
|
106
|
+
"error": str(e),
|
|
107
|
+
"message": f"Error querying reports: {str(e)}. Supported report_type values: {_supported_report_types_text()}",
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@mcp.tool()
|
|
112
|
+
def download_annual_reports_tool(
|
|
113
|
+
stock_code: str,
|
|
114
|
+
year: Optional[int] = None,
|
|
115
|
+
save_path: Optional[str] = None,
|
|
116
|
+
report_type: str = "annual",
|
|
117
|
+
) -> dict:
|
|
118
|
+
"""
|
|
119
|
+
Download periodic reports for a Chinese listed company.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
stock_code: Stock code (e.g., '000888' for 峨眉山, '688777' for 中科德芯)
|
|
123
|
+
year: Optional year to filter (e.g., 2024). If not provided, downloads all available years
|
|
124
|
+
save_path: Optional directory to save files (e.g., '/Users/me/reports'). Defaults to pdf/ in package directory
|
|
125
|
+
report_type: Optional report type. Supported values: annual, semiannual, q1, q3, prospectus. Defaults to annual for backward compatibility.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Dictionary containing:
|
|
129
|
+
- success: Boolean indicating if download was successful
|
|
130
|
+
- stock_code: The stock code
|
|
131
|
+
- report_type: The requested report type
|
|
132
|
+
- year: The filtered year (if any)
|
|
133
|
+
- downloaded: Number of files downloaded
|
|
134
|
+
- path: Directory where files were saved
|
|
135
|
+
- message: Status message
|
|
136
|
+
"""
|
|
137
|
+
try:
|
|
138
|
+
output_dir = save_path or saving_path
|
|
139
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
140
|
+
|
|
141
|
+
result = download_reports(
|
|
142
|
+
stock_code, report_type, year=year, save_path=output_dir
|
|
143
|
+
)
|
|
144
|
+
result["stock_code"] = stock_code
|
|
145
|
+
result["report_type"] = report_type
|
|
146
|
+
result["year"] = year
|
|
147
|
+
|
|
148
|
+
return result
|
|
149
|
+
|
|
150
|
+
except Exception as e:
|
|
151
|
+
return {
|
|
152
|
+
"success": False,
|
|
153
|
+
"stock_code": stock_code,
|
|
154
|
+
"report_type": report_type,
|
|
155
|
+
"year": year,
|
|
156
|
+
"downloaded": 0,
|
|
157
|
+
"path": save_path or saving_path,
|
|
158
|
+
"error": str(e),
|
|
159
|
+
"message": f"Error downloading reports: {str(e)}. Supported report_type values: {_supported_report_types_text()}",
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@mcp.resource("annual-reports-list://{stock_code}")
|
|
164
|
+
def get_annual_reports_list(stock_code: str) -> str:
|
|
165
|
+
"""返回指定股票代码的年度报告格式化列表"""
|
|
166
|
+
try:
|
|
167
|
+
reports = query_reports(stock_code, "annual")
|
|
168
|
+
|
|
169
|
+
if not reports:
|
|
170
|
+
return f"No annual reports found for stock {stock_code}"
|
|
171
|
+
|
|
172
|
+
output = [f"Annual Reports for {stock_code}:", "=" * 60]
|
|
173
|
+
|
|
174
|
+
for report in reports:
|
|
175
|
+
title = report.get("announcementTitle", "N/A")
|
|
176
|
+
time = report.get("announcementTime", "N/A")
|
|
177
|
+
name = report.get("secName", "N/A")
|
|
178
|
+
output.append(f"\n📄 {title}")
|
|
179
|
+
output.append(f" Company: {name}")
|
|
180
|
+
output.append(f" Date: {time}")
|
|
181
|
+
|
|
182
|
+
output.append("\n" + "=" * 60)
|
|
183
|
+
output.append(f"Total: {len(reports)} report(s)")
|
|
184
|
+
|
|
185
|
+
return "\n".join(output)
|
|
186
|
+
|
|
187
|
+
except Exception as e:
|
|
188
|
+
return f"Error retrieving annual reports: {str(e)}"
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
if __name__ == "__main__":
|
|
192
|
+
# 以 stdio 方式运行服务器
|
|
193
|
+
mcp.run()
|