Sitemap
Oracle Developers

Aggregation of articles from Oracle engineers, Oracle ACEs, and Java Champions on all things Oracle technology. The views expressed are those of the authors and not necessarily of Oracle.

Creating AI Agents with LangChain4J, Model Context Protocol, Oracle SQLcl MCP Server, and Oracle AI Database

12 min readDec 10, 2025

--

Press enter or click to view image in full size
LangChain4J with the Oracle AI Database 26ai

by Juarez Junior

Introduction

In this blog post, we’ll explore how to build powerful AI agents that can interface directly with an Oracle database using LangChain4J and the Oracle SQLcl MCP Server, which integrates an Oracle AI Database 26ai instance over the Model Context Protocol.

We’ll understand how LangChain4J supports MCP and walk through how to use that support to build AI assistants in Java that can run SQL, query data, and respond to user questions by talking directly to the database.

By combining these three pieces — LangChain4J, SQLcl MCP Server, and Model Context Protocol, you can get a seamless path from natural-language prompts to real database operations.

So without further ado, let’s get started!

Prerequisites

Step 1: Configure your Java application

Configure your Maven pom.xml file with the following dependencies - Oracle JDBC driver, UCP (Universal Connection Pool), LangChain4J Agentic Framework, LangChain4J MCP Integration, in-process embedding model, and other dependencies.

Using Maven

    <properties>
<java.version>23</java.version>
<maven.compiler.source>23</maven.compiler.source>
<maven.compiler.target>23</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdbc.version>23.26.0.0.0</jdbc.version>
</properties>

<dependencies>
<!-- Oracle AI Database 26ai JDBC / UCP -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc17</artifactId>
<version>${jdbc.version}</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ucp17</artifactId>
<version>${jdbc.version}</version>
</dependency>

<!-- LangChain4j -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>1.9.1</version>
</dependency>

<!-- LangChain4j Agentic -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-agentic</artifactId>
<version>1.9.1-beta17</version>
</dependency>

<!-- LangChain4j OpenAI -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.9.1</version>
</dependency>

<!-- LangChain4j MCP client -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-mcp</artifactId>
<version>1.9.1-beta17</version>
</dependency>

<!-- LangChain4j models -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-github-models</artifactId>
<version>1.9.1-beta17</version>
</dependency>

<!-- SLF4J -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
</dependency>

</dependencies>

Step 2: Install and configure SQLcl / SQLcl MCP Server

To install SQLcl, first download Oracle SQLcl 25.2 or later from its download page. Extract the ZIP file to a directory (C:\sqlcl on Windows or ~/sqlcl on Linux/Mac).

Then, ensure the sql.exe (Windows) or sql (Linux/Mac) binary is in your PATH or accessible in the installation directory (<path_to_sqlcl>/bin/).

Verify that SQLcl is properly installed and confirm its version.

sql -V
Press enter or click to view image in full size
SQLcl version check

Next, you have to set up a saved database connection. The MCP Server uses preconfigured connections stored in the ~/.dbtools directory.

Create a connection using your database credentials with the conn -save command and the -savepwd flag. Replace <DB_USERNAME>, <DB_PASSWORD>, and localhost:1521/freepdb1 with your database connection details.

<path_to_sqlcl>/bin/sql -nolog
SQL> conn -save my_mcp_connection -savepwd <DB_USERNAME>/<DB_PASSWORD>@localhost:1521/freepdb1

Provided that everything goes well as expected, you will see a message as shown below.

Press enter or click to view image in full size
SQL> conn -save my_mcp_connection -savepwd <DB_USERNAME>/<DB_PASSWORD>@localhost:1521/freepdb1

This saves a connection named my_mcp_connection with credentials securely stored. You can easily list it and confirm it persisted as shown below.

SQL> cm list
SQL> cm list

Step 3: Test it with an MCP Client

Before using the SQLcl MCP server from a Java application, it’s a good idea to test it with a client connection. Install VS Code and the Oracle SQL Developer Extension for VSCode.

