Skip to content

Help me, my mcp tool doesn't work。I would be very grateful if anyone could help me。 #3291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
qiuyueovo opened this issue May 22, 2025 · 32 comments

Comments

@qiuyueovo
Copy link

qiuyueovo commented May 22, 2025

Bug description
Now it can be called successfully. But it will not call the tools in mcp。
What I can confirm is that there are tools in sse, and sse can be linked normally。
openAiClientManager is my custom built OpenAiChatModel and it works fine.
I have tried many methods and asked cursor. I have also read the relevant documents of springai, but I still can't find the reason for this problem. I have been troubled for 3 days. I would be very grateful if anyone could help me。

maven

  ai:
    mcp:
      client:
        enabled: true
        name: mcp-test-client
        version: 1.0.0
        request-timeout: 30s
        type: SYNC  # 同步客户端类型
        sse:
          connections:
            mcp-server: # MCP服务器连接名称
              url: http://0.0.0.0:3000
              sse-endpoint: /sse  # SSE端点
<spring-ai.version>1.1.0-SNAPSHOT </spring-ai.version>
<dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
    @Autowired
    List<McpSyncClient> mcpSyncClients;

    @Test
    public void predefinedQuestions() {
        HashSet<String> names = new HashSet<>();
        OpenAiChatModel client = openAiClientManager.getClient(OpenAiProvider.xxxx);
        for (McpSyncClient mcpClient : mcpSyncClients) {
            for (McpSchema.Tool tool : mcpClient.listTools().tools()) {
                String name = tool.name();
                String description = tool.description();
                //System.err.println("name:" + name);
                //System.err.println("description:" + description);
                names.add("mcp_test_client_mcp_server_" + name);
            }
        }


        var mcpToolProvider = new SyncMcpToolCallbackProvider(mcpSyncClients);
        ToolCallback[] toolCallbacks = mcpToolProvider.getToolCallbacks();
        ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(mcpToolProvider).build();
        String userQuestion = """
                What tools are available?
                """;

        Prompt prompt = new Prompt(userQuestion, OpenAiChatOptions.builder()
                .model("gpt-4o") 
                .build());

        System.out.println("> USER: " + userQuestion);
        System.out.println("> ASSISTANT: " + chatClient.prompt(prompt).call().content());

    }
    private OpenAiChatModel buildModel(OpenAiProvider provider) {
        OpenAiApi openAiApi = OpenAiApi.builder().apiKey(cfg.getApiKey()).baseUrl(cfg.getBaseUrl()).build();
        OpenAiChatModel chatModel = OpenAiChatModel.builder().openAiApi(openAiApi).build();
        return chatModel;
    }
@qiuyueovo qiuyueovo changed the title Help me, my mcp tool doesn't work Help me, my mcp tool doesn't work。I would be very grateful if anyone could help me。 May 22, 2025
@sunyuhan1998
Copy link
Contributor

I tried to reproduce your scenario using the Qwen model combined with the Amap MCP server, but couldn't replicate the issue. In my tests, the model successfully called the tools in MCP. The only difference from your code is that I used HttpClientSseClientTransport to construct the NamedClientMcpTransport. Maybe you could give it a try as well?

like this:

@Configuration
public class McpConfig {

    @Bean
    public List<NamedClientMcpTransport> mcpClientTransport() {
        McpClientTransport transport = HttpClientSseClientTransport
                .builder("https://mcp.amap.com")
                .sseEndpoint("/sse?key=<your key>")
                .objectMapper(new ObjectMapper())
                .build();

        return Collections.singletonList(new NamedClientMcpTransport("amap", transport));
    }

}

@qiuyueovo
Copy link
Author

qiuyueovo commented May 23, 2025

I tried to reproduce your scenario using the Qwen model combined with the Amap MCP server, but couldn't replicate the issue. In my tests, the model successfully called the tools in MCP. The only difference from your code is that I used HttpClientSseClientTransport to construct the NamedClientMcpTransport. Maybe you could give it a try as well?

like this:

@Configuration
public class McpConfig {

    @Bean
    public List<NamedClientMcpTransport> mcpClientTransport() {
        McpClientTransport transport = HttpClientSseClientTransport
                .builder("https://mcp.amap.com")
                .sseEndpoint("/sse?key=<your key>")
                .objectMapper(new ObjectMapper())
                .build();

        return Collections.singletonList(new NamedClientMcpTransport("amap", transport));
    }

}

