Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 4 additions & 37 deletions model-context-protocol/sqlite/chatbot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand All @@ -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();

Expand All @@ -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<McpFunctionCallback> 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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -33,9 +34,11 @@ public CommandLineRunner interactiveChat(ChatClient.Builder chatClientBuilder,
List<McpSyncClient> 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();

Expand Down
63 changes: 12 additions & 51 deletions model-context-protocol/sqlite/simple/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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<McpFunctionCallback> functionCallbacks,
ConfigurableApplicationContext context) {
return args -> {
var chatClient = chatClientBuilder.defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0]))
.build();
List<McpSyncClient> 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());
Expand All @@ -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<McpFunctionCallback> 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:
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,9 +31,11 @@ public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilde
List<McpSyncClient> 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
Expand Down