MCP server for connecting to and querying SQL databases with support for MySQL, PostgreSQL, SQLite, SQL Server, and Oracle
SQL Explorer exhibits moderate quality with mixed strengths and significant gaps. All 4 tools are properly registered with FastMCP decorators and include descriptions, but parameter documentation is incomplete, output schemas are not formally documented, and error handling lacks recovery guidance. Parameter descriptions exist but are sparse (averaging 40-60 chars when baseline is 72 chars). No enum constraints for database types. The server accepts connection strings without validating format rigorously, inviting malformed input. Error messages are generic ('Failed to connect:', 'Query execution failed:') without actionable recovery hints. Tool naming follows verb_noun convention (connect_database, execute_query, list_tables, describe_table), a strength, but the server stores sensitive connection strings as plaintext dictionary keys in active_connections, a critical security issue.
Connect to a SQL database using SQLAlchemy. Automatically detects MySQL or PostgreSQL databases. Args: connection_string: Database connection string - MySQL format: "mysql+pymysql://user:password@host:port/database" - PostgreSQL format: "postgresql+psycopg2://user:password@host:port/database" Returns: Dictionary with connection status, database type, and available tables
Get detailed schema information for a specific table. Args: connection_id: Connection identifier returned from connect_database table_name: Name of the table to describe Returns: Dictionary with table schema information
Execute a SQL query on a previously connected database. Args: connection_id: Connection identifier returned from connect_database query: SQL query to execute params: Optional parameters for the query limit: Maximum number of rows to return (for SELECT queries) Returns: Dictionary with query results or affected row count
List all tables in the connected database. Args: connection_id: Connection identifier returned from connect_database Returns: Dictionary with list of tables and their schema information
CRITICAL: Credentials stored as plaintext dictionary keys in active_connections. Connection strings (including passwords) are used as connection_id and logged/returned to LLM context. Credentials must NEVER appear in tool parameters or responses.
Output schemas are undocumented. LLMs cannot parse the structure of list_tables, describe_table, execute_query responses. Formal schema definitions with typed fields are missing.
Error messages lack recovery guidance. 'Failed to connect: [exception]' and 'Query execution failed: [exception]' tell LLMs nothing about next steps. Should suggest alternate connection strings, retry logic, or schema discovery.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 63 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 24 | - | v1 |
execute_query is destructive (WRITE risk) but has no dry-run, confirmation, or idempotent hint. Agents can execute DELETE/DROP without safeguards. Should support preview mode or require confirmation for non-SELECT queries.
'params' parameter in execute_query is under-specified. Type is 'object' with no property constraints. Description says 'Optional parameters for the query' but does not clarify expected structure (dict of {param_name: value}?) or how parameterized queries work.
No enum constraint on database type. connect_database accepts any connection string and attempts to parse it. Should validate known dialects (mysql, postgresql, sqlite, mssql, oracle) or return actionable error.
No pagination or result limits documented for list_tables or describe_table. If a database has thousands of tables or columns, responses could exhaust context. Should cap results and offer offset/limit parameters.
describe_table returns schema_info dict but does not document field format (column names, types, constraints, nullable flags). LLM cannot infer structure from response.