But I don't know how to integrate the above code into my code. Can you modify it based on the code I provided? There is no configuration about mcpClientTransport in my code. The reference document of the code is: https://docs.spring.io/spring-ai/reference/1.1-SNAPSHOT/api/mcp/mcp-client-boot-starter-docs.html.

I would be grateful if you could help me

@jingsewu
Copy link

jingsewu commented May 23, 2025

I think what he means is inteading of these configurations by using code:​​

Image

​​But I doubt it will work. I’ve encountered an issue where using English input triggers the tool, but it doesn’t work with Chinese input.

@qiuyueovo
Copy link
Author

I think what he means is inteading of these configurations by using code:​​我认为他的意思是使用代码来实现这些配置:​​

Image

​​But I doubt it will work. I’ve encountered an issue where using English input triggers the tool, but it doesn’t work with Chinese input.但我怀疑它能否正常工作。我遇到过一个问题,使用英文输入可以触发该工具,但使用中文输入却不行。

After I commented out the content in your screenshot, I added the above configuration file to the code, but the mcp tool was still not called correctly. This problem has troubled me for 3 days, and I still have no idea.
And the prompt words of my question are in English. I can make sure that the sse port of mcp is working properly. I can call it normally using Cherry Studio tool. But it doesn't work in the code.

@jingbio
Copy link

jingbio commented May 23, 2025

bug 描述现在可以成功调用。但它不会调用 mcp 中的工具。我可以确认 sse 中有工具,并且 sse 可以正常链接。openAiClientManager 是我自定义构建的 OpenAiChatModel,它运行正常。我尝试了很多方法并咨询了光标,还阅读了 springai 的相关文档,但仍然找不到这个问题的原因。我已经困扰了 3 天。如果有人能帮助我,我将不胜感激。

maven

ai:
mcp:
client:
enabled: true
name: mcp-test-client
version: 1.0.0
request-timeout: 30s
type: SYNC # 同步客户端类型
sse:
connections:
mcp-server: # MCP服务器连接名称
url: http://0.0.0.0:3000
sse-endpoint: /sse # SSE端点

<spring-ai.version>1.1.0-SNAPSHOT </spring-ai.version>
<dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
@Autowired
List<McpSyncClient> mcpSyncClients;

@Test
public void predefinedQuestions() {
    HashSet<String> names = new HashSet<>();
    OpenAiChatModel client = openAiClientManager.getClient(OpenAiProvider.xxxx);
    for (McpSyncClient mcpClient : mcpSyncClients) {
        for (McpSchema.Tool tool : mcpClient.listTools().tools()) {
            String name = tool.name();
            String description = tool.description();
            //System.err.println("name:" + name);
            //System.err.println("description:" + description);
            names.add("mcp_test_client_mcp_server_" + name);
        }
    }


    var mcpToolProvider = new SyncMcpToolCallbackProvider(mcpSyncClients);
    ToolCallback[] toolCallbacks = mcpToolProvider.getToolCallbacks();
    ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(mcpToolProvider).build();
    String userQuestion = """
            What tools are available?
            """;

    Prompt prompt = new Prompt(userQuestion, OpenAiChatOptions.builder()
            .model("gpt-4o") 
            .build());

    System.out.println("> USER: " + userQuestion);
    System.out.println("> ASSISTANT: " + chatClient.prompt(prompt).call().content());

}
private OpenAiChatModel buildModel(OpenAiProvider provider) {
    OpenAiApi openAiApi = OpenAiApi.builder().apiKey(cfg.getApiKey()).baseUrl(cfg.getBaseUrl()).build();
    OpenAiChatModel chatModel = OpenAiChatModel.builder().openAiApi(openAiApi).build();
    return chatModel;
}

Do these two lines of comments print any content?
‘‘‘
//System.err.println("name:" + name);
//System.err.println("description:" + description);
’’’

@qiuyueovo
Copy link
Author

qiuyueovo commented May 23, 2025

They can print out the complete tool in the mcp, including name and description.
Like this:
name:create
description: create something
name: update
description: some updates

And the above results are consistent with the tools I viewed in Cherry Studio. They are all the tools in my mcp

But unfortunately, my mcp tool is not printed out in ASSISTANT.

@jingbio
Copy link

jingbio commented May 23, 2025

