Server defines 3 tools with mixed quality. All tools have names starting with action verbs (connect, eval_form, get_ns_vars), which is good. Descriptions are present and moderately detailed, ranging from 85-200 characters with examples. Input schemas are fully visible and properly typed with required fields declared. However, output schemas are completely undocumented, no tool describes what it returns, which violates the critical pattern:tool requirement. Parameter descriptions are adequate but could be more precise. Error handling is basic (McpError with some context but no recovery guidance). Resource definitions are present but tool composition relies on stateful nREPL client connections, which may cause issues with agent retry behavior.
Connect to an nREPL server. Example: (connect {:host "localhost" :port 1234})
Evaluate Clojure code in a specific namespace or the current one. Examples: - Define and call a function: {"code": "(defn greet [name] (str \"Hello, \" name \"!\"))(greet \"World\"))"} - Reload code: {"code": "(clj-reload.core/reload)"} - Evaluate in a specific namespace: {"code": "(clojure.repl.deps/sync-deps)", "ns": "user"}
Get all public vars (functions, values) in a namespace with their metadata and current values. Example: - List main namespace vars: (get_ns_vars {:ns "main"}) Returns a map where keys are var names and values contain: - :meta - Metadata including :doc string, :line number, :file path - :value - Current value of the var
No output schemas documented for any tool. Critical violation of pattern:tool which requires 'Document the output schema. LLMs need to know what fields to expect.' Tools return Clojure data structures (eval results, var metadata, status objects) but LLM cannot parse them without a schema.
eval_form tool accepts arbitrary Clojure code with no validation, sanitization, or input constraints. LLM can inject malicious Clojure code if prompt-injected. No sandboxing or code review mentioned. High security risk for any untrusted agent.
Server maintains stateful nREPL client connection (this.nreplClient) across tool calls. If an agent retries connect() after a transient error, the old client is closed but state may not be fully reset. Non-idempotent behavior violates pattern:idempotent-operation.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 58 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 45 | - | v1 |
eval_form description includes example JSON payloads but no formal parameter relationship documentation. The ns parameter is optional and 'changes persist for subsequent evaluations', but docs don't explain how persistence works across tool calls or how agents should manage namespace state. This is an undocumented dependency that could cause confusion.
connect tool has no description of return value. Successful connection should return session_id, port, host confirmation, or similar, but nothing is documented. LLM doesn't know whether to expect structured response or a status message.
get_ns_vars has no result limit documented. If a namespace has 1000+ vars, the full list could overwhelm the LLM context window. Production tools should cap results at 20-50 and offer pagination or filtering.
Error messages visible in code are minimal. CallToolRequestSchema handler throws McpError with ErrorCode.InvalidParams for connect, but doesn't guide recovery (e.g., 'Verify nREPL server is running on <host>:<port>'). Violates pattern:recovery-guide.