Spaces:
Sleeping
Sleeping
Upload 4 files
Browse files- PROJECT_STRUCTURE.md +184 -0
- USAGE.md +254 -0
- requirements.txt +11 -0
- test_mcp_sse.py +231 -0
PROJECT_STRUCTURE.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 📁 项目结构
|
| 2 |
+
|
| 3 |
+
```
|
| 4 |
+
EasyReportDateMCP/
|
| 5 |
+
│
|
| 6 |
+
├── 📄 README.md # 项目主文档
|
| 7 |
+
├── 📘 USAGE.md # 使用指南
|
| 8 |
+
├── 📋 PROJECT_STRUCTURE.md # 本文件
|
| 9 |
+
│
|
| 10 |
+
├── 🐳 Dockerfile # HF Space 部署配置
|
| 11 |
+
├── 📦 requirements.txt # Python 依赖
|
| 12 |
+
├── 🙈 .gitignore # Git 忽略规则
|
| 13 |
+
│
|
| 14 |
+
├── 🚀 mcp_server_sse.py # MCP Server 主程序(SSE 传输)
|
| 15 |
+
├── 📊 edgar_client.py # SEC EDGAR 数据客户端
|
| 16 |
+
├── 📈 financial_analyzer.py # 财务数据分析器
|
| 17 |
+
│
|
| 18 |
+
└── 🧪 test_mcp_sse.py # 测试脚本
|
| 19 |
+
```
|
| 20 |
+
|
| 21 |
+
---
|
| 22 |
+
|
| 23 |
+
## 核心文件说明
|
| 24 |
+
|
| 25 |
+
### 📄 README.md
|
| 26 |
+
项目主文档,包含:
|
| 27 |
+
- 快速开始指南
|
| 28 |
+
- 可用工具列表
|
| 29 |
+
- 使用示例
|
| 30 |
+
- 技术栈说明
|
| 31 |
+
|
| 32 |
+
### 📘 USAGE.md
|
| 33 |
+
详细使用指南,包含:
|
| 34 |
+
- 客户端配置步骤
|
| 35 |
+
- 7 个工具的详细说明
|
| 36 |
+
- 实际使用场景
|
| 37 |
+
- 故障排除
|
| 38 |
+
|
| 39 |
+
### 🚀 mcp_server_sse.py
|
| 40 |
+
MCP Server 主程序(583 行):
|
| 41 |
+
- FastAPI 应用
|
| 42 |
+
- SSE 传输实现
|
| 43 |
+
- 7 个 MCP 工具定义
|
| 44 |
+
- 格式化输出逻辑
|
| 45 |
+
- 健康检查和监控
|
| 46 |
+
|
| 47 |
+
### 📊 edgar_client.py
|
| 48 |
+
SEC EDGAR 客户端(600+ 行):
|
| 49 |
+
- 公司搜索
|
| 50 |
+
- 公司信息获取
|
| 51 |
+
- 财报文件检索
|
| 52 |
+
- XBRL 数据解析
|
| 53 |
+
- 财务数据提取
|
| 54 |
+
|
| 55 |
+
### 📈 financial_analyzer.py
|
| 56 |
+
财务分析器(340+ 行):
|
| 57 |
+
- 多年数据提取
|
| 58 |
+
- 数据格式化
|
| 59 |
+
- 智能搜索
|
| 60 |
+
- 最新数据获取
|
| 61 |
+
|
| 62 |
+
### 🐳 Dockerfile
|
| 63 |
+
Docker 部署配置:
|
| 64 |
+
- Python 3.10 基础镜像
|
| 65 |
+
- 依赖安装
|
| 66 |
+
- 应用文件复制
|
| 67 |
+
- Uvicorn 启动命令
|
| 68 |
+
|
| 69 |
+
### 📦 requirements.txt
|
| 70 |
+
Python 依赖:
|
| 71 |
+
```
|
| 72 |
+
fastapi==0.109.0
|
| 73 |
+
uvicorn[standard]==0.27.0
|
| 74 |
+
pydantic==2.5.3
|
| 75 |
+
sec-edgar-api==1.1.0
|
| 76 |
+
requests==2.31.0
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
### 🧪 test_mcp_sse.py
|
| 80 |
+
测试脚本(232 行):
|
| 81 |
+
- 健康检查测试
|
| 82 |
+
- MCP 协议测试
|
| 83 |
+
- 工具调用测试
|
| 84 |
+
- SSE 连接测试
|
| 85 |
+
|
| 86 |
+
---
|
| 87 |
+
|
| 88 |
+
## 部署文件
|
| 89 |
+
|
| 90 |
+
### HF Space 必需
|
| 91 |
+
- ✅ `README.md` (HF Space 主页显示)
|
| 92 |
+
- ✅ `Dockerfile` (构建镜像)
|
| 93 |
+
- ✅ `requirements.txt` (依赖)
|
| 94 |
+
- ✅ `mcp_server_sse.py` (主程序)
|
| 95 |
+
- ✅ `edgar_client.py` (核心库)
|
| 96 |
+
- ✅ `financial_analyzer.py` (核心库)
|
| 97 |
+
|
| 98 |
+
### 可选文件
|
| 99 |
+
- 📘 `USAGE.md` (用户文档)
|
| 100 |
+
- 🧪 `test_mcp_sse.py` (测试)
|
| 101 |
+
- 📋 `PROJECT_STRUCTURE.md` (本文件)
|
| 102 |
+
|
| 103 |
+
---
|
| 104 |
+
|
| 105 |
+
## 代码统计
|
| 106 |
+
|
| 107 |
+
| 文件 | 行数 | 说明 |
|
| 108 |
+
|------|-----|------|
|
| 109 |
+
| `mcp_server_sse.py` | 583 | MCP Server 主程序 |
|
| 110 |
+
| `edgar_client.py` | 600+ | SEC 数据客户端 |
|
| 111 |
+
| `financial_analyzer.py` | 340+ | 财务分析器 |
|
| 112 |
+
| `test_mcp_sse.py` | 232 | 测试套件 |
|
| 113 |
+
| **总计** | **~1,800** | 核心代码行数 |
|
| 114 |
+
|
| 115 |
+
---
|
| 116 |
+
|
| 117 |
+
## 依赖关系
|
| 118 |
+
|
| 119 |
+
```
|
| 120 |
+
mcp_server_sse.py
|
| 121 |
+
├── edgar_client.py
|
| 122 |
+
│ └── sec-edgar-api
|
| 123 |
+
│ └── requests
|
| 124 |
+
│
|
| 125 |
+
└── financial_analyzer.py
|
| 126 |
+
└── edgar_client.py
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
---
|
| 130 |
+
|
| 131 |
+
## 数据流
|
| 132 |
+
|
| 133 |
+
```
|
| 134 |
+
MCP Client (Claude Desktop)
|
| 135 |
+
↓ SSE
|
| 136 |
+
MCP Server (mcp_server_sse.py)
|
| 137 |
+
↓
|
| 138 |
+
Financial Analyzer (financial_analyzer.py)
|
| 139 |
+
↓
|
| 140 |
+
EDGAR Client (edgar_client.py)
|
| 141 |
+
↓ HTTPS
|
| 142 |
+
SEC EDGAR API
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## 开发工作流
|
| 148 |
+
|
| 149 |
+
### 1. 本地开发
|
| 150 |
+
```bash
|
| 151 |
+
# 启动服务器
|
| 152 |
+
python mcp_server_sse.py
|
| 153 |
+
|
| 154 |
+
# 运行测试
|
| 155 |
+
python test_mcp_sse.py
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
### 2. 部署到 HF Space
|
| 159 |
+
```bash
|
| 160 |
+
git add .
|
| 161 |
+
git commit -m "Update"
|
| 162 |
+
git push
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
### 3. 验证部署
|
| 166 |
+
```bash
|
| 167 |
+
curl https://jc321-easyreportdatemcp.hf.space/health
|
| 168 |
+
```
|
| 169 |
+
|
| 170 |
+
---
|
| 171 |
+
|
| 172 |
+
## 项目特点
|
| 173 |
+
|
| 174 |
+
✅ **简洁** - 核心文件少,结构清晰
|
| 175 |
+
✅ **专注** - 只保留 MCP Server 相关代码
|
| 176 |
+
✅ **完整** - 包含服务器、测试、文档
|
| 177 |
+
✅ **可维护** - 代码组织良好,易于理解
|
| 178 |
+
✅ **生产就绪** - 可直接部署到 HF Space
|
| 179 |
+
|
| 180 |
+
---
|
| 181 |
+
|
| 182 |
+
**总大小**: ~70 KB (不含 Python 缓存)
|
| 183 |
+
**文件数**: 9 个核心文件
|
| 184 |
+
**依赖数**: 5 个 Python 包
|
USAGE.md
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 📘 使用指南
|
| 2 |
+
|
| 3 |
+
## 🚀 快速开始
|
| 4 |
+
|
| 5 |
+
### 1. 连接到 MCP Server
|
| 6 |
+
|
| 7 |
+
#### Claude Desktop 配置
|
| 8 |
+
|
| 9 |
+
**Windows**: 编辑 `%APPDATA%\Claude\claude_desktop_config.json`
|
| 10 |
+
**macOS**: 编辑 `~/Library/Application Support/Claude/claude_desktop_config.json`
|
| 11 |
+
|
| 12 |
+
添加配置:
|
| 13 |
+
```json
|
| 14 |
+
{
|
| 15 |
+
"mcpServers": {
|
| 16 |
+
"sec-financial-data": {
|
| 17 |
+
"url": "https://jc321-easyreportdatemcp.hf.space/sse"
|
| 18 |
+
}
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
重启 Claude Desktop,查看右下角 🔌 图标。
|
| 24 |
+
|
| 25 |
+
---
|
| 26 |
+
|
| 27 |
+
## 🛠️ 可用工具 (7个)
|
| 28 |
+
|
| 29 |
+
### 1. `search_company`
|
| 30 |
+
按公司名称搜索 → 获取 CIK、ticker、官方名称
|
| 31 |
+
|
| 32 |
+
**示例**: "Search for Microsoft"
|
| 33 |
+
|
| 34 |
+
---
|
| 35 |
+
|
| 36 |
+
### 2. `get_company_info`
|
| 37 |
+
获取详细公司信息 → 行业、SIC 代码、财年等
|
| 38 |
+
|
| 39 |
+
**参数**: `cik` (公司 CIK 代码)
|
| 40 |
+
|
| 41 |
+
---
|
| 42 |
+
|
| 43 |
+
### 3. `get_company_filings`
|
| 44 |
+
列出所有 SEC 报告 → 10-K, 10-Q, 20-F 及日期、链接
|
| 45 |
+
|
| 46 |
+
**参数**:
|
| 47 |
+
- `cik`: 公司 CIK 代码
|
| 48 |
+
- `form_types` (可选): 如 `["10-K", "10-Q"]`
|
| 49 |
+
|
| 50 |
+
---
|
| 51 |
+
|
| 52 |
+
### 4. `get_financial_data`
|
| 53 |
+
获取特定期间财务数据 → Revenue, Net Income, EPS, Cash Flow
|
| 54 |
+
|
| 55 |
+
**参数**:
|
| 56 |
+
- `cik`: 公司 CIK 代码
|
| 57 |
+
- `period`: 格式 "YYYY" (年度) 或 "YYYYQX" (季度)
|
| 58 |
+
|
| 59 |
+
**示例**: "Show me Apple's financial data for 2024Q3"
|
| 60 |
+
|
| 61 |
+
---
|
| 62 |
+
|
| 63 |
+
### 5. `extract_financial_metrics` ⭐ 推荐
|
| 64 |
+
提取多年综合指标 → 年度 + 季度数据,按时间排序
|
| 65 |
+
|
| 66 |
+
**参数**:
|
| 67 |
+
- `cik`: 公司 CIK 代码
|
| 68 |
+
- `years`: 年数 (1-10, 默认 3)
|
| 69 |
+
|
| 70 |
+
**示例**: "Extract 5 years of financial metrics for Tesla"
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
### 6. `get_latest_financial_data`
|
| 75 |
+
获取最新可用财务数据
|
| 76 |
+
|
| 77 |
+
**参数**: `cik` (公司 CIK 代码)
|
| 78 |
+
|
| 79 |
+
---
|
| 80 |
+
|
| 81 |
+
### 7. `advanced_search_company`
|
| 82 |
+
智能搜索 → 自动识别公司名称、ticker 或 CIK
|
| 83 |
+
|
| 84 |
+
**参数**: `company_input` (任意格式的公司标识)
|
| 85 |
+
|
| 86 |
+
---
|
| 87 |
+
|
| 88 |
+
## 💬 使用示例
|
| 89 |
+
|
| 90 |
+
### 场景 1: 快速查询
|
| 91 |
+
**输入**: "Search for Tesla and show me their latest financial data"
|
| 92 |
+
|
| 93 |
+
**AI 工作流程**:
|
| 94 |
+
1. 🔍 `search_company("Tesla")` → 找到 CIK
|
| 95 |
+
2. 🆕 `get_latest_financial_data(cik)` → 获取最新数据
|
| 96 |
+
3. 📊 返回格式化结果
|
| 97 |
+
|
| 98 |
+
---
|
| 99 |
+
|
| 100 |
+
### 场景 2: 趋势分析
|
| 101 |
+
**输入**: "Extract 3 years of financial metrics for Apple and analyze revenue growth"
|
| 102 |
+
|
| 103 |
+
**AI 工作流程**:
|
| 104 |
+
1. 📈 `extract_financial_metrics(cik, years=3)`
|
| 105 |
+
2. 📊 返回 12+ 期数据(年度 + 季度)
|
| 106 |
+
3. 🤖 AI 分析并解释趋势
|
| 107 |
+
|
| 108 |
+
---
|
| 109 |
+
|
| 110 |
+
### 场景 3: 公司对比
|
| 111 |
+
**输入**: "Compare NVIDIA and AMD revenue for the past 2 years"
|
| 112 |
+
|
| 113 |
+
**AI 工作流程**:
|
| 114 |
+
1. 🔍 搜索两家公司
|
| 115 |
+
2. 📊 提取各自数据
|
| 116 |
+
3. 📈 AI 对比分析
|
| 117 |
+
|
| 118 |
+
---
|
| 119 |
+
|
| 120 |
+
## 🎨 格式化输出示例
|
| 121 |
+
|
| 122 |
+
### 成功查询
|
| 123 |
+
```
|
| 124 |
+
✅ Company Found:
|
| 125 |
+
{
|
| 126 |
+
"cik": "0000789019",
|
| 127 |
+
"name": "MICROSOFT CORP",
|
| 128 |
+
"ticker": "MSFT"
|
| 129 |
+
}
|
| 130 |
+
```
|
| 131 |
+
|
| 132 |
+
### 财务数据
|
| 133 |
+
```
|
| 134 |
+
💰 Financial Data for 2024Q3:
|
| 135 |
+
{
|
| 136 |
+
"period": "2024Q3",
|
| 137 |
+
"revenue": "$65.59B",
|
| 138 |
+
"net_income": "$24.67B",
|
| 139 |
+
"eps": "$3.30",
|
| 140 |
+
"operating_cash_flow": "$34.25B",
|
| 141 |
+
"free_cash_flow": "$19.28B"
|
| 142 |
+
}
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
### 多年数据
|
| 146 |
+
```
|
| 147 |
+
📈 Financial Metrics (12 periods):
|
| 148 |
+
[
|
| 149 |
+
{
|
| 150 |
+
"period": "2024Q3",
|
| 151 |
+
"type": "quarterly",
|
| 152 |
+
"revenue": "$65.59B",
|
| 153 |
+
...
|
| 154 |
+
},
|
| 155 |
+
...
|
| 156 |
+
]
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
---
|
| 160 |
+
|
| 161 |
+
## 🔧 本地开发和测试
|
| 162 |
+
|
| 163 |
+
### 启动服务器
|
| 164 |
+
```bash
|
| 165 |
+
python mcp_server_sse.py
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
访问: http://localhost:7860
|
| 169 |
+
|
| 170 |
+
### 运行测试
|
| 171 |
+
```bash
|
| 172 |
+
python test_mcp_sse.py
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
### 健康检查
|
| 176 |
+
```bash
|
| 177 |
+
curl http://localhost:7860/health
|
| 178 |
+
```
|
| 179 |
+
|
| 180 |
+
---
|
| 181 |
+
|
| 182 |
+
## 📦 部署到 Hugging Face Space
|
| 183 |
+
|
| 184 |
+
### 方法 1: Git 推送
|
| 185 |
+
```bash
|
| 186 |
+
git add .
|
| 187 |
+
git commit -m "Update MCP Server"
|
| 188 |
+
git push
|
| 189 |
+
```
|
| 190 |
+
|
| 191 |
+
### 方法 2: Web 界面
|
| 192 |
+
直接在 HF Space 上传文件。
|
| 193 |
+
|
| 194 |
+
### 验证部署
|
| 195 |
+
```bash
|
| 196 |
+
# 检查健康状态
|
| 197 |
+
curl https://jc321-easyreportdatemcp.hf.space/health
|
| 198 |
+
|
| 199 |
+
# 查看工具列表
|
| 200 |
+
curl https://jc321-easyreportdatemcp.hf.space/tools
|
| 201 |
+
```
|
| 202 |
+
|
| 203 |
+
---
|
| 204 |
+
|
| 205 |
+
## ⚠️ 常见问题
|
| 206 |
+
|
| 207 |
+
### Q: Claude Desktop 看不到工具?
|
| 208 |
+
**A**:
|
| 209 |
+
1. 检查 JSON 配置格式
|
| 210 |
+
2. 确认 URL 以 `/sse` 结尾
|
| 211 |
+
3. 完全退出并重启 Claude Desktop
|
| 212 |
+
|
| 213 |
+
### Q: 工具调用返回错误?
|
| 214 |
+
**A**:
|
| 215 |
+
1. 检查 CIK 格式(10位数字)
|
| 216 |
+
2. 验证期间格式("2024" 或 "2024Q3")
|
| 217 |
+
3. 稍等片刻再试(SEC API 限流)
|
| 218 |
+
|
| 219 |
+
### Q: Space 冷启动慢?
|
| 220 |
+
**A**:
|
| 221 |
+
首次访问需要 30-60 秒唤醒,访问主页即可唤醒。
|
| 222 |
+
|
| 223 |
+
---
|
| 224 |
+
|
| 225 |
+
## 📊 端点参考
|
| 226 |
+
|
| 227 |
+
| 端点 | 说明 |
|
| 228 |
+
|------|------|
|
| 229 |
+
| `/` | 主页(引导页面) |
|
| 230 |
+
| `/sse` | SSE 连接端点(MCP 客户端使用) |
|
| 231 |
+
| `/message` | MCP 消息处理 |
|
| 232 |
+
| `/tools` | 工具列表(JSON) |
|
| 233 |
+
| `/health` | 健康检查 |
|
| 234 |
+
|
| 235 |
+
---
|
| 236 |
+
|
| 237 |
+
## 🎯 数据来源
|
| 238 |
+
|
| 239 |
+
**SEC EDGAR API** - 美国证券交易委员会官方数据
|
| 240 |
+
|
| 241 |
+
**遵守规则**:
|
| 242 |
+
- User-Agent: Juntao Peng Financial Report Metrics App (jtyxabc@gmail.com)
|
| 243 |
+
- 速率限制: 最多 10 请求/秒
|
| 244 |
+
|
| 245 |
+
---
|
| 246 |
+
|
| 247 |
+
## 📞 支持
|
| 248 |
+
|
| 249 |
+
**访问主页**: https://jc321-easyreportdatemcp.hf.space/
|
| 250 |
+
**查看文档**: 主页包含完整的配置说明和示例
|
| 251 |
+
|
| 252 |
+
---
|
| 253 |
+
|
| 254 |
+
**享受你的 MCP Server!** 🚀
|
requirements.txt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# FastAPI RESTful API Server (original)
|
| 2 |
+
fastapi==0.109.0
|
| 3 |
+
uvicorn[standard]==0.27.0
|
| 4 |
+
pydantic==2.5.3
|
| 5 |
+
|
| 6 |
+
# FastMCP - Standard MCP Server
|
| 7 |
+
fastmcp==0.3.0
|
| 8 |
+
|
| 9 |
+
# SEC EDGAR API
|
| 10 |
+
sec-edgar-api==1.1.0
|
| 11 |
+
requests==2.31.0
|
test_mcp_sse.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Test script for MCP Server with SSE transport
|
| 3 |
+
Tests all endpoints and MCP protocol compliance
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import requests
|
| 7 |
+
import json
|
| 8 |
+
import time
|
| 9 |
+
|
| 10 |
+
# Configuration
|
| 11 |
+
BASE_URL = "http://localhost:7860" # Change to your HF Space URL for remote testing
|
| 12 |
+
|
| 13 |
+
def test_health_check():
|
| 14 |
+
"""Test health check endpoint"""
|
| 15 |
+
print("🔍 Testing health check...")
|
| 16 |
+
response = requests.get(f"{BASE_URL}/health")
|
| 17 |
+
print(f"Status: {response.status_code}")
|
| 18 |
+
print(f"Response: {json.dumps(response.json(), indent=2)}")
|
| 19 |
+
assert response.status_code == 200
|
| 20 |
+
assert response.json()["status"] == "healthy"
|
| 21 |
+
print("✅ Health check passed\n")
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def test_tools_list():
|
| 25 |
+
"""Test tools listing endpoint"""
|
| 26 |
+
print("🔍 Testing tools list...")
|
| 27 |
+
response = requests.get(f"{BASE_URL}/tools")
|
| 28 |
+
print(f"Status: {response.status_code}")
|
| 29 |
+
data = response.json()
|
| 30 |
+
print(f"Number of tools: {len(data['tools'])}")
|
| 31 |
+
for tool in data['tools']:
|
| 32 |
+
print(f" - {tool['name']}")
|
| 33 |
+
assert response.status_code == 200
|
| 34 |
+
assert len(data['tools']) == 7
|
| 35 |
+
print("✅ Tools list passed\n")
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def test_mcp_initialize():
|
| 39 |
+
"""Test MCP initialize method"""
|
| 40 |
+
print("🔍 Testing MCP initialize...")
|
| 41 |
+
payload = {
|
| 42 |
+
"jsonrpc": "2.0",
|
| 43 |
+
"id": 1,
|
| 44 |
+
"method": "initialize",
|
| 45 |
+
"params": {
|
| 46 |
+
"protocolVersion": "2024-11-05",
|
| 47 |
+
"capabilities": {},
|
| 48 |
+
"clientInfo": {
|
| 49 |
+
"name": "test-client",
|
| 50 |
+
"version": "1.0.0"
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
response = requests.post(f"{BASE_URL}/message", json=payload)
|
| 55 |
+
print(f"Status: {response.status_code}")
|
| 56 |
+
print(f"Response: {json.dumps(response.json(), indent=2)}")
|
| 57 |
+
assert response.status_code == 200
|
| 58 |
+
assert response.json()["result"]["serverInfo"]["name"] == "sec-financial-data"
|
| 59 |
+
print("✅ MCP initialize passed\n")
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def test_mcp_tools_list():
|
| 63 |
+
"""Test MCP tools/list method"""
|
| 64 |
+
print("🔍 Testing MCP tools/list...")
|
| 65 |
+
payload = {
|
| 66 |
+
"jsonrpc": "2.0",
|
| 67 |
+
"id": 2,
|
| 68 |
+
"method": "tools/list"
|
| 69 |
+
}
|
| 70 |
+
response = requests.post(f"{BASE_URL}/message", json=payload)
|
| 71 |
+
print(f"Status: {response.status_code}")
|
| 72 |
+
data = response.json()
|
| 73 |
+
print(f"Number of tools: {len(data['result']['tools'])}")
|
| 74 |
+
assert response.status_code == 200
|
| 75 |
+
assert len(data['result']['tools']) == 7
|
| 76 |
+
print("✅ MCP tools/list passed\n")
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def test_search_company():
|
| 80 |
+
"""Test search_company tool"""
|
| 81 |
+
print("🔍 Testing search_company tool...")
|
| 82 |
+
payload = {
|
| 83 |
+
"jsonrpc": "2.0",
|
| 84 |
+
"id": 3,
|
| 85 |
+
"method": "tools/call",
|
| 86 |
+
"params": {
|
| 87 |
+
"name": "search_company",
|
| 88 |
+
"arguments": {
|
| 89 |
+
"company_name": "Microsoft"
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
response = requests.post(f"{BASE_URL}/message", json=payload)
|
| 94 |
+
print(f"Status: {response.status_code}")
|
| 95 |
+
data = response.json()
|
| 96 |
+
print(f"Response preview: {data['result']['content'][0]['text'][:200]}...")
|
| 97 |
+
assert response.status_code == 200
|
| 98 |
+
assert "content" in data["result"]
|
| 99 |
+
print("✅ search_company passed\n")
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def test_get_company_info():
|
| 103 |
+
"""Test get_company_info tool"""
|
| 104 |
+
print("🔍 Testing get_company_info tool...")
|
| 105 |
+
payload = {
|
| 106 |
+
"jsonrpc": "2.0",
|
| 107 |
+
"id": 4,
|
| 108 |
+
"method": "tools/call",
|
| 109 |
+
"params": {
|
| 110 |
+
"name": "get_company_info",
|
| 111 |
+
"arguments": {
|
| 112 |
+
"cik": "0000789019" # Microsoft
|
| 113 |
+
}
|
| 114 |
+
}
|
| 115 |
+
}
|
| 116 |
+
response = requests.post(f"{BASE_URL}/message", json=payload)
|
| 117 |
+
print(f"Status: {response.status_code}")
|
| 118 |
+
data = response.json()
|
| 119 |
+
print(f"Response preview: {data['result']['content'][0]['text'][:200]}...")
|
| 120 |
+
assert response.status_code == 200
|
| 121 |
+
print("✅ get_company_info passed\n")
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def test_get_latest_financial_data():
|
| 125 |
+
"""Test get_latest_financial_data tool"""
|
| 126 |
+
print("🔍 Testing get_latest_financial_data tool...")
|
| 127 |
+
payload = {
|
| 128 |
+
"jsonrpc": "2.0",
|
| 129 |
+
"id": 5,
|
| 130 |
+
"method": "tools/call",
|
| 131 |
+
"params": {
|
| 132 |
+
"name": "get_latest_financial_data",
|
| 133 |
+
"arguments": {
|
| 134 |
+
"cik": "0000789019" # Microsoft
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
response = requests.post(f"{BASE_URL}/message", json=payload)
|
| 139 |
+
print(f"Status: {response.status_code}")
|
| 140 |
+
data = response.json()
|
| 141 |
+
print(f"Response preview: {data['result']['content'][0]['text'][:300]}...")
|
| 142 |
+
assert response.status_code == 200
|
| 143 |
+
print("✅ get_latest_financial_data passed\n")
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def test_extract_financial_metrics():
|
| 147 |
+
"""Test extract_financial_metrics tool"""
|
| 148 |
+
print("🔍 Testing extract_financial_metrics tool...")
|
| 149 |
+
payload = {
|
| 150 |
+
"jsonrpc": "2.0",
|
| 151 |
+
"id": 6,
|
| 152 |
+
"method": "tools/call",
|
| 153 |
+
"params": {
|
| 154 |
+
"name": "extract_financial_metrics",
|
| 155 |
+
"arguments": {
|
| 156 |
+
"cik": "0000789019", # Microsoft
|
| 157 |
+
"years": 2
|
| 158 |
+
}
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
response = requests.post(f"{BASE_URL}/message", json=payload)
|
| 162 |
+
print(f"Status: {response.status_code}")
|
| 163 |
+
data = response.json()
|
| 164 |
+
print(f"Response preview: {data['result']['content'][0]['text'][:300]}...")
|
| 165 |
+
assert response.status_code == 200
|
| 166 |
+
print("✅ extract_financial_metrics passed\n")
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def test_sse_endpoint():
|
| 170 |
+
"""Test SSE endpoint (basic connection)"""
|
| 171 |
+
print("🔍 Testing SSE endpoint...")
|
| 172 |
+
try:
|
| 173 |
+
response = requests.get(f"{BASE_URL}/sse", stream=True, timeout=5)
|
| 174 |
+
print(f"Status: {response.status_code}")
|
| 175 |
+
print("Reading first event...")
|
| 176 |
+
|
| 177 |
+
# Read first event
|
| 178 |
+
for line in response.iter_lines():
|
| 179 |
+
if line:
|
| 180 |
+
decoded_line = line.decode('utf-8')
|
| 181 |
+
print(f"Received: {decoded_line}")
|
| 182 |
+
if decoded_line.startswith('data:'):
|
| 183 |
+
break
|
| 184 |
+
|
| 185 |
+
print("✅ SSE endpoint passed\n")
|
| 186 |
+
except requests.exceptions.Timeout:
|
| 187 |
+
print("⚠️ SSE endpoint timeout (expected for streaming)\n")
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
def main():
|
| 191 |
+
"""Run all tests"""
|
| 192 |
+
print("=" * 60)
|
| 193 |
+
print("🧪 MCP Server SSE Transport Test Suite")
|
| 194 |
+
print("=" * 60)
|
| 195 |
+
print()
|
| 196 |
+
|
| 197 |
+
tests = [
|
| 198 |
+
("Health Check", test_health_check),
|
| 199 |
+
("Tools List", test_tools_list),
|
| 200 |
+
("MCP Initialize", test_mcp_initialize),
|
| 201 |
+
("MCP Tools List", test_mcp_tools_list),
|
| 202 |
+
("Search Company", test_search_company),
|
| 203 |
+
("Get Company Info", test_get_company_info),
|
| 204 |
+
("Get Latest Financial Data", test_get_latest_financial_data),
|
| 205 |
+
("Extract Financial Metrics", test_extract_financial_metrics),
|
| 206 |
+
("SSE Endpoint", test_sse_endpoint),
|
| 207 |
+
]
|
| 208 |
+
|
| 209 |
+
passed = 0
|
| 210 |
+
failed = 0
|
| 211 |
+
|
| 212 |
+
for name, test_func in tests:
|
| 213 |
+
try:
|
| 214 |
+
test_func()
|
| 215 |
+
passed += 1
|
| 216 |
+
except Exception as e:
|
| 217 |
+
print(f"❌ {name} failed: {e}\n")
|
| 218 |
+
failed += 1
|
| 219 |
+
|
| 220 |
+
print("=" * 60)
|
| 221 |
+
print(f"✅ Tests passed: {passed}/{len(tests)}")
|
| 222 |
+
if failed > 0:
|
| 223 |
+
print(f"❌ Tests failed: {failed}/{len(tests)}")
|
| 224 |
+
print("=" * 60)
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
if __name__ == "__main__":
|
| 228 |
+
print("\n⚠️ Make sure the server is running:")
|
| 229 |
+
print(" python mcp_server_sse.py\n")
|
| 230 |
+
time.sleep(1)
|
| 231 |
+
main()
|