diff --git a/model-context-protocol/brave/pom.xml b/model-context-protocol/brave/pom.xml index 7399b44..e719089 100644 --- a/model-context-protocol/brave/pom.xml +++ b/model-context-protocol/brave/pom.xml @@ -1,20 +1,23 @@ - 4.0.0 org.springframework.boot spring-boot-starter-parent 3.3.6 - + com.example ai-mcp-brave 0.0.1-SNAPSHOT Spring AI - Model Context Protocol - Brave Simple AI Application using MCP client to use Brave for Internet search + 17 + 1.0.0-SNAPSHOT @@ -22,7 +25,7 @@ org.springframework.ai spring-ai-bom - 1.0.0-SNAPSHOT + ${spring-ai.version} pom import @@ -40,13 +43,11 @@ spring-ai-openai-spring-boot-starter - org.springframework.ai - spring-ai-mcp + spring-ai-mcp-client-spring-boot-starter - @@ -78,4 +79,4 @@ - + \ No newline at end of file diff --git a/model-context-protocol/brave/src/main/java/org/springframework/ai/mcp/samples/brave/Application.java b/model-context-protocol/brave/src/main/java/org/springframework/ai/mcp/samples/brave/Application.java index e263869..0a9044a 100644 --- a/model-context-protocol/brave/src/main/java/org/springframework/ai/mcp/samples/brave/Application.java +++ b/model-context-protocol/brave/src/main/java/org/springframework/ai/mcp/samples/brave/Application.java @@ -1,14 +1,13 @@ package org.springframework.ai.mcp.samples.brave; -import io.modelcontextprotocol.client.McpClient; +import java.util.List; + import io.modelcontextprotocol.client.McpSyncClient; -import io.modelcontextprotocol.client.transport.ServerParameters; -import io.modelcontextprotocol.client.transport.StdioClientTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.mcp.SyncMcpToolCallback; +import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -26,16 +25,12 @@ public class Application { @Bean public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, - McpSyncClient mcpSyncClient, ConfigurableApplicationContext context) { + List mcpSyncClients, ConfigurableApplicationContext context) { return args -> { var chatClient = chatClientBuilder - .defaultTools(mcpSyncClient.listTools(null) - .tools() - .stream() - .map(tool -> new SyncMcpToolCallback(mcpSyncClient, tool)) - .toArray(SyncMcpToolCallback[]::new)) + .defaultTools(new SyncMcpToolCallbackProvider(mcpSyncClients)) .build(); String question = "Does Spring AI supports the Model Context Protocol? Please provide some references."; @@ -45,20 +40,4 @@ public class Application { context.close(); }; } - - @Bean - public McpSyncClient mcpClient() { - - // https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search - var stdioParams = ServerParameters.builder("npx") - .args("-y", "@modelcontextprotocol/server-brave-search") - .addEnvVar("BRAVE_API_KEY", System.getenv("BRAVE_API_KEY")) - .build(); - - var mcpClient = McpClient.sync(new StdioClientTransport(stdioParams)).build(); - var init = mcpClient.initialize(); - logger.info("MCP Initialized: {}", init); - return mcpClient; - } - } \ No newline at end of file diff --git a/model-context-protocol/brave/src/main/resources/application.properties b/model-context-protocol/brave/src/main/resources/application.properties index 861eae3..70c8077 100644 --- a/model-context-protocol/brave/src/main/resources/application.properties +++ b/model-context-protocol/brave/src/main/resources/application.properties @@ -3,6 +3,8 @@ spring.main.web-application-type=none spring.ai.openai.api-key=${OPENAI_API_KEY} +spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-servers-config.json + # Logging configuration logging.level.root=INFO logging.level.org.springframework.ai.mcp=WARN diff --git a/model-context-protocol/brave/src/main/resources/mcp-servers-config.json b/model-context-protocol/brave/src/main/resources/mcp-servers-config.json new file mode 100644 index 0000000..df98809 --- /dev/null +++ b/model-context-protocol/brave/src/main/resources/mcp-servers-config.json @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "brave-search": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-brave-search" + ], + "env": { + } + } + } +} \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-default-client/src/main/resources/application.properties b/model-context-protocol/client-starter/starter-default-client/src/main/resources/application.properties index d3b267e..0df91dc 100644 --- a/model-context-protocol/client-starter/starter-default-client/src/main/resources/application.properties +++ b/model-context-protocol/client-starter/starter-default-client/src/main/resources/application.properties @@ -14,4 +14,6 @@ spring.ai.mcp.client.stdio.connections.brave-search.args=-y,@modelcontextprotoco logging.level.io.modelcontextprotocol.client=WARN logging.level.io.modelcontextprotocol.spec=WARN -ai.user.input=What tools are available? \ No newline at end of file +ai.user.input=What tools are available? + +spring.ai.mcp.client.toolcallback.enabled=true \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/application.properties b/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/application.properties index 007a113..6d2d730 100644 --- a/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/application.properties +++ b/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/application.properties @@ -13,4 +13,7 @@ spring.ai.mcp.client.stdio.connections.brave-search.args=-y,@modelcontextprotoco logging.level.io.modelcontextprotocol.client=WARN logging.level.io.modelcontextprotocol.spec=WARN -ai.user.input=What tools are available? \ No newline at end of file +ai.user.input=What tools are available? + +# Enable the mcp client tool-callback auto-configuration +spring.ai.mcp.client.toolcallback.enabled=true \ No newline at end of file diff --git a/model-context-protocol/filesystem/pom.xml b/model-context-protocol/filesystem/pom.xml index 765ca0e..fe874d7 100644 --- a/model-context-protocol/filesystem/pom.xml +++ b/model-context-protocol/filesystem/pom.xml @@ -22,7 +22,7 @@ org.springframework.ai spring-ai-bom - 1.0.0-M5 + 1.0.0-SNAPSHOT pom import @@ -41,9 +41,8 @@ - org.springframework.experimental - spring-ai-mcp - 0.6.0 + org.springframework.ai + spring-ai-mcp-client-spring-boot-starter diff --git a/model-context-protocol/filesystem/src/main/java/org/springframework/ai/mcp/samples/filesystem/Application.java b/model-context-protocol/filesystem/src/main/java/org/springframework/ai/mcp/samples/filesystem/Application.java index 099ab0e..391dbce 100644 --- a/model-context-protocol/filesystem/src/main/java/org/springframework/ai/mcp/samples/filesystem/Application.java +++ b/model-context-protocol/filesystem/src/main/java/org/springframework/ai/mcp/samples/filesystem/Application.java @@ -2,14 +2,14 @@ package org.springframework.ai.mcp.samples.filesystem; import java.nio.file.Paths; import java.time.Duration; -import java.util.List; + +import io.modelcontextprotocol.client.McpClient; +import io.modelcontextprotocol.client.McpSyncClient; +import io.modelcontextprotocol.client.transport.ServerParameters; +import io.modelcontextprotocol.client.transport.StdioClientTransport; import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.mcp.client.McpClient; -import org.springframework.ai.mcp.client.McpSyncClient; -import org.springframework.ai.mcp.client.transport.ServerParameters; -import org.springframework.ai.mcp.client.transport.StdioClientTransport; -import org.springframework.ai.mcp.spring.McpFunctionCallback; +import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -25,22 +25,22 @@ public class Application { @Bean public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, - List functionCallbacks, ConfigurableApplicationContext context) { + McpSyncClient mcpClient, ConfigurableApplicationContext context) { return args -> { var chatClient = chatClientBuilder - .defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0])) + .defaultTools(new SyncMcpToolCallbackProvider(mcpClient)) .build(); System.out.println("Running predefined questions with AI model responses:\n"); // Question 1 - String question1 = "Can you explain the content of the spring-ai-mcp-overview.txt file?"; + String question1 = "Can you explain the content of the target/spring-ai-mcp-overview.txt file?"; System.out.println("QUESTION: " + question1); System.out.println("ASSISTANT: " + chatClient.prompt(question1).call().content()); // Question 2 - String question2 = "Pleses summarize the content of the spring-ai-mcp-overview.txt file and store it a new summary.md as Markdown format?"; + String question2 = "Pleses summarize the content of the target/spring-ai-mcp-overview.txt file and store it a new target/summary.md as Markdown format?"; System.out.println("\nQUESTION: " + question2); System.out.println("ASSISTANT: " + chatClient.prompt(question2).call().content()); @@ -50,17 +50,6 @@ public class Application { }; } - @Bean - public List functionCallbacks(McpSyncClient mcpClient) { - - var callbacks = mcpClient.listTools(null) - .tools() - .stream() - .map(tool -> new McpFunctionCallback(mcpClient, tool)) - .toList(); - return callbacks; - } - @Bean(destroyMethod = "close") public McpSyncClient mcpClient() { diff --git a/model-context-protocol/sampling/mcp-sampling-client/src/main/java/org/springframework/ai/mcp/samples/client/McpClientApplication.java b/model-context-protocol/sampling/mcp-sampling-client/src/main/java/org/springframework/ai/mcp/samples/client/McpClientApplication.java index c8854fb..5016d21 100644 --- a/model-context-protocol/sampling/mcp-sampling-client/src/main/java/org/springframework/ai/mcp/samples/client/McpClientApplication.java +++ b/model-context-protocol/sampling/mcp-sampling-client/src/main/java/org/springframework/ai/mcp/samples/client/McpClientApplication.java @@ -44,17 +44,16 @@ public class McpClientApplication { @Bean public CommandLineRunner predefinedQuestions(OpenAiChatModel openAiChatModel, - ConfigurableApplicationContext context, ObjectProvider> mcpClientsProvider) { + ConfigurableApplicationContext context, List mcpClients) { return args -> { - var mcpToolProvider = new SyncMcpToolCallbackProvider( - mcpClientsProvider.stream().flatMap(List::stream).toList()); + var mcpToolProvider = new SyncMcpToolCallbackProvider(mcpClients); ChatClient chatClient = ChatClient.builder(openAiChatModel).defaultTools(mcpToolProvider).build(); String userQuestion = """ - What is the wather in Amsterdam right now? + What is the weather in Amsterdam right now? Please incorporate all createive responses from all LLM providers. After the other providers add a poem that synthesizes the the poems from all the other providers. """; @@ -69,8 +68,8 @@ public class McpClientApplication { @Bean McpSyncClientCustomizer samplingCustomizer(Map chatClients) { - return (name, spec) -> { - spec.sampling(llmRequest -> { + return (name, mcpClientSpec) -> { + mcpClientSpec.sampling(llmRequest -> { var userPrompt = ((McpSchema.TextContent) llmRequest.messages().get(0).content()).text(); String modelHint = llmRequest.modelPreferences().hints().get(0).name(); diff --git a/model-context-protocol/sampling/mcp-sampling-client/src/main/resources/application.properties b/model-context-protocol/sampling/mcp-sampling-client/src/main/resources/application.properties index 5d6ea5a..6a2ece5 100644 --- a/model-context-protocol/sampling/mcp-sampling-client/src/main/resources/application.properties +++ b/model-context-protocol/sampling/mcp-sampling-client/src/main/resources/application.properties @@ -11,3 +11,6 @@ spring.ai.mcp.client.sse.connections.server1.url=http://localhost:8080 logging.level.io.modelcontextprotocol.client=WARN logging.level.io.modelcontextprotocol.spec=WARN + + +# spring.ai.mcp.client.toolcallback.enabled=false \ No newline at end of file diff --git a/model-context-protocol/sqlite/chatbot/pom.xml b/model-context-protocol/sqlite/chatbot/pom.xml index b0eb32f..ef7d1c1 100644 --- a/model-context-protocol/sqlite/chatbot/pom.xml +++ b/model-context-protocol/sqlite/chatbot/pom.xml @@ -22,7 +22,7 @@ org.springframework.ai spring-ai-bom - 1.0.0-M5 + 1.0.0-SNAPSHOT pom import @@ -41,9 +41,8 @@ - org.springframework.experimental - spring-ai-mcp - 0.6.0 + org.springframework.ai + spring-ai-mcp-client-spring-boot-starter diff --git a/model-context-protocol/sqlite/chatbot/src/main/java/org/springframework/ai/mcp/samples/sqlite/Application.java b/model-context-protocol/sqlite/chatbot/src/main/java/org/springframework/ai/mcp/samples/sqlite/Application.java index 0993dfb..83d6254 100644 --- a/model-context-protocol/sqlite/chatbot/src/main/java/org/springframework/ai/mcp/samples/sqlite/Application.java +++ b/model-context-protocol/sqlite/chatbot/src/main/java/org/springframework/ai/mcp/samples/sqlite/Application.java @@ -5,14 +5,15 @@ import java.time.Duration; import java.util.List; import java.util.Scanner; +import io.modelcontextprotocol.client.McpClient; +import io.modelcontextprotocol.client.McpSyncClient; +import io.modelcontextprotocol.client.transport.ServerParameters; +import io.modelcontextprotocol.client.transport.StdioClientTransport; + import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.memory.InMemoryChatMemory; -import org.springframework.ai.mcp.client.McpClient; -import org.springframework.ai.mcp.client.McpSyncClient; -import org.springframework.ai.mcp.client.transport.ServerParameters; -import org.springframework.ai.mcp.client.transport.StdioClientTransport; -import org.springframework.ai.mcp.spring.McpFunctionCallback; +import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -28,12 +29,12 @@ public class Application { @Bean public CommandLineRunner interactiveChat(ChatClient.Builder chatClientBuilder, - List functionCallbacks, + List mcpClients, ConfigurableApplicationContext context) { return args -> { var chatClient = chatClientBuilder - .defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0])) + .defaultTools(new SyncMcpToolCallbackProvider(mcpClients)) .defaultAdvisors(new MessageChatMemoryAdvisor(new InMemoryChatMemory())) .build(); @@ -61,16 +62,6 @@ public class Application { }; } - @Bean - public List functionCallbacks(McpSyncClient mcpClient) { - - var callbacks = mcpClient.listTools(null) - .tools() - .stream() - .map(tool -> new McpFunctionCallback(mcpClient, tool)) - .toList(); - return callbacks; - } @Bean(destroyMethod = "close") public McpSyncClient mcpClient() { diff --git a/model-context-protocol/sqlite/simple/pom.xml b/model-context-protocol/sqlite/simple/pom.xml index 0797eb3..b52dec3 100644 --- a/model-context-protocol/sqlite/simple/pom.xml +++ b/model-context-protocol/sqlite/simple/pom.xml @@ -22,7 +22,7 @@ org.springframework.ai spring-ai-bom - 1.0.0-M5 + 1.0.0-SNAPSHOT pom import @@ -41,9 +41,8 @@ - org.springframework.experimental - spring-ai-mcp - 0.6.0 + org.springframework.ai + spring-ai-mcp-client-spring-boot-starter diff --git a/model-context-protocol/sqlite/simple/src/main/java/org/springframework/ai/mcp/samples/sqlite/Application.java b/model-context-protocol/sqlite/simple/src/main/java/org/springframework/ai/mcp/samples/sqlite/Application.java index 4f09466..4db16d4 100644 --- a/model-context-protocol/sqlite/simple/src/main/java/org/springframework/ai/mcp/samples/sqlite/Application.java +++ b/model-context-protocol/sqlite/simple/src/main/java/org/springframework/ai/mcp/samples/sqlite/Application.java @@ -4,12 +4,13 @@ import java.nio.file.Paths; import java.time.Duration; import java.util.List; +import io.modelcontextprotocol.client.McpClient; +import io.modelcontextprotocol.client.McpSyncClient; +import io.modelcontextprotocol.client.transport.ServerParameters; +import io.modelcontextprotocol.client.transport.StdioClientTransport; + import org.springframework.ai.chat.client.ChatClient; -import org.springframework.ai.mcp.client.McpClient; -import org.springframework.ai.mcp.client.McpSyncClient; -import org.springframework.ai.mcp.client.transport.ServerParameters; -import org.springframework.ai.mcp.client.transport.StdioClientTransport; -import org.springframework.ai.mcp.spring.McpFunctionCallback; +import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -25,11 +26,11 @@ public class Application { @Bean public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, - List functionCallbacks, ConfigurableApplicationContext context) { + List mcpClients, ConfigurableApplicationContext context) { return args -> { var chatClient = chatClientBuilder - .defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0])) + .defaultTools(new SyncMcpToolCallbackProvider(mcpClients)) .build(); System.out.println("Running predefined questions with AI model responses:\n"); @@ -59,17 +60,6 @@ public class Application { }; } - @Bean - public List functionCallbacks(McpSyncClient mcpClient) { - - var callbacks = mcpClient.listTools(null) - .tools() - .stream() - .map(tool -> new McpFunctionCallback(mcpClient, tool)) - .toList(); - return callbacks; - } - @Bean(destroyMethod = "close") public McpSyncClient mcpClient() {