Skip to content

Add dry_run to tool schemas for editing tools#153

Open
aiba wants to merge 1 commit intobhauman:mainfrom
aiba:add-dry-run-to-tool-schemas
Open

Add dry_run to tool schemas for editing tools#153
aiba wants to merge 1 commit intobhauman:mainfrom
aiba:add-dry-run-to-tool-schemas

Conversation

@aiba
Copy link

@aiba aiba commented Feb 23, 2026

Summary

PR #121 added dry_run support to the editing tool pipelines (file_edit, clojure_edit, clojure_edit_replace_sexp), allowing clients to preview changes as a diff or full source without writing to disk. However, the dry_run parameter was only added to the pipeline and execution code — it was not added to the tool-schema definitions.

This means MCP clients that rely on the advertised tool schema to discover available parameters — such as Claude Code — have no way to know dry_run exists. Claude Code will only send parameters that appear in the tool's JSON schema, so in practice dry_run is unusable from Claude Code despite the backend fully supporting it.

This PR adds dry_run to the :properties map of the tool-schema multimethod for all three affected tools:

  • :file-edit (file_edit/tool.clj)
  • :clojure-edit-form (form_edit/combined_edit_tool.clj)
  • :clojure-update-sexp (form_edit/tool.clj)

The parameter is optional (not in :required) with enum ["diff" "new-source"], matching the existing pipeline behavior.

Test plan

  • Verify dry_run: "diff" returns a diff without writing the file for each of the three tools
  • Verify dry_run: "new-source" returns full modified source without writing
  • Verify omitting dry_run writes the file as before (no regression)
  • Confirm the parameter appears in MCP tool schema responses (e.g. via tools/list)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a dry_run option to file- and form-editing tools and the clojure-edit pipeline.
    • dry_run accepts "diff" (preview changes) and "new-source" (show proposed content) to inspect edits without applying them.
    • Inputs now validate dry_run values; invalid selections produce clear validation errors and prevent execution.

@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

Added an optional dry_run parameter (enum: ["diff", "new-source"]) to three editing tool schemas—:file-edit, :clojure-edit-form, and :clojure-update-sexp—with runtime validation and propagation through input validation paths.

Changes

Cohort / File(s) Summary
File-edit tool
src/clojure_mcp/tools/file_edit/tool.clj
Add optional dry_run string property (enum ["diff","new-source"]) to the :file-edit schema; validate value at runtime in input validation.
Clojure form-edit (combined)
src/clojure_mcp/tools/form_edit/combined_edit_tool.clj
Add public input dry_run (string, enum ["diff","new-source"]) to :clojure-edit-form schema; validate and include dry_run in returned input map forwarded downstream.
Clojure update-sexp tool
src/clojure_mcp/tools/form_edit/tool.clj
Add top-level :dry_run schema property for :clojure-update-sexp (string enum ["diff","new-source"]) and runtime validation rejecting invalid values before returning validated inputs.

Sequence Diagram(s)

(omitted — changes are schema and validation only, not multi-component control flow)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Poem

🐰 I nibble at lines with tidy care,
A dry_run peek before edits dare.
"diff" to spy, "new-source" to view,
I hop away if changes won't do.
🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a dry_run parameter to the tool schemas for three editing tools (file-edit, clojure-edit-form, and clojure-update-sexp).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/clojure_mcp/tools/file_edit/tool.clj (1)

35-46: ⚠️ Potential issue | 🟡 Minor

Validate dry_run values in validate-inputs.

The schema now exposes dry_run, but invalid values can still flow into the pipeline and produce unclear errors. Add an explicit guard when :dry_run is present.

(when (contains? inputs :dry_run)
  (when-not (#{"diff" "new-source"} dry_run)
    (throw (ex-info (str "Invalid dry_run: " dry_run
                         ". Supported values: diff, new-source")
                    {:inputs inputs}))))

As per coding guidelines, "Validate inputs and provide helpful error messages in MCP tool implementations".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clojure_mcp/tools/file_edit/tool.clj` around lines 35 - 46, Add explicit
validation for the :dry_run input in the validate-inputs function so invalid
values are rejected early: in validate-inputs, when (contains? inputs :dry_run)
check that the value (get inputs :dry_run) is one of "diff" or "new-source", and
if not throw an explanatory ex-info containing the bad value and the inputs map
(e.g., "Invalid dry_run: ... Supported values: diff, new-source"). This guard
should reference the inputs map and :dry_run key and ensure only the allowed
enum values flow into the rest of the file-edit pipeline.
src/clojure_mcp/tools/form_edit/tool.clj (1)

48-69: ⚠️ Potential issue | 🟡 Minor

Add explicit dry_run validation.

dry_run is now part of the public schema, but invalid values aren’t rejected in validate-inputs. Please add a guard so callers get a clear error.

(when (contains? inputs :dry_run)
  (when-not (#{"diff" "new-source"} dry_run)
    (throw (ex-info (str "Invalid dry_run: " dry_run
                         ". Supported values: diff, new-source")
                    {:inputs inputs}))))

As per coding guidelines, "Validate inputs and provide helpful error messages in MCP tool implementations".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clojure_mcp/tools/form_edit/tool.clj` around lines 48 - 69, Add explicit
validation for the dry_run input in the tool's input validation path (the
validate-inputs function used by the :clojure-update-sexp tool) so invalid
values are rejected with a clear error; specifically, in the input validation
logic referenced by tool-system/tool-schema :clojure-update-sexp, check (when
(contains? inputs :dry_run)) and throw an ex-info if the value is not one of
"diff" or "new-source" (include the offending value and inputs in the exception
data) to mirror the schema and provide a helpful error message to callers.
src/clojure_mcp/tools/form_edit/combined_edit_tool.clj (1)

101-118: ⚠️ Potential issue | 🟡 Minor

Validate dry_run in validate-inputs.

The new schema parameter isn’t validated, so invalid values can make it to the pipeline. Add an explicit check before building the validated map.

(when (contains? inputs "dry_run")
  (when-not (#{"diff" "new-source"} dry_run)
    (throw (ex-info (str "Invalid dry_run: " dry_run
                         ". Supported values: diff, new-source")
                    {:inputs inputs}))))

As per coding guidelines, "Validate inputs and provide helpful error messages in MCP tool implementations".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clojure_mcp/tools/form_edit/combined_edit_tool.clj` around lines 101 -
118, In validate-inputs, add an explicit validation for the "dry_run" key: if
(contains? inputs "dry_run") check that the value bound to dry_run is one of
"diff" or "new-source" and throw an ex-info with a clear message and the inputs
map when it is not; locate the check in the validate-inputs function before the
validated map is constructed and reference the "dry_run" symbol and inputs map
so invalid values never proceed into the pipeline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/clojure_mcp/tools/file_edit/tool.clj`:
- Around line 35-46: Add explicit validation for the :dry_run input in the
validate-inputs function so invalid values are rejected early: in
validate-inputs, when (contains? inputs :dry_run) check that the value (get
inputs :dry_run) is one of "diff" or "new-source", and if not throw an
explanatory ex-info containing the bad value and the inputs map (e.g., "Invalid
dry_run: ... Supported values: diff, new-source"). This guard should reference
the inputs map and :dry_run key and ensure only the allowed enum values flow
into the rest of the file-edit pipeline.

In `@src/clojure_mcp/tools/form_edit/combined_edit_tool.clj`:
- Around line 101-118: In validate-inputs, add an explicit validation for the
"dry_run" key: if (contains? inputs "dry_run") check that the value bound to
dry_run is one of "diff" or "new-source" and throw an ex-info with a clear
message and the inputs map when it is not; locate the check in the
validate-inputs function before the validated map is constructed and reference
the "dry_run" symbol and inputs map so invalid values never proceed into the
pipeline.

In `@src/clojure_mcp/tools/form_edit/tool.clj`:
- Around line 48-69: Add explicit validation for the dry_run input in the tool's
input validation path (the validate-inputs function used by the
:clojure-update-sexp tool) so invalid values are rejected with a clear error;
specifically, in the input validation logic referenced by
tool-system/tool-schema :clojure-update-sexp, check (when (contains? inputs
:dry_run)) and throw an ex-info if the value is not one of "diff" or
"new-source" (include the offending value and inputs in the exception data) to
mirror the schema and provide a helpful error message to callers.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 203944d and fefdd91.

📒 Files selected for processing (3)
  • src/clojure_mcp/tools/file_edit/tool.clj
  • src/clojure_mcp/tools/form_edit/combined_edit_tool.clj
  • src/clojure_mcp/tools/form_edit/tool.clj

@aiba aiba force-pushed the add-dry-run-to-tool-schemas branch from fefdd91 to 7409ecd Compare February 23, 2026 21:34
@aiba
Copy link
Author

aiba commented Feb 23, 2026

Thanks for the review! Added explicit dry_run validation in validate-inputs for all three tools (file_edit, clojure_edit, clojure_edit_replace_sexp). Invalid values now get a clear error message before reaching the pipeline.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/clojure_mcp/tools/file_edit/tool.clj`:
- Around line 72-76: The dry_run validation incorrectly checks membership using
a set that includes nil, causing nil to be treated as invalid due to Clojure's
truthiness rules; update the guard so you only validate when :dry_run is present
and non-nil (use some? on (:dry_run inputs)) and then check membership against
the allowed values set #{"diff" "new-source"} before throwing the ex-info; refer
to the existing symbols inputs and :dry_run and the throw/ex-info block to
locate and change the conditional.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fefdd91 and 7409ecd.

📒 Files selected for processing (3)
  • src/clojure_mcp/tools/file_edit/tool.clj
  • src/clojure_mcp/tools/form_edit/combined_edit_tool.clj
  • src/clojure_mcp/tools/form_edit/tool.clj
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/clojure_mcp/tools/form_edit/tool.clj

…edit_replace_sexp

The dry_run parameter was already supported in the pipeline and execution
code (PR bhauman#121) but was missing from the tool-schema definitions, so MCP
clients like Claude Code couldn't discover or pass the parameter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aiba aiba force-pushed the add-dry-run-to-tool-schemas branch from 7409ecd to f0b638b Compare February 23, 2026 21:43
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/clojure_mcp/tools/form_edit/tool.clj (1)

71-117: Use kebab-case for local dry-run binding.

Local symbol dry_run violates the kebab-case naming guideline. Consider aliasing to dry-run while keeping the input key :dry_run.

♻️ Minimal refactor
 (defmethod tool-system/validate-inputs :clojure-update-sexp
   [{:keys [nrepl-client-atom multi-op]} inputs]
   (let [file-path (validate-file-path inputs nrepl-client-atom)
-        {:keys [match_form new_form operation replace_all whitespace_sensitive dry_run]} inputs]
+        {:keys [match_form new_form operation replace_all whitespace_sensitive] :as inputs} inputs
+        dry-run (:dry_run inputs)]
     ...
-    (when (and dry_run (not (#{"diff" "new-source"} dry_run)))
-      (throw (ex-info (str "Invalid dry_run: " dry_run
+    (when (and dry-run (not (#{"diff" "new-source"} dry-run)))
+      (throw (ex-info (str "Invalid dry_run: " dry-run
                            ". Supported values: diff, new-source")
                       {:inputs inputs})))
     {:file_path file-path
      :match_form match_form
      :new_form new_form
      :operation operation
      :replace_all (boolean (if (#{"insert_before" "insert_after"} operation)
                              false
                              (or replace_all false)))
      :whitespace_sensitive (boolean (or whitespace_sensitive false))
-     :dry_run dry_run}))
+     :dry_run dry-run}))

As per coding guidelines, use kebab-case for variable and function names in Clojure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/clojure_mcp/tools/form_edit/tool.clj` around lines 71 - 117, The local
binding dry_run in the defmethod for tool-system/validate-inputs
:clojure-update-sexp violates kebab-case; change the destructuring to stop
binding :dry_run directly (keep :dry_run key in inputs) and introduce a
kebab-case local like dry-run (e.g., remove dry_run from :keys and add (let
[dry-run (:dry_run inputs)] ...) or bind it with :or/rename style), then update
all references from dry_run to dry-run inside the method (affecting the dry_run
validation near the end). Ensure only the local symbol name changes; the input
key :dry_run remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/clojure_mcp/tools/form_edit/tool.clj`:
- Around line 71-117: The local binding dry_run in the defmethod for
tool-system/validate-inputs :clojure-update-sexp violates kebab-case; change the
destructuring to stop binding :dry_run directly (keep :dry_run key in inputs)
and introduce a kebab-case local like dry-run (e.g., remove dry_run from :keys
and add (let [dry-run (:dry_run inputs)] ...) or bind it with :or/rename style),
then update all references from dry_run to dry-run inside the method (affecting
the dry_run validation near the end). Ensure only the local symbol name changes;
the input key :dry_run remains unchanged.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7409ecd and f0b638b.

📒 Files selected for processing (3)
  • src/clojure_mcp/tools/file_edit/tool.clj
  • src/clojure_mcp/tools/form_edit/combined_edit_tool.clj
  • src/clojure_mcp/tools/form_edit/tool.clj
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/clojure_mcp/tools/file_edit/tool.clj
  • src/clojure_mcp/tools/form_edit/combined_edit_tool.clj

@aiba
Copy link
Author

aiba commented Feb 23, 2026

Generally, yes kebab case, but in this case, it seems like there is already an established pattern of using underscore, for example file_path, new_string, old_string. I'm guessing the underscore is more conventional for the agent interface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant