diff --git a/model-context-protocol/sqlite/chatbot/README.md b/model-context-protocol/sqlite/chatbot/README.md index 386c822..2cd280d 100644 --- a/model-context-protocol/sqlite/chatbot/README.md +++ b/model-context-protocol/sqlite/chatbot/README.md @@ -2,7 +2,7 @@ A demo application showcasing the integration of Spring AI with SQLite databases using the Model Context Protocol (MCP). This application enables natural language interactions with your SQLite database through a command-line interface. -It uses the [SQLite MCP-Server](https://github.com/modelcontextprotocol/servers/tree/main/src/sqlite) to enable running SQL queries, analyzing business data, and automatically generating business insight memos. +It uses the [SQLite MCP-Server](https://pypi.org/project/mcp-server-sqlite/) to enable running SQL queries, analyzing business data, and automatically generating business insight memos. The demo starts a simple chatbot where your can ask qustions about the data stored in the database. @@ -68,7 +68,7 @@ It has a `PRODUCTS` table and was created using the script `create-database.sh` Enables real-time conversation with your database: ```bash -./mvnw spring-boot:run -Dspring-boot.run.profiles=chat +./mvnw spring-boot:run ``` ## Architecture Overview @@ -85,8 +85,8 @@ public McpSyncClient mcpClient() { .args("mcp-server-sqlite", "--db-path", getDbPath()) .build(); - var mcpClient = McpClient.sync(new StdioServerTransport(stdioParams), - Duration.ofSeconds(10), new ObjectMapper()); + var mcpClient = McpClient.sync(new StdioClientTransport(stdioParams, McpJsonMapper.createDefault())) + .requestTimeout(Duration.ofSeconds(10)).build(); var init = mcpClient.initialize(); @@ -105,39 +105,6 @@ This configuration: The `destroyMethod = "close"` annotation ensures proper cleanup when the application shuts down. -### Function Callbacks - -The application registers MCP tools with Spring AI using function callbacks: - -```java -@Bean -public List functionCallbacks(McpSyncClient mcpClient) { - return mcpClient.listTools(null) - .tools() - .stream() - .map(tool -> new McpFunctionCallback(mcpClient, tool)) - .toList(); -} -``` - -#### Purpose - -This bean is responsible for: -1. Discovering available MCP tools from the client -2. Converting each tool into a Spring AI function callback -3. Making these callbacks available for use with the ChatClient - - -#### How It Works - -1. `mcpClient.listTools(null)` queries the MCP server for all available tools - - The `null` parameter represents a pagination cursor - - When null, returns the first page of results - - A cursor string can be provided to get results after that position -2. `.tools()` extracts the tool list from the response -3. Each tool is transformed into a `McpFunctionCallback` using `.map()` -4. These callbacks are collected into an array using `.toArray(McpFunctionCallback[]::new)` - #### Usage The registered callbacks enable the ChatClient to: 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 885495b..5aa8c7f 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 @@ -14,6 +14,7 @@ import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.memory.MessageWindowChatMemory; +import org.springframework.ai.mcp.McpToolNamePrefixGenerator; import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; @@ -33,9 +34,11 @@ public CommandLineRunner interactiveChat(ChatClient.Builder chatClientBuilder, List mcpClients, ConfigurableApplicationContext context) { return args -> { - - var chatClient = chatClientBuilder - .defaultToolCallbacks(new SyncMcpToolCallbackProvider(mcpClients)) + var toolCallbackProvider = SyncMcpToolCallbackProvider.builder() + .mcpClients(mcpClients) + .toolNamePrefixGenerator(McpToolNamePrefixGenerator.noPrefix()) + .build(); + var chatClient = chatClientBuilder.defaultToolCallbacks(toolCallbackProvider) .defaultAdvisors(MessageChatMemoryAdvisor.builder(MessageWindowChatMemory.builder().build()).build()) .build(); diff --git a/model-context-protocol/sqlite/simple/README.md b/model-context-protocol/sqlite/simple/README.md index 88ca50f..e2536e2 100644 --- a/model-context-protocol/sqlite/simple/README.md +++ b/model-context-protocol/sqlite/simple/README.md @@ -2,7 +2,7 @@ A demo application showcasing the integration of Spring AI with SQLite databases using the Model Context Protocol (MCP). This application enables natural language interactions with your SQLite database through a command-line interface. -It uses the [SQLite MCP-Server](https://github.com/modelcontextprotocol/servers/tree/main/src/sqlite) to enable running SQL queries, analyzing business data, and automatically generating business insight memos. +It uses the [SQLite MCP-Server](https://pypi.org/project/mcp-server-sqlite/) to enable running SQL queries, analyzing business data, and automatically generating business insight memos. ## Features @@ -67,13 +67,15 @@ The bean definitions are described below, starting with the `ChatClient` ```java @Bean -@Profile("!chat") public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, - List functionCallbacks, - ConfigurableApplicationContext context) { - return args -> { - var chatClient = chatClientBuilder.defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0])) - .build(); + List mcpClients, ConfigurableApplicationContext context) { + + return args -> { + var toolCallbackProvider = SyncMcpToolCallbackProvider.builder() + .mcpClients(mcpClients) + .toolNamePrefixGenerator(McpToolNamePrefixGenerator.noPrefix()) + .build(); + var chatClient = chatClientBuilder.defaultToolCallbacks(toolCallbackProvider).build(); // Run Predefined Questions System.out.println(chatClient.prompt( "Can you connect to my SQLite database and tell me what products are available, and their prices?").call().content()); @@ -82,51 +84,10 @@ public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilde } ``` -The chat client setup is remarkably simple - it just needs the function callbacks that were automatically created from the MCP tools. Spring's dependency injection handles all the wiring, making the integration seamless. +The chat client setup is remarkably simple - it just needs the mcp clients. Spring's dependency injection handles all the wiring, making the integration seamless. Now let's look at the other bean definitions in detail... -### Function Callbacks - -The application registers MCP tools with Spring AI using function callbacks: - -```java -@Bean -public List functionCallbacks(McpSyncClient mcpClient) { - return mcpClient.listTools(null) - .tools() - .stream() - .map(tool -> new McpFunctionCallback(mcpClient, tool)) - .toList(); -} -``` - -#### Purpose - -This bean is responsible for: -1. Discovering available MCP tools from the client -2. Converting each tool into a Spring AI function callback -3. Making these callbacks available for use with the ChatClient - - -#### How It Works - -1. `mcpClient.listTools(null)` queries the MCP server for all available tools - - The `null` parameter represents a pagination cursor - - When null, returns the first page of results - - A cursor string can be provided to get results after that position -2. `.tools()` extracts the tool list from the response -3. Each tool is transformed into a `McpFunctionCallback` using `.map()` -4. These callbacks are collected into an array using `.toArray(McpFunctionCallback[]::new)` - -#### Usage - -The registered callbacks enable the ChatClient to: -- Access MCP tools during conversations -- Handle function calls requested by the AI model -- Execute tools against the MCP server (e.g., SQLite database) - - ### MCP Client The application uses a synchronous MCP client to communicate with the SQLite database: @@ -138,8 +99,8 @@ public McpSyncClient mcpClient() { .args("mcp-server-sqlite", "--db-path", getDbPath()) .build(); - var mcpClient = McpClient.sync(new StdioServerTransport(stdioParams), - Duration.ofSeconds(10), new ObjectMapper()); + var mcpClient = McpClient.sync(new StdioClientTransport(stdioParams, McpJsonMapper.createDefault())) + .requestTimeout(Duration.ofSeconds(10)).build(); var init = mcpClient.initialize(); System.out.println("MCP Initialized: " + init); 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 a75a2ee..d69a4d8 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 @@ -11,6 +11,7 @@ import io.modelcontextprotocol.json.McpJsonMapper; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.mcp.McpToolNamePrefixGenerator; import org.springframework.ai.mcp.SyncMcpToolCallbackProvider; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; @@ -30,9 +31,11 @@ public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilde List mcpClients, ConfigurableApplicationContext context) { return args -> { - var chatClient = chatClientBuilder - .defaultToolCallbacks(new SyncMcpToolCallbackProvider(mcpClients)) - .build(); + var toolCallbackProvider = SyncMcpToolCallbackProvider.builder() + .mcpClients(mcpClients) + .toolNamePrefixGenerator(McpToolNamePrefixGenerator.noPrefix()) + .build(); + var chatClient = chatClientBuilder.defaultToolCallbacks(toolCallbackProvider).build(); System.out.println("Running predefined questions with AI model responses:\n"); // Question 1