Bug description Now it can be called successfully. But it will not call the tools in mcp。 What I can confirm is that there are tools in sse, and sse can be linked normally。 openAiClientManager is my custom built OpenAiChatModel and it works fine. I have tried many methods and asked cursor. I have also read the relevant documents of springai, but I still can't find the reason for this problem. I have been troubled for 3 days. I would be very grateful if anyone could help me。

maven

ai:
mcp:
client:
enabled: true
name: mcp-test-client
version: 1.0.0
request-timeout: 30s
type: SYNC # 同步客户端类型
sse:
connections:
mcp-server: # MCP服务器连接名称
url: http://0.0.0.0:3000
sse-endpoint: /sse # SSE端点

<spring-ai.version>1.1.0-SNAPSHOT </spring-ai.version>
<dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-client</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-openai</artifactId>
            <version>${spring-ai.version}</version>
        </dependency>
@Autowired
List<McpSyncClient> mcpSyncClients;

@Test
public void predefinedQuestions() {
    HashSet<String> names = new HashSet<>();
    OpenAiChatModel client = openAiClientManager.getClient(OpenAiProvider.xxxx);
    for (McpSyncClient mcpClient : mcpSyncClients) {
        for (McpSchema.Tool tool : mcpClient.listTools().tools()) {
            String name = tool.name();
            String description = tool.description();
            //System.err.println("name:" + name);
            //System.err.println("description:" + description);
            names.add("mcp_test_client_mcp_server_" + name);
        }
    }


    var mcpToolProvider = new SyncMcpToolCallbackProvider(mcpSyncClients);
    ToolCallback[] toolCallbacks = mcpToolProvider.getToolCallbacks();
    ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(mcpToolProvider).build();
    String userQuestion = """
            What tools are available?
            """;

    Prompt prompt = new Prompt(userQuestion, OpenAiChatOptions.builder()
            .model("gpt-4o") 
            .build());

    System.out.println("> USER: " + userQuestion);
    System.out.println("> ASSISTANT: " + chatClient.prompt(prompt).call().content());

}
private OpenAiChatModel buildModel(OpenAiProvider provider) {
    OpenAiApi openAiApi = OpenAiApi.builder().apiKey(cfg.getApiKey()).baseUrl(cfg.getBaseUrl()).build();
    OpenAiChatModel chatModel = OpenAiChatModel.builder().openAiApi(openAiApi).build();
    return chatModel;
}

try it:
'''
var mcpToolProvider = new SyncMcpToolCallbackProvider(mcpSyncClients);
ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(mcpToolProvider).build();
String userQuestion = """
What tools are available?
""";
System.out.println("> USER: " + userQuestion);
System.out.println("> ASSISTANT: " + chatClient.prompt().user(userQuestion).call().content());
'''

@qiuyueovo
Copy link
Author

Unfortunately, it still doesn't work.

System.out.println("> ASSISTANT: " + chatClient.prompt(prompt).call().content());
System.out.println("> ASSISTANT: " + chatClient.prompt().user(userQuestion).call().content());

There is no difference between these two calling methods. The result is the same. There is no output of mcp tool
And I need to pass prompt in chatClient because I set the model and conversation memory and other related information in prompt.

@jingbio
Copy link

jingbio commented May 23, 2025

Unfortunately, it still doesn't work.

System.out.println("> ASSISTANT: " + chatClient.prompt(prompt).call().content());
System.out.println("> ASSISTANT: " + chatClient.prompt().user(userQuestion).call().content());
There is no difference between these two calling methods. The result is the same. There is no output of mcp tool And I need to pass prompt in chatClient because I set the model and conversation memory and other related information in prompt.

I almost replicated your code. The line missing is: OpenAiChatModel client = openAiClientManager.getClient(OpenAiProvider.xxxx);

@sunyuhan1998
Copy link
Contributor

Hi @qiuyueovo , it seems your issue hasn't been resolved yet. I suggest you organize the code that can reproduce the problem into a minimal project and share it. This might make it easier for others to help you identify the issue.

@qiuyueovo
Copy link
Author

qiuyueovo commented May 23, 2025

OpenAiClientManager
    private final Map<OpenAiProvider, OpenAiChatModel> clientMap = new EnumMap<>(OpenAiProvider.class);

    @Resource(name = "aClient")
    private OpenAiChatModel aClient;
    @Resource(name = "bClient")
    private OpenAiChatModel bClient;

    @PostConstruct
    public void init() {
        clientMap.put(OpenAiProvider.a, aClient);
        clientMap.put(OpenAiProvider.b, bClient);
    }

    public OpenAiChatModel getClient(OpenAiProvider provider) {
        return clientMap.get(provider);
    }