Next, ensure GitHub Copilot or another MCP-compatible extension is installed and set to Agent mode.

The SQL Developer Extension automatically registers the SQLcl MCP Server when installed.

Verify by checking the MCP Servers list in VS Code. Open the Command Palette (Ctrl+Shift+P or Cmd+Shift+P), type MCP: List Servers.

Press enter or click to view image in full size
MCP: List Servers

You will see the SQLcl MCP Server listed.

Press enter or click to view image in full size
SQLcl MCP Server (Running)

Select start if it’s not running yet, and you should see log messages as shown below.

Press enter or click to view image in full size
MCP Server started successfully

Using GitHub Copilot Chat, make sure to set it to use Agent mode, and pick the model you want to use (or use the default one).

Agent mode and model selection

Now you can use natural language to interact with the database, such as “Connect to the database my_mcp_connection and list all the tables in the schema”.

The MCP Server will translate this into proper commands and SQL queries. Note that some approval actions (Allow) may be required, and you will get a result similar to the one below.

Connect to the database my_mcp_connection and list all the tables in the schema

As usual in database applications, remember to disconnect the client, so you can use something like “Disconnect from the database, and finish this session”.

Disconnect from the database, and finish this session

Step 4: Run the SQLcl MCP Server from the CLI

You can also run the SQLcl MCP Server from the CLI, externally (not using an IDE) if you want.

To run SQLcl as an MCP Server on Windows, use the -mcp flag.

<path_to_sqlcl>\bin\sql.exe -mcp

The command above starts SQLcl in MCP mode, where it communicates via JSON messages through stdin/stdout and listens for MCP requests.

The server will initialize as expected and wait for connections from an MCP client. It enables MCP clients, such as Java applications, IDEs, and tools like VS Code, to interact with your Oracle AI Database 26ai.

You should see a message similar to the one below.

Press enter or click to view image in full size
sql.exe -mcp

From this point, I will assume you have the SQLcl running as an MCP Server (MCP mode). To perform additional custom configurations, please refer to the official documentation — Using the Oracle SQLcl MCP Server.

Step 5: Create an AI Assistant with LangChain4J and the SQLcl MCP Server

Now, the most interesting part of our blog post is that we’ll explore how to use Java client code to interact with the SQLcl MCP Server.

Better, we’ll use LangChain4J to create an AI Assistant that supports running database operations using natural language.

It uses the AI Services API provided by LangChain4J, and if you need an introduction to it, please check my previous blog post — The LangChain4J AI Services API — Creating RAG services with Oracle AI Vector Search, OracleEmbeddingStore, and the Oracle Database 23ai.

First, we have to define an interface that expresses the contract for our AI Service as usual — DatabaseAssistant.java.

package com.oracle.dev.jdbc.langchain4j;

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;

public interface DatabaseAssistant {

@SystemMessage("You are a helpful Oracle Database Assistant who uses the Oracle SQLcl MCP Server and its MCP tools to execute database operations.")
String executeTask(@UserMessage String taskInstructions) throws Exception;

}

Then, we have a Java class that has a concrete implementation of our AI Assistant, including the MCP-related components as supported by LangChain4J — LangChain4jMcpSqlclDemo.java.

The implementation is quite straightforward, and now that you understand how the interaction with our MCP is expected to work, I will explain the main code sections and use the same couple of prompts in the previous example with VS Code.

We have two utility methods to check database availability by performing a simple database connection, and in a similar fashion, check
the availability of a configured SQLcl installation. The Java methods are testDatabaseConnection() and testSqlclAvailability(), respectively.

The core functionality is implemented in a Java method called runMcpDemo(), as shown below. We have comments on each relevant line of code. Nevertheless, let’s quickly have a look at each important code section.

The code below creates the MCP transport instance that will interact with the SQLcl MCP Server, which is also started along with it in MCP mode using stdio.

    // Create MCP transport for SQLcl using stdio in MCP mode
