Spring AI MCP客户端连接成功却看不到工具?从初始化、传输、过滤到ChatClient完整排查

文章摘要

Spring AI项目接入MCP时,最常见的问题之一是:应用启动没有报错,MCP Server日志也显示连接成功,但ChatClient始终不调用工具,甚至工具列表为空。问题可能发生在初始化、传输配置、工具回调开关、客户端类型、工具过滤、名称冲突、Schema生成、权限或ChatClient注册等多个环节。本文给出一条从MCP连接到模型工具调用的完整排查链路。

一、先区分三种不同故障

“工具不可用”至少分三类:

1. MCP客户端没有连接成功

表现:

连接超时
初始化失败
协议版本不匹配
认证失败

2. 客户端连接成功,但没有发现工具

表现:

tools/list为空
工具被过滤
服务器没有注册工具
缓存仍是旧列表

3. 工具已经发现,但模型不调用

表现:

ChatClient中可以看到ToolCallback
模型始终直接回答
工具Description不清楚
用户问题不需要工具
模型不支持工具调用

排查时必须先判断属于哪一类。

二、第一步:确认客户端是否完成初始化

Spring AI MCP客户端默认可以自动初始化。

配置:

spring:
  ai:
    mcp:
      client:
        enabled: true
        initialized: true
        request-timeout: 20s

如果配置为:

initialized: false

客户端创建后可能尚未完成协议初始化和能力发现。

检查启动日志:

客户端名称
服务端地址
传输类型
初始化状态
协议版本
工具数量

不要只看“Application started”。

三、第二步:确认传输配置匹配

服务端:

spring:
  ai:
    mcp:
      server:
        protocol: STREAMABLE

客户端必须使用对应的Streamable HTTP连接配置。

如果服务端是:

STDIO

客户端却按HTTP连接,当然无法发现工具。

常见不匹配:

服务端STATELESS
客户端仍按旧SSE端点连接

服务端WebMVC
客户端URL指向错误上下文路径

服务端STDIO
客户端命令或参数错误

四、第三步:确认连接地址不是普通业务接口

MCP端点通常不是你的:

/api/chat
/api/tools

而是MCP Starter配置或默认暴露的协议端点。

如果服务部署在反向代理后:

外部:https://api.example.com/ai/mcp
内部:http://mcp-service:8080/mcp

需要检查:

  • 网关Path Rewrite;
  • Context Path;
  • HTTPS终止;
  • Content-Type;
  • 请求头转发;
  • 流式响应缓冲;
  • 超时。

五、第四步:确认服务端真的注册了工具

使用注解:

@Component
public class OrderTools {

    @McpTool(
        name = "query_order",
        description = "根据订单号查询订单当前状态"
    )
    public OrderResult queryOrder(
            String orderId
    ) {
        return orderService.query(orderId);
    }
}

检查:

类是否是Spring Bean
注解扫描是否启用
包是否在扫描路径下
方法是否为public
参数是否能生成JSON Schema
返回类型是否可序列化
工具名称是否合法

如果类是自己new出来的,不属于Spring容器,自动扫描不会注册。

六、第五步:检查工具回调集成是否关闭

Spring AI MCP客户端可以把远程MCP Tool转换为Spring AI ToolCallback

关键配置:

spring:
  ai:
    mcp:
      client:
        toolcallback:
          enabled: true

如果设为:

enabled: false

MCP客户端仍可能连接成功,但工具不会自动进入Spring AI工具执行体系。

这是一类非常隐蔽的问题。

七、第六步:检查是否配置了工具过滤

生产项目通常不会把所有MCP工具暴露给模型。

可能配置:

允许列表
拒绝列表
按Server过滤
按工具名过滤
按租户过滤

如果过滤规则写错:

query_*

而实际工具名是:

order.query

最终列表可能为空。

建议启动时输出:

原始工具数
过滤后工具数
每个被排除工具的原因

不要只输出最终结果。

八、第七步:检查工具名称冲突

多个MCP Server可能都暴露:

search
query
get_status

Spring AI支持工具名前缀,用于避免冲突。

最终工具可能变成:

crm_search
knowledge_search
order_get_status

如果Prompt仍要求模型调用:

search

模型可能找不到准确工具。

工具名称建议:

领域_动作

例如:

order_query_status
customer_search_profile
knowledge_search_policy

九、第八步:检查工具Description是否足够明确

工具已注册但模型不调用,最常见原因之一是描述不清楚。

错误:

@McpTool(description = "查询数据")

模型不知道查询什么、何时调用。

推荐:

@McpTool(
    name = "order_query_status",
    description = "当用户询问某个具体订单的当前状态、物流节点或是否已签收时调用。必须提供orderId。不能用于查询商品库存。"
)

