test_amap_mcp.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. from __future__ import annotations
  2. """测试高德MCP的文本搜索与周边搜索等工具调用。"""
  3. import asyncio
  4. import json
  5. from typing import Any
  6. # 直接运行本文件时(如 python scripts/test_amap_mcp.py),Python 只把 scripts/ 加入 sys.path,
  7. # 找不到项目根的 app 包。此时需要把项目根目录注入 sys.path:
  8. # sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
  9. # 使用 `python -m scripts.test_amap_mcp` 运行时则无需此处理,项目根会自动加入 sys.path。
  10. from rich.console import Console
  11. from rich.table import Table
  12. from langchain_core.tools import BaseTool
  13. from langchain_mcp_adapters.client import MultiServerMCPClient
  14. from app.config import get_settings
  15. console = Console()
  16. def get_tool_schema(tool:BaseTool)->dict[str, Any]:
  17. """兼容不同 LangChain 工具 Schema 表示。"""
  18. schema = tool.args_schema
  19. if schema is None:
  20. return {}
  21. if isinstance(schema,dict):
  22. return schema
  23. if hasattr(schema,"model_json_schema"):
  24. return schema.model_json_schema()
  25. return {}
  26. async def invoke_text_search(tools:list[BaseTool])->None:
  27. """如果发现高德关键词搜索工具,则执行一次真实POI查询。"""
  28. candidate_names = {
  29. "maps_text_search",
  30. "map_text_search",
  31. "text_search",
  32. }
  33. search_tool = next(
  34. (
  35. tool
  36. for tool in tools
  37. if tool.name in candidate_names
  38. or "text_search" in tool.name.lower()
  39. ),
  40. None,
  41. )
  42. if search_tool is None:
  43. console.print(
  44. "[yellow]MCP 已连接成功,但没有匹配到预设的关键词搜索工具名。[/yellow]"
  45. )
  46. console.print(
  47. "这是正常的版本差异。先保留工具列表,后续根据实际名称接入。"
  48. )
  49. return
  50. schema = get_tool_schema(search_tool)
  51. properties = schema.get("properties",{})
  52. # 注意:JSON Schema 中 required 和 properties 是平级字段,不是嵌套关系。
  53. required = schema.get("required",[])
  54. console.rule("[bold]关键词搜索工具 Schema")
  55. console.print_json(json.dumps(schema,ensure_ascii=False))
  56. args:dict[str, Any] = {}
  57. keyword_names = {"keywords","keyword","query"}
  58. city_names = {"city","region"}
  59. for name in properties:
  60. if name in keyword_names:
  61. args[name] = "宽窄巷子"
  62. elif name in city_names:
  63. args[name] = "成都"
  64. missing_required = [
  65. name
  66. for name in required
  67. if name not in args
  68. ]
  69. if missing_required:
  70. console.print(
  71. "[yellow]发现关键词搜索工具,但存在无法自动填充的必填参数:"
  72. f"{missing_required}[/yellow]"
  73. )
  74. return
  75. console.rule("[bold]执行真实 POI 查询")
  76. console.print(f"工具:{search_tool.name}")
  77. console.print(f"参数:{args}")
  78. result = await search_tool.ainvoke(args)
  79. console.print("[green]POI 查询成功:[/green]")
  80. console.print(result)
  81. async def main()->None:
  82. """主函数,用于测试高德关键词搜索工具。"""
  83. settings = get_settings()
  84. # 高德 key 在 modelscope MCP 端点中通常通过 URL token 鉴权,这里读取备用。
  85. settings.require("amap_api_key")
  86. mcp_client = MultiServerMCPClient(
  87. {
  88. "amap": {
  89. "transport": "streamable_http",
  90. "url": "https://mcp.api-inference.modelscope.net/8ac378c1961447/mcp",
  91. }
  92. }
  93. )
  94. console.rule("[bold]连接 高德MCP")
  95. tools = await mcp_client.get_tools()
  96. if not tools:
  97. raise RuntimeError("MCP 连接成功,但服务端未返回任何工具")
  98. table = Table(title=f"高德MCP 工具列表,共{len(tools)}个")
  99. table.add_column("序号")
  100. table.add_column("工具名")
  101. table.add_column("说明")
  102. for index,tool in enumerate(tools,start=1):
  103. description = (tool.description or "").replace("\n"," ")
  104. table.add_row(
  105. str(index),
  106. tool.name,
  107. description[:100],
  108. )
  109. console.print(table)
  110. await invoke_text_search(tools)
  111. if __name__ == "__main__":
  112. try:
  113. asyncio.run(main())
  114. except Exception as e:
  115. console.print(f"[red]高德mcp测试失败:{type(e).__name__}:{e}[/red]")
  116. raise SystemExit(1) from e