Wednesday, December 17, 2025

Playing with MCP Server for Oracle Database - SQLcl MCP Server & Claude Desktop client

I was trying to connect to my database using SQLcl MCP Server/protocol using Claude desktop so I can make use of Claude AI to get my work done on the database.
To know more on what is MCP protocol, MCP server/client, setting up Claude desktop on how to connect to the database, etc., I would suggest you to go through the below posts and documentation.

https://blogs.oracle.com/database/introducing-mcp-server-for-oracle-database
https://www.thatjeffsmith.com/archive/2025/07/getting-started-with-our-mcp-server-for-oracle-database/
https://docs.oracle.com/en/database/oracle/sql-developer-command-line/25.2/sqcug/using-oracle-sqlcl-mcp-server.html

There are many MCP clients we can use such as Claude desktop, VS code, Copilot, Cursor, etc. 
See https://modelcontextprotocol.io/clients for available clients at this time.

I chose Claude desktop since I already use Claude and configuration seems a bit easy at the first go. 

Make sure you have SQLcl version 25.2 and above. Else you will get the below error

2025-12-13T01:33:00.679Z [error] [sqlcl] Unexpected end of JSON input
2025-12-13T01:33:00.680Z [error] [sqlcl] Unexpected token 'B', "Bad Option: -mcp" is not valid JSON
MCP Server support is introduced only from SQLcl version 25.2.0.

My configuration file looks like below:

  {
  "mcpServers": {
    "sqlcl": {
      "command": "D:\\Oracle\\sqlcl\\bin\\sql",
      "args": ["-mcp"]
    }
   }
  }

See that we need \\ since I'm on Windows for the json escaping rules or you can simply use / in the path separator. Choice is yours.

My saved connection in SQLcl is configured as below 

SQL> conn -save cline_mcp -savepwd moviestream/oracle@192.168.56.126:1521/freepdb1
Name: cline_mcp
Connect String: 192.168.56.126:1521/freepdb1
User: moviestream
Password: ******
Connected.
SQL>
SQL> cm show cline_mcp
Name: cline_mcp
Connect String: 192.168.56.126:1521/freepdb1
User: moviestream
Password: ******
SQL>
SQL> cm test cline_mcp
Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free
Connection Test Successful
SQL>

All is well until now. Then started the actual issue when I try to connect and get some details from the database. 

 
I had very limited roles/privileges (CONNECT, RESOURCE, CREATE TABLE) granted to MOVIESTREAM user so that we don't expose unnecessary data to the LLM than what is required.
You can see from the above, the client is successfully connecting to the database and we have the following as a response. 

 

Response

### DATABASE CONNECTION ESTABLISHED ###
Successfully connected to: **cline_mcp**
Response


### DATABASE ENVIRONMENT CONTEXT ###
Response

**1. Oracle Database Version:** 
23.26.0.0.0
Response

**2. Access Mode:** 
The Oracle database is currently in 'null' mode
Response

**3. NLS Parameters:** 
The current Oracle database uses the following NLS configuration:
Database character set:
Value is not valid for option json.   Remaining options are ignored.

Value is not valid for option parameter,.   Remaining options are ignored.

 Full NLS parameters: 

Value is not valid for option json.   Remaining options are ignored.

Value is not valid for option *.   Remaining options are ignored.

 This is important for correctly interpreting data formats, encodings, and locale-specific behavior.
Response

Here’s the Oracle database context you need: version, open mode, and NLS parameters. Use this information to run the following queries accurately and ensure they align with the database’s current environment and settings.
 

From the above response, Claude got the Access Mode as 'null' which is expected as the connect runs query against v$database to get the open mode of the database. User don't have privilege. 

NLS Parameters is also messed up in the response.
The client actually runs the below queries against database once the connection is successful to get the NLS related data.

SELECT * FROM nls_database_parameters
SELECT parameter, value FROM nls_session_parameters

These queries are not getting registered in the DBTOOLS$MCP_LOG table. 