@Configuration
public class OpenAiClientConfig {

    @Autowired
    private AiProperties aiProperties;

    @Bean("aClient")
    public OpenAiChatModel aClient() {
        return buildModel(OpenAiProvider.a);
    }

    @Bean("bClient")
    public OpenAiChatModel bClient() {
        return buildModel(OpenAiProvider.b);
    }

    private OpenAiChatModel buildModel(OpenAiProvider provider) {
        AiProperties.AiProviderConfig cfg = aiProperties.getProviders().get(key);
        if (cfg == null) throw new IllegalArgumentException("没有配置:" + provider);
        //return new OpenAiChatModel(new OpenAiApi(cfg.getApiKey(), cfg.getBaseUrl()));
        OpenAiApi openAiApi = OpenAiApi.builder().apiKey(cfg.getApiKey()).baseUrl(cfg.getBaseUrl()).build();
        OpenAiChatModel chatModel = OpenAiChatModel.builder().openAiApi(openAiApi).build();
        return chatModel;
    }
}

The role of OpenAiClientManager is that I can freely choose and switch when I have multiple service providers.

@qiuyueovo
Copy link
Author

I only set the base url and api key. Nothing else changed.

@qiuyueovo
Copy link
Author

Hi @qiuyueovo , it seems your issue hasn't been resolved yet. I suggest you organize the code that can reproduce the problem into a minimal project and share it. This might make it easier for others to help you identify the issue.

The core code related to springai in the project has been pasted in the issues. There is almost no configuration. I also followed the official website documentation step by step. But it didn't work, which made me crazy. If it still doesn't work, I will streamline my project and share it

@jingbio
Copy link

jingbio commented May 23, 2025

Hi @qiuyueovo , 你的问题似乎还没有解决。我建议你将能够重现问题的代码整理成一个最小的项目并分享出来。这可能有助于其他人更容易地帮你找出问题。

该项目中与 springai 相关的核心代码已在 issues 中粘贴。几乎没有任何配置。我也按照官方网站文档一步步操作了。但还是不行,这让我很抓狂。如果还是不行,我会精简我的项目并分享。

There is a fatal bug in your code: two @bean methods have the same name, both are "aClient".

@qiuyueovo
Copy link
Author

Sorry. I made a typo when mosaicking part of my code. The actual code is correct

@jingbio
Copy link

jingbio commented May 23, 2025

Sorry. I made a typo when mosaicking part of my code. The actual code is correct

I think you should minimize your code. This is more helpful for analysis.

@qiuyueovo
Copy link
Author

Thank you. My question may be complicated. I sent you an email

@hbsjz-swl
Copy link

一群中国人在这用英文交流看起来很怪异, chatClient.defaultToolCallBack(ToolCallBackProvider).build(); 然后直接chatclient.prompt(YourQuestion).call().content(); 就可以了, toolcallbackprovider直接从容器中获取 不要自己配置, 这样就可以了, 在使用指定的mcpclient的时候 ,直接在容器中获取 mcpclients 然后过滤出你想使用的指定mcpclient 就能使用指定mcpclient 了,如果不单独获取 它,chatclient会自动根据所有mcpserver中工具的描述自己选择使用哪个工具来回答问题了

@qiuyueovo
Copy link
Author

qiuyueovo commented May 26, 2025

  1. 虽然很怪异,毕竟在springai 的 issues 中大部分都是使用的英文,所以我提交也是用的英文。都有翻译软件都能看得懂。
  2. 我最简单的实现是:
    // 2. 在应用程序中使用 MCP 服务
    @Resource
    private ToolCallbackProvider toolCallbackProvider;

        ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(toolCallbackProvider).build();
        String userQuestion = """
                What tools are available?
                """;
        System.out.println("> USER: " + userQuestion);
        System.out.println("> ASSISTANT: " + chatClient.prompt(userQuestion).call().content());

这样还是不行。

Although it is very strange, after all, most of the issues in springai are in English, so I also submitted it in English. There are translation software that can understand it.
My simplest implementation is:

// 2. Use MCP service in the application
@Resource
private ToolCallbackProvider toolCallbackProvider;

ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(toolCallbackProvider).build();
String userQuestion = """
What tools are available?
""";
System.out.println("> USER: " + userQuestion);
System.out.println("> ASSISTANT: " + chatClient.prompt(userQuestion).call().content());

