Skip to content

Commit 21ff05a

Browse files
tninjaKang Tu
andauthored
Chore: Remove eval_elisp mode and symbol restrictions (#322)
* Remove eval_elisp mode and symbol restrictions * addressing comments * update HISTORY, bump version --------- Co-authored-by: Kang Tu <kang_tu@apple.com>
1 parent c660173 commit 21ff05a

5 files changed

Lines changed: 140 additions & 176 deletions

File tree

HISTORY.org

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22
* Release history
33

44
** Main branch change
5+
6+
** 1.77
7+
- Chore: Remove eval_elisp mode and symbol restrictions
8+
- Chore: Treat documentation changes as non-code changes
59
- Breaking: Remove =ai-code-mcp-editor-tools.el= and merge its remaining MCP tools into the core server and debug modules
610
- =editor_state= and =visible_buffers= are now built-in MCP tools in =ai-code-mcp-server.el=
711
- =eval_elisp= now lives in =ai-code-mcp-debug-tools.el= and is gated by =ai-code-mcp-debug-tools-enable-eval-elisp=
812
- Remove the legacy =messages_tail= tool in favor of =get_recent_messages=
913
- Remove the old =ai-code-mcp-editor-tools-enabled= and =ai-code-mcp-editor-tools-allow-effect-eval= settings
1014
- Move the dedicated editor-tools tests into the server/debug MCP test files
1115
- Update MCP docs and release notes to match the new tool layout
16+
- Feat: Add Kilo backend support (Opencode fork)
17+
- Feat: Support Org TODO headlines in implement-todo
1218

1319
** 1.74
1420
- Fix: Guard eat/ghostel process filters against deleted buffers on exit and add regression tests

README.org

Lines changed: 2 additions & 6 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
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,11 +235,7 @@ To register =eval_elisp=:
235235
(setq ai-code-mcp-debug-tools-enable-eval-elisp t)
236236
#+end_src
237237

238-
=eval_elisp= only allows =query= mode by default. To allow editor-local side effects too:
239-
240-
#+begin_src emacs-lisp
241-
(setq ai-code-mcp-debug-tools-allow-effect-eval t)
242-
#+end_src
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.
243239

244240
screenshot inside Codex cli:
245241

ai-code-mcp-debug-tools.el

Lines changed: 36 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
;;; Code:
1010

11-
(require 'cl-lib)
1211
(require 'json)
1312
(require 'ai-code-mcp-common)
1413
(require 'nadvice)
@@ -31,11 +30,6 @@
3130
:type 'boolean
3231
:group 'ai-code-mcp-debug-tools)
3332

34-
(defcustom ai-code-mcp-debug-tools-allow-effect-eval nil
35-
"When non-nil, allow `eval_elisp' to run in effect mode."
36-
:type 'boolean
37-
:group 'ai-code-mcp-debug-tools)
38-
3933
(defvar ai-code-mcp--last-error-record nil
4034
"Most recent Emacs error snapshot recorded for MCP diagnostics tools.")
4135

@@ -87,14 +81,10 @@
8781
(defconst ai-code-mcp-debug-tools--eval-spec
8882
'(:function ai-code-mcp-eval-elisp
8983
:name "eval_elisp"
90-
:description "Evaluate a single Emacs Lisp form."
84+
:description "Evaluate arbitrary Emacs Lisp with possible side effects once explicitly enabled."
9185
:args ((:name "code"
9286
:type string
9387
:description "Single Emacs Lisp form to evaluate.")
94-
(:name "mode"
95-
:type string
96-
:description "Evaluation mode."
97-
:optional t)
9888
(:name "buffer_name"
9989
:type string
10090
:description "Optional buffer context."
@@ -117,21 +107,6 @@
117107
:optional t)))
118108
"Optional MCP eval tool specification.")
119109

120-
(defconst ai-code-mcp-debug-tools--always-denied-symbols
121-
'(append-to-file async-shell-command call-interactively call-process
122-
command-execute compile copy-file delete-file delete-frame
123-
delete-window eval funcall kill-buffer load load-file
124-
make-directory make-network-process make-process rename-file
125-
recompile require save-buffer save-buffers-kill-emacs shell-command
126-
start-process url-retrieve write-file write-region)
127-
"Symbols that `eval_elisp' rejects in every mode.")
128-
129-
(defconst ai-code-mcp-debug-tools--query-denied-symbols
130-
'(add-hook delete-region erase-buffer indent-region insert kill-region
131-
newline put remove-hook replace-buffer-contents set setf setq
132-
setq-local switch-to-buffer yank)
133-
"Additional symbols that `eval_elisp' rejects in query mode.")
134-
135110
(defun ai-code-mcp-debug-tools-setup ()
136111
"Register optional MCP debugging tools when enabled."
137112
(when ai-code-mcp-debug-tools-enabled
@@ -215,39 +190,16 @@
215190
changed))))))
216191

