mcp_client.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. from __future__ import annotations
  2. """MCP工具加载器:连接自建旅行MCP与高德MCP两个服务器,校验必需工具存在后打包为MCPToolBundle供Agent使用。"""
  3. import sys
  4. from dataclasses import dataclass
  5. from langchain_core.tools import BaseTool
  6. from langchain_mcp_adapters.client import (
  7. MultiServerMCPClient,
  8. )
  9. from app.config import get_settings
  10. TRAVEL_TOOL_NAMES = {
  11. "search_airports",
  12. "search_flights",
  13. "search_return_flights",
  14. "search_hotels",
  15. }
  16. @dataclass
  17. class MCPToolBundle:
  18. """项目使用的全部MCP工具。"""
  19. client: MultiServerMCPClient
  20. all_tools: list[BaseTool]
  21. travel_tools: list[BaseTool]
  22. amap_tools: list[BaseTool]
  23. async def load_mcp_tools() -> MCPToolBundle:
  24. """连接自建旅行MCP和高德MCP。"""
  25. settings = get_settings()
  26. client = MultiServerMCPClient(
  27. {
  28. "travel_search": {
  29. # 使用当前虚拟环境的Python启动本地Server。
  30. "transport": "stdio",
  31. "command": sys.executable,
  32. "args": [
  33. "-m",
  34. "mcp_servers.travel_search_server",
  35. ],
  36. },
  37. "amap": {
  38. # LangChain配置中写http,
  39. # 实际协议为Streamable HTTP。
  40. "transport": "http",
  41. "url": (
  42. "https://mcp.amap.com/mcp"
  43. f"?key={settings.require('amap_api_key')}"
  44. ),
  45. },
  46. }
  47. )
  48. all_tools = await client.get_tools()
  49. travel_tools = [
  50. tool
  51. for tool in all_tools
  52. if tool.name in TRAVEL_TOOL_NAMES
  53. ]
  54. amap_tools = [
  55. tool
  56. for tool in all_tools
  57. if tool.name.startswith("maps_")
  58. ]
  59. loaded_travel_names = {
  60. tool.name
  61. for tool in travel_tools
  62. }
  63. missing_tools = (
  64. TRAVEL_TOOL_NAMES
  65. - loaded_travel_names
  66. )
  67. if missing_tools:
  68. raise RuntimeError(
  69. "旅行MCP缺少工具:"
  70. + "、".join(sorted(missing_tools))
  71. )
  72. if not amap_tools:
  73. raise RuntimeError(
  74. "没有从高德MCP加载到任何地图工具。"
  75. )
  76. return MCPToolBundle(
  77. client=client,
  78. all_tools=all_tools,
  79. travel_tools=travel_tools,
  80. amap_tools=amap_tools,
  81. )