I’d been looking for a simple, verifiable scenario to showcase Oracle SQLcl MCP Server with Claude Desktop. At DOAG (the German Oracle user conference), one question kept coming up: how do you convert comments into annotations? While chatting with colleagues, someone said, “Just try the SQLcl MCP server.” The example breaks into small, testable steps, is easy to double-check, and solves a real problem—so I went with it.

What is Oracle MCP integration?
Oracle has integrated MCP into our core developer tools, i.e. your Oracle Database is available for your local AI assistants (coding and otherwise) via our MCP Server, SQLcl. If you use GitHub Copilot in VS Code, you can access the SQLcl MCP Server through SQL Developer for VS Code: create a database connection and start asking Copilot questions. However, you can also use any MCP-capable client such as Cline or Claude. After configuration, the client starts the server as needed, manages its lifecycle, and closes it cleanly, enabling natural-language interactions with Oracle Database. To configure a client, specify the server location.

More information can be found e.g. in
How the SQLcl MCP Server Works (documentation)
Introducing MCP Server for Oracle Database (posting)
Getting Started with our MCP Server for Oracle Database (posting)

And what are annotations? Annotations are stored centrally in the database, enrich database objects, and let you share metadata across applications, modules, and microservices. Compared with comments, schema annotations have a much broader scope, are easier to manage, and are Oracle’s forward path for metadata enrichment. As of Database RU 19.28, annotations are also available in 19c.

Here is a simple example to show how to create table and column annotations.

create table emp_annotated
(empno number,
ename varchar2(50) annotations (display 'lastname'),
salary number annotations (person_salary, column_hidden)
)
annotations (usage 'reports');

The second example shows a table with a vector data column. To add an table annotation to an existing table you can use the ALTER TABLE command. The column annotation called embedding_model indicates that the embedding model ‘all_MiniLM-L12-v2’.

create table if not exists CCNEWS (id number(10) not null,
info varchar2(4000),
vec vector);

alter table CCNEWS modify vec annotations (embedding_model 'all-MiniLM-L12-v2');


More information about annotations can be found e.g. in :

– SQL Language Reference: annotations_clause (documentation)
Best Practices for Enriching Your Database Schema (documentation)
Schema Annotations – the new metadata (posting)

To handle moving comments into annotations using SQL —since Oracle doesn’t have a built-in feature for this yet —you could use an ALTER TABLE command. The idea is to make use of the existing comments from USER_TAB_COMMENTS and USER_COL_COMMENTS, then use ALTER TABLE to add the annotations you need.
Just keep in mind that you can add comments to different types of objects—not just tables. These include table and view columns, materialized views, unified audit policies, editions, indextypes, mining models, and operators. You can find the full list in the Oracle documentation here .

Since annotations have names, you may need to provide names for the annotations. Afterward, you can check everything with USER_ANNOTATIONS_USAGE and delete the original comments if you want. Chris Saxon wrote also a blog post on how to do this (check out “How to convert object comments to schema annotations).

The aim of this post is to show how you can use SQLcl MCP server and Claude Desktop to request and execute scripts that convert comments to annotations in the HR schema, check the generated scripts, and keep an eye on database access.
You’ll find a complete walkthrough with step-by-step instructions (for Claude Desktop on Windows and SQLcl 25.3) so you can easily follow along and try it out yourself.

This is the posting structure (skip setup if you’re already configured)

  1. Setup: SQLcl, HR schema, and saved database connections
  2. Use and double-check
  3. Monitoring
  4. Learnings


1. Setup: SQLcl, HR Schema, and saved database connections

a) Install SQLcl and setup HR

Download the latest Oracle SQLcl, unzip it, and verify you can connect to your Oracle Database. If the HR schema isn’t installed, you may use the SQL scripts here from github. It’s straightforward and takes only a few minutes.

b) Enable secure, seamless AI client access  in SQlcl or SQL developer for VSCode