McpTransport transport = new StdioMcpTransport.Builder().command(List.of(SQLCL_PATH, "-mcp")).logEvents(true)
.build();

Then, we create an MCP client instance.

    // Create MCP client
McpClient mcpClient = new DefaultMcpClient.Builder().key("SQLCL-MCP-Client").transport(transport).build();

Then we have an optional health check call.

    // Run a health check
mcpClient.checkHealth();

The next code section has to do with the MCP tools provider and the respective available tools.

    // Create MCP tool provider
McpToolProvider toolProvider = McpToolProvider.builder().mcpClients(mcpClient).build();

// Tool discovery
List<ToolSpecification> tools = mcpClient.listTools();
System.out.println("MCP tools discovered:");
tools.forEach(t -> System.out.println(" - " + t.name()));

For the next couple of ones, business as usual, just plain LLM chat mode instances, and I added a chat memory instance as well.

    // Create a simple chat model
ChatModel chatModel = OpenAiChatModel.builder().apiKey(System.getenv("OPENAI_API_KEY")).modelName(GPT_4_O_MINI)
.build();

// Create chat memory
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(1000);

Then, it’s time to use the AiServices API in LangChain4J to instantiate our AI Assistant.

    // Create assistant service with the SQLcl MCP Server tools
DatabaseAssistant assistant = AiServices.builder(DatabaseAssistant.class).chatModel(chatModel)
.chatMemory(chatMemory).toolProvider(toolProvider).build();

Finally, we have the interactions with the SQLcl MCP Server using natural language, pretty much the same way as we performed using VS Code.

Note that we used the very same prompts (tasks) as expected, to get similar results.

    // First task
System.out.println("\nList all tables in the schema:");
String response = assistant.executeTask("""
Connect to the database my_mcp_connection and list all tables in the schema.
""");
System.out.println("Response 1: " + response);

// Second task
System.out.println("\nDisconnect from the database, and finish this session:");
String responseTwo = assistant.executeTask("""
Disconnect from the database, and finish this session.
""");
System.out.println("Response 2: " + responseTwo);

Finally, release all resources.

    // Release resources
mcpClient.close();
transport.close();
System.exit(0);

Step 6: Run the sample application

When you run this, the Java AI Assistant will interact with the SQLcl MCP Server and ask a couple of questions as expected.

The screenshots for each step are shown below.

Testing Database Connection

Testing Database Connection

Testing SQLcl Availability

Press enter or click to view image in full size
Testing SQLcl Availability

Starting the interaction with the SQLcl MCP Server and its tools

Press enter or click to view image in full size
Starting the interaction with the SQLcl MCP Server and its tools

List all tables in the schema

Press enter or click to view image in full size
List all tables in the schema

Disconnect from the database, and finish this session

Press enter or click to view image in full size
Disconnect from the database, and finish this session

The complete code sample is below.

package com.oracle.dev.jdbc.langchain4j;

import static dev.langchain4j.model.openai.OpenAiChatModelName.GPT_4_O_MINI;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;

import dev.langchain4j.agent.tool.ToolSpecification;
import dev.langchain4j.mcp.McpToolProvider;
import dev.langchain4j.mcp.client.DefaultMcpClient;
import dev.langchain4j.mcp.client.McpClient;
import dev.langchain4j.mcp.client.transport.McpTransport;
import dev.langchain4j.mcp.client.transport.stdio.StdioMcpTransport;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;

