This MCP server has critical definition quality issues. Both tools have minimal or missing descriptions, no parameter validation metadata, and empty input schemas. The 'run_your_query' tool is particularly dangerous, it accepts arbitrary SQL strings with no validation, escaping, or injection protection. Neither tool provides structured guidance for LLM behavior. The 'get_schema' tool has a vague one-sentence description (15 chars, below the 20-char floor), and 'run_your_query' lacks parameter documentation entirely. Output schemas are not documented, LLMs cannot plan multi-step queries without knowing what fields to expect. This server exemplifies poor agent-tool design: high-risk operations (arbitrary SQL execution) exposed with minimal guardrails.
CRITICAL: 'run_your_query' tool accepts arbitrary SQL with zero input validation, SQL injection protection, or parameter escaping. The parameter lacks any description, format constraints, or examples. This exposes the database to prompt injection attacks, an LLM can be tricked into passing 'DROP TABLE users' or exfiltrating sensitive data.
Tool name 'run_your_query' violates verb_noun convention and is vague. 'execute_sql_query' or 'query_database' would be clearer. The name does not convey risk (WRITE operation) or that this is for AI-generated queries only.
Description for 'run_your_query' is missing entirely. Parameter 'query' has no description explaining what SQL dialect is accepted, what operations are allowed/forbidden, expected result format, or limitations. Baseline requires 10-1024 chars; this is 0.
run_your_query
Recommendations
Rename 'run_your_query' to 'execute_sql_query' or 'query_database' and add a comprehensive description (50-150 chars): 'Execute a SQL SELECT query against the MS SQL database. Parameters: query (string, SELECT only). Returns: list of dicts with column names as keys. Errors: invalid SQL raises exception with context.'
Add a required, fully-described parameter to 'query': {"type": "string", "description": "SQL query to execute. Must be a SELECT query. No INSERT, UPDATE, DELETE, or DDL allowed. Max 10,000 chars. Example: SELECT * FROM users WHERE status='active'"}. Make the schema visible in JSON Schema, not just Python type hints.
Document output schemas explicitly. For 'get_schema': {"database": string, "schema": [{"table": string, "columns": [{"name": string, "type": string}]}]}. For 'run_your_query': [{ <column1>: value, <column2>: value, ... }], clarify that keys are table column names and types vary.
Add SQL injection safeguards: use parameterized queries, validate the query starts with SELECT, and reject known dangerous patterns (DROP, TRUNCATE, EXEC, xp_). Return a clear error: 'Query must be SELECT only. Attempted INSERT detected.' This prevents accidental or malicious data destruction.
Implement a dry-run mode: add an optional 'dry_run: bool' parameter to 'run_your_query'. If true, parse and validate the query but do not execute. Return expected columns and limits without side effects. This lets LLMs preview results before committing.
Add error handling with recovery guidance. Catch timeout, permission, and syntax errors and return: {'error': 'Query timed out (10s limit). Check for expensive joins or missing indexes. Or try schema introspection with get_schema().', 'retryable': true}. This lets LLMs self-correct.
Description for 'get_schema' is 31 chars ('Returns database schema structure.'), under the 10-1024 baseline but borderline. It lacks context on when to call this, what fields are returned, or whether it includes permissions/constraints. No guidance for LLM on what to do with the output.
Input schema for 'run_your_query' is empty: {} with no properties. The 'query' parameter is defined in the function signature but NOT in the JSON Schema. This tool cannot be called correctly via standard MCP protocol.
Output schemas are not documented. 'get_schema' returns a dict with 'database' and 'schema' keys, but the nested structure is not declared. 'run_your_query' returns a list of dicts, but the keys and types are unknown to the LLM. Without documented output schemas, LLMs cannot plan multi-step operations or extract required fields for chaining.
No error handling guidance. If a query times out, returns no rows, or fails due to permissions, the user/LLM receives an exception with no recovery path. No indication whether errors are retryable or what the LLM should do next.
Credentials (DB_DRIVER, DB_SERVER, DB_DATABASE, DB_UID, DB_PWD) are correctly injected via environment variables, not tool parameters. However, there is no audit trail, permission gating, or rate limiting to track who ran what query. An agent can execute unlimited queries without logs.
No idempotency safeguards. If an LLM retries a write query (INSERT, UPDATE, DELETE) due to a transient error, duplicate records or unintended side effects occur. No confirmation step, dry-run, or transaction rollback offered.
run_your_query
Implement audit logging: log tool calls with timestamp, query text (sanitized), row count returned, and duration. Write to server logs (stderr) or an audit table. Track agent-initiated database changes for compliance.
Add pagination support to 'run_your_query'. If results exceed 1,000 rows, truncate and return: {'rows': [...first 1000...], 'total_rows': 50000, 'limit': 1000, 'offset': 0}. Provide optional 'limit' and 'offset' parameters so LLMs can fetch large datasets in chunks without context explosion.
Expand 'get_schema' description to 50+ chars: 'Retrieve the complete MS SQL database schema, including all tables, columns, and data types. Call this first to understand database structure before writing queries. Returns: database name and list of tables with column metadata.'
Add scope declarations and permission gating. Document which database roles are required (e.g. db_datareader for SELECT, db_datawriter for DML). Validate caller permissions before execution. Return clear errors: 'User lacks db_datawriter permission for UPDATE operations.'
Consider adding a separate 'describe_table' tool to fetch detailed metadata (indexes, constraints, primary keys) for a specific table. This would enable richer query planning without requiring LLMs to parse raw schema for every lookup.