The SQLcl MCP Server uses named, saved connections. You can manage these with SQLcl  commands connect and connmgr/cm or via the Oracle SQL Developer extension for VS Code.
Important: for an MCP client to use a connection, its password must be saved.


Documentation:
Connection manager (connmgr/cm)
CONNECT command

Let’s create and save a new connection called “claude_hr”. When you create a new connection, use the -savepwd flag to store credentials securely.

sql /nolog
SQLcl: Release 25.3 Production on Sun Dec 14 12:08:09 2025

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

SQL> conn -save claude_hr -savepwd hr@(DESCRIPTION =(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = xxxxx)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = ulrike.de.oracle.com)))
Password? (**********?) **
Name: claude_hr
Connect String: (DESCRIPTION =(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = xxxx)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = ulrike.de.oracle.com)))
User: hr
Password: ******
Connected.

-- Display connection claude_hr.

SQL> cm show claude_hr
Name: claude_hr
Connect String: (DESCRIPTION =(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = xxx)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = ulrike.de.oracle.com)))
User: hr
Password: ******

-- Connect to claude_hr

SQL> conn -name claude_hr
Connected.
SQL> cm list
.
+--- atp23_textuser
+--- claude_hr
+--- hp_test
+--- hpcexa01_textuser
+--- hpcexa01_vecus
+--- hpexa_hr
|___ hpexa_scott

You may also use Oracle SQL Developer Extension for VS Code and save the connection.

c) Install and configure Claude Desktop

Install Claude Desktop (see Installing Claude for Desktop). Review the SQLcl MCP Server setup doc here.

  • Open Claude Desktop > Menu > File > Settings > Developer.
  • Click “Edit the configuration” to open claude_desktop_config.json.
  • Add the SQLcl command path (sql) to the MCP tools section, then save.

In my example the entry looks like. 

{
"mcpServers": {    
    "sqlcl": {
      "command": "c:\\Data\\sqlcl1\\sqlcl\\bin\\sql",
      "args": ["-mcp"]
    }
  }
}

For improved security, Oracle SQLcl’s restrict option lets you disable certain OS-related commands to prevent unsafe operations. By default, the SQLcl MCP Server uses the strictest security (level 4) when started with “args”: [“-mcp”]. You can adjust the restrict level by editing your server configuration file and adding the -R argument with your desired level (0–3) to the args array. For details, (see About Restrict Levels in SQLcl).

2. Use and double-check

Before we start, let’s first check the comments in the schema HR Schema and display the table comments.

SQL> select table_name, comments
from user_tab_comments
where table_type = 'TABLE' AND comments IS NOT NULL
order by table_name;

TABLE_NAME COMMENTS
-------------------- ---------------------------------------------------------------
COUNTRIES country table. References with locations table.
DEPARTMENTS Departments table that shows details of departments where ..
EMPLOYEES employees table. References with departments,
JOBS jobs table with job titles and salary ranges.
JOB_HISTORY Table that stores job history of the employees. If an employee
LOCATIONS Locations table that contains specific address of a specific..
REGIONS Regions table that contains region numbers and names...

7 rows selected.

Now let’s check the column comments with user_col_comments.

SQL> select table_name, column_name, comments
from user_col_comments
where comments IS NOT NULL
order by table_name, column_name;

TABLE_NAME COLUMN_NAME COMMENTS
-------------------- ------------------------- -------------------------------------
COUNTRIES COUNTRY_ID Primary key of countries table.
COUNTRIES COUNTRY_NAME Country name
COUNTRIES REGION_ID Region ID for the country...
DEPARTMENTS DEPARTMENT_ID Primary key column of departments ...
DEPARTMENTS DEPARTMENT_NAME A not null column that shows name ...
...
REGIONS REGION_ID Primary key of regions table.
REGIONS REGION_NAME Names of regions. Locations are in the countries of these regions.

35 rows selected.

Now let’s interact with Claude desktop. Open a chat window and click on “Search and tools”. You will see an entry for sqlcl.


Now let’s start asking questions. In any case we will double-check the answers.

Chat: “List database connections!”

As we can see the connection claude_hr is available.

Chat: “Connect to claude_hr.”

Chat: “Create a script to list all table and column comments of schema HR and execute it”

Claude: Perfect! The script has been executed successfully. Here’s the summary:

Table Comments (7 tables):

  1. COUNTRIES – country table. References with locations table.
  2. DEPARTMENTS – Departments table that shows details of departments where employees work
  3. EMPLOYEES – employees table. References with departments, jobs, job_history tables
  4. JOBS – jobs table with job titles and salary ranges
  5. JOB_HISTORY – Table that stores job history of the employees
  6. LOCATIONS – Locations table that contains specific address of offices, warehouses, and production sites
  7. REGIONS – Regions table that contains region numbers and names

Column Comments (35 columns):

  • COUNTRIES: 3 columns (COUNTRY_ID, COUNTRY_NAME, REGION_ID)
  • DEPARTMENTS: 4 columns (DEPARTMENT_ID, DEPARTMENT_NAME, LOCATION_ID, MANAGER_ID)
  • EMPLOYEES: 10 columns (COMMISSION_PCT, DEPARTMENT_ID, EMAIL, EMPLOYEE_ID, FIRST_NAME, HIRE_DATE, JOB_ID, LAST_NAME, MANAGER_ID, PHONE_NUMBER, SALARY)
  • JOBS: 4 columns (JOB_ID, JOB_TITLE, MAX_SALARY, MIN_SALARY)
  • JOB_HISTORY: 5 columns (DEPARTMENT_ID, EMPLOYEE_ID, END_DATE, JOB_ID, START_DATE)
  • LOCATIONS: 6 columns (CITY, COUNTRY_ID, LOCATION_ID, POSTAL_CODE, STATE_PROVINCE, STREET_ADDRESS)
  • REGIONS: 2 columns (REGION_ID, REGION_NAME)

Total: 7 table comments + 35 column comments = 42 comments

Above we already checked the comments. So let’s continue.

Chat: “Please provide a script to add exactly 7 table annotations to the HR tables. Use the existing comments for the 7 table annotation values and “<table_name>_ann” – where table_name is the name of the table – for the table annotation name. Do not execute it!”

Claude: Here’s the script to add exactly 7 table annotations for the HR schema tables with custom annotation names. The annotation names follow the pattern <table_name>_ann:

  1. COUNTRIES_ann – for COUNTRIES table
  2. DEPARTMENTS_ann – for DEPARTMENTS table
  3. EMPLOYEES_ann – for EMPLOYEES table
  4. JOBS_ann – for JOBS table
  5. JOB_HISTORY_ann – for JOB_HISTORY table
  6. LOCATIONS_ann – for LOCATIONS table
  7. REGIONS_ann – for REGIONS table

Each annotation uses the existing table comment as its value. You can review and execute it whenever you’re ready.
I checked the script and executed it. Here is a snippet.

- Script to add exactly 7 table annotations for HR schema tables
-- Using custom annotation names: <table_name>_ann
-- Using existing table comments as annotation values
-- Created: December 16, 2025
-- NOTE: Review this script before executing

SET ECHO ON
SET FEEDBACK ON
SET VERIFY ON

PROMPT ====================================
PROMPT Adding 7 Table Annotations for HR Schema
PROMPT With Custom Annotation Names
PROMPT ====================================
PROMPT

-- COUNTRIES table annotation
PROMPT Adding annotation COUNTRIES_ann for COUNTRIES table...
ALTER TABLE HR.COUNTRIES ANNOTATIONS (ADD COUNTRIES_ann 'country table. References with locations table.');

