futu-stock-mcp-server 0.1.0__py3-none-any.whl → 0.1.2__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 futu-stock-mcp-server might be problematic. Click here for more details.
- futu_stock_mcp_server/server.py +38 -11
- {futu_stock_mcp_server-0.1.0.dist-info → futu_stock_mcp_server-0.1.2.dist-info}/METADATA +176 -10
- futu_stock_mcp_server-0.1.2.dist-info/RECORD +7 -0
- {futu_stock_mcp_server-0.1.0.dist-info → futu_stock_mcp_server-0.1.2.dist-info}/licenses/LICENSE +1 -1
- futu_stock_mcp_server-0.1.0.dist-info/RECORD +0 -7
- {futu_stock_mcp_server-0.1.0.dist-info → futu_stock_mcp_server-0.1.2.dist-info}/WHEEL +0 -0
- {futu_stock_mcp_server-0.1.0.dist-info → futu_stock_mcp_server-0.1.2.dist-info}/entry_points.txt +0 -0
futu_stock_mcp_server/server.py
CHANGED
|
@@ -42,13 +42,20 @@ logger.add(
|
|
|
42
42
|
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}"
|
|
43
43
|
)
|
|
44
44
|
|
|
45
|
-
# Add console handler
|
|
45
|
+
# Add console handler - output to stderr to avoid polluting MCP JSON communication
|
|
46
46
|
logger.add(
|
|
47
|
-
|
|
47
|
+
sys.stderr,
|
|
48
48
|
level="INFO",
|
|
49
|
-
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}"
|
|
49
|
+
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
|
|
50
|
+
colorize=False # Disable colors to avoid ANSI escape sequences
|
|
50
51
|
)
|
|
51
52
|
|
|
53
|
+
# Suppress other library logs that might interfere with MCP communication
|
|
54
|
+
import logging
|
|
55
|
+
logging.getLogger().setLevel(logging.WARNING) # Suppress INFO logs from other libraries
|
|
56
|
+
logging.getLogger("mcp").setLevel(logging.WARNING) # Suppress MCP internal logs
|
|
57
|
+
logging.getLogger("futu").setLevel(logging.WARNING) # Suppress Futu API logs
|
|
58
|
+
|
|
52
59
|
logger.info(f"Starting server with log directory: {log_dir}")
|
|
53
60
|
|
|
54
61
|
# PID file path
|
|
@@ -167,15 +174,24 @@ def signal_handler(signum, frame):
|
|
|
167
174
|
"""Handle process signals"""
|
|
168
175
|
global _is_shutting_down
|
|
169
176
|
if _is_shutting_down:
|
|
170
|
-
|
|
177
|
+
logger.info("Already shutting down, forcing exit...")
|
|
178
|
+
os._exit(1)
|
|
171
179
|
|
|
172
180
|
# 只处理 SIGINT 和 SIGTERM
|
|
173
181
|
if signum not in (signal.SIGINT, signal.SIGTERM):
|
|
174
182
|
return
|
|
175
183
|
|
|
176
184
|
logger.info(f"Received signal {signum}, cleaning up...")
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
_is_shutting_down = True
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
cleanup_all()
|
|
189
|
+
logger.info("Cleanup completed, exiting...")
|
|
190
|
+
except Exception as e:
|
|
191
|
+
logger.error(f"Error during cleanup: {e}")
|
|
192
|
+
finally:
|
|
193
|
+
# 强制退出,确保进程能够终止
|
|
194
|
+
os._exit(0)
|
|
179
195
|
|
|
180
196
|
# Register cleanup functions
|
|
181
197
|
atexit.register(cleanup_all)
|
|
@@ -1438,8 +1454,13 @@ async def get_current_time() -> Dict[str, Any]:
|
|
|
1438
1454
|
'timezone': datetime.now().astimezone().tzname()
|
|
1439
1455
|
}
|
|
1440
1456
|
|
|
1441
|
-
|
|
1457
|
+
def main():
|
|
1458
|
+
"""Main entry point for the futu-mcp-server command."""
|
|
1442
1459
|
try:
|
|
1460
|
+
# Ensure no color output in MCP mode
|
|
1461
|
+
os.environ['NO_COLOR'] = '1'
|
|
1462
|
+
os.environ['TERM'] = 'dumb'
|
|
1463
|
+
|
|
1443
1464
|
# 清理旧的进程和文件
|
|
1444
1465
|
cleanup_stale_processes()
|
|
1445
1466
|
|
|
@@ -1457,19 +1478,25 @@ if __name__ == "__main__":
|
|
|
1457
1478
|
if init_futu_connection():
|
|
1458
1479
|
logger.info("Successfully initialized Futu connection")
|
|
1459
1480
|
logger.info("Starting MCP server in stdio mode...")
|
|
1481
|
+
logger.info("Press Ctrl+C to stop the server")
|
|
1460
1482
|
try:
|
|
1461
1483
|
mcp.run(transport='stdio')
|
|
1462
1484
|
except KeyboardInterrupt:
|
|
1463
1485
|
logger.info("Received keyboard interrupt, shutting down...")
|
|
1464
|
-
|
|
1486
|
+
cleanup_all()
|
|
1487
|
+
os._exit(0)
|
|
1465
1488
|
except Exception as e:
|
|
1466
1489
|
logger.error(f"Error running server: {str(e)}")
|
|
1467
|
-
|
|
1490
|
+
cleanup_all()
|
|
1491
|
+
os._exit(1)
|
|
1468
1492
|
else:
|
|
1469
1493
|
logger.error("Failed to initialize Futu connection. Server will not start.")
|
|
1470
|
-
|
|
1494
|
+
os._exit(1)
|
|
1471
1495
|
except Exception as e:
|
|
1472
1496
|
logger.error(f"Error starting server: {str(e)}")
|
|
1473
1497
|
sys.exit(1)
|
|
1474
1498
|
finally:
|
|
1475
|
-
cleanup_all()
|
|
1499
|
+
cleanup_all()
|
|
1500
|
+
|
|
1501
|
+
if __name__ == "__main__":
|
|
1502
|
+
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: futu-stock-mcp-server
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A Model Context Protocol (MCP) server for accessing Futu OpenAPI functionality
|
|
5
5
|
Project-URL: Homepage, https://github.com/shuizhengqi1/futu-stock-mcp-server
|
|
6
6
|
Project-URL: Documentation, https://github.com/shuizhengqi1/futu-stock-mcp-server#readme
|
|
@@ -40,6 +40,8 @@ Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
|
40
40
|
Requires-Dist: ruff; extra == 'dev'
|
|
41
41
|
Description-Content-Type: text/markdown
|
|
42
42
|
|
|
43
|
+
[](https://mseep.ai/app/shuizhengqi1-futu-stocp-mcp-server)
|
|
44
|
+
|
|
43
45
|
# Futu Stock MCP Server
|
|
44
46
|
|
|
45
47
|
[](https://www.python.org)
|
|
@@ -101,16 +103,25 @@ Description-Content-Type: text/markdown
|
|
|
101
103
|
|
|
102
104
|
## 🚀 快速开始
|
|
103
105
|
|
|
104
|
-
### 方式一:通过
|
|
106
|
+
### 方式一:通过 pipx 安装(推荐)
|
|
105
107
|
|
|
106
108
|
```bash
|
|
109
|
+
# 安装 pipx(如果还没有安装)
|
|
110
|
+
brew install pipx # macOS
|
|
111
|
+
# 或者 pip install --user pipx # 其他系统
|
|
112
|
+
|
|
107
113
|
# 安装包
|
|
108
|
-
|
|
114
|
+
pipx install futu-stock-mcp-server
|
|
109
115
|
|
|
110
116
|
# 运行服务器
|
|
111
117
|
futu-mcp-server
|
|
112
118
|
```
|
|
113
119
|
|
|
120
|
+
> **为什么使用 pipx?**
|
|
121
|
+
> - pipx 专门用于安装 Python 应用程序到全局环境
|
|
122
|
+
> - 自动管理独立的虚拟环境,避免依赖冲突
|
|
123
|
+
> - 命令直接可用,无需激活虚拟环境
|
|
124
|
+
|
|
114
125
|
### 方式二:通过 Docker 运行
|
|
115
126
|
|
|
116
127
|
```bash
|
|
@@ -216,22 +227,61 @@ Run formatting:
|
|
|
216
227
|
ruff format .
|
|
217
228
|
```
|
|
218
229
|
|
|
219
|
-
##
|
|
230
|
+
## 🔧 MCP Server 配置
|
|
220
231
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
232
|
+
### 在 Claude Desktop 中配置
|
|
233
|
+
|
|
234
|
+
1. **找到配置文件位置**:
|
|
235
|
+
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
236
|
+
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
237
|
+
|
|
238
|
+
2. **添加服务器配置**:
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"mcpServers": {
|
|
242
|
+
"futu-stock": {
|
|
243
|
+
"command": "futu-mcp-server",
|
|
244
|
+
"env": {
|
|
245
|
+
"FUTU_HOST": "127.0.0.1",
|
|
246
|
+
"FUTU_PORT": "11111"
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
3. **故障排除配置**:
|
|
254
|
+
如果上述配置不工作,可以尝试使用完整路径:
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"mcpServers": {
|
|
258
|
+
"futu-stock": {
|
|
259
|
+
"command": "/Users/your-username/.local/bin/futu-mcp-server",
|
|
260
|
+
"env": {
|
|
261
|
+
"FUTU_HOST": "127.0.0.1",
|
|
262
|
+
"FUTU_PORT": "11111"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
224
267
|
```
|
|
225
268
|
|
|
226
|
-
|
|
269
|
+
> **提示**:使用 `which futu-mcp-server` 命令查看完整路径
|
|
270
|
+
|
|
271
|
+
### 在其他 MCP 客户端中配置
|
|
272
|
+
|
|
273
|
+
#### 使用 Python MCP 客户端
|
|
227
274
|
```python
|
|
228
275
|
from mcp import ClientSession, StdioServerParameters
|
|
229
276
|
from mcp.client.stdio import stdio_client
|
|
230
277
|
|
|
231
278
|
async def main():
|
|
232
279
|
server_params = StdioServerParameters(
|
|
233
|
-
command="
|
|
234
|
-
|
|
280
|
+
command="futu-mcp-server",
|
|
281
|
+
env={
|
|
282
|
+
"FUTU_HOST": "127.0.0.1",
|
|
283
|
+
"FUTU_PORT": "11111"
|
|
284
|
+
}
|
|
235
285
|
)
|
|
236
286
|
|
|
237
287
|
async with stdio_client(server_params) as (read, write):
|
|
@@ -241,7 +291,123 @@ async def main():
|
|
|
241
291
|
|
|
242
292
|
# List available tools
|
|
243
293
|
tools = await session.list_tools()
|
|
294
|
+
print("Available tools:", [tool.name for tool in tools.tools])
|
|
295
|
+
```
|
|
244
296
|
|
|
297
|
+
#### 使用 Node.js MCP 客户端
|
|
298
|
+
```javascript
|
|
299
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
300
|
+
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
301
|
+
|
|
302
|
+
const transport = new StdioClientTransport({
|
|
303
|
+
command: "futu-mcp-server",
|
|
304
|
+
env: {
|
|
305
|
+
FUTU_HOST: "127.0.0.1",
|
|
306
|
+
FUTU_PORT: "11111"
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const client = new Client({
|
|
311
|
+
name: "futu-stock-client",
|
|
312
|
+
version: "1.0.0"
|
|
313
|
+
}, {
|
|
314
|
+
capabilities: {}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
await client.connect(transport);
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## 📋 使用方法
|
|
321
|
+
|
|
322
|
+
### 1. 启动服务器(独立运行)
|
|
323
|
+
```bash
|
|
324
|
+
# 通过 pip 安装后
|
|
325
|
+
futu-mcp-server
|
|
326
|
+
|
|
327
|
+
# 或从源码运行
|
|
328
|
+
python -m futu_stock_mcp_server.server
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### 2. 环境变量配置
|
|
332
|
+
创建 `.env` 文件或设置环境变量:
|
|
333
|
+
```bash
|
|
334
|
+
FUTU_HOST=127.0.0.1
|
|
335
|
+
FUTU_PORT=11111
|
|
336
|
+
LOG_LEVEL=INFO
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### 3. 验证连接
|
|
340
|
+
启动服务器后,你应该看到类似的日志:
|
|
341
|
+
```
|
|
342
|
+
2024-10-02 14:20:52 | INFO | Initializing Futu connection...
|
|
343
|
+
2024-10-02 14:20:52 | INFO | Successfully initialized Futu connection
|
|
344
|
+
2024-10-02 14:20:52 | INFO | Starting MCP server in stdio mode...
|
|
345
|
+
2024-10-02 14:20:52 | INFO | Press Ctrl+C to stop the server
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 4. 在 AI 工具中使用
|
|
349
|
+
配置完成后,重启 Claude Desktop 或其他 MCP 客户端,你就可以:
|
|
350
|
+
- 查询股票实时行情
|
|
351
|
+
- 获取历史K线数据
|
|
352
|
+
- 订阅股票数据推送
|
|
353
|
+
- 查询账户信息
|
|
354
|
+
- 执行交易操作(需要交易权限)
|
|
355
|
+
|
|
356
|
+
## 🔧 故障排除
|
|
357
|
+
|
|
358
|
+
### 常见问题
|
|
359
|
+
|
|
360
|
+
#### 1. 命令 `futu-mcp-server` 找不到
|
|
361
|
+
```bash
|
|
362
|
+
# 确保已正确安装
|
|
363
|
+
pipx install futu-stock-mcp-server
|
|
364
|
+
|
|
365
|
+
# 检查命令是否可用
|
|
366
|
+
which futu-mcp-server
|
|
367
|
+
|
|
368
|
+
# 如果还是找不到,检查 PATH
|
|
369
|
+
echo $PATH | grep -o '[^:]*\.local/bin[^:]*'
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
#### 2. Ctrl+C 无法退出服务器
|
|
373
|
+
- 新版本已修复此问题
|
|
374
|
+
- 如果仍然遇到,可以使用 `kill -9 <pid>` 强制终止
|
|
375
|
+
|
|
376
|
+
#### 3. 连接富途 OpenD 失败
|
|
377
|
+
```bash
|
|
378
|
+
# 检查 OpenD 是否运行
|
|
379
|
+
netstat -an | grep 11111
|
|
380
|
+
|
|
381
|
+
# 检查环境变量
|
|
382
|
+
echo $FUTU_HOST
|
|
383
|
+
echo $FUTU_PORT
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
#### 4. Claude Desktop 无法识别服务器
|
|
387
|
+
- 确保配置文件路径正确
|
|
388
|
+
- 检查 JSON 格式是否有效
|
|
389
|
+
- 重启 Claude Desktop
|
|
390
|
+
- 查看 Claude Desktop 的日志文件
|
|
391
|
+
|
|
392
|
+
#### 5. 权限问题
|
|
393
|
+
```bash
|
|
394
|
+
# 确保有执行权限
|
|
395
|
+
chmod +x ~/.local/bin/futu-mcp-server
|
|
396
|
+
|
|
397
|
+
# 或者使用完整路径
|
|
398
|
+
python -m futu_stock_mcp_server.server
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### 日志调试
|
|
402
|
+
启用详细日志:
|
|
403
|
+
```bash
|
|
404
|
+
export LOG_LEVEL=DEBUG
|
|
405
|
+
futu-mcp-server
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
日志文件位置:`./logs/futu_server.log`
|
|
409
|
+
tools = await session.list_tools()
|
|
410
|
+
|
|
245
411
|
# Call a tool
|
|
246
412
|
result = await session.call_tool(
|
|
247
413
|
"get_stock_quote",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
futu_stock_mcp_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
futu_stock_mcp_server/server.py,sha256=xFtYbURXhj0DOkbCFgwHDKHCAATWlSxdBZudrWsodVc,52810
|
|
3
|
+
futu_stock_mcp_server-0.1.2.dist-info/METADATA,sha256=CmSaX6UUSExUdbci62zSZER2udDlV6Fqfqd3SSYHSlg,20453
|
|
4
|
+
futu_stock_mcp_server-0.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
5
|
+
futu_stock_mcp_server-0.1.2.dist-info/entry_points.txt,sha256=GAdKqPJD9dJ_fRA3e3m0NRia0elN5OcjEeAI30vOcIM,70
|
|
6
|
+
futu_stock_mcp_server-0.1.2.dist-info/licenses/LICENSE,sha256=XQBSQkjjpkymu_uLdyis4oNynV60VH1X7nS16uwM6g0,1069
|
|
7
|
+
futu_stock_mcp_server-0.1.2.dist-info/RECORD,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
futu_stock_mcp_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
futu_stock_mcp_server/server.py,sha256=UcP4esdCD2BlPhsdok0OrhBu_ipGnTaI1VUtGAI_-pY,51723
|
|
3
|
-
futu_stock_mcp_server-0.1.0.dist-info/METADATA,sha256=QEbY7SIHGOZzsKTzQmayzDkvXd2VkhTrELHKsxT5KT4,16529
|
|
4
|
-
futu_stock_mcp_server-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
5
|
-
futu_stock_mcp_server-0.1.0.dist-info/entry_points.txt,sha256=GAdKqPJD9dJ_fRA3e3m0NRia0elN5OcjEeAI30vOcIM,70
|
|
6
|
-
futu_stock_mcp_server-0.1.0.dist-info/licenses/LICENSE,sha256=0sCjXbZOqpxlrCLnRTr9M9mNvvltzqUqzyK8d42nMN0,1078
|
|
7
|
-
futu_stock_mcp_server-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
{futu_stock_mcp_server-0.1.0.dist-info → futu_stock_mcp_server-0.1.2.dist-info}/entry_points.txt
RENAMED
|
File without changes
|