real-time-stock-mcp-service 1.1.2__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.
- real_time_stock_mcp_service-1.1.2/.gitignore +54 -0
- real_time_stock_mcp_service-1.1.2/LICENSE +21 -0
- real_time_stock_mcp_service-1.1.2/PKG-INFO +129 -0
- real_time_stock_mcp_service-1.1.2/README.md +117 -0
- real_time_stock_mcp_service-1.1.2/pyproject.toml +27 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/__init__.py +0 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/__main__.py +8 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/app.py +113 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/__init__.py +0 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/base_crawler.py +153 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/basic_data.py +106 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/financial_analysis.py +246 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/fundamental_data.py +240 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/market.py +306 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/real_time_data.py +92 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/smart_review.py +246 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/technical_data.py +238 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/test.py +16 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/test_count_changes.py +21 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/crawler/valuation_data.py +326 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/data_source_interface.py +651 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/__init__.py +2 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/financial_analysis.py +465 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/fundamental.py +289 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/kline_data.py +257 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/market.py +960 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/real_time_data.py +157 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/search.py +143 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/smart_review.py +255 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/mcp_tools/valuation.py +412 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/stock_data_source.py +212 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/utils/__init__.py +0 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/utils/markdown_formatter.py +40 -0
- real_time_stock_mcp_service-1.1.2/src/stock_mcp/utils/utils.py +273 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual Environment
|
|
24
|
+
venv/
|
|
25
|
+
ENV/
|
|
26
|
+
env/
|
|
27
|
+
.venv
|
|
28
|
+
|
|
29
|
+
# IDEs
|
|
30
|
+
.vscode/
|
|
31
|
+
.idea/
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
*~
|
|
35
|
+
.DS_Store
|
|
36
|
+
|
|
37
|
+
# Environment variables
|
|
38
|
+
.env
|
|
39
|
+
|
|
40
|
+
# Logs
|
|
41
|
+
*.log
|
|
42
|
+
logs/
|
|
43
|
+
|
|
44
|
+
# Testing
|
|
45
|
+
.pytest_cache/
|
|
46
|
+
.coverage
|
|
47
|
+
htmlcov/
|
|
48
|
+
|
|
49
|
+
# uv
|
|
50
|
+
.uv/
|
|
51
|
+
|
|
52
|
+
# MCP
|
|
53
|
+
.mcp/
|
|
54
|
+
/.lingma/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Danny Wong
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: real-time-stock-mcp-service
|
|
3
|
+
Version: 1.1.2
|
|
4
|
+
Summary: 一个获取实时股票数据服务和分析的MCP服务器
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: mcp>=1.1.2
|
|
8
|
+
Requires-Dist: pandas>=2.2.0
|
|
9
|
+
Requires-Dist: python-dateutil>=2.9.0
|
|
10
|
+
Requires-Dist: requests>=2.32.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# 实时股票分析 MCP 服务
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
这是一个实时股票数据服务的MCP服务器。它通过东方财富网获取金融数据,并将这些数据以工具的形式暴露给支持MCP的AI模型。
|
|
18
|
+
|
|
19
|
+
> **代码仓库:** https://github.com/DannyWongIsAvailable/real-time-stock-mcp-service.git
|
|
20
|
+
|
|
21
|
+
- 免费免登录获取数据,免token
|
|
22
|
+
- 部分功能支持B股,H股
|
|
23
|
+
|
|
24
|
+
## 功能特性
|
|
25
|
+
|
|
26
|
+
- 📊 查找股票
|
|
27
|
+
- 📈 K线数据查询(支持B股,H股,大盘)
|
|
28
|
+
- 📉 技术指标分析 (MA,MACD,BOLL,KDJ等等)
|
|
29
|
+
- 💰 基本面数据分析(主营构成、经营范围等)
|
|
30
|
+
- 📊 财务分析(财务比率、业绩概况等)
|
|
31
|
+
- 💰 估值分析数据(市盈率、市净率等)
|
|
32
|
+
- 📈 市场行情跟踪(板块行情、同行对比、资金流向等)
|
|
33
|
+
- 🤖 智能点评和评分
|
|
34
|
+
|
|
35
|
+
共33个MCP工具
|
|
36
|
+
|
|
37
|
+
## 使用方法
|
|
38
|
+
|
|
39
|
+
您可以通过以下2种方式使用本服务:
|
|
40
|
+
|
|
41
|
+
### 1. 魔搭社区免费云资源一键部署
|
|
42
|
+
|
|
43
|
+
您可以在魔搭社区MCP实验场中在线体验该服务,也支持客户端远程连接(streamable HTTP或SSE协议)
|
|
44
|
+
|
|
45
|
+
https://modelscope.cn/mcp/servers/DannyWong/real-time-stock-mcp
|
|
46
|
+
|
|
47
|
+
### 2. 本地stdio模式(以Claude Desktop为例)
|
|
48
|
+
|
|
49
|
+
#### 在 Claude Desktop 中配置
|
|
50
|
+
|
|
51
|
+
编辑 Claude Desktop 的配置文件:
|
|
52
|
+
|
|
53
|
+
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
54
|
+
**MacOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
55
|
+
|
|
56
|
+
添加以下配置:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"stock-mcp": {
|
|
62
|
+
"args": [
|
|
63
|
+
"real-time-stock-mcp-service"
|
|
64
|
+
],
|
|
65
|
+
"command": "uvx"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> **注意:** 将路径替换为你的实际项目路径。
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
#### 视频教程参考:
|
|
75
|
+
- [火遍全网的MCP是什么?怎么用?如何自己开发一个MCP服务?一个视频带你入门!](https://www.bilibili.com/video/BV13R5EzbE6E/?spm_id_from=333.337.search-card.all.click&vd_source=08fc400fe0cfc7eaa723687b764b29f3)
|
|
76
|
+
- [Cherry Studio MCP 使用入门教程:从配置到使用](https://www.bilibili.com/video/BV1bkdAYTEYp/?spm_id_from=333.337.search-card.all.click&vd_source=08fc400fe0cfc7eaa723687b764b29f3)
|
|
77
|
+
|
|
78
|
+
## 核心设计
|
|
79
|
+
|
|
80
|
+
本项目采用**依赖注入**设计模式:
|
|
81
|
+
|
|
82
|
+
1. `crawler` 模块获取数据
|
|
83
|
+
2. `data_source_interface.py` 定义抽象数据源接口
|
|
84
|
+
3. `stock_data_source.py` 提供具体实现
|
|
85
|
+
4. 各工具模块通过依赖注入获取数据源实例
|
|
86
|
+
|
|
87
|
+
这种设计使得:
|
|
88
|
+
- ✅ 易于扩展新功能
|
|
89
|
+
- ✅ 可以轻松切换不同数据源
|
|
90
|
+
- ✅ 便于单元测试
|
|
91
|
+
- ✅ 代码解耦,维护性强
|
|
92
|
+
|
|
93
|
+
## 工具模块
|
|
94
|
+
|
|
95
|
+
项目包含33个MCP工具模块,每个模块提供特定领域的功能:
|
|
96
|
+
|
|
97
|
+
- `search.py` - 股票搜索和交易日信息
|
|
98
|
+
- `real_time_data.py` - 实时股票行情数据
|
|
99
|
+
- `kline_data.py` - K线数据和技术指标
|
|
100
|
+
- `fundamental.py` - 基本面数据(主营构成、经营范围等)
|
|
101
|
+
- `valuation.py` - 估值分析数据(市盈率、市净率等)
|
|
102
|
+
- `financial_analysis.py` - 财务分析数据(财务比率、业绩概况等)
|
|
103
|
+
- `market.py` - 市场行情数据(板块行情、资金流向等)
|
|
104
|
+
- `smart_review.py` - 智能点评和评分
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
## 开发指南
|
|
108
|
+
|
|
109
|
+
详情请查看[开发指南](DEVELOPMENT.md)
|
|
110
|
+
|
|
111
|
+
## 注意事项
|
|
112
|
+
|
|
113
|
+
⚠️ **重要提醒**:
|
|
114
|
+
1. 本服务提供的数据仅供参考,不构成投资建议
|
|
115
|
+
2. 仅允许个人学习、研究、使用,禁止用于商业用途。严禁滥用!
|
|
116
|
+
3. 请遵守数据使用协议和相关法律法规
|
|
117
|
+
|
|
118
|
+
## 开源协议
|
|
119
|
+
|
|
120
|
+
[MIT License](LICENSE)
|
|
121
|
+
|
|
122
|
+
## 贡献
|
|
123
|
+
|
|
124
|
+
欢迎提交 Issue 和 Pull Request!
|
|
125
|
+
|
|
126
|
+
## 联系方式
|
|
127
|
+
|
|
128
|
+
如有问题,请提交 Issue 或联系项目开发者。
|
|
129
|
+
求一个star,感激不尽!
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# 实时股票分析 MCP 服务
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
这是一个实时股票数据服务的MCP服务器。它通过东方财富网获取金融数据,并将这些数据以工具的形式暴露给支持MCP的AI模型。
|
|
6
|
+
|
|
7
|
+
> **代码仓库:** https://github.com/DannyWongIsAvailable/real-time-stock-mcp-service.git
|
|
8
|
+
|
|
9
|
+
- 免费免登录获取数据,免token
|
|
10
|
+
- 部分功能支持B股,H股
|
|
11
|
+
|
|
12
|
+
## 功能特性
|
|
13
|
+
|
|
14
|
+
- 📊 查找股票
|
|
15
|
+
- 📈 K线数据查询(支持B股,H股,大盘)
|
|
16
|
+
- 📉 技术指标分析 (MA,MACD,BOLL,KDJ等等)
|
|
17
|
+
- 💰 基本面数据分析(主营构成、经营范围等)
|
|
18
|
+
- 📊 财务分析(财务比率、业绩概况等)
|
|
19
|
+
- 💰 估值分析数据(市盈率、市净率等)
|
|
20
|
+
- 📈 市场行情跟踪(板块行情、同行对比、资金流向等)
|
|
21
|
+
- 🤖 智能点评和评分
|
|
22
|
+
|
|
23
|
+
共33个MCP工具
|
|
24
|
+
|
|
25
|
+
## 使用方法
|
|
26
|
+
|
|
27
|
+
您可以通过以下2种方式使用本服务:
|
|
28
|
+
|
|
29
|
+
### 1. 魔搭社区免费云资源一键部署
|
|
30
|
+
|
|
31
|
+
您可以在魔搭社区MCP实验场中在线体验该服务,也支持客户端远程连接(streamable HTTP或SSE协议)
|
|
32
|
+
|
|
33
|
+
https://modelscope.cn/mcp/servers/DannyWong/real-time-stock-mcp
|
|
34
|
+
|
|
35
|
+
### 2. 本地stdio模式(以Claude Desktop为例)
|
|
36
|
+
|
|
37
|
+
#### 在 Claude Desktop 中配置
|
|
38
|
+
|
|
39
|
+
编辑 Claude Desktop 的配置文件:
|
|
40
|
+
|
|
41
|
+
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
42
|
+
**MacOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
43
|
+
|
|
44
|
+
添加以下配置:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"mcpServers": {
|
|
49
|
+
"stock-mcp": {
|
|
50
|
+
"args": [
|
|
51
|
+
"real-time-stock-mcp-service"
|
|
52
|
+
],
|
|
53
|
+
"command": "uvx"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
> **注意:** 将路径替换为你的实际项目路径。
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
#### 视频教程参考:
|
|
63
|
+
- [火遍全网的MCP是什么?怎么用?如何自己开发一个MCP服务?一个视频带你入门!](https://www.bilibili.com/video/BV13R5EzbE6E/?spm_id_from=333.337.search-card.all.click&vd_source=08fc400fe0cfc7eaa723687b764b29f3)
|
|
64
|
+
- [Cherry Studio MCP 使用入门教程:从配置到使用](https://www.bilibili.com/video/BV1bkdAYTEYp/?spm_id_from=333.337.search-card.all.click&vd_source=08fc400fe0cfc7eaa723687b764b29f3)
|
|
65
|
+
|
|
66
|
+
## 核心设计
|
|
67
|
+
|
|
68
|
+
本项目采用**依赖注入**设计模式:
|
|
69
|
+
|
|
70
|
+
1. `crawler` 模块获取数据
|
|
71
|
+
2. `data_source_interface.py` 定义抽象数据源接口
|
|
72
|
+
3. `stock_data_source.py` 提供具体实现
|
|
73
|
+
4. 各工具模块通过依赖注入获取数据源实例
|
|
74
|
+
|
|
75
|
+
这种设计使得:
|
|
76
|
+
- ✅ 易于扩展新功能
|
|
77
|
+
- ✅ 可以轻松切换不同数据源
|
|
78
|
+
- ✅ 便于单元测试
|
|
79
|
+
- ✅ 代码解耦,维护性强
|
|
80
|
+
|
|
81
|
+
## 工具模块
|
|
82
|
+
|
|
83
|
+
项目包含33个MCP工具模块,每个模块提供特定领域的功能:
|
|
84
|
+
|
|
85
|
+
- `search.py` - 股票搜索和交易日信息
|
|
86
|
+
- `real_time_data.py` - 实时股票行情数据
|
|
87
|
+
- `kline_data.py` - K线数据和技术指标
|
|
88
|
+
- `fundamental.py` - 基本面数据(主营构成、经营范围等)
|
|
89
|
+
- `valuation.py` - 估值分析数据(市盈率、市净率等)
|
|
90
|
+
- `financial_analysis.py` - 财务分析数据(财务比率、业绩概况等)
|
|
91
|
+
- `market.py` - 市场行情数据(板块行情、资金流向等)
|
|
92
|
+
- `smart_review.py` - 智能点评和评分
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
## 开发指南
|
|
96
|
+
|
|
97
|
+
详情请查看[开发指南](DEVELOPMENT.md)
|
|
98
|
+
|
|
99
|
+
## 注意事项
|
|
100
|
+
|
|
101
|
+
⚠️ **重要提醒**:
|
|
102
|
+
1. 本服务提供的数据仅供参考,不构成投资建议
|
|
103
|
+
2. 仅允许个人学习、研究、使用,禁止用于商业用途。严禁滥用!
|
|
104
|
+
3. 请遵守数据使用协议和相关法律法规
|
|
105
|
+
|
|
106
|
+
## 开源协议
|
|
107
|
+
|
|
108
|
+
[MIT License](LICENSE)
|
|
109
|
+
|
|
110
|
+
## 贡献
|
|
111
|
+
|
|
112
|
+
欢迎提交 Issue 和 Pull Request!
|
|
113
|
+
|
|
114
|
+
## 联系方式
|
|
115
|
+
|
|
116
|
+
如有问题,请提交 Issue 或联系项目开发者。
|
|
117
|
+
求一个star,感激不尽!
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "real-time-stock-mcp-service"
|
|
3
|
+
version = "1.1.2"
|
|
4
|
+
description = "一个获取实时股票数据服务和分析的MCP服务器"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"mcp>=1.1.2",
|
|
9
|
+
"requests>=2.32.0",
|
|
10
|
+
"pandas>=2.2.0",
|
|
11
|
+
"python-dateutil>=2.9.0",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
# 给托管/本地一个稳定的命令入口:执行 stock-mcp 就能跑
|
|
15
|
+
[project.scripts]
|
|
16
|
+
real-time-stock-mcp-service = "stock_mcp.app:main"
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["hatchling"]
|
|
20
|
+
build-backend = "hatchling.build"
|
|
21
|
+
|
|
22
|
+
# 告诉 hatchling 包在 src/ 下,且包名是 stock_mcp
|
|
23
|
+
[tool.hatch.build.targets.wheel]
|
|
24
|
+
packages = ["src/stock_mcp"]
|
|
25
|
+
|
|
26
|
+
[tool.hatch.build.targets.sdist]
|
|
27
|
+
include = ["src/stock_mcp/**", "README.md", "pyproject.toml"]
|
|
File without changes
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
股票数据 MCP Server(托管友好入口)
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
|
|
9
|
+
from mcp.server.fastmcp import FastMCP
|
|
10
|
+
|
|
11
|
+
from stock_mcp.data_source_interface import FinancialDataInterface
|
|
12
|
+
from stock_mcp.stock_data_source import WebCrawlerDataSource
|
|
13
|
+
from stock_mcp.utils.utils import setup_logging
|
|
14
|
+
|
|
15
|
+
from stock_mcp.mcp_tools.search import register_search_tools
|
|
16
|
+
from stock_mcp.mcp_tools.kline_data import register_kline_tools
|
|
17
|
+
from stock_mcp.mcp_tools.real_time_data import register_real_time_data_tools
|
|
18
|
+
from stock_mcp.mcp_tools.fundamental import register_fundamental_tools
|
|
19
|
+
from stock_mcp.mcp_tools.valuation import register_valuation_tools
|
|
20
|
+
from stock_mcp.mcp_tools.financial_analysis import register_financial_analysis_tools
|
|
21
|
+
from stock_mcp.mcp_tools.market import register_market_tools
|
|
22
|
+
from stock_mcp.mcp_tools.smart_review import register_smart_review_tools
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def build_app(active_data_source: FinancialDataInterface) -> FastMCP:
|
|
26
|
+
"""
|
|
27
|
+
构建 FastMCP app(只做“创建 + 注册工具”)
|
|
28
|
+
"""
|
|
29
|
+
current_date = datetime.now().strftime("%Y-%m-%d")
|
|
30
|
+
|
|
31
|
+
app = FastMCP(
|
|
32
|
+
name="real-time-stock-mcp-service",
|
|
33
|
+
instructions=f"""📊 一个获取实时股票数据服务和分析的MCP服务器
|
|
34
|
+
|
|
35
|
+
**今天日期**: {current_date}
|
|
36
|
+
|
|
37
|
+
📈 主要功能:
|
|
38
|
+
- 查找股票名称,代码
|
|
39
|
+
- 实时股票数据
|
|
40
|
+
- K线数据(日线、周线、月线)
|
|
41
|
+
- 计算技术指标
|
|
42
|
+
- 基本面数据(主营构成、经营范围、经营评述等)
|
|
43
|
+
- 估值分析数据(市盈率、市净率等)
|
|
44
|
+
- 板块行情数据
|
|
45
|
+
- 智能点评和评分
|
|
46
|
+
""",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# ✅ 注册所有工具
|
|
50
|
+
register_search_tools(app, active_data_source)
|
|
51
|
+
register_real_time_data_tools(app, active_data_source)
|
|
52
|
+
register_kline_tools(app, active_data_source)
|
|
53
|
+
register_fundamental_tools(app, active_data_source)
|
|
54
|
+
register_valuation_tools(app, active_data_source)
|
|
55
|
+
register_financial_analysis_tools(app, active_data_source)
|
|
56
|
+
register_market_tools(app, active_data_source)
|
|
57
|
+
register_smart_review_tools(app, active_data_source)
|
|
58
|
+
|
|
59
|
+
return app
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def main() -> None:
|
|
63
|
+
"""
|
|
64
|
+
程序主入口:
|
|
65
|
+
1) 配日志
|
|
66
|
+
2) 创建数据源(依赖注入)
|
|
67
|
+
3) 构建 app + 注册工具
|
|
68
|
+
4) 初始化数据源
|
|
69
|
+
5) app.run() 启动(stdio)
|
|
70
|
+
6) finally 清理资源
|
|
71
|
+
"""
|
|
72
|
+
# ✅ 托管环境常用环境变量控制日志级别,方便排障
|
|
73
|
+
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
|
|
74
|
+
setup_logging(level=getattr(logging, log_level, logging.INFO))
|
|
75
|
+
logger = logging.getLogger(__name__)
|
|
76
|
+
|
|
77
|
+
# 1) 依赖注入:后续切换数据源只改这里
|
|
78
|
+
active_data_source: FinancialDataInterface = WebCrawlerDataSource()
|
|
79
|
+
logger.info("数据源: %s", active_data_source.__class__.__name__)
|
|
80
|
+
|
|
81
|
+
# 2) 构建 app(注册工具)
|
|
82
|
+
app = build_app(active_data_source)
|
|
83
|
+
logger.info("工具模块注册完成")
|
|
84
|
+
|
|
85
|
+
# 3) 初始化数据源
|
|
86
|
+
try:
|
|
87
|
+
if active_data_source.initialize():
|
|
88
|
+
logger.info("✅ 数据源初始化成功")
|
|
89
|
+
else:
|
|
90
|
+
logger.warning("⚠️ 数据源初始化失败,某些功能可能不可用")
|
|
91
|
+
except Exception:
|
|
92
|
+
logger.exception("💥 数据源初始化异常:将继续启动(功能可能受限)")
|
|
93
|
+
|
|
94
|
+
# 4) 运行服务(托管通常走 stdio,保持默认)
|
|
95
|
+
try:
|
|
96
|
+
logger.info("🚀 启动 MCP Server(stdio)")
|
|
97
|
+
app.run()
|
|
98
|
+
except KeyboardInterrupt:
|
|
99
|
+
logger.info("🛑 服务被中断")
|
|
100
|
+
except Exception:
|
|
101
|
+
logger.exception("💥 服务运行出错")
|
|
102
|
+
raise
|
|
103
|
+
finally:
|
|
104
|
+
# 5) 清理资源
|
|
105
|
+
try:
|
|
106
|
+
active_data_source.cleanup()
|
|
107
|
+
logger.info("🧹 资源清理完成")
|
|
108
|
+
except Exception:
|
|
109
|
+
logger.exception("💥 资源清理异常")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
if __name__ == "__main__":
|
|
113
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import time
|
|
3
|
+
import json
|
|
4
|
+
import random
|
|
5
|
+
import requests
|
|
6
|
+
from abc import ABC
|
|
7
|
+
from typing import Optional, Dict, Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EastMoneyBaseSpider(ABC):
|
|
11
|
+
"""
|
|
12
|
+
东方财富爬虫基类
|
|
13
|
+
|
|
14
|
+
提供通用功能:
|
|
15
|
+
- Session 管理
|
|
16
|
+
- 请求头/Cookies 配置
|
|
17
|
+
- JSONP 解析
|
|
18
|
+
- 股票代码格式转换
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# 子类可覆盖的默认配置
|
|
22
|
+
DEFAULT_TIMEOUT = 10
|
|
23
|
+
DEFAULT_HEADERS = {
|
|
24
|
+
"Accept": "application/json, text/plain, */*",
|
|
25
|
+
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
|
26
|
+
"Connection": "keep-alive",
|
|
27
|
+
"User-Agent": (
|
|
28
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
|
29
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
30
|
+
"Chrome/129.0.0.0 Safari/537.36"
|
|
31
|
+
),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
session: Optional[requests.Session] = None,
|
|
37
|
+
timeout: int = None,
|
|
38
|
+
):
|
|
39
|
+
self.session = session or requests.Session()
|
|
40
|
+
self.timeout = timeout or self.DEFAULT_TIMEOUT
|
|
41
|
+
self.headers = self.DEFAULT_HEADERS.copy()
|
|
42
|
+
self.cookies: Dict[str, str] = {}
|
|
43
|
+
|
|
44
|
+
# ==================== 通用工具方法 ====================
|
|
45
|
+
|
|
46
|
+
def _get(
|
|
47
|
+
self,
|
|
48
|
+
url: str,
|
|
49
|
+
params: Dict[str, Any] = None,
|
|
50
|
+
**kwargs
|
|
51
|
+
) -> requests.Response:
|
|
52
|
+
"""封装 GET 请求"""
|
|
53
|
+
return self.session.get(
|
|
54
|
+
url,
|
|
55
|
+
params=params,
|
|
56
|
+
headers=self.headers,
|
|
57
|
+
cookies=self.cookies,
|
|
58
|
+
timeout=self.timeout,
|
|
59
|
+
**kwargs
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def _get_json(self, url: str, params: Dict[str, Any] = None) -> Dict:
|
|
63
|
+
"""GET 请求并解析 JSON"""
|
|
64
|
+
resp = self._get(url, params)
|
|
65
|
+
resp.raise_for_status()
|
|
66
|
+
return resp.json()
|
|
67
|
+
|
|
68
|
+
def _get_jsonp(self, url: str, params: Dict[str, Any] = None) -> Optional[Dict]:
|
|
69
|
+
"""GET 请求并解析 JSONP"""
|
|
70
|
+
resp = self._get(url, params)
|
|
71
|
+
resp.raise_for_status()
|
|
72
|
+
return self._parse_jsonp(resp.text)
|
|
73
|
+
|
|
74
|
+
@staticmethod
|
|
75
|
+
def _parse_jsonp(text: str) -> Optional[Dict]:
|
|
76
|
+
# 允许末尾有分号
|
|
77
|
+
match = re.search(r'^\w+\((.*)\);?$', text.strip(), re.DOTALL)
|
|
78
|
+
if not match:
|
|
79
|
+
return None
|
|
80
|
+
try:
|
|
81
|
+
return json.loads(match.group(1))
|
|
82
|
+
except json.JSONDecodeError:
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def _generate_callback() -> str:
|
|
87
|
+
"""生成 jQuery 风格的 JSONP callback 名称"""
|
|
88
|
+
rand_part = random.randint(10 ** 19, 10 ** 20 - 1)
|
|
89
|
+
ts = int(time.time() * 1000)
|
|
90
|
+
return f"jQuery{rand_part}_{ts}"
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def _timestamp_ms() -> int:
|
|
94
|
+
"""当前时间戳(毫秒)"""
|
|
95
|
+
return int(time.time() * 1000)
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def format_secid(stock_code: str) -> str:
|
|
99
|
+
"""
|
|
100
|
+
将股票代码转换为东方财富的 secid 格式
|
|
101
|
+
|
|
102
|
+
支持格式:
|
|
103
|
+
- "000977" -> "0.000977" (深市)
|
|
104
|
+
- "600000" -> "1.600000" (沪市)
|
|
105
|
+
- "000977.SZ" -> "0.000977"
|
|
106
|
+
- "600000.SH" -> "1.600000"
|
|
107
|
+
- "0.000977" -> "0.000977" (已是 secid)
|
|
108
|
+
- "00977.HK" -> "116.00977" (H股)
|
|
109
|
+
- "116.00977" -> "116.00977" (已是 secid)
|
|
110
|
+
- "01810" -> "116.01810" (港股)
|
|
111
|
+
- "01810.HK" -> "116.01810" (港股)
|
|
112
|
+
|
|
113
|
+
:param stock_code: 股票代码
|
|
114
|
+
:return: secid 格式字符串
|
|
115
|
+
"""
|
|
116
|
+
code = stock_code.strip().upper()
|
|
117
|
+
|
|
118
|
+
if "." in code:
|
|
119
|
+
left, right = code.split(".", maxsplit=1)
|
|
120
|
+
|
|
121
|
+
# 已经是 secid 格式
|
|
122
|
+
if left in {"0", "1", "116"} and right.isdigit():
|
|
123
|
+
return f"{left}.{right}"
|
|
124
|
+
|
|
125
|
+
# 带后缀格式:000977.SZ
|
|
126
|
+
if right in {"SZ", "SH"}:
|
|
127
|
+
market = "0" if right == "SZ" else "1"
|
|
128
|
+
return f"{market}.{left}"
|
|
129
|
+
|
|
130
|
+
# H股格式:00977.HK 或 01810.HK
|
|
131
|
+
if right == "HK":
|
|
132
|
+
return f"116.{left.zfill(5)}" # 港股代码补齐为5位
|
|
133
|
+
|
|
134
|
+
# 纯数字代码
|
|
135
|
+
if code.isdigit():
|
|
136
|
+
# 6 开头沪市,其他深市
|
|
137
|
+
if code.startswith("6"):
|
|
138
|
+
return f"1.{code}"
|
|
139
|
+
# 5位数港股代码(通常以0开头)
|
|
140
|
+
elif len(code) == 5:
|
|
141
|
+
return f"116.{code}"
|
|
142
|
+
# 其他情况为深市
|
|
143
|
+
else:
|
|
144
|
+
return f"0.{code}"
|
|
145
|
+
|
|
146
|
+
raise ValueError(f"无法解析股票代码: {stock_code}")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|