DBTOOLS$MCP_LOG table keeps track of all the queries executed by the MCP client for future auditing. The table just shows a log_message entry as "Connect to MOVIESTREAM" and not the actual queries run against database. Reason being the queries are automatically executed by SQLcl client with the connect command used to connect the user session with the database. 

In this case, after the initial connection both the queries failed to execute and subsequent chat were all just error responses as shown in the Claude chat above.

The client will have its MCP logs by name mcp-server-sqlcl.log which has the following repeated messages 

2025-12-15T01:55:13.423Z [sqlcl] [info] Message from server: {"jsonrpc":"2.0","id":12,"result":{"content":[{"type":"text","text":"### DATABASE CONNECTION ESTABLISHED ###\nSuccessfully connected to: **cline_mcp**"},{"type":"text","text":"\n### DATABASE ENVIRONMENT CONTEXT ###\n"},{"type":"text","text":"**
1. Oracle Database Version:** \n23.26.0.0.0"},{"type":"text","text":"**
2. Access Mode:** \nThe Oracle database is currently in 'null' mode"},{"type":"text","text":"**
3. NLS Parameters:** 
The current Oracle database uses the following NLS configuration:
Database character set:
Value is not valid for option json.   Remaining options are ignored.
Value is not valid for option parameter,.   Remaining options are ignored.
Full NLS parameters: 
Value is not valid for option json.   Remaining options are ignored.
Value is not valid for option *.   Remaining options are ignored.
This is important for correctly interpreting data formats, encodings, and locale-specific behavior.\n"},{"type":"text","text":"Here’s the Oracle database context you need: version, open mode, and NLS parameters. Use this information to run the following queries accurately and ensure they align with the database’s current environment and settings."}],"isError":false}} { metadata: undefined }

..
..

2025-12-15T02:13:54.531Z [sqlcl] [info] Message from server: {"jsonrpc":"2.0","id":17,"result":{"content":[{"type":"text","text":"\nValue is not valid for option LLM.   Remaining options are ignored.\n"}],"isError":false}} { metadata: undefined }

..
..

2025-12-15T02:18:55.109Z [sqlcl] [info] Message from server: {"jsonrpc":"2.0","id":21,"result":{"content":[{"type":"text","text":"### DATABASE CONNECTION ESTABLISHED ###\nSuccessfully connected to: **cline_mcp**"},{"type":"text","text":"\n### DATABASE ENVIRONMENT CONTEXT ###\n"},{"type":"text","text":"**
1. Oracle Database Version:** \n23.26.0.0.0"},{"type":"text","text":"**
2. Access Mode:** \nThe Oracle database is currently in 'READ WRITE' mode"},{"type":"text","text":"**
3. NLS Parameters:** \nThe current Oracle database uses the following NLS configuration:\nDatabase character set:\nValue is not valid for option json.   Remaining options are ignored.\n\nValue is not valid for option parameter,.   Remaining options are ignored.\n\n Full NLS parameters: \n\nValue is not valid for option json.   Remaining options are ignored.\n\nValue is not valid for option *.   Remaining options are ignored.\n\n This is important for correctly interpreting data formats, encodings, and locale-specific behavior.\n"},{"type":"text","text":"Here’s the Oracle database context you need: version, open mode, and NLS parameters. Use this information to run the following queries accurately and ensure they align with the database’s current environment and settings."}],"isError":false}} { metadata: undefined }
 
I thought if these were errors due to some permission issues against internal tables/views and tried to grant the privileges and even DBA role to check if that makes a difference
grant select on sys.v_$nls_parameters to moviestream;
grant select on sys.v_$database to moviestream;
grant dba to moviestream;

Result is the same errors. These additional privileges/roles are not needed for MCP to work properly. 
Interestingly, the queries which are run against the database is being captured in the DBTOOLS$MCP_LOG table under MOVIESTREAM schema. 

Below is a screenshot of the tables content for basic understanding


The query passed to database by the Claude client is as below

SELECT /* LLM in use is claude-sonnet-4-5 */ table_name FROM user_tables;

All the queries will be added a comment with what LLM is being used when it's executed by the MCP client and the query is executed. The query execution resulted in the error below

Value is not valid for option LLM. Remaining options are ignored.

From logs what we have is the below 
2025-12-14T01:21:23.569Z [sqlcl] [info] Message from client: {"method":"tools/call","params":{"name":"run-sql","arguments":{"model":"claude-sonnet-4-5-20250929","sql":"SELECT table_name FROM user_tables"}},"jsonrpc":"2.0","id":10} { metadata: undefined }
2025-12-14T01:21:23.599Z [sqlcl] [info] Message from server: {"jsonrpc":"2.0","id":10,"result":{"content":[{"type":"text","text":"\nValue is not valid for option LLM.   Remaining options are ignored.\n"}],"isError":false}} { metadata: undefined }
 

Basically, client sends a request with a few args and MCP server (SQLcl) sends back a error response.

Doesn't make sense on why SQLcl send error response on argument (LLM) which was not passed to it. 

After a long time trying to debug the issue by different prompts from the client, executing query directly in the SQLcl prompt with/without comments, etc., none of which resolved the issue. 

I just deleted the sqlcl directory and uninstalled Java and downloaded them both again using the same way I used to do the first time and installed Java and started the SQLcl and reconfigured Claude desktop.

This time everything started to work without any issues as expected.


I'm not sure what caused the issue but with this issue, I was able to get a proper hands-on with the MCP Server, it's working and debugging methods. Hope this post will help others as well. 



References:

https://blogs.oracle.com/database/introducing-mcp-server-for-oracle-database
https://www.thatjeffsmith.com/archive/2025/07/getting-started-with-our-mcp-server-for-oracle-database/
https://docs.oracle.com/en/database/oracle/sql-developer-command-line/25.2/sqcug/using-oracle-sqlcl-mcp-server.html


 Happy playing with AI...!!! 

 

 

Tuesday, February 13, 2024

Connection to Oracle Autonomous Database

This article explains how to connect to an Oracle Autonomous database using SQL developer, SQL plus or other tools.

When we create an Oracle ADB on OCI, we just can't connect directly to the database even though the Network ACL is disabled. The reason is mTLS authentication is set to Required by default. 

Let us see how to connect to the ADB using SQL developer first and then SQL plus.

If you have downloaded SQL developer for connecting to your database on cloud, it's super easy to connect.

Method 1: Using mTLS  

Mutual TLS (mTLS) is a 2-way handshake between a client and a server, and a more secure way of connection compared to TLS.

Step 1: Download the wallet (This is required for mTLS)

Go to your Autonomous database details page => Click on Database connection => Click on Download wallet



Provide the password and click on Download. This is your wallet password and not the password for the database Admin user or the database application user you are trying to connect. 

Step 2: Once you have this credentials wallet zip, Open SQL Developer and edit the connection properties to connect to the Autonomous database as below



Make sure we have the connection type selected as Cloud Wallet and provide the downloaded zip file under configuration file. 
While selecting Service, we have different default service to choose from which differs on how the connection works. I have selected atp01_high of the below 5 available.
  • atp01_high
  • atp01_low
  • atp01_medium
  • atp01_tp
  • atp01_tpurgent
Click on the Test button to check the connectivity and we now have a Successful connection. 

How do we connect to using SQL Plus? 

To make a SQL Plus or any Oracle Call Interface (OCI), JDBC connection to the Autonomous database, we need the client software to be installed in the server from where we are trying to connect. 
Since we need the wallet location to be specified, we should have sqlnet.ora file and tnsnames.ora file

I'll use my existing on-prem Linux server to attempt a connection without the wallet file location specified in the sqlnet.ora but with only the tnsnames.ora edited with the connection details of the ADB. 
[oracle@linux-8 db-sample-schemas-main]$ cd order_entry/
[oracle@linux-8 order_entry]$ sqlplus admin/xxxxx@'(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)
(host=adb.us-ashburn-1.oraclecloud.com))(connect_data=(service_name=g34efa58d1e9751_atp01_high.adb.oraclecloud.com))
(security=(ssl_server_dn_match=yes)))'

SQL*Plus: Release 19.0.0.0.0 - Production on Wed Feb 7 03:56:14 2024
Version 19.20.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

ERROR:
ORA-12506: TNS:listener rejected connection based on service ACL filtering


Enter user-name:
 
So where do I get the connection description information from? 
When I click on the Database connection button on the Database details page, I'll get the connection strings for all the 5 services or the downloaded zip will include the tnsnames.ora file containing this information. 

As you see when we didn't provide the wallet location, we are not able to connect with error ORA-12506. 

There are 2 things you can do to fix this. 
Easy way is to unzip the contents of the downloaded zip file to a directory on the server and define the TNS_ADMIN environment variable value to this directory and attempt the connection. Make sure to make changes in the sqlnet.ora file to denote the wallet location
[oracle@linux-8 db-sample-schemas-main]$ ls -lrt
total 28
-rwxrwx---. 1 root vboxsf 21984 Jan  9 21:17 Wallet_ATP01.zip
drwxrwx---. 1 root vboxsf  4096 Feb  7 04:00 db-sample-schemas-main
[oracle@linux-8 db-sample-schemas-main]$ unzip Wallet_ATP01.zip -d ./Wallet_ATP01
Archive:  Wallet_ATP01.zip
  inflating: ./Wallet_ATP01/ewallet.pem
  inflating: ./Wallet_ATP01/README
  inflating: ./Wallet_ATP01/cwallet.sso
  inflating: ./Wallet_ATP01/tnsnames.ora
  inflating: ./Wallet_ATP01/truststore.jks
  inflating: ./Wallet_ATP01/ojdbc.properties
  inflating: ./Wallet_ATP01/sqlnet.ora
  inflating: ./Wallet_ATP01/ewallet.p12
  inflating: ./Wallet_ATP01/keystore.jks
[oracle@linux-8 db-sample-schemas-main]$ cd Wallet_ATP01/
[oracle@linux-8 Wallet_ATP01]$ vi sqlnet.ora
[oracle@linux-8 Wallet_ATP01]$ more sqlnet.ora
WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY="?/network/admin")))
SSL_SERVER_DN_MATCH=yes
[oracle@linux-8 Wallet_ATP01]$ vi sqlnet.ora
[oracle@linux-8 Wallet_ATP01]$ more sqlnet.ora
WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY="/media/sf_Oracle/software/db-sample-schemas-main/Wallet_ATP01")))
SSL_SERVER_DN_MATCH=yes
[oracle@linux-8 Wallet_ATP01]$ export TNS_ADMIN=/media/sf_Oracle/software/db-sample-schemas-main/Wallet_ATP01
[oracle@linux-8 Wallet_ATP01]$ sqlplus admin/xxxxx@atp01_high

