chore: upgrade Pipecat to 1.13.0 and adapt MCP 2.x

This commit is contained in:
Xin Wang
2026-10-23 14:03:42 +08:00
parent 81a6fdc30c
commit d45be1e686
4 changed files with 95 additions and 15 deletions
+77 -1
View File
@@ -1,13 +1,89 @@
import json
import unittest
from contextlib import asynccontextmanager
from unittest.mock import patch
import httpx2
from models import RuntimeMcpServer
from schemas import McpServerUpsert
from services.tools.mcp_client import McpToolClient
from services.tools.mcp_client import McpClientError, McpToolClient
class McpTransportTests(unittest.IsolatedAsyncioTestCase):
async def test_streamable_http_discovery_and_call_with_real_sdk(self):
requests = []
def respond(request):
self.assertEqual(request.headers["Authorization"], "Bearer test")
message = json.loads(request.content)
requests.append(message)
if "id" not in message:
return httpx2.Response(202)
if message["method"] == "initialize":
result = {
"protocolVersion": "2025-06-18",
"capabilities": {"tools": {}},
"serverInfo": {"name": "test", "version": "1"},
}
elif message["method"] == "tools/list":
if (message.get("params") or {}).get("cursor") == "page2":
result = {"tools": []}
else:
result = {
"tools": [{
"name": "get_order",
"inputSchema": {"type": "object", "properties": {}},
}],
"nextCursor": "page2",
}
elif message["method"] == "tools/call":
result = {
"content": [{"type": "text", "text": "已发货"}],
"structuredContent": {"status": "shipped"},
}
else:
self.fail(f"Unexpected MCP method: {message['method']}")
return httpx2.Response(200, json={
"jsonrpc": "2.0", "id": message["id"], "result": result,
})
client_class = httpx2.AsyncClient
def client_factory(**kwargs):
return client_class(transport=httpx2.MockTransport(respond), **kwargs)
server = RuntimeMcpServer(
id="mcp_http",
url="https://mcp.example.com/mcp",
secret_headers={"Authorization": "Bearer test"},
)
client = McpToolClient()
with patch("services.tools.mcp_client.httpx.AsyncClient", client_factory):
tools = await client.list_tools(server)
listings = [item for item in requests if item["method"] == "tools/list"]
self.assertEqual(len(listings), 2)
self.assertEqual(listings[1]["params"]["cursor"], "page2")
result = await client.call_tool(server, "get_order", {"order_id": "A-100"})
self.assertEqual(tools[0]["name"], "get_order")
self.assertEqual(result["text"], "已发货")
self.assertEqual(result["structuredContent"], {"status": "shipped"})
call = next(item for item in requests if item["method"] == "tools/call")
self.assertEqual(call["params"]["arguments"], {"order_id": "A-100"})
async def test_sdk_timeout_has_readable_error(self):
@asynccontextmanager
async def timed_out(*args):
raise httpx2.ReadTimeout("read timed out")
yield
server = RuntimeMcpServer(id="mcp_timeout", url="https://mcp.example.com/mcp")
client = McpToolClient()
with patch.object(client, "_transport_streams", timed_out):
with self.assertRaisesRegex(McpClientError, "超时"):
await client.list_tools(server)
def test_server_schema_accepts_sse(self):
server = McpServerUpsert(
name="旧版 MCP 服务",