| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- from __future__ import annotations
- """测试高德MCP的文本搜索与周边搜索等工具调用。"""
- import asyncio
- import json
- from typing import Any
- # 直接运行本文件时(如 python scripts/test_amap_mcp.py),Python 只把 scripts/ 加入 sys.path,
- # 找不到项目根的 app 包。此时需要把项目根目录注入 sys.path:
- # sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
- # 使用 `python -m scripts.test_amap_mcp` 运行时则无需此处理,项目根会自动加入 sys.path。
- from rich.console import Console
- from rich.table import Table
- from langchain_core.tools import BaseTool
- from langchain_mcp_adapters.client import MultiServerMCPClient
- from app.config import get_settings
- console = Console()
- def get_tool_schema(tool:BaseTool)->dict[str, Any]:
- """兼容不同 LangChain 工具 Schema 表示。"""
- schema = tool.args_schema
- if schema is None:
- return {}
- if isinstance(schema,dict):
- return schema
- if hasattr(schema,"model_json_schema"):
- return schema.model_json_schema()
- return {}
- async def invoke_text_search(tools:list[BaseTool])->None:
- """如果发现高德关键词搜索工具,则执行一次真实POI查询。"""
- candidate_names = {
- "maps_text_search",
- "map_text_search",
- "text_search",
- }
- search_tool = next(
- (
- tool
- for tool in tools
- if tool.name in candidate_names
- or "text_search" in tool.name.lower()
- ),
- None,
- )
- if search_tool is None:
- console.print(
- "[yellow]MCP 已连接成功,但没有匹配到预设的关键词搜索工具名。[/yellow]"
- )
- console.print(
- "这是正常的版本差异。先保留工具列表,后续根据实际名称接入。"
- )
- return
-
- schema = get_tool_schema(search_tool)
- properties = schema.get("properties",{})
- # 注意:JSON Schema 中 required 和 properties 是平级字段,不是嵌套关系。
- required = schema.get("required",[])
- console.rule("[bold]关键词搜索工具 Schema")
- console.print_json(json.dumps(schema,ensure_ascii=False))
- args:dict[str, Any] = {}
- keyword_names = {"keywords","keyword","query"}
- city_names = {"city","region"}
-
- for name in properties:
- if name in keyword_names:
- args[name] = "宽窄巷子"
- elif name in city_names:
- args[name] = "成都"
- missing_required = [
- name
- for name in required
- if name not in args
- ]
- if missing_required:
- console.print(
- "[yellow]发现关键词搜索工具,但存在无法自动填充的必填参数:"
- f"{missing_required}[/yellow]"
- )
- return
-
- console.rule("[bold]执行真实 POI 查询")
- console.print(f"工具:{search_tool.name}")
- console.print(f"参数:{args}")
- result = await search_tool.ainvoke(args)
- console.print("[green]POI 查询成功:[/green]")
- console.print(result)
- async def main()->None:
- """主函数,用于测试高德关键词搜索工具。"""
- settings = get_settings()
- # 高德 key 在 modelscope MCP 端点中通常通过 URL token 鉴权,这里读取备用。
- settings.require("amap_api_key")
- mcp_client = MultiServerMCPClient(
- {
- "amap": {
- "transport": "streamable_http",
- "url": "https://mcp.api-inference.modelscope.net/8ac378c1961447/mcp",
- }
- }
- )
- console.rule("[bold]连接 高德MCP")
- tools = await mcp_client.get_tools()
- if not tools:
- raise RuntimeError("MCP 连接成功,但服务端未返回任何工具")
-
- table = Table(title=f"高德MCP 工具列表,共{len(tools)}个")
- table.add_column("序号")
- table.add_column("工具名")
- table.add_column("说明")
- for index,tool in enumerate(tools,start=1):
- description = (tool.description or "").replace("\n"," ")
- table.add_row(
- str(index),
- tool.name,
- description[:100],
- )
-
- console.print(table)
- await invoke_text_search(tools)
- if __name__ == "__main__":
- try:
- asyncio.run(main())
- except Exception as e:
- console.print(f"[red]高德mcp测试失败:{type(e).__name__}:{e}[/red]")
- raise SystemExit(1) from e
|