| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- from __future__ import annotations
- """MCP工具加载器:连接自建旅行MCP与高德MCP两个服务器,校验必需工具存在后打包为MCPToolBundle供Agent使用。"""
- import sys
- from dataclasses import dataclass
- from langchain_core.tools import BaseTool
- from langchain_mcp_adapters.client import (
- MultiServerMCPClient,
- )
- from app.config import get_settings
- TRAVEL_TOOL_NAMES = {
- "search_airports",
- "search_flights",
- "search_return_flights",
- "search_hotels",
- }
- @dataclass
- class MCPToolBundle:
- """项目使用的全部MCP工具。"""
- client: MultiServerMCPClient
- all_tools: list[BaseTool]
- travel_tools: list[BaseTool]
- amap_tools: list[BaseTool]
- async def load_mcp_tools() -> MCPToolBundle:
- """连接自建旅行MCP和高德MCP。"""
- settings = get_settings()
- client = MultiServerMCPClient(
- {
- "travel_search": {
- # 使用当前虚拟环境的Python启动本地Server。
- "transport": "stdio",
- "command": sys.executable,
- "args": [
- "-m",
- "mcp_servers.travel_search_server",
- ],
- },
- "amap": {
- # LangChain配置中写http,
- # 实际协议为Streamable HTTP。
- "transport": "http",
- "url": (
- "https://mcp.amap.com/mcp"
- f"?key={settings.require('amap_api_key')}"
- ),
- },
- }
- )
- all_tools = await client.get_tools()
- travel_tools = [
- tool
- for tool in all_tools
- if tool.name in TRAVEL_TOOL_NAMES
- ]
- amap_tools = [
- tool
- for tool in all_tools
- if tool.name.startswith("maps_")
- ]
- loaded_travel_names = {
- tool.name
- for tool in travel_tools
- }
- missing_tools = (
- TRAVEL_TOOL_NAMES
- - loaded_travel_names
- )
- if missing_tools:
- raise RuntimeError(
- "旅行MCP缺少工具:"
- + "、".join(sorted(missing_tools))
- )
- if not amap_tools:
- raise RuntimeError(
- "没有从高德MCP加载到任何地图工具。"
- )
- return MCPToolBundle(
- client=client,
- all_tools=all_tools,
- travel_tools=travel_tools,
- amap_tools=amap_tools,
- )
|