Selcan Yukcu
commited on
Commit
Β·
676f4cd
1
Parent(s):
6a5afc3
fix: conflicts with main solved
Browse files- README.md +13 -46
- langchain_mcp_client.py +5 -5
- postgre_mcp_server.py +94 -86
README.md
CHANGED
|
@@ -14,17 +14,17 @@ A PostgreSQL MCP server and client system that accepts natural language queries
|
|
| 14 |
|
| 15 |
## Tech Stack
|
| 16 |
|
| 17 |
-
| Layer
|
| 18 |
-
|
| 19 |
-
| LLM Framework
|
| 20 |
-
| LLM Provider
|
| 21 |
| Agent Runtime | LangGraphβs `create_react_agent` | Runs the ReAct-style LLM agent |
|
| 22 |
-
| Communication
|
| 23 |
-
| Tooling
|
| 24 |
-
|
|
| 25 |
-
| UI (optional)
|
| 26 |
-
| Memory
|
| 27 |
-
|
|
| 28 |
|
| 29 |
|
| 30 |
## Installation
|
|
@@ -61,10 +61,6 @@ You can start by copying the example file provided:
|
|
| 61 |
|
| 62 |
### .env variables
|
| 63 |
* API_KEY: Your Google Gemini API key
|
| 64 |
-
* DSN: PostgreSQL connection string (used by MCP)
|
| 65 |
-
* SCHEMA: Schema name to describe table structure
|
| 66 |
-
### config variables
|
| 67 |
-
* TABLE_SUMMARY_PATH: Path to the table descriptions file
|
| 68 |
* MCP_SERVER_PATH: Path to the MCP server script (e.g. ./postgres_mcp_server.py)
|
| 69 |
|
| 70 |
## Running the Project
|
|
@@ -85,11 +81,11 @@ Once you've installed the dependencies and configured the `.env` file, you're re
|
|
| 85 |
.
|
| 86 |
βββ gradio_app.py # Gradio UI to interact with any client (LangChain or SmolAgent)
|
| 87 |
βββ langchain_mcp_client.py # Uses LangChain ReAct agent + ConversationBufferMemory (in-memory, also saves to memory.json)
|
| 88 |
-
βββ postgre_mcp_client.py # Uses ReAct agent + custom memory class (in-session only), WIP
|
| 89 |
-
βββ postgre_smolagent_client.py # Uses SmolAgent (lightweight), no memory support yet, WIP
|
| 90 |
βββ postgre_mcp_server.py # MCP server that handles actual PostgreSQL communication
|
| 91 |
βββ conversation_memory.py # Built-in memory class used by some clients
|
| 92 |
-
βββ
|
| 93 |
βββ table_summary.txt # Database table descriptions used to enrich tools
|
| 94 |
βββ utils.py # Helper functions: intent classification, output parsing, etc.
|
| 95 |
βββ .env.sample # Template for your environment config
|
|
@@ -97,34 +93,6 @@ Once you've installed the dependencies and configured the `.env` file, you're re
|
|
| 97 |
βββ README.md
|
| 98 |
```
|
| 99 |
|
| 100 |
-
### Switching Clients in Gradio
|
| 101 |
-
|
| 102 |
-
The `gradio_app.py` file is designed to work with **all three clients**.
|
| 103 |
-
To change the active one:
|
| 104 |
-
|
| 105 |
-
1. Open `gradio_app.py`
|
| 106 |
-
2. Replace the function call with one of the following:
|
| 107 |
-
|
| 108 |
-
```python
|
| 109 |
-
from langchain_mcp_client import lc_mcp_exec
|
| 110 |
-
|
| 111 |
-
async def run_agent(request):
|
| 112 |
-
result = await lc_mcp_exec(request)
|
| 113 |
-
return result
|
| 114 |
-
# or
|
| 115 |
-
from postgre_mcp_client import pg_mcp_exec
|
| 116 |
-
|
| 117 |
-
async def run_agent(request):
|
| 118 |
-
result = await pg_mcp_exec(request)
|
| 119 |
-
return result
|
| 120 |
-
# or
|
| 121 |
-
from postgre_smolagent_client import pg_mcp_smolagent_exec
|
| 122 |
-
|
| 123 |
-
async def run_agent(request):
|
| 124 |
-
result = await pg_mcp_smolagent_exec(request)
|
| 125 |
-
return result
|
| 126 |
-
```
|
| 127 |
-
|
| 128 |
### Work In Progress (WIP) Notes
|
| 129 |
* postgre_mcp_client.py:
|
| 130 |
- needs improvement in build_prompt() function
|
|
@@ -136,6 +104,5 @@ async def run_agent(request):
|
|
| 136 |
- Uses a different output format β not yet compatible with parse_mcp_output()
|
| 137 |
|
| 138 |
- Also needs build_prompt() logic finalized
|
| 139 |
-
* config file for the variables TABLE_SUMMARY_PATH and MCP_SERVER_PATH
|
| 140 |
* gradio_app.py:
|
| 141 |
- Doesn't support conversation chat ui
|
|
|
|
| 14 |
|
| 15 |
## Tech Stack
|
| 16 |
|
| 17 |
+
| Layer | Technology / Library | Purpose |
|
| 18 |
+
|-------------|------------------------------------|--------------------------------------------------------------|
|
| 19 |
+
| LLM Framework | [LangChain](https://www.langchain.com/) | Manages agent behavior, memory, and tool interaction |
|
| 20 |
+
| LLM Provider | Google Gemini (via LangChain) | Converts natural language into SQL queries |
|
| 21 |
| Agent Runtime | LangGraphβs `create_react_agent` | Runs the ReAct-style LLM agent |
|
| 22 |
+
| Communication | Modular Command Protocol (MCP) | Handles communication between client and PostgreSQL backend|
|
| 23 |
+
| Tooling | `langchain_mcp_adapters` | Loads and manages tools for the agent |
|
| 24 |
+
| Database | PostgreSQL | Serves queried data |
|
| 25 |
+
| UI (optional) | [Gradio](https://www.gradio.app/) | Provides a lightweight web interface for querying |
|
| 26 |
+
| Memory | `FileChatMessageHistory` | Stores short-term in-session memory for conversation context |
|
| 27 |
+
| Language | Python 3.10+ | Core programming language used for development |
|
| 28 |
|
| 29 |
|
| 30 |
## Installation
|
|
|
|
| 61 |
|
| 62 |
### .env variables
|
| 63 |
* API_KEY: Your Google Gemini API key
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
* MCP_SERVER_PATH: Path to the MCP server script (e.g. ./postgres_mcp_server.py)
|
| 65 |
|
| 66 |
## Running the Project
|
|
|
|
| 81 |
.
|
| 82 |
βββ gradio_app.py # Gradio UI to interact with any client (LangChain or SmolAgent)
|
| 83 |
βββ langchain_mcp_client.py # Uses LangChain ReAct agent + ConversationBufferMemory (in-memory, also saves to memory.json)
|
| 84 |
+
βββ postgre_mcp_client.py # Uses ReAct agent + custom memory class (in-session only), **WIP**: needs prompt fix
|
| 85 |
+
βββ postgre_smolagent_client.py # Uses SmolAgent (lightweight), no memory support yet, **WIP**: output parsing + prompt building
|
| 86 |
βββ postgre_mcp_server.py # MCP server that handles actual PostgreSQL communication
|
| 87 |
βββ conversation_memory.py # Built-in memory class used by some clients
|
| 88 |
+
βββ chat_history.json # Keeps session memory. Needs to be deleted after each session
|
| 89 |
βββ table_summary.txt # Database table descriptions used to enrich tools
|
| 90 |
βββ utils.py # Helper functions: intent classification, output parsing, etc.
|
| 91 |
βββ .env.sample # Template for your environment config
|
|
|
|
| 93 |
βββ README.md
|
| 94 |
```
|
| 95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
### Work In Progress (WIP) Notes
|
| 97 |
* postgre_mcp_client.py:
|
| 98 |
- needs improvement in build_prompt() function
|
|
|
|
| 104 |
- Uses a different output format β not yet compatible with parse_mcp_output()
|
| 105 |
|
| 106 |
- Also needs build_prompt() logic finalized
|
|
|
|
| 107 |
* gradio_app.py:
|
| 108 |
- Doesn't support conversation chat ui
|
langchain_mcp_client.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import os.path
|
|
|
|
| 2 |
from typing import Tuple, Any
|
| 3 |
|
| 4 |
from mcp import ClientSession, StdioServerParameters
|
|
@@ -15,11 +16,10 @@ import logging
|
|
| 15 |
from dotenv import load_dotenv
|
| 16 |
|
| 17 |
|
| 18 |
-
load_dotenv()
|
| 19 |
-
logger = logging.getLogger(__name__)
|
| 20 |
-
|
| 21 |
|
| 22 |
-
|
|
|
|
|
|
|
| 23 |
"""
|
| 24 |
Execute the full PostgreSQL MCP pipeline with persistent memory.
|
| 25 |
"""
|
|
@@ -121,6 +121,7 @@ def load_table_summary(path: str) -> str:
|
|
| 121 |
|
| 122 |
def get_server_params() -> StdioServerParameters:
|
| 123 |
# TODO: give server params from config
|
|
|
|
| 124 |
return StdioServerParameters(
|
| 125 |
command="python",
|
| 126 |
args=[os.environ["MCP_SERVER_PATH"]],
|
|
@@ -134,7 +135,6 @@ async def build_prompt(session, intent, request, tools, summary, chat_history):
|
|
| 134 |
superset_prompt = await session.read_resource("resource://last_prompt")
|
| 135 |
conversation_prompt = await session.read_resource("resource://base_prompt")
|
| 136 |
|
| 137 |
-
|
| 138 |
if intent == "superset_request":
|
| 139 |
template = superset_prompt.contents[0].text
|
| 140 |
return template.format(
|
|
|
|
| 1 |
import os.path
|
| 2 |
+
import json
|
| 3 |
from typing import Tuple, Any
|
| 4 |
|
| 5 |
from mcp import ClientSession, StdioServerParameters
|
|
|
|
| 16 |
from dotenv import load_dotenv
|
| 17 |
|
| 18 |
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
+
logger = logging.getLogger(__name__)
|
| 21 |
+
load_dotenv()
|
| 22 |
+
async def lc_mcp_exec(request: str, history) -> tuple[Any, Any]:
|
| 23 |
"""
|
| 24 |
Execute the full PostgreSQL MCP pipeline with persistent memory.
|
| 25 |
"""
|
|
|
|
| 121 |
|
| 122 |
def get_server_params() -> StdioServerParameters:
|
| 123 |
# TODO: give server params from config
|
| 124 |
+
load_dotenv()
|
| 125 |
return StdioServerParameters(
|
| 126 |
command="python",
|
| 127 |
args=[os.environ["MCP_SERVER_PATH"]],
|
|
|
|
| 135 |
superset_prompt = await session.read_resource("resource://last_prompt")
|
| 136 |
conversation_prompt = await session.read_resource("resource://base_prompt")
|
| 137 |
|
|
|
|
| 138 |
if intent == "superset_request":
|
| 139 |
template = superset_prompt.contents[0].text
|
| 140 |
return template.format(
|
postgre_mcp_server.py
CHANGED
|
@@ -59,119 +59,128 @@ async def base_prompt_query() -> str:
|
|
| 59 |
|
| 60 |
base_prompt = """
|
| 61 |
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
|
| 66 |
-
|
| 67 |
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
|
| 72 |
|
| 73 |
-
|
|
|
|
|
|
|
| 74 |
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
|
| 79 |
-
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
-
|
| 86 |
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
4. Execute the query and **return the execution result of the query**.
|
| 91 |
-
5. **Chain tools logically to build toward the answer.**
|
| 92 |
-
6. Explain your reasoning at every step for clarity and transparency.
|
| 93 |
-
7. Show the result of the **execute_query** in your final answer.
|
| 94 |
|
| 95 |
-
|
| 96 |
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
|
| 101 |
-
|
| 102 |
-
- **Never** use destructive operations like **DELETE**, **UPDATE**, **INSERT**, or **DROP**.
|
| 103 |
-
- Always show the SQL query you generate along with the execution result.
|
| 104 |
-
- Validate SQL syntax before execution.
|
| 105 |
-
- Never assume table or column names. Use tools to confirm structure.
|
| 106 |
-
- Use memory efficiently. Donβt rerun a tool unless necessary.
|
| 107 |
-
- If you generate a SQL query, immediately call the **execute_query** tool using that query. Do not delay or wait for user confirmation.
|
| 108 |
|
|
|
|
|
|
|
|
|
|
| 109 |
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
-
|
|
|
|
|
|
|
| 117 |
|
| 118 |
-
|
| 119 |
|
| 120 |
-
|
| 121 |
|
| 122 |
-
|
| 123 |
-
# Tools
|
| 124 |
-
==========================
|
| 125 |
|
| 126 |
-
You can use the following FastMCP tools. These allow you to create **read-only** queries, such as `SELECT`, `COUNT`, or queries with `GROUP BY`, `ORDER BY`, and similar clauses. You may chain tools together to gather the necessary information before generating your SQL query.
|
| 127 |
|
| 128 |
-
|
|
|
|
| 129 |
|
| 130 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
-
|
| 134 |
-
**User Request:** "Delete all customers from Germany."
|
| 135 |
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
> Destructive operations such as `DELETE` are not permitted. I can help you retrieve the customers from Germany using a `SELECT` query instead:
|
| 140 |
-
> ```sql
|
| 141 |
-
> SELECT * FROM customers WHERE country = 'Germany';
|
| 142 |
-
> ```
|
| 143 |
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
# Output Format
|
| 147 |
-
==========================
|
| 148 |
-
|
| 149 |
-
Present your final answer using the following structure **exactly**. When necessary, bold the important parts of your answer or use `` inline code blocks.:
|
| 150 |
-
|
| 151 |
-
```markdown
|
| 152 |
-
# Result
|
| 153 |
-
{{Take the result from the execute_query tool and format it nicely using Markdown. Use a Markdown table for tabular data (rows and columns) including headers. Use bullet points or items in markdown for answers that include lists of names or descriptions. Use plain text for single values or simple messages. Ensure data alignment and clarity.}}
|
| 154 |
-
|
| 155 |
-
# Explanation
|
| 156 |
-
{{Provide a concise explanation or interpretation of the results in 1-3 sentences. Explain what the data in the 'Result' section represents in the context of the user's request.}}
|
| 157 |
-
|
| 158 |
-
# Query
|
| 159 |
-
```sql
|
| 160 |
-
{{Display the exact SQL query you generated and executed here to answer the user's request.}}
|
| 161 |
-
|
| 162 |
-
**Reminder:**
|
| 163 |
-
**Every time you generate a SQL query, call **execute_query** right after and include the result in your final response.**
|
| 164 |
-
**If you do not execute the generated SQL query, this will be the violation of the instructions**
|
| 165 |
-
**Your final answer cannot be only a SQL query, you will have to call **execute_query** and give the result of the call with the SQL query.**
|
| 166 |
-
---
|
| 167 |
-
=========================
|
| 168 |
-
# New User Request
|
| 169 |
-
=========================
|
| 170 |
|
| 171 |
-
|
|
|
|
|
|
|
| 172 |
|
| 173 |
-
|
| 174 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
|
| 176 |
return base_prompt
|
| 177 |
|
|
@@ -442,7 +451,6 @@ async def test_connection(ctx: Context) -> str:
|
|
| 442 |
return f"Connection failed: {str(e)}"
|
| 443 |
|
| 444 |
|
| 445 |
-
|
| 446 |
@mcp.tool(description="Executes a read-only SQL SELECT query and returns formatted results or an error message.")
|
| 447 |
async def execute_query(
|
| 448 |
query: str = Field(description="SQL query to execute (SELECT only)"),
|
|
|
|
| 59 |
|
| 60 |
base_prompt = """
|
| 61 |
|
| 62 |
+
==========================
|
| 63 |
+
# Your Role
|
| 64 |
+
==========================
|
| 65 |
|
| 66 |
+
You are an expert in generating and executing SQL queries and interacting with a PostgreSQL database using **FastMCP tools**. These tools allow you to:
|
| 67 |
|
| 68 |
+
- List available tables
|
| 69 |
+
- Retrieve schema details
|
| 70 |
+
- Execute SQL queries
|
| 71 |
|
| 72 |
|
| 73 |
+
Each tool may also return previews or summaries of table contents to help you better understand the data structure.
|
| 74 |
+
|
| 75 |
+
---
|
| 76 |
|
| 77 |
+
==========================
|
| 78 |
+
# Your Objective
|
| 79 |
+
==========================
|
| 80 |
|
| 81 |
+
When a user submits a request, you must:
|
| 82 |
|
| 83 |
+
1. **Analyze the request** to determine the required data or action.
|
| 84 |
+
2. **Use FastMCP tools** to gather any necessary information (e.g., list tables or retrieve schema).
|
| 85 |
+
3. **Generate a valid SQL SELECT query**, if needed, and clearly show the full query.
|
| 86 |
+
4. **Execute the SQL query** and return the results.
|
| 87 |
+
5. **Chain tools logically**, such as: List Tables β Get Schema β Write and Run Query.
|
| 88 |
+
6. **Explain your reasoning and each step taken** to ensure clarity and transparency.
|
| 89 |
|
| 90 |
+
---
|
| 91 |
|
| 92 |
+
==========================
|
| 93 |
+
# Your Objective
|
| 94 |
+
==========================
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
|
| 96 |
+
When a user submits a request, follow these steps:
|
| 97 |
|
| 98 |
+
1. Analyze the request to determine the desired data or action.
|
| 99 |
+
2. Use tools to gather any necessary information (e.g., list tables, get schema).
|
| 100 |
+
3. Generate a valid SQL query (such as **SELECT**, **COUNT**, or other read-only operations) and clearly display the full query.
|
| 101 |
+
4. Execute the query and **return the execution result of the query**.
|
| 102 |
+
5. **Chain tools logically to build toward the answer.**
|
| 103 |
+
6. Explain your reasoning at every step for clarity and transparency.
|
| 104 |
+
7. Show the result of the **execute_query** in your final answer.
|
| 105 |
|
| 106 |
+
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
+
==========================
|
| 109 |
+
# Critical Rules
|
| 110 |
+
==========================
|
| 111 |
|
| 112 |
+
- Only use **read-only** SQL queries such as **SELECT**, **COUNT**, or queries with **GROUP BY**, **ORDER BY**, etc.
|
| 113 |
+
- **Never** use destructive operations like **DELETE**, **UPDATE**, **INSERT**, or **DROP**.
|
| 114 |
+
- Always show the SQL query you generate along with the execution result.
|
| 115 |
+
- Validate SQL syntax before execution.
|
| 116 |
+
- Never assume table or column names. Use tools to confirm structure.
|
| 117 |
+
- Use memory efficiently. Donβt rerun a tool unless necessary.
|
| 118 |
+
- If you generate a SQL query, immediately call the **execute_query** tool using that query. Do not delay or wait for user confirmation.
|
| 119 |
|
| 120 |
+
---
|
| 121 |
+
|
| 122 |
+
==========================
|
| 123 |
+
# Database Description
|
| 124 |
+
==========================
|
| 125 |
+
|
| 126 |
+
{descriptions}
|
| 127 |
+
|
| 128 |
+
---
|
| 129 |
|
| 130 |
+
==========================
|
| 131 |
+
# Tools
|
| 132 |
+
==========================
|
| 133 |
|
| 134 |
+
You can use the following FastMCP tools. These allow you to create **read-only** queries, such as `SELECT`, `COUNT`, or queries with `GROUP BY`, `ORDER BY`, and similar clauses. You may chain tools together to gather the necessary information before generating your SQL query.
|
| 135 |
|
| 136 |
+
{tools}
|
| 137 |
|
| 138 |
+
---
|
|
|
|
|
|
|
| 139 |
|
|
|
|
| 140 |
|
| 141 |
+
### Invalid Example β DELETE Operation (Not Allowed):
|
| 142 |
+
**User Request:** "Delete all customers from Germany."
|
| 143 |
|
| 144 |
+
**Response Guidance:**
|
| 145 |
+
- **Do not generate or execute** destructive queries such as `DELETE`.
|
| 146 |
+
- Instead, respond with a message like:
|
| 147 |
+
> Destructive operations such as `DELETE` are not permitted. I can help you retrieve the customers from Germany using a `SELECT` query instead:
|
| 148 |
+
> ```sql
|
| 149 |
+
> SELECT * FROM customers WHERE country = 'Germany';
|
| 150 |
+
> ```
|
| 151 |
|
| 152 |
+
==========================
|
| 153 |
+
# Output Format
|
| 154 |
+
==========================
|
| 155 |
|
| 156 |
+
Present your final answer using the following structure **exactly**. When necessary, bold the important parts of your answer or use `` inline code blocks.:
|
|
|
|
| 157 |
|
| 158 |
+
```markdown
|
| 159 |
+
# Result
|
| 160 |
+
{{Take the result from the execute_query tool and format it nicely using Markdown. Use a Markdown table for tabular data (rows and columns) including headers. Use bullet points or items in markdown for answers that include lists of names or descriptions. Use plain text for single values or simple messages. Ensure data alignment and clarity.}}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
|
| 162 |
+
# Explanation
|
| 163 |
+
{{Provide a concise explanation or interpretation of the results in 1-3 sentences. Explain what the data in the 'Result' section represents in the context of the user's request.}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
|
| 165 |
+
# Query
|
| 166 |
+
```sql
|
| 167 |
+
{{Display the exact SQL query you generated and executed here to answer the user's request.}}
|
| 168 |
|
| 169 |
+
**Reminder:**
|
| 170 |
+
**Every time you generate a SQL query, call **execute_query** right after and include the result in your final response.**
|
| 171 |
+
**If you do not execute the generated SQL query, this will be the violation of the instructions**
|
| 172 |
+
**Your final answer cannot be only a SQL query, you will have to call **execute_query** and give the result of the call with the SQL query.**
|
| 173 |
+
---
|
| 174 |
+
{chat_history}
|
| 175 |
+
---
|
| 176 |
+
=========================
|
| 177 |
+
# New User Request
|
| 178 |
+
=========================
|
| 179 |
+
|
| 180 |
+
Please fulfill the following request based on the above context:
|
| 181 |
+
|
| 182 |
+
{new_request}
|
| 183 |
+
"""
|
| 184 |
|
| 185 |
return base_prompt
|
| 186 |
|
|
|
|
| 451 |
return f"Connection failed: {str(e)}"
|
| 452 |
|
| 453 |
|
|
|
|
| 454 |
@mcp.tool(description="Executes a read-only SQL SELECT query and returns formatted results or an error message.")
|
| 455 |
async def execute_query(
|
| 456 |
query: str = Field(description="SQL query to execute (SELECT only)"),
|