217192
(defun ai-code-mcp-debug-tools--context-summary (buffer)
218-
"Return a summary of BUFFER after an evaluation."
219-
(let ((position (ai-code-mcp-debug-tools--point-line-column
220-
buffer
221-
(with-current-buffer buffer (point)))))
222-
`((buffer_name . ,(buffer-name buffer))
223-
(file_path . ,(buffer-file-name buffer))
224-
(line . ,(alist-get 'line position))
225-
(column . ,(alist-get 'column position)))))
226-
227-
(defun ai-code-mcp-debug-tools--symbol-denied-p (form denied-symbols)
228-
"Return the first symbol in FORM that appears in DENIED-SYMBOLS."
229-
(cond
230-
((symbolp form)
231-
(and (memq form denied-symbols) form))
232-
((consp form)
233-
(let ((head (car form)))
234-
(cond
235-
((and (symbolp head)
236-
(memq head denied-symbols))
237-
head)
238-
(t
239-
(or (ai-code-mcp-debug-tools--symbol-denied-p head denied-symbols)
240-
(cl-some
241-
(lambda (item)
242-
(ai-code-mcp-debug-tools--symbol-denied-p
243-
item denied-symbols))
244-
(cdr form)))))))
245-
((vectorp form)
246-
(cl-some
247-
(lambda (item)
248-
(ai-code-mcp-debug-tools--symbol-denied-p item denied-symbols))
249-
(append form nil)))
250-
(t nil)))
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))))))
251203

252204
(defun ai-code-mcp-debug-tools--parse-single-form (code)
253205
"Parse CODE and return exactly one top-level Emacs Lisp form."
@@ -278,16 +230,15 @@
278230
(buffer-string)))
279231

280232
(defun ai-code-mcp-debug-tools--encode-eval-result
281-
(mode target-buffer before-messages capture-messages timed-out
233+
(target-buffer before-messages capture-messages timed-out
282234
value changed-buffers &optional error-object backtrace)
283-
"Return a JSON response for MODE in TARGET-BUFFER.
235+
"Return a JSON eval response for TARGET-BUFFER.
284236
BEFORE-MESSAGES and CAPTURE-MESSAGES control message collection.
285237
TIMED-OUT records timeout state, VALUE carries the result,
286238
CHANGED-BUFFERS lists modified buffers, and ERROR-OBJECT or BACKTRACE
287239
describe failures."
288240
(json-encode
289241
`((ok . ,(ai-code-mcp--json-bool (null error-object)))
290-
(mode . ,mode)
291242
(value_repr . ,(and (null error-object) (prin1-to-string value)))
292243
(value_type . ,(and (null error-object)
293244
(symbol-name (type-of value))))
@@ -302,10 +253,10 @@ describe failures."
302253
target-buffer))
303254
(timed_out . ,(ai-code-mcp--json-bool timed-out)))))
304255

305-
(defun ai-code-mcp-debug-tools--run-eval (form mode target-buffer timeout-ms
256+
(defun ai-code-mcp-debug-tools--run-eval (form target-buffer timeout-ms
306257
capture-messages
307258
include-backtrace)
308-
"Evaluate FORM in MODE within TARGET-BUFFER using TIMEOUT-MS.
259+
"Evaluate FORM within TARGET-BUFFER using TIMEOUT-MS.
309260
CAPTURE-MESSAGES controls message collection, and INCLUDE-BACKTRACE
310261
keeps the backtrace on failures."
311262
(let ((before-messages (ai-code-mcp--message-lines))
@@ -320,16 +271,9 @@ keeps the backtrace on failures."
320271
(setq timed-out t)
321272
(throw 'ai-code-mcp-debug-tools-timeout nil))
322273
(setq value
323-
(if (string= mode "query")
324-
(save-current-buffer
325-
(with-current-buffer target-buffer
326-
(save-excursion
327-
(save-match-data
328-
(save-restriction
329-
(eval form t))))))
330-
(save-current-buffer
331-
(with-current-buffer target-buffer
332-
(eval form t)))))))
274+
(save-current-buffer
275+
(with-current-buffer target-buffer
276+
(eval form t))))))
333277
(error
334278
(setq error-object
335279
(ai-code-mcp-debug-tools--error-alist
@@ -343,7 +287,6 @@ keeps the backtrace on failures."
343287
"timeout"
344288
"Evaluation exceeded the configured timeout")))
345289
(ai-code-mcp-debug-tools--encode-eval-result
346-
mode
347290
target-buffer
348291
before-messages
349292
capture-messages
@@ -606,14 +549,14 @@ existing bound variable."
606549
(limit . ,limit)
607550
(messages . ,(vconcat messages))))))
608551

