agentscope-ai / agentscope-ai/QwenPaw
[Bug]: MCP driver ignoring transport config \u2014 hardcoded SSE client breaks streamable_http servers
- Ngôn ngữ chính
- Python
- Star
- 34.9k
- Fork
- 3.1k
- Merge trung bình
- 1 ngày 15 giờ
- Pull request đã merge (30 ngày)
- 225
Mô tả
## QwenPaw Version
v2.0.1 (Windows, exe installer)
## Description
MCP driver 在建立 transport 连接时硬编码使用了 `sse_client`,完全忽略了 YAML 配置文件中指定的 `transport: streamable_http`。这导致所有配置为 Streamable HTTP 传输协议的 MCP 服务器连接失败,工具无法加载。
**根因**:`mcp_stateful_client.py` 约第 800 行的 `_setup_transport` 方法直接调用 `mcp.client.sse.sse_client()`,没有读取配置中的 transport 字段来决定使用 `sse_client` 还是 `streamablehttp_client`。
**影响**:所有使用 `transport: streamable_http` 的 MCP 驱动(如 Jin10 金融数据 MCP)均无法工作。
**相关 PR(s):** 无
**安全考量:** 无
## Component(s) Affected
- [x] Core / Backend (app, agents, config, providers, utils, local_models)
- [ ] Console (frontend web UI)
- [ ] Channels (DingTalk, Feishu, QQ, Discord, iMessage, etc.)
- [x] Skills
- [ ] CLI
- [ ] Documentation (website)
- [ ] Tests
- [ ] CI/CD
- [ ] Scripts / Deploy
## Environment
- **QwenPaw 版本:** v2.0.1
- **操作系统:** Windows 10 (AMD64)
- **安装方式:** exe 安装包
- **Python 版本:** 3.11 (bundled in exe)
## Steps to Reproduce
1. 配置一个使用 `transport: streamable_http` 的 MCP 驱动,例如 Jin10 金融数据 MCP:
```yaml
# drivers/mcp/jin10.yaml
name: jin10
transport: streamable_http
url: https://mcp.jin10.com/mcp
headers:
Authorization: "Bearer "
```
2. 确保 `credentials.yaml` 中有对应的凭证条目。
3. 重启 QwenPaw daemon。
4. 在 Agent 中尝试调用 Jin10 MCP 工具(如 `list_calendar`)。
5. 观察 daemon 日志和工具调用结果。
## Actual vs Expected
- **Actual:**
- Daemon 启动时日志报错:`Error in MCP client lifecycle for jin10`
- 完整错误堆栈:
```
File "qwenpaw\drivers\handlers\mcp_stateful_client.py", line 157, in _run_lifecycle
File "qwenpaw\drivers\handlers\mcp_stateful_client.py", line 800, in _setup_transport
File "contextlib.py", line 650, in enter_async_context
File "mcp\client\sse.py", line 62, in sse_client
...
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://mcp.jin10.com/mcp'
```
- MCP 工具列表为空,Agent 无法调用任何 Jin10 工具。
- 框架重试 10+ 次后超时,MCP 驱动完全不可用。
- **Expected:**
- 框架应读取 YAML 中的 `transport: streamable_http` 配置。
- 使用 `mcp.client.streamablehttp.streamablehttp_client()` 建立连接。
- Jin10 MCP 工具正常加载并可调用。
## Root Cause Analysis
### 证据 1:daemon 日志
```
2026-07-25 08:45:02 | ERROR | mcp_stateful_client.py:203 | Error in MCP client lifecycle for jin10:
+ Exception Group Traceback:
| File "qwenpaw\drivers\handlers\mcp_stateful_client.py", line 157, in _run_lifecycle
| File "qwenpaw\drivers\handlers\mcp_stateful_client.py", line 800, in _setup_transport
| File "contextlib.py", line 650, in enter_async_context
| File "mcp\client\sse.py", line 62, in sse_client \u2190 hardcoded SSE
| ...
| httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://mcp.jin10.com/mcp'
```
### 证据 2:raw HTTP 对比测试
使用原生 HTTP POST 直接调用金十 MCP 服务端(Streamable HTTP 协议):
```bash
# initialize \u2192 success,获得 session ID
curl -X POST https://mcp.jin10.com/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer " \
-d '{"jsonrpc":"2.0","id":"1","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
# tools/list \u2192 success,returns 8 tools
# tools/call list_calendar \u2192 success,returns full calendar data
```
**Conclusion**: The Jin10 MCP server is online and Streamable HTTP protocol works correctly. The issue is entirely on the framework side.
### 证据 3:YAML 配置正确
```yaml
# Both workspaces have identical jin10.yaml:
transport: streamable_http \u2190 config is correct
url: https://mcp.jin10.com/mcp
```
## Suggested Fix
Modify `qwenpaw/drivers/handlers/mcp_stateful_client.py` around line 800, the `_setup_transport` method:
**Current code (pseudocode)**:
```python
async def _setup_transport(self):
# Line 800 - hardcoded SSE
async with sse_client(url, headers=headers) as (read_stream, write_stream, _):
...
```
**Suggested fix**:
```python
async def _setup_transport(self):
transport = self.endpoint_config.get("transport", "sse")
if transport == "streamable_http":
from mcp.client.streamablehttp import streamablehttp_client
async with streamablehttp_client(url, headers=headers) as (read_stream, write_stream, _):
...
else:
async with sse_client(url, headers=headers) as (read_stream, write_stream, _):
...
```
**Key points**:
1. Read `transport` field from `self.endpoint_config` (or equivalent config object)
2. Select `streamablehttp_client` or `sse_client` based on the value
3. Maintain backward compatibility: drivers without transport config or with `sse` still use SSE
## Workaround
Before the framework fix, use an independent Python script to bypass the MCP driver:
```bash
python jin10_client.py list_calendar # Economic calendar
python jin10_client.py list_flash # Flash news
python jin10_client.py search_flash --keyword "央行"
python jin10_client.py stock_quotes --market_codes SH,SZ
```
The script uses raw HTTP + Streamable HTTP protocol with 3-layer defense (session rebuild / ping detection / error retry), tested stable.
## Impact
- Affects all MCP drivers configured with `transport: streamable_http`
- Currently known affected MCP: Jin10 financial data
- MCP drivers using default SSE transport (e.g. tavily_search) are NOT affected
- Fix should ensure backward compatibility
## Additional Context
- MCP SDK version: mcp Python SDK (QwenPaw v2.0.1 bundled)
- Streamable HTTP transport: `mcp/client/streamablehttp.py`
- SSE transport: `mcp/client/sse.py`
- Reproducible in both `default` and `cloud-orchestrator` workspaces
- Framework code is compiled in exe, users cannot modify source code, requires official update
Hướng dẫn đóng góp
Đánh giá
Issue này chưa được đánh giá.