MCP server for recutils database operations providing CRUD functionality for recutils record databases
Recutils MCP presents a collection of 5 tools for querying, inserting, updating, and deleting records in recutils databases. While tool names follow a clear verb_noun pattern (recutils_query, recutils_insert, etc.) and are distinct, the implementation has significant quality gaps: (1) Tool descriptions are minimal (10-29 chars), well below the 194-char baseline and 50-200 char LLM-optimization target, providing no context on WHEN to use each tool or WHAT to do next. (2) Parameter schemas are present but lack descriptions, InsertArgs.fields, UpdateArgs.fields, and QueryArgs.query_expression have no descriptions in the code, forcing LLMs to infer purpose from names alone. (3) No output schema documentation is visible; tool responses are serialized JSON but callers cannot predict the structure. (4) Error handling is generic, all errors return 'Error: <message>' text without recovery guidance, categorization, or actionable next steps. (5) Destructive operations (delete, insert, update) have no dry-run, confirmation, or idempotency signals. (6) No input validation shown, database_file and query_expression parameters are passed directly without sanitization, risking path traversal or injection attacks.
Delete records from recutils database
Get recutils database info
Insert new record into recutils database
Query records in recutils database
Update records in recutils database
Tool descriptions are 10-29 characters, far below the 50-200 char LLM-optimization baseline. Descriptions like 'Query records in recutils database' and 'Insert new record into recutils database' lack context on WHEN to call the tool, what it returns, and when to use it instead of similar tools. LLMs cannot distinguish intent with such minimal descriptions.
Parameter descriptions are missing or invisible in the code. InsertArgs.fields, UpdateArgs.fields, QueryArgs.query_expression, and QueryArgs.output_format are not annotated with descriptions (no struct tags or docstrings visible). The 'fields' parameter in particular is a map[string]interface{} with no hint on what key-value pairs are valid, what types values should have, or whether they are required. LLMs cannot infer parameter semantics from names alone.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 43 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 22 | - | v1 |
No output schema is documented. Tool responses are serialized JSON (result marshaled to JSON string), but the structure of 'result' is not visible or described in the MCP tool definitions. Callers cannot predict what fields are present, what types they have, or what they mean. This forces LLMs to reason blindly about response structure and breaks downstream tool composition.
Error handling is non-actionable. All errors return 'Error: <message>' or 'Error marshaling result: <message>' as plain text with no guidance on recovery, retry eligibility, or next steps. There is no error categorization (retryable vs user-fixable vs fatal), no invalid value echoing, and no suggestions for alternatives. An LLM receiving 'Error: file not found' cannot decide whether to retry, ask the user, or give up.
No input validation or sanitization is visible for the database_file parameter. The code passes args.DatabaseFile directly to recutils operations without checking for path traversal (../../etc/passwd), symlink attacks, or permission validation. The query_expression parameter is similarly unchecked, risking recutils injection if the underlying command-line tool is vulnerable.
Destructive and write operations (insert, update, delete) lack dry-run, confirmation, or idempotency guarantees. The delete operation has no 'confirm_before_execute' pattern, an LLM could accidentally delete all records with an overly broad query. There is no indication whether operations are idempotent or what happens if called twice with the same input.
Parameter constraints and formats are not documented. The 'output_format' parameter example mentions 'plain, csv' but these are not declared as an enum. The 'query_expression' syntax is not explained, is it recutils query language, SQL, or something else? Expected format, syntax, and allowed values are invisible to callers.