This still doesn't work.

@qiuyueovo
Copy link
Author

而当这样使用的时候又会提示:
When using it like this, it will prompt:
java.lang.IllegalStateException: Multiple tools with the same name xxxx

     ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(toolCallbackProvider).build();
        ChatClient.CallResponseSpec call = chatClient.prompt(userQuestion).toolCallbacks(toolCallbackProvider).call();

@hbsjz-swl
Copy link

@qiuyueovo
Copy link
Author

老铁,https://github.com/spring-projects/spring-ai-examples这是spring-ai官方的示例项目,你照着这个项目配吧 先跑通了再秀,先写的low一些

是呀,我在没有调用 mcp 之前。其他功能都是正常使用的。

@luguangdong
Copy link

兄弟,你的问题是mcp-client 配置有问题。可以使用如下配置。添加 工具调用toolcallback为开启状态。
mcp:
client:
enabled: true
name: mcp-test-client
version: 1.0.0
request-timeout: 30s
type: SYNC
sse:
connections:
server1:
url:http://0.0.0.0:3000
# 开启工具调用,默认是关闭的
toolcallback:
enabled: true

@luguangdong
Copy link

Image

@qiuyueovo
Copy link
Author

@qiuyueovo
Copy link
Author

当这里我用了自己自定义的 时就不行。

        ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(mcpToolProvider).build();

哪怕是我启动时候手动用框架手动注入都不行

    @Bean
    public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, ToolCallbackProvider tools,
                                                 ConfigurableApplicationContext context) {
        String userQuestion = """
                What tools are available?
                """;
        return args -> {

            var chatClient = chatClientBuilder
                    .defaultToolCallbacks(tools)
                    .build();

            System.out.println("\n>>> QUESTION: " + userQuestion);
            System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userQuestion).call().content());

            context.close();
        };
    }

@luguangdong
Copy link

Image
试试这种

@qiuyueovo
Copy link
Author

这种也还是不行 就很奇怪

    @Resource
    private SyncMcpToolCallbackProvider toolCallbackProvider;
    
    OpenAiChatModel client = openAiClientManager.getClient(OpenAiProvider.a);      
 ChatClient chatClient = ChatClient.builder(client).defaultToolCallbacks(toolCallbackProvider.getToolCallbacks()).build();
        System.out.println("> ASSISTANT: " + chatClient.prompt(prompt).call().content());

@qiuyueovo
Copy link
Author

qiuyueovo commented May 27, 2025

Image
在这一步中 参数已经传入进去了。就很奇怪。

官方原版demo中也是这样的。

@qiuyueovo
Copy link
Author

感谢各位。
我知道了,可能是因为springai 适配模型的原因,在代码中使用模型 grok3,gpt-4o,gpt-4.1,是不可以的。但是相同的的代码使用 claude-3-7-sonnet 是可以的。
然而我使用工具:Cherry Studio。不管是使用那个模型都是可以正常调用mcp的
虽然问题可以被解决。但我还是比较困惑。

Thanks everyone.
I understand. It may be because of the springai adaptation model. It is not possible to use the models grok3, gpt-4o, gpt-4.1 in the code. But the same code can use claude-3-7-sonnet.
However, I use the tool: Cherry Studio. No matter which model is used, mcp can be called normally.
Although the problem can be solved. But I am still confused.

@sunyuhan1998
Copy link
Contributor

It is not possible to use the models grok3, gpt-4o, gpt-4.1 in the code. But the same code can use claude-3-7-sonnet.

Interesting, I tested GPT-4.1 and GPT-4o, and in my tests, both models were able to call the MCP tool normally — that's really strange. May I ask whether the GPT-series model interface you're using is officially provided by OpenAI, or are you accessing it through a third-party agent?

@qiuyueovo
Copy link
Author

qiuyueovo commented May 27, 2025

It is not possible to use the models grok3, gpt-4o, gpt-4.1 in the code. But the same code can use claude-3-7-sonnet.

Interesting, I tested GPT-4.1 and GPT-4o, and in my tests, both models were able to call the MCP tool normally — that's really strange. May I ask whether the GPT-series model interface you're using is officially provided by OpenAI, or are you accessing it through a third-party agent?

The above models are all accessed through third-party agents, but Cherry Studio can call them normally.That means that a third-party agent is normal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants