Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5aa52baeb4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| (group (ai-code-mcp--display-path | ||
| (xref-location-group location))) |
There was a problem hiding this comment.
Preserve full paths for external xref hits
Wrapping xref-location-group with ai-code-mcp--display-path truncates any location outside the active project to file-name-nondirectory, so references/definitions from different external files with the same basename become indistinguishable (for example, two different index.js files). Before this change, the formatter kept the full group path, so this is a regression in result accuracy whenever the backend returns matches outside the project root.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Adds additional MCP tools to ai-code-mcp-server.el to expose more Emacs editor/project navigation capabilities (ported from claude-code-ide-extras), plus accompanying ERT coverage.
Changes:
- Add MCP tools for buffer line-range querying, project file listing, and project buffer listing.
- Add MCP tool to find xref definitions at a specific file location (line/column).
- Extend ERT tests to cover the new tools and ensure they appear in the tools list.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
ai-code-mcp-server.el |
Registers new MCP tools and implements buffer/project/xref helpers, plus tweaks xref formatting and result formatting. |
test/test_ai-code-mcp-server.el |
Updates tool-list expectations and adds tests for the new MCP tools. |
| @@ -14,6 +14,7 @@ | |||
| (require 'cl-lib) | |||
| (require 'imenu) | |||
| (require 'project) | |||
There was a problem hiding this comment.
ai-code-mcp-server.el uses several seq-* functions (e.g., seq-remove, seq-filter) but does not (require 'seq). Many other modules in this repo explicitly require seq when using these functions; adding the require here avoids load-order dependent runtime failures and byte-compile warnings when this file is loaded standalone.
| (require 'project) | |
| (require 'project) | |
| (require 'seq) |
| (string-trim-right | ||
| (buffer-substring-no-properties start-pos (point)))))))))) |
There was a problem hiding this comment.
ai-code-mcp-buffer-query uses string-trim-right on the extracted substring. This will strip all trailing whitespace from the last returned line (not just the final newline), which can corrupt code/text where trailing spaces are significant. Prefer only removing a single trailing newline (or return the exact substring unchanged) to preserve buffer contents faithfully.
| (string-trim-right | |
| (buffer-substring-no-properties start-pos (point)))))))))) | |
| (let ((text (buffer-substring-no-properties start-pos (point)))) | |
| (if (string-suffix-p "\n" text) | |
| (substring text 0 -1) | |
| text))))))))) |
| (when (or (and start-line (not num-lines)) | ||
| (and num-lines (not start-line))) | ||
| (error "Arguments start_line and num_lines must both be provided or both be omitted")) | ||
| (with-current-buffer buffer | ||
| (save-excursion | ||
| (if (not start-line) | ||
| (buffer-substring-no-properties (point-min) (point-max)) | ||
| (goto-char (point-min)) | ||
| (forward-line (1- start-line)) | ||
| (let ((start-pos (point))) | ||
| (forward-line num-lines) |
There was a problem hiding this comment.
ai-code-mcp-buffer-query claims start_line is 1-based, but it doesn’t validate start_line >= 1 and num_lines >= 1. Passing 0/negative values will produce surprising results (or errors) due to (forward-line (1- start-line)) / (forward-line num-lines). Add explicit validation with a clear error message (or normalize inputs) before moving point.
| (defun ai-code-mcp-get-project-files () | ||
| "Return regular files in the current project as relative paths." | ||
| (let ((project-dir (ai-code-mcp--project-directory))) | ||
| (if (not (and project-dir (file-directory-p project-dir))) | ||
| nil | ||
| (mapcar #'ai-code-mcp--display-path | ||
| (seq-filter | ||
| #'file-regular-p | ||
| (directory-files-recursively project-dir ".*" t)))))) |
There was a problem hiding this comment.
ai-code-mcp-get-project-files walks the entire project directory via directory-files-recursively ".*", which will include files like .git/* and can be very slow on large repos. Prefer project-current + project-files (with a recursive fallback like ai-code-session-link--project-files uses) so the result respects project backends/ignores and avoids scanning VCS internals.
| (defun ai-code-mcp-get-project-files () | |
| "Return regular files in the current project as relative paths." | |
| (let ((project-dir (ai-code-mcp--project-directory))) | |
| (if (not (and project-dir (file-directory-p project-dir))) | |
| nil | |
| (mapcar #'ai-code-mcp--display-path | |
| (seq-filter | |
| #'file-regular-p | |
| (directory-files-recursively project-dir ".*" t)))))) | |
| (defun ai-code-mcp--project-files (project-dir) | |
| "Return regular files for PROJECT-DIR using project APIs when available. | |
| Fall back to a recursive directory walk that skips VCS internals." | |
| (let* ((default-directory (file-name-as-directory project-dir)) | |
| (project (project-current nil)) | |
| (project-root default-directory)) | |
| (cond | |
| ((and project (fboundp 'project-files)) | |
| (seq-filter | |
| #'file-regular-p | |
| (mapcar (lambda (file) | |
| (if (file-name-absolute-p file) | |
| file | |
| (expand-file-name file project-root))) | |
| (project-files project)))) | |
| (t | |
| (cl-labels | |
| ((collect-files (dir) | |
| (apply | |
| #'append | |
| (mapcar | |
| (lambda (entry) | |
| (cond | |
| ((member entry '("." "..")) nil) | |
| ((string-prefix-p "." entry) nil) | |
| (t | |
| (let ((path (expand-file-name entry dir))) | |
| (cond | |
| ((file-directory-p path) | |
| (collect-files path)) | |
| ((file-regular-p path) | |
| (list path)) | |
| (t nil)))))) | |
| (directory-files dir nil nil t)))) | |
| (collect-files project-root)))))) | |
| (defun ai-code-mcp-get-project-files () | |
| "Return regular files in the current project as relative paths." | |
| (let ((project-dir (ai-code-mcp--project-directory))) | |
| (if (not (and project-dir (file-directory-p project-dir))) | |
| nil | |
| (mapcar #'ai-code-mcp--display-path | |
| (ai-code-mcp--project-files project-dir))))) |
| (defun ai-code-mcp--format-xref-item (item) | ||
| "Return a human-readable line for xref ITEM." | ||
| (let* ((location (xref-item-location item)) | ||
| (group (xref-location-group location)) | ||
| (group (ai-code-mcp--display-path | ||
| (xref-location-group location))) | ||
| (marker (xref-location-marker location)) |
There was a problem hiding this comment.
ai-code-mcp--format-xref-item now runs xref-location-group through ai-code-mcp--display-path, but ai-code-mcp--display-path uses a simple string-prefix-p check against project-dir. That can misclassify paths like /tmp/proj2/... as being under /tmp/proj and produce misleading relative paths with ... Consider switching the containment check to file-in-directory-p (or ensure project-dir is normalized with a trailing slash) before calling file-relative-name.
| (ert-deftest ai-code-test-mcp-xref-find-definitions-at-point-uses-location-context () | ||
| "Definitions-at-point should resolve via the xref backend at a file location." | ||
| (let* ((project-dir (make-temp-file "ai-code-mcp-xref-defs-" t)) | ||
| (file-path (expand-file-name "defs.el" project-dir)) | ||
| (buffer (generate-new-buffer " *ai-code-mcp-xref-defs*"))) | ||
| (unwind-protect | ||
| (progn | ||
| (with-temp-file file-path | ||
| (insert "(defun alpha ()\n") | ||
| (insert " (beta))\n\n") | ||
| (insert "(defun beta ()\n") | ||
| (insert " t)\n")) | ||
| (cl-letf (((symbol-function 'xref-find-backend) | ||
| (lambda () 'mock-backend)) | ||
| ((symbol-function 'xref-backend-identifier-at-point) | ||
| (lambda (_backend) "beta")) | ||
| ((symbol-function 'xref-backend-definitions) | ||
| (lambda (_backend identifier) | ||
| (list (xref-make | ||
| (format "%s definition" identifier) | ||
| (xref-make-file-location file-path 4 0)))))) | ||
| (should (equal '("defs.el:4: beta definition") | ||
| (ai-code-mcp-xref-find-definitions-at-point | ||
| file-path | ||
| 2 | ||
| 3))))) | ||
| (when (buffer-live-p buffer) | ||
| (kill-buffer buffer)) | ||
| (delete-directory project-dir t)))) |
There was a problem hiding this comment.
In ai-code-test-mcp-xref-find-definitions-at-point-uses-location-context, the local buffer created with generate-new-buffer is never used, while the file-visiting buffer created by ai-code-mcp-xref-find-definitions-at-point (via find-file-noselect) is not cleaned up. This can leak buffers across the test suite; remove the unused buffer and explicitly kill the file-visiting buffer (or bind/kill it via ai-code-mcp--file-buffer).
|
feedbacks are addressed. |
Referencing https://github.com/acmorrow/claude-code-ide-extras, port 4 mcps from there.