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
101 changes: 100 additions & 1 deletion src/dbtools-mcp-server/dbtools-mcp-server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1279,12 +1279,111 @@ def heatwave_ask_ml_rag(dbtools_connection_display_name: str, question: str) ->
response_data = json.loads(response)
if 'items' in response_data and len(response_data['items']) > 0:
json_column_name = response_data['items'][2]['resultSet']['metadata'][0]['jsonColumnName']
return json.loads(response_data['items'][2]['resultSet']['items'][0][json_column_name])
return json.loads(response_data['items'][2]['resultSet']['items'][0][json_column_name])

return json.dumps({"error": "Unexpected response format from Heatwave ML_RAG"})
except Exception as e:
return json.dumps({"error": f"Error with ML_RAG: {str(e)}"})

@mcp.tool()
def ask_nl_sql(dbtools_connection_display_name: str, question: str) -> str:
"""
Convert natural language questions into SQL queries and execute them automatically.

This tool is ideal for database exploration using plain English questions like:
- "Show me the average price by category"
- "How many users registered last month?"
- "What are the column names in the customers table?"

Args:
dbtools_connection_display_name (str): MySQL dbtools connection name.
question (str): Natural language query.

Returns:
JSON object containing:

sql_response(str): The response from executing the generated SQL query.
sql_query(str): The generated SQL query
schemas(json): The schemas where metadata was retrieved
tables(json): The tables where metadata was retrieved
is_sql_valid(bool): Whether the generated SQL statement is valid
model_id(str): The LLM used for generation
"""
connection_info = get_minimal_connection_by_name(dbtools_connection_display_name)

if connection_info is None:
return json.dumps({
"error": f"No connection found with name '{dbtools_connection_display_name}'",
"suggestion": "Use list_all_connections() to see available connections"
})

try:
if connection_info.get('type') != 'MYSQL':
return json.dumps({
"error": "This connection is not a MySQL database. NL_SQL is only available for MySQL databases.",
"suggestion": "Please provide a MySQL database connection."
})

call_sql = f"CALL sys.NL_SQL('{question.replace("'","''")}', @response, JSON_OBJECT('execute', FALSE)); SELECT @response;"

response = execute_sql_tool_by_connection_id(connection_info['id'], call_sql)
# Parse the response
if isinstance(response, str):
response_data = json.loads(response)
if 'items' in response_data and len(response_data['items']) > 0:
json_column_name = response_data['items'][1]['resultSet']['metadata'][0]['jsonColumnName']
return response_data['items'][1]['resultSet']['items'][0][json_column_name]

return json.dumps({"error": "Unexpected response format from Heatwave NL_SQL"})

except Exception as e:
return json.dumps({"error": f"Error with NL_SQL: {str(e)}"})

@mcp.tool()
def retrieve_relevant_schema_information(dbtools_connection_display_name: str, question: str) -> str:
"""
Retrieve relevant schemas and tables for a given natural language question.

This tool analyzes the input question and identifies tables that are relevant with respect to the question.
It can optionally consider table and column comments for improved semantic matching.
The results contain only the relevant schemas and tables in a JSON object.

Args:
dbtools_connection_display_name (str): MySQL dbtools connection name.
question (str): Input question for use with ML_RETRIEVE_SCHEMA.

Returns:
A single JSON of the form:
{
"create_statements": "CREATE ...; CREATE ...;"
}
Where the DDL/CREATE statements of all relevant tables are listed
"""
connection_info = get_minimal_connection_by_name(dbtools_connection_display_name)
if connection_info is None:
return json.dumps({
"error": f"No connection found with name '{dbtools_connection_display_name}'",
"suggestion": "Use list_all_connections() to see available connections"
})
try:
if connection_info.get('type') != 'MYSQL':
return json.dumps({
"error": "This connection is not a MySQL database. ML_RETRIEVE_SCHEMA is only available for MySQL databases.",
"suggestion": "Please provide a MySQL database connection."
})

call_sql = f"CALL sys.ML_RETRIEVE_SCHEMA_METADATA('{question.replace("'","''")}', @response, NULL);SELECT JSON_OBJECT('create_statements', @response) AS jobj;"
response = execute_sql_tool_by_connection_id(connection_info['id'], call_sql)
# Parse the response
if isinstance(response, str):
response_data = json.loads(response)
if 'items' in response_data and len(response_data['items']) > 0:
json_column_name = response_data['items'][1]['resultSet']['metadata'][0]['jsonColumnName']
return json.dumps(response_data['items'][1]['resultSet']['items'][0][json_column_name])
return json.dumps({"error": "Unexpected response format from Heatwave NL_SQL"})
except Exception as e:
return json.dumps({"error": f"Error with ML_RETRIEVE_SCHEMA: {str(e)}"})

if __name__ == "__main__":
# Initialize and run the server
mcp.run(transport='stdio')
1 change: 1 addition & 0 deletions src/mysql-mcp-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
local_config.json
35 changes: 35 additions & 0 deletions src/mysql-mcp-server/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Copyright (c) 2025 Oracle and/or its affiliates.

The Universal Permissive License (UPL), Version 1.0

Subject to the condition set forth below, permission is hereby granted to any
person obtaining a copy of this software, associated documentation and/or data
(collectively the "Software"), free of charge and under any and all copyright
rights in the Software, and any and all patent rights owned or freely
licensable by each licensor hereunder covering either (i) the unmodified
Software as contributed to or provided by such licensor, or (ii) the Larger
Works (as defined below), to deal in both

(a) the Software, and
(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
one is included with the Software (each a "Larger Work" to which the Software
is contributed by such licensors),

without restriction, including without limitation the rights to copy, create
derivative works of, display, perform, and distribute the Software and make,
use, sell, offer for sale, import, export, have made, and have sold the
Software and the Larger Work(s), and to sublicense the foregoing rights on
either these or other terms.

This license is subject to the following condition:
The above copyright notice and either this complete permission notice or at
a minimum a reference to the UPL must be included in all copies or
substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
40 changes: 14 additions & 26 deletions src/mysql-mcp-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,37 +35,18 @@ A Python-based MCP (Model Context Protocol) server that provides a suite of tool
- List objects in a bucket

## Prerequisites

- Python 3.x
- `fastmcp`
- `oci` SDK
- `mysql-connector-python` SDK
- Valid database connection file. Resolution order:
1) Path specified by environment variable `MYSQL_MCP_CONFIG` (absolute or relative to this module)
2) `src/mysql-mcp-server/local_config.json` (default)
2) `local_config.json` (default)
- Valid OCI configuration file (`~/.oci/config`) or environment variables

## Installation

1. Clone this repository.
2. Install required dependencies using pip:
```
pip install -r requirements.txt
```
This will install `oci`, `fastmcp`, `mysql-connector-python`, and all other dependencies.
3. Set up your OCI config file at ~/.oci/config

## OCI Configuration

The server requires a valid OCI config file with proper credentials.
The default location is ~/.oci/config. For instructions on setting up this file,
see the [OCI SDK documentation](https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm).

## Required Python Packages

- `oci`
- `fastmcp`
- `mysql-connector-python`

## Supported Database Modes

Expand All @@ -74,19 +55,23 @@ see the [OCI SDK documentation](https://docs.oracle.com/en-us/iaas/Content/API/C

## MCP Server Configuration

Installation is dependent on the MCP Client being used, it usually consists of adding the MCP Server invocation in a json config file, for example with Claude UI on windows it looks like this:
Installation is dependent on the MCP Client being used, it usually consists of adding the MCP Server invocation in a json config file, for example with Claude UI on Windows it looks like this:
```json
{
"mcpServers": {
"mysqltools": {
"command": "C:\\Python\\python.exe",
"command": "uv",
"args": [
"C:\\Users\\user1\\mysql-mcp-server\\mysql_mcp_server.py"
"--directory",
"C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\mysql-mcp-server",
"run",
"oracle.mysql_mcp_server"
]
}
}
}
```
**Note**: On Windows you may have to provide the suffix *.exe* to "oracle.mysql_mcp_server".



Expand All @@ -95,9 +80,12 @@ Example with TENANCY_ID_OVERRIDE::
{
"mcpServers": {
"mysqltools": {
"command": "C:\\Python\\python.exe",
"command": "uv",
"args": [
"C:\\Users\\user1\\mysql-mcp-server\\mysql_mcp_server.py"
"--directory",
"C:\\ABSOLUTE\\PATH\\TO\\PARENT\\FOLDER\\mysql-mcp-server",
"run",
"oracle.mysql_mcp_server"
],
"env": {
"TENANCY_ID_OVERRIDE": "ocid1.tenancy.oc1..deadbeef"
Expand Down Expand Up @@ -196,7 +184,7 @@ Note:
The server runs using stdio transport and can be started by running:

```bash
python mysql_mcp_server.py
uv run oracle.mysql_mcp_server
```

## API Tools
Expand Down
11 changes: 0 additions & 11 deletions src/mysql-mcp-server/local_config.json

This file was deleted.

Empty file.
Empty file.
9 changes: 9 additions & 0 deletions src/mysql-mcp-server/oracle/mysql_mcp_server/consts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""
Copyright (c) 2025, Oracle and/or its affiliates.
Licensed under the Universal Permissive License v1.0 as shown at
https://oss.oracle.com/licenses/upl.
"""

MIN_CONTEXT_SIZE = 10
DEFAULT_CONTEXT_SIZE = 20
MAX_CONTEXT_SIZE = 100
Loading