609-
(defun ai-code-mcp-eval-elisp (code &optional mode buffer-name file-path
552+
(defun ai-code-mcp-eval-elisp (code &optional buffer-name file-path
610553
capture-messages include-backtrace
611554
timeout-ms)
612-
"Evaluate CODE as a single form using MODE and BUFFER-NAME.
613-
Return a JSON payload for BUFFER-NAME, FILE-PATH,
614-
CAPTURE-MESSAGES, INCLUDE-BACKTRACE, and TIMEOUT-MS."
615-
(let* ((mode (or mode "query"))
616-
(capture-messages (ai-code-mcp-debug-tools--bool-arg
555+
"Evaluate CODE as a single Emacs Lisp form.
556+
Return a JSON payload. BUFFER-NAME or FILE-PATH select the evaluation
557+
context. CAPTURE-MESSAGES, INCLUDE-BACKTRACE, and TIMEOUT-MS control
558+
diagnostics."
559+
(let* ((capture-messages (ai-code-mcp-debug-tools--bool-arg
617560
capture-messages
618561
t))
619562
(include-backtrace (ai-code-mcp-debug-tools--bool-arg
@@ -624,93 +567,32 @@ CAPTURE-MESSAGES, INCLUDE-BACKTRACE, and TIMEOUT-MS."
624567
buffer-name
625568
file-path))
626569
(parse-error nil)
627-
form
628-
always-denied
629-
query-denied)
630-
(unless (member mode '("query" "effect"))
631-
(error "Argument mode must be either query or effect"))
570+
form)
632571
(unless (and (integerp timeout-ms) (> timeout-ms 0))
633572
(error "Argument timeout_ms must be a positive integer"))
634573
(condition-case err
635574
(setq form (ai-code-mcp-debug-tools--parse-single-form code))
636575
(error
637576
(setq parse-error err)))
638-
(cond
639-
(parse-error
640-
(ai-code-mcp-debug-tools--encode-eval-result
641-
mode
642-
target-buffer
643-
(ai-code-mcp--message-lines)
644-
capture-messages
645-
nil
646-
nil
647-
'()
648-
(ai-code-mcp-debug-tools--error-alist
649-
(symbol-name (car parse-error))
650-
(error-message-string parse-error))
651-
(and include-backtrace
652-
(ai-code-mcp-debug-tools--backtrace-string))))
653-
(t
654-
(setq always-denied
655-
(ai-code-mcp-debug-tools--symbol-denied-p
656-
form
657-
ai-code-mcp-debug-tools--always-denied-symbols))
658-
(setq query-denied
659-
(and (string= mode "query")
660-
(ai-code-mcp-debug-tools--symbol-denied-p
661-
form
662-
ai-code-mcp-debug-tools--query-denied-symbols)))
663-
(cond
664-
(always-denied
577+
(if parse-error
665578
(ai-code-mcp-debug-tools--encode-eval-result
666-
mode
667579
target-buffer
668580
(ai-code-mcp--message-lines)
669581
capture-messages
670582
nil
671583
nil
672584
'()
673585
(ai-code-mcp-debug-tools--error-alist
674-
"symbol_denied"
675-
(format "Symbol `%s' is not allowed in eval_elisp"
676-
always-denied))
677-
nil))
678-
(query-denied
679-
(ai-code-mcp-debug-tools--encode-eval-result
680-
mode
681-
target-buffer
682-
(ai-code-mcp--message-lines)
683-
capture-messages
684-
nil
685-
nil
686-
'()
687-
(ai-code-mcp-debug-tools--error-alist
688-
"query_symbol_denied"
689-
(format "Symbol `%s' is not allowed in query mode"
690-
query-denied))
691-
nil))
692-
((and (string= mode "effect")
693-
(not ai-code-mcp-debug-tools-allow-effect-eval))
694-
(ai-code-mcp-debug-tools--encode-eval-result
695-
mode
696-
target-buffer
697-
(ai-code-mcp--message-lines)
698-
capture-messages
699-
nil
700-
nil
701-
'()
702-
(ai-code-mcp-debug-tools--error-alist
703-
"effect_mode_disabled"
704-
"Effect mode is disabled by configuration")
705-
nil))
706-
(t
707-
(ai-code-mcp-debug-tools--run-eval
708-
form
709-
mode
710-
target-buffer
711-
timeout-ms
712-
capture-messages
713-
include-backtrace)))))))
586+
(symbol-name (car parse-error))
587+
(error-message-string parse-error))
588+
(and include-backtrace
589+
(ai-code-mcp-debug-tools--backtrace-string)))
590+
(ai-code-mcp-debug-tools--run-eval
591+
form
592+
target-buffer
593+
timeout-ms
594+
capture-messages
595+
include-backtrace))))
714596

715597
(add-to-list 'ai-code-mcp-server-tool-setup-functions
716598
#'ai-code-mcp-debug-tools-setup)

ai-code.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
;;; ai-code.el --- Unified interface for AI coding backends such as Codex CLI, Copilot CLI, Claude Code, Gemini CLI, Opencode, Kilo, Grok CLI, etc -*- lexical-binding: t; -*-
22

33
;; Author: Kang Tu <tninja@gmail.com>
4-
;; Version: 1.74
4+
;; Version: 1.77
55
;; Package-Requires: ((emacs "29.1") (transient "0.9.0") (magit "2.1.0"))
66
;; URL: https://github.com/tninja/ai-code-interface.el
77

0 commit comments

Comments
 (0)