连接多个MCP服务

本节的任务是:连接多个MCP服务,打造全能AI助理。

在之前的章节中,我们成功接入了百度地图的 MCP 服务,让 AI 拥有了查路线、看天气的能力。但在真实的业务场景中,用户的需求往往是复合的:

显然,单独一个 MCP 服务无法满足所有需求。我们需要让 AI 同时连接多个 MCP 服务端,变成一个全能助理。

但在实际操作中,这会带来两个致命问题:

1. 工具重名冲突:不同服务之间极容易出现工具重名(比如百度有 geocode,高德也有 geocode,如果直接注册给 AI,会导致冲突报错)。

2. 路由分发困难:AI 调用工具时只会告诉你工具名,不会告诉你它属于哪个服务,客户端必须把请求转发给正确的 MCP 服务器。

解决这两个问题的标准方案是:“前缀命名法 + 路由字典”。

核心架构设计

1. 拉取工具时加前缀:在注册工具时,给来自同一个 MCP 的工具名加上统一的前缀。例如来自百度的工具加前缀"baidu",来自高德的工具加前缀"gaode"

2. 建立路由字典:用一个字典记录这些工具前缀对应的 MCP 服务器地址。

3. 转发时剥离前缀:在 ToolExecutor 拦截到调用时,根据下划线切分出前缀和真实的工具名。去字典查出目标 URL,并向目标MCP发送剥离了前缀的真实工具名。

如何给MCP工具指定前缀

用
LLMCaller的AddMCPTools方法注册MCP工具时,可用第二个参数指定前缀,例如:

caller.AddMCPTools(mcptools,
"baidu_")

注册时会自动给工具名加上前缀"baidu_",例如"
map_directions"会变为"baidu_map_directions"

完整参考代码

以下代码演示了如何通过路由字典,同时接入百度地图、高德地图和千问的MCP服务。

注意不同的MCP服务,鉴权方式可能不同,例如千问使用请求头鉴权。

以下代码可以直接在 Foxtable 命令窗口执行:

Dim deepseekKey As String = "sk-a734b83536da45e9aedc3e42605bfb3a" ' 你的DeepSeek密钥
Dim
caller As New LLMCaller("https://api.deepseek.com/chat/completions", "deepseek-chat", deepseekKey)
caller.Messages =
New JArray()
caller.SystemPrompt =
"你是一个智能出行助手。你可以使用地图工具来查询地点、规划路线、获取天气等。请根据用户需求自主选择合适的工具。"

' ==================== 1.
创建MCP路由字典 ====================
Dim
mapRouters As New Dictionary(Of String, String)
mapRouters(
"baidu") = "https://mcp.map.baidu.com/mcp?ak=bYDdADrPUCNkSAID9bJU70EF8Iy5htGu" '请替换为自己的百度地图AK
'mapRouters("gaode") = "https://mcp.amap.com/mcp?ak=
你的高德AK" '注意:高德实际地址可能需查阅官方文档,这里仅作演示
'mapRouters("qwen") = "https://maas.qianwenaiapi.com/api/v1/mcps/EnhancedSearch/mcp" '
注意:千问使用请求头鉴权,实际地址请查阅官方文档

' ==================== 2.
循环拉取注册每个MCP服务的工具 ====================
For
Each key As String In mapRouters.Keys  ' 用Try捕获错误,避免个别MCP连接出错影响整体
   
Try
       
Dim mcpUrl As String = mapRouters(key) ' 获取MCP服务的地址
       
Dim hc As New HttpClient(mcpUrl)
        hc.SkipError =
True
        hc.ContentType =
"application/json"
        hc.Headers.Add(
"Accept", "application/json, text/event-stream") ' 核心必填项:声明客户端支持的数据格式
       
If key = "qwen" Then
            hc.Headers.Add(
"Authorization", "Bearer 你的千问API_Key")
       
End If
        hc.Content =
<![CDATA[ {"jsonrpc":"2.0", "id":1, "method":"tools/list", "params":{}} ]]>.Value
       
Dim listResp As String = hc.GetData()
       
Dim listJson As JObject = JsonConvert.DeserializeObject(listResp)
       
Dim mcpTools As JArray = listJson("result")("tools")
        caller.AddMCPTools(mcptools, key &
"_") '将MCP工具注册到LLMCaller,注意要指定前缀,前缀和工具名用符号"_"隔开       
   
Catch ex As Exception
        MessageBoxA.Show(key &
"MCP连接失败")
   
End Try
Next


' ==================== 4.
设置工具执行器(自动路由转发) ====================
caller.ToolExecutor =

Function
(ttoolName As String, targs As JObject) As String
   
Dim realToolName As String = ttoolName
   
Dim prefix As String = ""
   
Dim spidx As Integer = ttoolName.IndexOf("_")
   
If spidx > 0 Then
        prefix = ttoolName.Substring(0, spidx)
'获取前缀
        realToolName = ttoolName.Substring(spidx + 1)
'获取去掉前缀后的真实工具名
   
End If
   
If prefix <> "" AndAlso mapRouters.ContainsKey(prefix) Then ' 如果路由表包括这个前缀,表示这是来自某个MCP的工具
       
Dim callReq As New JObject From { {"jsonrpc", "2.0"}, {"id", Rand.NextString(10)}, {"method", "tools/call"}, {"params", New JObject From {{"name", realToolName}, {"arguments", targs}}} }
       
Dim url As String = mapRouters(prefix) '从路由表获取MCP地址
       
Dim hc As New HttpClient(url)
        hc.SkipError =
True
        hc.ContentType =
"application/json"
        hc.Headers.Add(
"Accept", "application/json, text/event-stream")
       
If prefix = "qwen" Then
            hc.Headers.Add(
"Authorization", "Bearer 你的千问API_Key")
       
End If
        hc.Content = callReq.ToString()
       
Dim resp As String = hc.GetData()
       
Dim respJson As JObject = JsonConvert.DeserializeObject(resp)
       
If respJson("result") IsNot Nothing AndAlso respJson("result")("content") IsNot Nothing Then
           
Dim content As JArray = respJson("result")("content")
           
If content.Count > 0 Then
               
Return content(0)("text").ToString()
           
End If
       
End If
       
Return "MCP调用失败:" & vbCrLf & ttoolName & vbCrLf & targs.ToString() & vbCrLf & resp
   
Else
       
'如果不是来自MCP的工具,那么就是自定义的工具,需要自己写执行逻辑,这里直接返回错误:
       
Return "工具[" & ttoolName & "]执行错误!"
   
End If
End
Function

' ==================== 5.
发起提问 ====================
caller.UserMessage =
"帮我查一下从北京天安门到故宫的步行路线,大概需要走多久?"
If
caller.GetResult() Then
    MessageBoxA.Show(caller.Result)

Else

    MessageBoxA.Show(caller.Error)

End
If


本页地址:http://www.foxtable.com/webhelp/topics/7240.htm