SQL*Plus: Release 19.0.0.0.0 - Production on Sat Feb 10 05:02:32 2024
Version 19.20.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

Last Successful login time: Sat Feb 10 2024 04:11:47 +05:30

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.22.0.1.0

SQL> select instance_name from v$instance;

INSTANCE_NAME
----------------
feky1pod2

SQL>

 
I just used atp01_high as my connect identifier as they are already defined in the tnsnames.ora file thats bundled in the zip. 

If you already have a working TNS_ADMIN (which defaults to $ORACLE_HOME/network/admin), all you have to do is to only mention the below 2 parameters in the existing sqlnet.ora file and add the connection string for the ADB connection in the tnsnames.ora file. 
WALLET_LOCATION = (SOURCE = (METHOD = file) (METHOD_DATA = (DIRECTORY="/media/sf_Oracle/software/db-sample-schemas-main/Wallet_ATP01")))
SSL_SERVER_DN_MATCH=yes

Method 2: Using TLS connection.

Now let's see how to connect to the Autonomous database without the wallet files using a TLS connection. 

We can connect to the autonomous database without the wallet files as well. If we wan't to allow TLS connection to connect to Autonomous database, we need to enable Access Control List (ACL). To do that, we can click on edit adjacent to the Disabled status of Access Control List

