Add --no-mcp flag, feature-gate jerboa-native-rs, fix binary build

ober

7030c5a4e95854d9494b1ae709f99c0a3578c018

diff --git a/Makefile b/Makefile
index 763fbfc..29956f9 100644
--- a/Makefile
+++ b/Makefile
@@ -101,10 +101,13 @@ binary: build
 	DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \
 	$(SCHEME) -q --libdirs $(JERBOA_HOME)/lib:./lib:vendor/chez-sqlite/src \
 	--script build-binary.ss
+	cp vendor/termbox2/jcode_tui_shim.dylib ./jcode_tui_shim.dylib 2>/dev/null || true
+	cp vendor/termbox2/jcode_tui_shim.so ./jcode_tui_shim.so 2>/dev/null || true
 
 install: binary
 	mkdir -p $(HOME)/.local/bin
 	cp jcode $(HOME)/.local/bin/jcode
+	cp vendor/termbox2/jcode_tui_shim.dylib $(HOME)/.local/bin/jcode_tui_shim.dylib 2>/dev/null || true
 	cp vendor/chez-sqlite/chez_sqlite_shim.so $(PREFIX)/lib/chez_sqlite_shim.so 2>/dev/null || true
 	@echo "Installed to ~/.local/bin/jcode"
 
diff --git a/build-binary.ss b/build-binary.ss
index b07f6fc..31d73d0 100644
--- a/build-binary.ss
+++ b/build-binary.ss
@@ -185,22 +185,37 @@
 (define tui-ffi-sls "lib/jcode/ui/tui-ffi.sls")
 (define tui-ffi-backup "lib/jcode/ui/tui-ffi.sls.bak")
 (system (format "cp ~a ~a" tui-ffi-sls tui-ffi-backup))
