mcp-kinetica has 9 tools with consistent naming (verb-first pattern: query_, describe_, list_, get_, insert_, generate_, start_), good descriptions (most 40-80 chars), and visible input schemas. However, several tools lack comprehensive parameter descriptions, output schemas are documented only as return type hints (not in schema format for LLM consumption), and error handling is basic. The server demonstrates solid foundation patterns but falls short of production-grade tool design in output documentation and error guidance. Tools are well-composed (single responsibility), but discovery and chaining support could be stronger.
Tools (9)
describe_tableread onlyauthsource verified75/100
Return a dictionary of column name to column type.
generate_sqlread onlyauthsource verified73/100
Generate SQL queries using Kinetica's text-to-SQL capabilities.
Output schemas not documented for LLM consumption. Tools return structured data (list[dict], dict[str, str], int), but no JSON Schema definitions are visible in tool registration. LLMs cannot plan downstream chaining or validate field names without seeing output structure.
start_table_monitor lacks clear return type documentation. Code shows it starts monitoring (implies async/streaming behavior), but description and output schema are missing. LLM cannot determine if this is fire-and-forget, returns a monitor_id for later polling, or streams events.
Pagination not implemented for list_tables, list_sql_contexts, get_records, query_sql. These tools return bounded results (limit=10 default) but lack total_count, next_cursor, or offset parameters. If a database has 1000 tables, LLM cannot discover all of them.
Recommendations
Add JSON Schema output documentation to every tool. For query_sql, define: { type: 'array', items: { type: 'object', description: 'Row object with column names as keys' }, description: 'List of query result rows as JSON objects' }. Similarly for describe_table: { type: 'object', description: 'Column name → type mapping' }, etc.
Implement pagination for list_tables, list_sql_contexts, get_records, query_sql. Add offset/limit params (with min 1, max 100), return total_count, and document how to iterate.
Add tool annotations: set readOnlyHint=true for query_sql, describe_table, list_tables, get_records, list_sql_contexts, generate_sql, get_user_info. Set destructiveHint=true for insert_records. Set idempotentHint=true for query_sql (same query always returns same results).
Enhance parameter descriptions. For query_sql sql param: 'A read-only SELECT query (no INSERT, UPDATE, DELETE, CREATE, DROP). Max 5000 chars. Queries are validated before execution.' For limit: 'Number of rows to return. Must be 1-1000. Defaults to 10 to avoid overwhelming responses.'
Add recovery guidance to error messages. E.g., in describe_table exception handler: raise ToolError(f"Table '{table_name}' not found. Call list_tables() to see available tables.") from e
Add error classification. Wrap ToolError messages with severity and retryability. E.g., 'RETRYABLE: Connection timeout, server may be restarting. Retry in 5 seconds.' or 'USER_FIXABLE: Table name contains invalid characters, use alphanumeric and underscores only.'
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Score history
Overall score trend
↑ 32 points across a rubric change (v1 → v2)
68/100
Scored
Grade
Overall
Spec posture
Rubric
2026-09-22
C
68
<=2025-11-25
v2
2026-03-09
F
36
-
v1
List all available tables, views, and schemas in the database.
Error handling is minimal. ToolError exceptions provide basic messages ('Failed to describe table...', 'Insertion failed...'), but do not guide LLM on next steps. E.g., no recovery suggestions, no retryability classification, no validation of parameters before API call.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). insert_records is destructive and should declare destructiveHint=true; query_sql, describe_table, list_tables, get_records, etc. are read-only and should declare readOnlyHint=true. This helps LLMs reason about side effects.
query_sql accepts raw SQL strings without documented constraints or sanitization hints. While tool docstring says 'safe SQL query', it is unclear what safety is enforced (e.g., no DDL? no insert/update/delete?). LLM cannot know if it can safely pass arbitrary WHERE clauses.
insert_records lacks confirmation/dry-run pattern. Destructive operations should support validation before commit. No way for LLM to preview what records will be inserted or roll back if the insert is wrong.
Parameter descriptions are minimal. E.g., 'sql' in query_sql has description 'SQL query to execute' (30 chars); should include format constraints, limits, and safety guardrails. 'limit' defaults to 10 but no min/max specified; LLM could pass 0 or 1000000.
No rate limiting documented. Agents could loop and call query_sql or get_records thousands of times per minute without guards. Runaway agents could overwhelm Kinetica.
insert_records returns an int (number of inserted records), but no success/failure breakdown is provided. If 1 record fails out of 100, the LLM gets one error message and must retry all 100. Per-item success/failure array would enable partial recovery.
insert_records
For insert_records, add a dry_run parameter (boolean, default=false). When dry_run=true, validate records against table schema and return validation errors without inserting. Enable LLM to preview before committing.
Document table_name and table parameters as accepting both schema.table format and simple table names. Add hint in descriptions: 'E.g., my_schema.my_table or my_table. If schema is omitted, defaults to the configured schema.'
Implement server-side rate limiting: quota 100 read calls per minute, 10 write calls per minute per authenticated user. Return 429 with Retry-After header and guidance: 'Rate limit exceeded. Try again after 30 seconds. Consider batching multiple records in insert_records rather than calling repeatedly.'
Add start_table_monitor output documentation. Clarify: does it return a monitor_id? does it stream events? is it async? Add to description: 'Returns { monitor_id: string, status: 'active' }. Use monitor_id to poll for events or unsubscribe. Events are published to a resource://<monitor_id> endpoint.'
For generate_sql, add context_name enum or discovery. Document: 'Call list_sql_contexts() first to get valid context names.' Include hint about what each context represents.
Add audit logging for insert_records (and any future write tools). Log user identity, table name, record count, timestamp, and success/failure. Enable compliance tracking.