public class LangChain4jMcpSqlclDemo {

// SQLCL path
private final static String SQLCL_PATH = "C:\\sqlcl\\bin\\sql.exe";

public static void main(String[] args) {

System.out.println("=== LangChain4J AI Assistant + SQLcl MCP Server Demo ===");

try {
// Test database connection
testDatabaseConnection();

// Test SQLCL availability
testSqlclAvailability();

// Run the SQLcl MCP Server interactions
runMcpDemo();

} catch (Exception e) {
System.err.println("Error running demo: " + e.getMessage());
e.printStackTrace();
}
}

private static void runMcpDemo() throws Exception {
System.out.println("\n--- Starting the interaction with the SQLcl MCP Server and its tools ---");

// Create MCP transport for SQLcl using stdio in MCP mode
McpTransport transport = new StdioMcpTransport.Builder().command(List.of(SQLCL_PATH, "-mcp")).logEvents(true)
.build();

// Create MCP client
McpClient mcpClient = new DefaultMcpClient.Builder().key("SQLCL-MCP-Client").transport(transport).build();

// Run a health check
mcpClient.checkHealth();

// Create MCP tool provider
McpToolProvider toolProvider = McpToolProvider.builder().mcpClients(mcpClient).build();

// Tool discovery
List<ToolSpecification> tools = mcpClient.listTools();
System.out.println("MCP tools discovered:");
tools.forEach(t -> System.out.println(" - " + t.name()));

// Create a simple chat model
ChatModel chatModel = OpenAiChatModel.builder().apiKey(System.getenv("OPENAI_API_KEY")).modelName(GPT_4_O_MINI)
.build();

// Create chat memory
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(1000);

// Create assistant service with the SQLcl MCP Server tools
DatabaseAssistant assistant = AiServices.builder(DatabaseAssistant.class).chatModel(chatModel)
.chatMemory(chatMemory).toolProvider(toolProvider).build();

// First task
System.out.println("\n--- List all tables in the schema ---");
String response = assistant.executeTask("""
Connect to the database my_mcp_connection and list all tables in the schema.
""");
System.out.println("Response 1: " + response);

// Second task
System.out.println("\n--- Disconnect from the database, and finish this session ---");
String responseTwo = assistant.executeTask("""
Disconnect from the database, and finish this session.
""");
System.out.println("Response 2: " + responseTwo);

// Release resources
mcpClient.close();
transport.close();
System.exit(0);

}

private static void testDatabaseConnection() throws Exception {
System.out.println("\n--- Testing Database Connection ---");
try (Connection conn = OracleDbUtils.getConnectionFromPooledDataSource()) {
System.out.println("Database connection successful");

String sql = "SELECT SYSDATE FROM DUAL";
try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) {

if (rs.next()) {
System.out.println("Current database time: " + rs.getTimestamp(1));
}
}
}
}

private static void testSqlclAvailability() {

System.out.println("\n--- Testing SQLcl Availability ---");
ProcessBuilder pb = new ProcessBuilder(SQLCL_PATH, "-V");

try {
Process process = pb.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {

StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}

StringBuilder errors = new StringBuilder();
while ((line = errorReader.readLine()) != null) {
errors.append(line).append("\n");
}

int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println("SQLcl is available");
System.out.println("SQLcl version info: " + output.toString().trim());
} else {
System.out.println("✗ SQLcl returned exit code: " + exitCode);
if (errors.length() > 0) {
System.out.println("Error output: " + errors.toString().trim());
}
}
} finally {
process.destroy();
}

} catch (IOException | InterruptedException e) {
System.err.println("✗ Error testing SQLcl: " + e.getMessage());
Thread.currentThread().interrupt();
}
}

}

Last but not least, here’s the OracleDBUtils.java implementation. Note that I have externalized the JDBC connection details as environment variables, so I do not have to disclose my database credentials.

package com.oracle.dev.jdbc.langchain4j;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;