Description应说明:

  • 解决什么问题;
  • 什么时候调用;
  • 必填参数;
  • 不能做什么;
  • 是否有副作用。

十、检查参数Schema是否生成成功

模型选择工具后,还需要生成合法参数。

复杂参数类:

public record OrderQuery(
        @NotBlank String orderId,
        boolean includeLogistics
) {
}

检查生成Schema:

{
  "type": "object",
  "properties": {
    "orderId": {
      "type": "string"
    },
    "includeLogistics": {
      "type": "boolean"
    }
  },
  "required": ["orderId"]
}

常见问题:

  • 参数类型无法反射;
  • Jackson无法序列化;
  • 泛型过于复杂;
  • 参数名丢失;
  • 必填字段未标记;
  • Schema过大。

十一、确认MCP Tool已经加入ChatClient

如果使用自动配置,MCP ToolCallback通常会由框架接入。

但自定义ChatClient时可能遗漏。

例如业务代码重新构建:

this.chatClient = builder.build();

而不是注入已经完成MCP工具集成的Bean。

建议检查:

当前ChatClient工具数量
工具名称列表
工具来源Server

不要假设所有ChatClient.Builder都具有相同工具集合。

十二、确认模型支持Tool Calling

不是所有兼容OpenAI接口的模型都完整支持工具调用。

检查:

  • Provider是否支持;
  • 模型版本是否支持;
  • 是否关闭Tool Calling;
  • JSON Schema支持程度;
  • 最大工具数量;
  • 流式工具调用支持;
  • 并行工具调用支持。

固定测试:

请查询订单A1001的实时状态。
你必须调用订单查询工具,不得猜测。

如果仍然不产生Tool Call,应查看模型原始响应。

十三、不要用模型常识能够回答的问题测试

测试问题:

北京是中国首都吗?

即使存在知识工具,模型也可能直接回答。

更好的测试:

查询订单A1001当前状态。

或:

查询公司内部制度V4.2的差旅住宿标准。

问题必须依赖外部实时数据。

十四、权限失败可能被误判为没有工具

服务端可能按用户Scope过滤工具列表。

例如:

当前Token只有order:read
工具要求order:refund

服务端可以:

  • 不返回该工具;
  • 返回工具但调用时拒绝;
  • 触发增量授权。

检查:

Access Token是否存在
Scope是否正确
Token是否过期
Audience是否匹配
租户信息是否进入请求

十五、工具列表缓存可能仍是旧数据

新规范允许工具列表带TTL。

如果服务端刚增加工具,而客户端仍使用缓存:

连接成功
但新工具不可见

处理:

  • 等待TTL;
  • 主动刷新;
  • 发送listChanged;
  • 重建客户端;
  • 检查缓存键。

十六、建议增加启动自检

应用启动后执行:

连接每个MCP Server
→ 完成初始化
→ 拉取工具列表
→ 校验必需工具
→ 输出兼容报告

例如:

public record McpServerHealth(
        String serverName,
        boolean connected,
        String protocolVersion,
        int toolCount,
        List missingRequiredTools
) {
}

必需工具缺失时,可以阻止生产实例接收流量。

十七、完整排查顺序

1. 客户端是否创建
2. 是否完成初始化
3. 传输与端点是否匹配
4. 鉴权是否成功
5. 服务端是否注册工具
6. tools/list是否有结果
7. 工具是否被过滤
8. 工具名称是否冲突
9. ToolCallback集成是否开启
10. ChatClient是否获得工具
11. 模型是否支持Tool Calling
12. 测试问题是否必须调用工具
13. 工具Schema是否有效
14. 缓存是否过期

十八、最小诊断日志

建议记录:

mcp.server.name
mcp.transport
mcp.protocol.version
mcp.initialized
mcp.tools.raw_count
mcp.tools.filtered_count
mcp.tool.names
chatclient.tool_count
model.name
model.tool_call_count

注意不要把Token、密码和完整敏感参数写入日志。

总结

MCP客户端“连接成功却没有工具”,通常不是一个问题,而是链路中某一层没有完成:

连接
→ 初始化
→ tools/list
→ 工具过滤
→ ToolCallback适配
→ ChatClient注册
→ 模型选择

按照这条链路逐层检查,比反复修改Prompt或重启服务更有效。

延伸阅读

如果你正在关注企业级 AI 应用、Spring AI、RAG、Agent 与 MCP 工程化落地,欢迎访问 智元界

https://www.zyentor.com/

智元界将持续分享可运行的技术实战、架构设计、问题排查与企业应用案例。