We can configure different type of ACLs such as with specific IPs, CIDR block, VCNs or VCN OCID and the combination of these can be used in real environments. 

For our testing purpose, I'm just going to add my ip address to show the ACL and TLS connection. 

Just click on Add my IP address and click Save. This will add our IP address to the ACL and the status of the ACL will turn as Enabled. 
Now click on Edit adjacent to mTLS: Required

Uncheck the Require mTLS authentication check box to disable mTLS


Now, we have enabled TLS authentication to the Autonomous database but only the connections from my IP is allowed since we have also enabled ACLs. 

Now, as we changed the configuration, lets try to connect to the ADB without the wallet files to the database using SQL Developer first and then using SQL Plus. 

The configuration will look like the below. 

We have now selected Custom JDBC instead of Cloud wallet since we are not using TLS connection for the database. 
For the JDBC URL, the format should be 
jdbc:oracle:thin:@<connection string for the service intended> 

In my example, I'm trying to connect to atp01_high service and hence the JDBC URL will be as below. 
jdbc:oracle:thin:@(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)
(port=1522)(host=adb.us-ashburn-1.oraclecloud.com))
(connect_data=(service_name=g34efa58d1e9750_atp01_high.adb.oraclecloud.com))
(security=(ssl_server_dn_match=yes)))
Click on Test to see the connection status is Success. 