-- DEPARTMENTS table annotation
PROMPT Adding annotation DEPARTMENTS_ann for DEPARTMENTS table...
ALTER TABLE HR.DEPARTMENTS ANNOTATIONS (ADD DEPARTMENTS_ann 'Departments table that shows details of departments where employees
work. references with locations, employees, and job_history tables.');
...

Chat: “Please provide a script to add exactly 35 column annotations. Use the existing column comments from HR column comments for the values and the pattern <column_name>_ann for the name. Do not execute it!”

Claude: Here’s the script to add exactly 35 column annotations with custom annotation names following the pattern <column_name>_ann. The breakdown is:

COUNTRIES (3 columns):

  • COUNTRY_ID_ann
  • COUNTRY_NAME_ann
  • REGION_ID_ann

DEPARTMENTS (4 columns):

  • DEPARTMENT_ID_ann
  • DEPARTMENT_NAME_ann
  • LOCATION_ID_ann
  • MANAGER_ID_ann

EMPLOYEES (10 columns):

  • COMMISSION_PCT_ann
  • DEPARTMENT_ID_ann
  • EMAIL_ann
  • EMPLOYEE_ID_ann
  • FIRST_NAME_ann
  • HIRE_DATE_ann
  • JOB_ID_ann
  • LAST_NAME_ann
  • MANAGER_ID_ann
  • PHONE_NUMBER_ann
  • SALARY_ann

JOBS (4 columns):

  • JOB_ID_ann
  • JOB_TITLE_ann
  • MAX_SALARY_ann
  • MIN_SALARY_ann

JOB_HISTORY (5 columns):

  • DEPARTMENT_ID_ann
  • EMPLOYEE_ID_ann
  • END_DATE_ann
  • JOB_ID_ann
  • START_DATE_ann

LOCATIONS (6 columns):

  • CITY_ann
  • COUNTRY_ID_ann
  • LOCATION_ID_ann
  • POSTAL_CODE_ann
  • STATE_PROVINCE_ann

REGIONS (2 columns):

  • REGION_ID_ann
  • REGION_NAME_ann

Total: 35 column annotations

Each annotation uses the existing column comment as its value. You can review and execute it whenever you’re ready.


I checked the script and executed it. Here is a snippet…

- Script to add exactly 35 column annotations for HR schema columns
-- Using custom annotation names: <column_name>_ann
-- Using existing column comments as annotation values
-- Created: December 16, 2025
-- NOTE: Review this script before executing

SET ECHO ON
SET FEEDBACK ON
SET VERIFY ON

PROMPT ====================================
PROMPT Adding 35 Column Annotations for HR Schema
PROMPT With Custom Annotation Names
PROMPT ====================================
PROMPT

-- COUNTRIES table column annotations (3 columns)
PROMPT Adding annotations for COUNTRIES columns...
ALTER TABLE HR.COUNTRIES MODIFY (COUNTRY_ID ANNOTATIONS (ADD COUNTRY_ID_ann 'Primary key of countries table.'));
ALTER TABLE HR.COUNTRIES MODIFY (COUNTRY_NAME ANNOTATIONS (ADD COUNTRY_NAME_ann 'Country name'));
ALTER TABLE HR.COUNTRIES MODIFY (REGION_ID ANNOTATIONS (ADD REGION_ID_ann 'Region ID for the country. Foreign key to region_id column in the departments table.'));

-- DEPARTMENTS table column annotations (4 columns)
PROMPT Adding annotations for DEPARTMENTS columns...
ALTER TABLE HR.DEPARTMENTS MODIFY (DEPARTMENT_ID ANNOTATIONS (ADD DEPARTMENT_ID_ann 'Primary key column of departments table.'));
...


In the last step, let’s check the annotations.
To obtain object-level schema annotations for tables, I used the following query.

SQL> select object_name,  annotation_name, annotation_value
from user_annotations_usage
where object_type='TABLE' and column_name is null order by 2,1

OBJECT_NAME ANNOTATION_NAME
--------------- ---------------
ANNOTATION_VALUE
------------------------------------------------------------------------------------
COUNTRIES COUNTRIES_ANN
country table. References with locations table.

DEPARTMENTS DEPARTMENTS_ANN
Departments table that shows details of departments where employees
work. references with locations, employees, and job_history tables.

EMPLOYEES EMPLOYEES_ANN
employees table. References with departments,
jobs, job_history tables. Contains a self reference.

...

REGIONS REGIONS_ANN
Regions table that contains region numbers and names. references with the Countries table.

7 rows selected.

To obtain column-level schema annotations, I used this query.

SQL> select object_name, object_type, column_name, annotation_name, annotation_value
from user_annotations_usage
where column_name is not null order by 2,1;

OBJECT_NAME OBJECT_TYP COLUMN_NAME ANNOTATION_NAME
--------------- ---------- ------------------------- ---------------
ANNOTATION_VALUE
------------------------------------------------------------------------------------
COUNTRIES TABLE REGION_ID REGION_ID_ANN
Region ID for the country. Foreign key to region_id column in the departments table.

COUNTRIES TABLE COUNTRY_NAME COUNTRY_NAME_ANN
Country name

COUNTRIES TABLE COUNTRY_ID COUNTRY_ID_ANN
Primary key of countries table.

DEPARTMENTS TABLE MANAGER_ID MANAGER_ID_ANN
Manager_id of a department. Foreign key to employee_id column of employees table. The manager_id column of the employee table references this column.
...
REGIONS TABLE REGION_ID REGION_ID_ANN
Primary key of regions table.

REGIONS TABLE REGION_NAME REGION_NAME_ANN
Names of regions. Locations are in the countries of these regions.

35 rows selected.

So this looks good.
If the comments are no longer used by any application, they can be removed.

3. Monitoring

How can you monitor what is executed in the database? All queries being executed via your database connection’s user, is being logged in that schema, via the DBTOOLS$MCP_LOG table. This table provides a complete audit trail of all database operations the server performs. It captures request details, execution times, and results to help you with analysis and troubleshooting. So let’s review it for our usage scenario.

SQL> select ID, MCP_CLIENT, MODEL, END_POINT_TYPE, END_POINT_NAME, LOG_MESSAGE
from DBTOOLS$MCP_LOG
order by id;


ID MCP_CLIENT MODEL END_POINT_TYPE END_POINT_NAME
---------- --------------- -------------------- --------------- --------------------
LOG_MESSAGE
------------------------------------------------------------------------------------
1 claude-ai claude-sonnet-4.5 tool connect
Connect to HR

2 claude-ai claude-sonnet-4.5 tool run-sql
SELECT /* LLM in use is claude-sonnet-4.5 */ table_name, comments FROM user_tab_comments WHERE table_type = 'TABLE' AND comments IS NOT NULL ORDER BY table_name


3 claude-ai claude-sonnet-4.5 tool run-sql
SELECT /* LLM in use is claude-sonnet-4.5 */ table_name, column_name, comments FROM user_col_comments WHERE comments IS NOT NULL ORDER BY table_name, column_name


4 claude-ai claude-sonnet-4.5 tool run-sql
SELECT /* LLM in use is claude-sonnet-4.5 */ 'Tables with comments' AS category, COUNT(*) AS count FROM user_tab_comments WHERE table_type = 'TABLE' AND comments IS NOT NULL UNION
ALL SELECT 'Columns with comments' AS category, COUNT(*) AS count FROM user_col_comments WHERE comments IS NOT NULL

4. Learnings

What I learned:

  • Setup is simple: connecting an MCP client (e.g., Claude Desktop) to the database is quick, and natural-language prompts work well.
  • Great for repetitive scripting: it can generate well-documented, easy-to-read scripts.
  • Safety first: ask it to produce scripts, but don’t let it execute them—review before running, and explicitly tell it not to execute.
  • Always verify: even good-looking, well-documented scripts can be wrong or have syntax errors.
  • Be specific: clearly state what you want. If you need exact names, counts, or a fixed number of commands/annotations, spell that out.