Personal finance tracker (income / expenses / cashflow) designed to be operated by AI agents. Reachable over MCP, CLI, or HTTP. Every mutation is idempotent, dry-runnable, and reversible. Self-host, no login, no dashboard.
krabs demonstrates solid fundamentals: all 10 tools have descriptions (avg 85 chars), input schemas with types, and clear verb-noun naming (schema_describe, account_get, api_key_create, etc.). Mutation tools include intent, idempotencyKey, and dryRun parameters, excellent safety primitives. However, output schemas are not documented in the source; parameter descriptions lack format constraints and range limits (e.g., 'name: 1-200 characters' stated in description but not in schema); error handling is generic (ApiClientError with code/message/hint/field) without recovery guidance; and no tool annotations (readOnlyHint, destructiveHint, idempotentHint) are visible. The schema_describe tool is a strong discovery pattern, but its output structure is not defined. Composition is clean, each tool has one responsibility, but responses are JSON-stringified text blocks rather than structured MCP output, limiting downstream tool chaining.
Return the current account.
Update account email or name.
Issue a new API key. The plaintext token is returned once; save it.
List all API keys for this account.
Immediately revoke an API key.
Create a product/plan. unitAmountCents is integer cents.
Fetch a product by id.
Output schemas not documented. Tools return JSON-stringified text blocks (textResult/errorResult) rather than structured MCP ToolResult with typed fields. LLMs cannot infer response structure for downstream chaining.
Parameter constraints not formalized in schema. Descriptions state 'name: 1-200 characters' and 'label: 1-100 characters' as text, but JSON Schema lacks minLength/maxLength. Regex patterns (e.g., prd_[0-9A-HJKMNP-TV-Z]{26}) defined in code but not exposed in tool schema.
Enum parameters not declared as enums in schema. 'kind', 'pricingModel', 'billingCycle', 'status' reference enums (productKinds, pricingModels, billingCycles, productStatuses) but schema shows type:string with no enum constraint. LLMs cannot discover valid values.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 58 | 2026-07-28+ | v2 |
List products with filters.
Partially update a product.
Returns the full agent-facing contract: every operation, its input schema, and metadata (destructive? idempotent? supports dry-run?).
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). Risk metadata is tracked in code (Risk: READ_ONLY, WRITE, DESTRUCTIVE) but not exposed via MCP tool annotations. Agents cannot infer safety properties from tool definitions.
Error handling lacks recovery guidance. ApiClientError returns code/message/hint/field, but no actionable next steps. E.g., 'Product not found' should suggest 'Call product_list() to see available products.'