Model Context Protocol server for MySQL database integration with dynamic per-project permissions
MySQL MCP server has 20 tools with mostly complete schemas and descriptions, but suffers from inconsistent parameter documentation, missing output schema specifications, and lack of error guidance. Naming conventions are generally good (verb_noun pattern), but many parameters lack detailed constraints and validation hints. No tool annotations (readOnlyHint/destructiveHint) are visible despite clear risk classifications. Error handling is minimal, most tools return generic success/error objects without actionable recovery steps. The server does provide input schemas for all tools (good baseline), but output structures are not formally documented. Descriptions range from adequate to brief; many lack dependency hints and constraints. This is typical community-grade work, functional but not production-optimized.
Add a foreign key constraint to a table with specified columns, referenced table, and cascade rules.
Delete multiple records from a table based on filter conditions.
Insert multiple records into a table in a single operation.
Update multiple records in a table based on filter conditions.
Create a new record in the specified table with validated input data.
Delete records from a table based on filter conditions.
Drop a foreign key constraint from a table.
Execute a custom SELECT query and export results to CSV format.
Missing output schema documentation across all 20 tools. Tool definitions declare input schemas but nowhere in the visible source do output structures appear formally documented. LLMs cannot plan downstream operations or extract chaining IDs (e.g., does readRecords return record_id for use in updateRecord?). This violates the schema & output pattern.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) visible in the source. Risk classifications exist in the evaluation metadata (READ_ONLY, WRITE, DESTRUCTIVE) but are NOT embedded in tool definitions. MCP spec 2026-07-28 rewards tool annotations. This prevents clients from optimizing tool invocation or warning users about destructive operations.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 54 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 34 | - | v1 |
Export table data to CSV format with optional filters, pagination, and sorting.
Find candidate tables by keyword across schema metadata (table names, column names, comments).
Get statistics for a specific column including total rows, null count, distinct count, unique ratio, min/max values, and top frequent values.
Get a high-level summary of the database including tables, columns, row counts, primary keys, and foreign key relationships.
List all constraints (PK, FK, UNIQUE, CHECK) for a specified table.
List only the connected database (security restriction to prevent access to other databases).
List all foreign keys for a specified table including constraint names, referenced tables, columns, and cascade rules.
List all tables in the selected database.
Read records from a table with optional filters, pagination, and sorting.
Read table schema including column names, data types, nullability, keys, defaults, and extra attributes.
Analyzes a query (and optional error) to suggest repairs or optimizations using EXPLAIN.
Update records in a table based on filter conditions.
Insufficient error handling and recovery guidance. Tools return generic { status, error } objects with minimal context. E.g., repairQuery returns 'Failed to analyze query: <message>' without suggesting what the LLM should do next (retry? ask user for SQL syntax? call a schema tool first?). No categorization of errors as retryable vs user-fixable.
Parameter descriptions lack constraint and format hints. E.g., findTablesByKeyword accepts 'limit' (1-100) but the description does not mention the range; updateRecord's 'filters' array has no specification of filter structure (is it [{ field, operator, value }]? unparseable from docs); createRecord's 'data' object has no schema or example structure. LLMs cannot validate input without explicit constraints.
CRUD and bulk operation tools lack idempotency and confirmation patterns. deleteRecord and bulkDelete are destructive but have no dry-run or confirmation step. Repeated calls with identical parameters may succeed multiple times on accident (e.g., if an agent retries). No safeguards against accidental data loss.
Parameter naming inconsistencies. Some tools use 'database' (optional, defaults to connected db), others use 'table_name', but CRUD tools use 'table_name' for both source and some accept 'data' object without type hints. Filters parameter structure is undocumented across readRecords, updateRecord, deleteRecord, bulkUpdate, bulkDelete. LLMs cannot infer filter syntax without explicit schema.
Pagination support is incomplete. readRecords and exportTableToCSV accept pagination objects but no specification of response structure (does it return total_count? next_cursor?). List tools (listTables, listDatabases, listConstraints) lack pagination entirely. With many tables/constraints, responses could blow context window without offset/limit support.
Descriptions are often brief (under 100 chars). E.g., 'List all constraints' lacks context on when to call it vs listForeignKeys, what structure is returned, or that it covers PK, FK, UNIQUE, CHECK types. Baseline for A-tier is 50-200 chars with explanation of WHAT, WHEN, and output shape.