Skip to content

Commit c04bf60

Browse files
committed
addressing comments
1 parent ad40785 commit c04bf60

3 files changed

Lines changed: 56 additions & 11 deletions

File tree

README.org

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ These tools add:
225225
- =get_feature_load_state=: inspect whether an Emacs feature is loaded and where it comes from
226226
- =get_recent_messages=: return the latest lines from =*Messages*=
227227
- =get_last_error_backtrace=: return the most recently recorded Emacs command error snapshot
228-
- =eval_elisp=: evaluate a single Emacs Lisp form in a chosen buffer context when explicitly enabled (no restrictions once enabled)
228+
- =eval_elisp=: evaluate arbitrary Emacs Lisp with possible side effects in a chosen buffer context when explicitly enabled (no restrictions once enabled)
229229

230230
The old =ai-code-mcp-editor-tools.el= module has been removed. Its live-editor read tools are now built in, while =eval_elisp= remains an explicit opt-in.
231231

@@ -235,7 +235,7 @@ To register =eval_elisp=:
235235
(setq ai-code-mcp-debug-tools-enable-eval-elisp t)
236236
#+end_src
237237

238-
Once enabled, =eval_elisp= can evaluate any Emacs Lisp form without restrictions. It takes =code= (a single top-level form), optional =buffer_name= or =file_path= for evaluation context, and optional =timeout_ms=. This is useful for letting the AI apply fixes by evaluating modified function definitions directly.
238+
Once enabled, =eval_elisp= can evaluate any Emacs Lisp form without restrictions. It takes =code= (a single top-level form), optional =buffer_name= or =file_path= for evaluation context, optional =capture_messages= to collect new =*Messages*= output, optional =include_backtrace= to include a backtrace on failure, and optional =timeout_ms=. This is useful for letting the AI apply fixes by evaluating modified function definitions directly.
239239

240240
screenshot inside Codex cli:
241241

ai-code-mcp-debug-tools.el

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
(defconst ai-code-mcp-debug-tools--eval-spec
8282
'(:function ai-code-mcp-eval-elisp
8383
:name "eval_elisp"
84-
:description "Evaluate a single Emacs Lisp form."
84+
:description "Evaluate arbitrary Emacs Lisp with possible side effects once explicitly enabled."
8585
:args ((:name "code"
8686
:type string
8787
:description "Single Emacs Lisp form to evaluate.")
@@ -190,14 +190,16 @@
190190
changed))))))
191191

192192
(defun ai-code-mcp-debug-tools--context-summary (buffer)
193-
"Return a summary of BUFFER after an evaluation."
194-
(let ((position (ai-code-mcp-debug-tools--point-line-column
195-
buffer
196-
(with-current-buffer buffer (point)))))
197-
`((buffer_name . ,(buffer-name buffer))
198-
(file_path . ,(buffer-file-name buffer))
199-
(line . ,(alist-get 'line position))
200-
(column . ,(alist-get 'column position)))))
193+
"Return a summary of BUFFER after an evaluation.
194+
Return nil when BUFFER is no longer live."
195+
(when (buffer-live-p buffer)
196+
(let ((position (ai-code-mcp-debug-tools--point-line-column
197+
buffer
198+
(with-current-buffer buffer (point)))))
199+
`((buffer_name . ,(buffer-name buffer))
200+
(file_path . ,(buffer-file-name buffer))
201+
(line . ,(alist-get 'line position))
202+
(column . ,(alist-get 'column position))))))
201203

202204
(defun ai-code-mcp-debug-tools--parse-single-form (code)
203205
"Parse CODE and return exactly one top-level Emacs Lisp form."

test/test_ai-code-mcp-debug-tools.el

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,21 @@
121121
(alist-get 'tools tools-result))))
122122
(should (member "eval_elisp" tool-names)))))
123123

124+
(ert-deftest ai-code-test-mcp-tools-list-warns-eval-elisp-is-unrestricted ()
125+
"Eval tool metadata should warn about unrestricted side effects."
126+
(let ((ai-code-mcp-server-tools nil)
127+
(ai-code-mcp-debug-tools-enabled t)
128+
(ai-code-mcp-debug-tools-enable-eval-elisp t))
129+
(let* ((tools-result (ai-code-mcp-dispatch "tools/list"))
130+
(eval-tool (seq-find
131+
(lambda (tool)
132+
(equal "eval_elisp" (alist-get 'name tool)))
133+
(alist-get 'tools tools-result)))
134+
(description (alist-get 'description eval-tool)))
135+
(should eval-tool)
136+
(should (string-match-p "arbitrary Emacs Lisp" description))
137+
(should (string-match-p "side effects" description)))))
138+
124139
(ert-deftest ai-code-test-mcp-eval-elisp-uses-target-buffer ()
125140
"Eval should run against the requested buffer context."
126141
(let ((ai-code-mcp-server-tools nil)
@@ -197,6 +212,26 @@
197212
(when (buffer-live-p buffer)
198213
(kill-buffer buffer)))))
199214

215+
(ert-deftest ai-code-test-mcp-eval-elisp-survives-killed-target-buffer ()
216+
"Eval should still return JSON when the target buffer is killed."
217+
(let ((ai-code-mcp-server-tools nil)
218+
(ai-code-mcp-debug-tools-enabled t)
219+
(ai-code-mcp-debug-tools-enable-eval-elisp t)
220+
(buffer (generate-new-buffer " *ai-code-mcp-eval-kill*")))
221+
(let ((payload
222+
(unwind-protect
223+
(ai-code-test-mcp-debug-tools--read-json-payload
224+
(ai-code-mcp-dispatch
225+
"tools/call"
226+
`((name . "eval_elisp")
227+
(arguments . ((code . "(kill-buffer (current-buffer))")
228+
(buffer_name . ,(buffer-name buffer)))))))
229+
(when (buffer-live-p buffer)
230+
(kill-buffer buffer)))))
231+
(should (equal t (alist-get 'ok payload)))
232+
(should (equal "t" (alist-get 'value_repr payload)))
233+
(should-not (alist-get 'context_after payload)))))
234+
200235
(ert-deftest ai-code-test-mcp-get-variable-value-returns-bound-variable ()
201236
"Variable value tool should stringify the requested Emacs variable."
202237
(let ((ai-code-mcp-server-tools nil)
@@ -516,6 +551,14 @@
516551
(when (fboundp (intern-soft func-name))
517552
(fmakunbound (intern func-name))))))
518553

554+
(ert-deftest ai-code-test-readme-documents-eval-elisp-debug-options ()
555+
"README should mention the eval_elisp debugging options."
556+
(with-temp-buffer
557+
(insert-file-contents "README.org")
558+
(dolist (option '("=capture_messages=" "=include_backtrace="))
559+
(goto-char (point-min))
560+
(should (search-forward option nil t)))))
561+
519562
(provide 'test_ai-code-mcp-debug-tools)
520563

521564
;;; test_ai-code-mcp-debug-tools.el ends here

0 commit comments

Comments
 (0)