Skip to content

Commit 39a460f

Browse files
committed
Show database version in db.list and sql.query tool description
Adds SQLExecutor.get_version() using SELECT VERSION() / sqlite_version(). db.list now includes a version field per connection. sql.query description shows the exact engine and version (e.g. "MySQL 5.7.41") so AI agents can choose the correct SQL dialect.
1 parent 8e5bd2b commit 39a460f

4 files changed

Lines changed: 47 additions & 1 deletion

File tree

app/config.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ def db_type(self) -> str:
150150
return "SQLite"
151151
return "SQL"
152152

153+
@property
154+
def db_version(self) -> str:
155+
from app.sql.executor import SQLExecutor
156+
157+
try:
158+
return SQLExecutor(self.db_url).get_version()
159+
except Exception:
160+
return ""
161+
153162
@classmethod
154163
def from_env(cls) -> "Config":
155164
return cls.load()

app/mcp/tools.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,8 @@ def db_use(payload: Dict[str, Any]) -> Dict[str, Any]:
490490
name="sql.query",
491491
title="SQL Query",
492492
description=(
493-
f"Execute a read-only SQL query against {config.db_type}. "
493+
f"Execute a read-only SQL query against {config.db_type}"
494+
f"{' ' + config.db_version if config.db_version else ''}. "
494495
f"Use {config.db_type}-compatible syntax. "
495496
"SELECT, WITH, EXPLAIN, SHOW, and DESCRIBE statements are allowed. "
496497
"For INSERT, UPDATE, DELETE, or DDL statements use db.apply."
@@ -588,6 +589,7 @@ def db_use(payload: Dict[str, Any]) -> Dict[str, Any]:
588589
"id": {"type": "integer"},
589590
"name": {"type": "string"},
590591
"db_type": {"type": "string"},
592+
"version": {"type": "string"},
591593
"mode": {"type": "string"},
592594
"host": {"type": "string"},
593595
"is_active": {"type": "boolean"},

app/session_db.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ def get_engine_for_session(self, session_id: str | None) -> Engine:
5858
url = self.get_db_url(session_id)
5959
return self._get_engine(url)
6060

61+
def get_db_version(self, session_id: str | None) -> str:
62+
"""Return the DB version string for a session's active connection."""
63+
from app.sql.executor import SQLExecutor
64+
65+
url = self.get_db_url(session_id)
66+
try:
67+
return SQLExecutor(url).get_version()
68+
except Exception:
69+
return ""
70+
6171
def get_db_type(self, session_id: str | None) -> str:
6272
"""Return the DB type name for a session's active connection."""
6373
url = self.get_db_url(session_id).lower()
@@ -78,15 +88,25 @@ def get_mode(self, session_id: str | None, default_mode: str) -> str:
7888

7989
def list_connections(self) -> list[dict[str, Any]]:
8090
"""Return all registered connections with metadata (no secrets)."""
91+
from app.sql.executor import SQLExecutor
92+
8193
connections = settings_db.get_all_db_connections()
8294
result = []
8395
for c in connections:
8496
url = c.get("url", "")
97+
version = ""
98+
if url:
99+
try:
100+
ex = SQLExecutor(url)
101+
version = ex.get_version()
102+
except Exception:
103+
pass
85104
result.append(
86105
{
87106
"id": c["id"],
88107
"name": c.get("name", ""),
89108
"db_type": c.get("db_type", ""),
109+
"version": version,
90110
"mode": c.get("mode", "read-only"),
91111
"is_active": bool(c.get("is_active")),
92112
"host": _extract_host(url),

app/sql/executor.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ class SQLExecutor:
2525
def __init__(self, db_url: str) -> None:
2626
self.engine: Engine = create_engine(db_url)
2727

28+
def get_version(self) -> str:
29+
"""Return the database server version string."""
30+
dialect = self.engine.dialect.name
31+
try:
32+
with self.engine.connect() as conn:
33+
if dialect == "sqlite":
34+
row = conn.execute(text("SELECT sqlite_version()")).fetchone()
35+
else:
36+
row = conn.execute(text("SELECT VERSION()")).fetchone()
37+
if row:
38+
return str(row[0])
39+
except SQLAlchemyError:
40+
pass
41+
return ""
42+
2843
def execute(
2944
self,
3045
sql: str,

0 commit comments

Comments
 (0)