+;; In static binary, all termbox symbols are linked in via Sforeign_symbol, so
+;; we just need _shim-loaded to be #t.  Replace the multi-line definition.
 (let* ((src (call-with-input-file tui-ffi-sls get-string-all))
-       (src (string-replace-first src
-              (string-append
-                "(def _shim-loaded\n"
-                "       (or (guard (e [list #t #f])\n"
-                "             (load-shared-object \"jcode_tui_shim.dylib\"))\n"
-                "           (guard (e [list #t #f])\n"
-                "             (load-shared-object \"jcode_tui_shim.so\"))\n"
-                "           (guard (e [list #t #f])\n"
-                "             (load-shared-object\n"
-                "               (path-join\n"
-                "                 (path-directory (car (command-line)))\n"
-                "                 \"jcode_tui_shim.dylib\")))\n"
-                "           #f))")
-              "(def _shim-loaded #t)")))
-  (call-with-output-file tui-ffi-sls (lambda (p) (put-string p src)) 'replace))
+       (start-marker "(def _shim-loaded")
+       (start-pos (let lp ((i 0))
+                    (cond
+                      ((> (+ i (string-length start-marker)) (string-length src)) #f)
+                      ((string=? start-marker
+                                 (substring src i (+ i (string-length start-marker))))
+                       i)
+                      (else (lp (+ i 1)))))))
+  (when start-pos
+    ;; Find matching close paren for the (def ...) form
+    (let lp ((i start-pos) (depth 0) (started? #f))
+      (cond
+        ((>= i (string-length src))
+         (printf "  Warning: could not find end of _shim-loaded definition~n"))
+        ((char=? (string-ref src i) #\()
+         (lp (+ i 1) (+ depth 1) #t))
+        ((char=? (string-ref src i) #\))
+         (if (and started? (= depth 1))
+           ;; Found end — replace the whole form
+           (let ((replacement "(def _shim-loaded #t)"))
+             (call-with-output-file tui-ffi-sls
+               (lambda (p)
+                 (put-string p (substring src 0 start-pos))
+                 (put-string p replacement)
+                 (put-string p (substring src (+ i 1) (string-length src))))
+               'replace))
+           (lp (+ i 1) (- depth 1) started?)))
+        (else (lp (+ i 1) depth started?))))))
 (when (file-exists? "lib/jcode/ui/tui-ffi.so")
   (delete-file "lib/jcode/ui/tui-ffi.so"))
 
diff --git a/lib/jcode/ui/cli.sls b/lib/jcode/ui/cli.sls
index dc6413e..b0979e9 100644
--- a/lib/jcode/ui/cli.sls
+++ b/lib/jcode/ui/cli.sls
@@ -32,6 +32,7 @@
            (printf "jcode ~a~n" *version*)
            (exit 0))
          (when (assoc '\x2D;-debug opts) (current-log-level 'debug))
+         (when (assoc '\x2D;-no-mcp opts) (set! *no-mcp* #t))
          (load-config)
          (session-init-db)
          (init-tools)
@@ -68,6 +69,8 @@
             (loop (cdr args) (cons '(\x2D;-tui . #t) opts))]
            [(equal? (car args) "--no-tui")
             (loop (cdr args) (cons '(\x2D;-no-tui . #t) opts))]
+           [(equal? (car args) "--no-mcp")
+            (loop (cdr args) (cons '(\x2D;-no-mcp . #t) opts))]
            [(equal? (car args) "--verbose")
             (loop (cdr args) (cons '(\x2D;-verbose . #t) opts))]
            [(and (equal? (car args) "--model") (pair? (cdr args)))
@@ -87,17 +90,18 @@
               (cddr args)
               (cons (cons '\x2D;-provider (cadr args)) opts))]
            [else (cons (cons '\x2D;- args) (reverse opts))])))
+  (def *no-mcp* #f)
   (def (init-tools) (init-file-tools) (init-bash-tool)
        (init-web-tools) (init-batch-tool) (init-git-tools)
-       (let ([t-mcp (spawn init-mcp-tools)]
+       (let ([t-mcp (and (not *no-mcp*) (spawn init-mcp-tools))]
              [t-lsp (spawn init-lsp-tools)]
              [t-plugins (spawn init-plugins)])
-         (thread-join! t-mcp)
+         (when t-mcp (thread-join! t-mcp))
          (thread-join! t-lsp)
          (thread-join! t-plugins)))
   (def (display-help)
        (display
-         "jcode - Portable AI coding agent\n\nUSAGE:\n    jcode [OPTIONS] [PROMPT]\n    jcode [COMMAND]\n\nOPTIONS:\n    -h, --help       Show this help message\n    -v, --version    Show version\n    -d, --debug      Enable debug logging\n    -m, --model      Model to use (default: claude-sonnet-4-20250514)\n    -p, --provider   Provider to use (default: anthropic)\n    --tui            Launch terminal UI mode\n    --no-tui         Force line-mode REPL (default)\n    --verbose        Log TUI events to ~/jcode.log\n\nCOMMANDS:\n    session list     List all sessions\n    session resume   Resume a previous session\n    config           Show or edit configuration\n    serve            Start JSONL server (stdio mode)\n    serve --port N   Start TCP server on 127.0.0.1:N\n    serve --rotate-token   Generate new auth token and exit\n    serve --show-token     Display current auth token and exit\n\nEXAMPLES:\n    jcode                           Start interactive session\n    jcode \"Read main.ss\"           One-shot query\n    jcode session list              List sessions\n    jcode serve --port 8321         Start TCP server for Android app\n"))
+         "jcode - Portable AI coding agent\n\nUSAGE:\n    jcode [OPTIONS] [PROMPT]\n    jcode [COMMAND]\n\nOPTIONS:\n    -h, --help       Show this help message\n    -v, --version    Show version\n    -d, --debug      Enable debug logging\n    -m, --model      Model to use (default: claude-sonnet-4-20250514)\n    -p, --provider   Provider to use (default: anthropic)\n    --tui            Launch terminal UI mode\n    --no-tui         Force line-mode REPL (default)\n    --no-mcp         Skip MCP server initialization\n    --verbose        Log TUI events to ~/jcode.log\n\nCOMMANDS:\n    session list     List all sessions\n    session resume   Resume a previous session\n    config           Show or edit configuration\n    serve            Start JSONL server (stdio mode)\n    serve --port N   Start TCP server on 127.0.0.1:N\n    serve --rotate-token   Generate new auth token and exit\n    serve --show-token     Display current auth token and exit\n\nEXAMPLES:\n    jcode                           Start interactive session\n    jcode \"Read main.ss\"           One-shot query\n    jcode session list              List sessions\n    jcode serve --port 8321         Start TCP server for Android app\n"))
   (def (interactive-mode opts)
        (printf "jcode ~a~n" *version*)
        (printf
diff --git a/lib/jcode/ui/tui-ffi.sls b/lib/jcode/ui/tui-ffi.sls
index d3bca48..3303879 100644
--- a/lib/jcode/ui/tui-ffi.sls
+++ b/lib/jcode/ui/tui-ffi.sls
@@ -43,15 +43,24 @@
     (jerboa core)
     (jerboa runtime))
   (def _shim-loaded
-       (or (guard (e [#t #f])
-             (load-shared-object "jcode_tui_shim.dylib"))
-           (guard (e [#t #f]) (load-shared-object "jcode_tui_shim.so"))
-           (guard (e [#t #f])
-             (load-shared-object
-               (path-join
-                 (path-directory (car (command-line)))
-                 "jcode_tui_shim.dylib")))
-           #f))
+       (let ([try-load
+              (lambda (p)
+                (guard (e [#t #f])
+                  (and (file-exists? p) (load-shared-object p))))])
+         (or (try-load "jcode_tui_shim.dylib")
+             (try-load "jcode_tui_shim.so")
+             (try-load
+               (path-join (path-directory (car (command-line)))
+                 "jcode_tui_shim.dylib"))
+             (try-load
+               (path-join (path-directory (car (command-line)))
+                 "jcode_tui_shim.so"))
+             (try-load
+               (path-join (getenv "HOME") ".local" "bin"
+                 "jcode_tui_shim.dylib"))
+             (try-load "vendor/termbox2/jcode_tui_shim.dylib")
+             (try-load "vendor/termbox2/jcode_tui_shim.so")
+             #f)))
   (defrule
     (define-tb name c-name arg-types ret-type)
     (def name
diff --git a/src/jcode/ui/cli.ss b/src/jcode/ui/cli.ss
index 52f2f45..84be37c 100644
--- a/src/jcode/ui/cli.ss
+++ b/src/jcode/ui/cli.ss
@@ -42,6 +42,8 @@
       (printf "jcode ~a~n" *version*) (exit 0))
     (when (assoc '--debug opts)
       (current-log-level 'debug))
+    (when (assoc '--no-mcp opts)
+      (set! *no-mcp* #t))
     (load-config)
     (session-init-db)
     (init-tools)
@@ -74,6 +76,7 @@
       ((equal? (car args) "-d")        (loop (cdr args) (cons '(--debug . #t) opts)))
       ((equal? (car args) "--tui")     (loop (cdr args) (cons '(--tui . #t) opts)))
       ((equal? (car args) "--no-tui")  (loop (cdr args) (cons '(--no-tui . #t) opts)))
+      ((equal? (car args) "--no-mcp")  (loop (cdr args) (cons '(--no-mcp . #t) opts)))
       ((equal? (car args) "--verbose") (loop (cdr args) (cons '(--verbose . #t) opts)))
       ((and (equal? (car args) "--model") (pair? (cdr args)))
        (loop (cddr args) (cons (cons '--model (cadr args)) opts)))
@@ -85,6 +88,8 @@
        (loop (cddr args) (cons (cons '--provider (cadr args)) opts)))
       (else (cons (cons '-- args) (reverse opts))))))
 
+(def *no-mcp* #f)
+
 (def (init-tools)
   ;; Register local tools (fast, no I/O)
   (init-file-tools)
@@ -93,10 +98,10 @@
   (init-batch-tool)
   (init-git-tools)
   ;; External servers in parallel (spawn subprocesses, handshake)
-  (let ((t-mcp (spawn init-mcp-tools))
+  (let ((t-mcp (and (not *no-mcp*) (spawn init-mcp-tools)))
         (t-lsp (spawn init-lsp-tools))
         (t-plugins (spawn init-plugins)))
-    (thread-join! t-mcp)
+    (when t-mcp (thread-join! t-mcp))
     (thread-join! t-lsp)
     (thread-join! t-plugins)))
 
@@ -116,6 +121,7 @@ OPTIONS:
     -p, --provider   Provider to use (default: anthropic)
     --tui            Launch terminal UI mode
     --no-tui         Force line-mode REPL (default)
+    --no-mcp         Skip MCP server initialization
     --verbose        Log TUI events to ~/jcode.log
 
 COMMANDS:
diff --git a/src/jcode/ui/tui-ffi.ss b/src/jcode/ui/tui-ffi.ss
index 015cf68..86ff10f 100644
--- a/src/jcode/ui/tui-ffi.ss
+++ b/src/jcode/ui/tui-ffi.ss
@@ -61,14 +61,21 @@
 ;; ---- Load shared library ----
 
 (def _shim-loaded
-  (or (guard (e [#t #f])
-        (load-shared-object "jcode_tui_shim.dylib"))
-      (guard (e [#t #f])
-        (load-shared-object "jcode_tui_shim.so"))
-      (guard (e [#t #f])
-        (load-shared-object
-          (path-join (path-directory (car (command-line))) "jcode_tui_shim.dylib")))
-      #f))
+  (let ((try-load (lambda (p)
+                    (guard (e [#t #f])
+                      (and (file-exists? p)
+                           (load-shared-object p))))))
+    (or (try-load "jcode_tui_shim.dylib")
+        (try-load "jcode_tui_shim.so")
+        ;; Next to the binary
+        (try-load (path-join (path-directory (car (command-line))) "jcode_tui_shim.dylib"))
+        (try-load (path-join (path-directory (car (command-line))) "jcode_tui_shim.so"))
+        ;; ~/.local/bin (common install location)
+        (try-load (path-join (getenv "HOME") ".local" "bin" "jcode_tui_shim.dylib"))
+        ;; vendor dir (development)
+        (try-load "vendor/termbox2/jcode_tui_shim.dylib")
+        (try-load "vendor/termbox2/jcode_tui_shim.so")
+        #f)))
 
 ;; Safe FFI binding — returns error-raising lambda if symbol not found
 (defrule (define-tb name c-name arg-types ret-type)