jmcp: dispatcher tool-name enum + fix compile-check bracket reader

ober

c47c290eeac03c0014dd5637592ede50c5dd639b

diff --git a/mcp/server.ss b/mcp/server.ss
index 6d15625..d5cb91c 100644
--- a/mcp/server.ss
+++ b/mcp/server.ss
@@ -164,19 +164,29 @@
    "    (write result)\n"
    "    (newline)))\n"))
 
+;; Mirror the real .ss -> .sls front-end (jerboa translator's translate-file):
+;; apply the default string transforms, read forms with the native Chez reader
+;; (where [..] are parens, matching the language), run the default s-expr
+;; transforms per form, then compile. The (jerboa reader)'s jerboa-read must NOT
+;; be used here: it reads [x y] as (list x y) (Clojure-compat), which mangles
+;; bracket bindings like (let loop ([x y]) ...) into false syntax errors.
 (def (build-syntax-script code imports)
   (def escaped (scheme-escape code))
   (string-append
    (join-lines (import-lines imports))
-   "\n\n"
+   "\n(import (jerboa translator))\n\n"
    "(guard (e [else\n"
    "           (display \"" error-marker "\\n\")\n"
    "           (display-condition e (current-output-port))])\n"
-   "  (let ([port (open-string-input-port \"" escaped "\")])\n"
+   "  (let* ([cooked (translate-method-dispatch\n"
+   "                  (translate-hash-bang\n"
+   "                   (translate-keywords \"" escaped "\")))]\n"
+   "         [xlate (apply make-translator (default-transforms))]\n"
+   "         [port (open-string-input-port cooked)])\n"
    "    (let loop ()\n"
-   "      (let ([expr (jerboa-read port)])\n"
+   "      (let ([expr (read port)])\n"
    "        (unless (eof-object? expr)\n"
-   "          (compile expr)\n"
+   "          (compile (xlate expr))\n"
    "          (loop)))))\n"
   "  (display \"" valid-marker "\\n\"))\n"))
 
@@ -340,22 +350,29 @@
                 (string=? (hash-ref t "name") "jerboa")))
           *tools*))
 
+(def (tool-short-name t)
+  (if (string-prefix? "jerboa_" (hash-ref t "name"))
+      (substring (hash-ref t "name") 7 (string-length (hash-ref t "name")))
+      (hash-ref t "name")))
+
+(def (routable-tools)
+  (filter (lambda (t)
+            (and (not (hash-ref t 'critical))
+                 (not (string=? (hash-ref t "name") "jerboa"))))
+          *tools*))
+
+;; Names placed on the dispatcher's `tool` enum: a cheap always-visible
+;; table of contents (names only, ~hundreds of tokens) so a model can find a
+;; deferred tool without first calling tool="list". Schemas stay lazy.
+(def (routable-tool-names)
+  (unique (append '("list" "describe")
+                  (map tool-short-name (routable-tools)))))
+
 (def (manifest-line t)
-  (string-append "- "
-                 (if (string-prefix? "jerboa_" (hash-ref t "name"))
-                     (substring (hash-ref t "name") 7 (string-length (hash-ref t "name")))
-                     (hash-ref t "name"))
-                 ": "
-                 (hash-ref t "description")))
+  (string-append "- " (tool-short-name t) ": " (hash-ref t "description")))
 
 (def (dispatcher-manifest)
-  (string-join
-   (map manifest-line
-        (filter (lambda (t)
-                  (and (not (hash-ref t 'critical))
-                       (not (string=? (hash-ref t "name") "jerboa"))))
-                *tools*))
-   "\n"))
+  (string-join (map manifest-line (routable-tools)) "\n"))
 
 (def (format-schema s)
   (def props (hash-ref s "properties"))
@@ -4168,8 +4185,14 @@
                          '("file_path"))
                  tool-bisect-crash #f '())
   (register-tool "jerboa" "Jerboa Tool Dispatcher"
-                 "Invoke any non-critical jerboa_* tool by name."
-                 (schema (list (list "tool" (property "string" "Tool name"))
+                 (string-append
+                  "Invoke any non-critical jerboa_* tool by name. The `tool` enum lists "
+                  "every routable tool. Use tool=\"describe\" with args={\"name\":\"<tool>\"} "
+                  "to see a tool's arguments, then call it with args={...}. "
+                  "tool=\"list\" returns names plus descriptions.")
+                 (schema (list (list "tool" (jhash "type" "string"
+                                                   "description" "Tool to invoke, or \"list\"/\"describe\""
+                                                   "enum" (routable-tool-names)))
                                (list "args" (property "object" "Tool arguments")))
                          '("tool"))
                  dispatcher #f '()))