Your AI forgets everything between sessions. cachly fixes that permanently: 124 MCP tools for Claude Code, Cursor, Copilot & Windsurf. Learns from every bug fix, commit and CI run. Arrives pre-briefed. Free tier forever, EU servers, GDPR.
cachly MCP server demonstrates solid definition quality across 14 tools. All tools have clear verb-prefixed names following action-oriented patterns (list_, create_, get_, cache_, delete_, semantic_search). Descriptions are consistently detailed (80-250+ chars) and explain both the action and use case. All tools include input schemas with type declarations. However, critical gaps exist: (1) instance_id is a REQUIRED parameter in most cache tools but the schema for cache_get, cache_set, cache_delete, cache_exists, cache_ttl, cache_keys, cache_stats, and semantic_search does NOT mark instance_id as required, it's nullable or missing from required arrays. (2) Output schemas are entirely undocumented, no response structures are declared anywhere in the source. (3) Error handling descriptions are minimal, no guidance on retry behavior, recovery steps, or error categories. (4) Parameter constraints are inconsistent: ttl is documented as 'seconds' but no min/max bounds stated; pattern glob in cache_keys accepts no description of valid glob syntax. (5) Tool annotations (readOnlyHint, destructiveHint) are absent, the LLM cannot infer which tools are safe to retry or which will destroy data without reading descriptions carefully.
Permanently delete one or more keys from a running cache instance (uses Redis DEL). This operation is destructive and irreversible — deleted keys cannot be recovered. Deleting a non-existent key is safe and returns 0 for that key (no error). Returns the count of keys that were actually deleted (existing keys only). Use this to explicitly remove stale entries; prefer cache_set with a short TTL for auto-expiring data. Do NOT use this to clear an entire instance — use the dashboard or delete_instance for that.
Check whether one or more keys exist in a running cache instance (uses Redis EXISTS). Read-only — no side effects. Returns the count of keys that currently exist (integer 0 to N). If none of the keys exist, returns 0. If all exist, returns the total key count passed in. Duplicate keys in the input array are each counted separately (Redis behavior). Use this to check presence before a cache_get to avoid null handling, or to verify a cache warm-up completed. Use cache_get instead if you also need the value; use cache_ttl if you need expiry info.
Get a value from a running cache instance by key. Returns the stored value (string or deserialized JSON object) or null if the key does not exist or has expired. Read-only — no side effects. Use cache_mget when you need multiple keys in one round-trip. Use cache_exists to check existence without retrieving the value. Use semantic_search when you need fuzzy/vector search across stored values.
List keys in a cache instance matching an optional glob pattern (e.g. "user:*", "session:*"). Uses SCAN to avoid blocking the server. Returns at most `count` keys.
Missing instance_id from required arrays in cache operation tools. cache_get, cache_set, cache_delete, cache_exists, cache_ttl, cache_keys, cache_stats input schemas list instance_id in properties but do NOT mark it in required[]. This allows LLMs to call tools without a critical parameter, causing runtime failures. The schema shows instance_id: {type:string, description:...} but required:[] omits it.
No output schemas documented for ANY tool. Descriptions state what tools return (e.g., 'returns an array of instance objects, each with id, name, tier, status, region, RAM, and redis:// connection string') but no formal response schema is provided. LLMs cannot predict field names, types, or presence of optional fields. This forces LLMs to reason about response structure from natural language alone, increasing errors and token waste.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 68 | 2026-07-28+ | v2 |
Set a key-value pair in a running cache instance. Overwrites any existing value at the key — not idempotent for new data. Returns "OK" on success; returns an error if the instance_id is invalid or the instance is paused. Value can be a string or a JSON-serialized object. Optionally set a TTL in seconds (omit for no expiry). Use cache_mset instead for setting multiple keys in a single pipeline round-trip. Use cache_stream_set instead for caching LLM token streams (ordered string chunks).
Get real-time stats for a cache instance: memory usage, hit/miss rate, commands/sec, connected clients, keyspace info, and uptime. Read-only — no side effects. The instance_id identifies the target instance (obtain from list_instances). Use this for monitoring, capacity planning, or debugging performance issues — not for reading cached values (use cache_get for that). Use cache_exists or cache_ttl if you only need key-level information.
Get the remaining time-to-live (TTL) of a key in seconds. Returns -1 if the key exists but has no expiry, -2 if the key does not exist. Read-only — no side effects. Use cache_set with a ttl parameter to set or update the expiry.
Create a new managed Valkey/Redis cache instance on cachly.dev. Free tier provisions in ~30 seconds. Paid tiers return a Stripe checkout URL. Available tiers: free (25 MB), dev (200 MB, €19/mo), pro (900 MB, €49/mo), speed (900 MB Dragonfly + Semantic Cache, €79/mo), business (7 GB, €199/mo).
Permanently delete a cache instance. Deprovisions the Kubernetes workload and removes all data. This action is irreversible.
Check API health + JWT auth info (Keycloak). Read-only. Returns server uptime, JWT validation status, and cachly account info.
Get the Redis/Valkey connection string (redis:// URL) for a running instance. Use this to configure your application or set environment variables.
Get full metadata for a specific cache instance: name, tier, status (provisioning / running / paused), region, RAM limit, Redis connection string, created_at, and expiry. Read-only. Returns an error if the instance_id is not found or belongs to another account. Call list_instances first to discover valid UUIDs. Use get_connection_string instead if you only need the redis:// URL for your app config.
List all your cachly cache instances with their status and connection details. Read-only. Returns an array of instance objects — each with id, name, tier, status, region, RAM, and redis:// connection string. Returns an empty array if no instances exist. No pagination: all instances are returned in one call (typical accounts have < 20). Use this first to discover instance UUIDs required by get_instance, cache_get, cache_set, and all other cache tools. Use get_instance to retrieve full metadata for a single instance.
Find cached entries that are semantically similar to a natural-language query. Read-only — no side effects. Returns an array of objects, each with: key, value, similarity_score (0–1), and namespace. Returns an empty array if no entries meet the similarity threshold. Requires OPENAI_API_KEY (or compatible provider embedding model).
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are completely absent. Per the current MCP spec (2026-07-28), tools should declare their safety properties. 'delete_instance' and 'cache_delete' are destructive and irreversible; this MUST be communicated via destructiveHint:true in the tool registration, not just in description text. LLMs cannot reliably parse natural language safety warnings, they need formal annotations.
Minimal error handling guidance in descriptions. Most tool descriptions do NOT explain failure modes, retry conditions, or recovery steps. E.g., 'cache_set' says 'returns an error if the instance_id is invalid or the instance is paused' but provides no guidance on what to do next (check instance status? Retry? Provision a new instance?). Per pattern:recovery-guide, error descriptions should tell the LLM what to do next.
Parameter constraints are loosely documented. 'ttl' is described as 'Time-to-live in seconds (optional, omit for no expiry)' but lacks min/max bounds (is 1 second valid? 365 days?). 'pattern' in cache_keys is described as 'Glob pattern (default: *)' but provides no specification of valid glob syntax or escaping rules. 'count' has default 50 and max 500 (good) but no minimum stated. Per pattern:constrained-input, constraints should be explicit and machine-parseable.
Missing required parameter in delete_instance schema. Input schema shows properties: {instance_id, confirm} but required: ['confirm'] only. instance_id is required to identify which instance to delete, but the schema does not mark it required. This is a critical bug that will allow LLMs to call delete_instance with confirm:true but no instance_id, causing runtime failure.
Pagination/result limits are documented in prose but not formally in schemas. cache_keys description states 'Returns at most `count` keys' with default 50 and max 500, but the schema does not use maxItems or validation constraints. list_instances states 'No pagination: all instances are returned in one call (typical accounts have < 20)', this is fragile; if an account grows beyond 20, response size explodes and context window is exhausted.