If we need to connect using SQL Plus, we can save this connect string in the tnsnames.ora file and connect directly. 
[oracle@linux-8 admin]$ pwd
/oracle/db/db19/network/admin
[oracle@linux-8 admin]$ ls -lrt sqlnet.ora tnsnames.ora
-rw-r-----. 1 oracle oinstall 1629 Feb  7 04:33 tnsnames.ora
-rw-r--r--. 1 oracle oinstall  619 Feb 10 05:16 sqlnet.ora
[oracle@linux-8 admin]$ rm sqlnet.ora
[oracle@linux-8 admin]$ tail tnsnames.ora
rmancat =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = linux-8.selvapc.com)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = rmancat.selvapc.com)
    )
  )

atp = (description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=adb.us-ashburn-1.oraclecloud.com))(connect_data=(service_name=g34efa58d1e9751_atp01_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))
[oracle@linux-8 admin]$
[oracle@linux-8 admin]$ tnsping atp

TNS Ping Utility for Linux: Version 19.0.0.0.0 - Production on 13-FEB-2024 10:18:22

Copyright (c) 1997, 2023, Oracle.  All rights reserved.

Used parameter files:


Used TNSNAMES adapter to resolve the alias
Attempting to contact (description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=adb.us-ashburn-1.oraclecloud.com))(connect_data=(service_name=g34efa58d1e9750_atp01_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))
OK (380 msec)
[oracle@linux-8 admin]$
[oracle@linux-8 admin]$ sqlplus admin/xxxxx@atp

SQL*Plus: Release 19.0.0.0.0 - Production on Tue Feb 13 10:18:37 2024
Version 19.20.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

Last Successful login time: Mon Feb 12 2024 11:49:25 +05:30

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.22.0.1.0

SQL>
  
In the above demo, I just removed my tnsnames.ora file meaning we don't pass any location for the wallet files which is confirmed by blank o/p for Used parameter files of the tnsping. 
We are now able to connect to the autonomous database using TLS but only from my specific IP address. 
Any connection attempt from other addresses will not be allowed as per the ACL. 

Requirements of TLS connection: 

SQL Developer - version 18.2 or later
SQL Plus - Oracle instant client/database client 19.14 or later and 21.5 or later (if you need it on Windows)

References: 

Connect to Autonomous Database Using Oracle Database Tools

Happy Connecting...!!!