public class OracleDbUtils {

// JDBC connection details
private final static String URL = "jdbc:oracle:thin:@localhost:1521/FREEPDB1";
private final static String USERNAME = System.getenv("DB_USERNAME");
private final static String PASSWORD = System.getenv("DB_PASSWORD");

public static Connection getConnectionFromPooledDataSource() throws SQLException {
// Create pool-enabled data source instance
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
// set connection properties on the data source
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pds.setURL(URL);
pds.setUser(USERNAME);
pds.setPassword(PASSWORD);
// Configure pool properties with a Properties instance
Properties prop = new Properties();
prop.setProperty("oracle.jdbc.vectorDefaultGetObjectType", "String");
pds.setConnectionProperties(prop);
// Override any pool properties directly
pds.setInitialPoolSize(10);
// Get a database connection from the pool-enabled data source
Connection conn = pds.getConnection();
return conn;
}

public static DataSource getPooledDataSource() throws SQLException {
// Create pool-enabled data source instance
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
// set connection properties on the data source
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pds.setURL(URL);
pds.setUser(USERNAME);
pds.setPassword(PASSWORD);
// Configure pool properties with a Properties instance
Properties prop = new Properties();
prop.setProperty("oracle.jdbc.vectorDefaultGetObjectType", "String");
pds.setConnectionProperties(prop);
// Override any pool properties directly
pds.setInitialPoolSize(10);
return pds;
}

}

If you need to configure a running instance of Oracle AI Database 26ai, my previous blog posts listed below provide all the details.

You can also get a Maven project with a complete code sample on GitHub.

Wrapping it up

That’s it! You learnt about the potential of MCP in Java-based AI development, starting with the Oracle SQLcl MCP Server’s role in exposing database operations as callable tools.

The integration of MCP support within LangChain4J enables developers to create highly efficient applications that amplify human capabilities by combining the intelligence of LLMs with the reliability of enterprise data systems.

This powerful combination simplifies the complexity of tool invocation and response handling, making it straightforward to build and manage agentic workflows in Java.

Last, I invite you to check out the new Database Navigator tool available at the JetBrains Marketplace. In a nutshell, it features a robust SQL and PL/SQL editor with advanced capabilities for managing database connections, executing scripts, editing database objects, and modifying data and code with IntelliJ!

I will soon post more examples of scenarios involving LangChain4J, SpringAI, GraalVM, Micronaut, Quarkus, and other GenAI / Agentic AI-related topics!

We hope you liked this blog post. Stay tuned!

References

LangChain4J

LangChain4J — Javadoc

LangChain4J —Model Context Protocol

LangChain4J — Oracle Embedding Store

The LangChain4J AI Services API — Creating RAG services with Oracle AI Vector Search, OracleEmbeddingStore, and the Oracle Database 23ai

The LangChain4J Agentic AI API — Creating RAG Agents with Oracle AI Vector Search, OracleEmbeddingStore, and the Oracle AI Database 26ai

RAG the Easy Way with Oracle AI Vector Search, LangChain4J, OracleEmbeddingStore, and Oracle Database 23ai

Getting started with Oracle’s contribution to LangChain4J

Retrieval-Augmented Generation (RAG) with LangChain4j, OpenAI, and the Oracle Database 23ai

Maven — Oracle Embedding Store (langchain4j-oracle)

Oracle AI Database 26ai

Oracle AI Database 26ai Free Container Image

Oracle JDBC Driver

Oracle® AI Database JDBC Java API Reference, Release 26ai

Oracle AI Vector Search User’s Guide

Oracle AI Vector Search Technical Architecture

Quickstart: Connect to Oracle Database using IntelliJ IDEA

SQLcl — Downloads

Using the Oracle SQLcl MCP Server

Introducing MCP Server for Oracle Database

Oracle JDBC Development Center

Oracle Developers and Oracle OCI Free Tier

Join our Oracle Developers channel on Slack to discuss Java, GenAI, Agentic AI, JDK, JDBC, GraalVM, Micronaut, Spring Boot, Helidon, Quarkus, Reactive Streams, Cloud, DevOps, SRE, IaC, and other topics!

Build, test, and deploy your applications on Oracle Cloud — for free! Get access to OCI Cloud Free Tier!

--

--

Juarez Junior
Juarez Junior

Written by Juarez Junior

Senior Principal Developer Evangelist @ Oracle ☕️🐍🥑 https://linktr.ee/juarezjunior

Oracle Developers
Oracle Developers

Published in Oracle Developers

Aggregation of articles from Oracle engineers, Oracle ACEs, and Java Champions on all things Oracle technology. The views expressed are those of the authors and not necessarily of Oracle.