Skip to content

Conversation

@bhauman
Copy link
Owner

@bhauman bhauman commented Nov 20, 2025

Summary

  • Migrated from clojure.tools.logging to taoensso.timbre for pure Clojure logging
  • Created centralized logging configuration with namespace filtering
  • Updated all entry points to configure logging with customizable options
  • Suppressed logging during tests for clean test output
  • Changed default logging behavior to disabled by default

Changes

  • New: src/clojure_mcp/logging.clj - Centralized Timbre configuration with convenience functions
  • New: test/clojure_mcp/test_helper.clj - Test logging suppression
  • Updated: All 26 source files changed from clojure.tools.logging to taoensso.timbre
  • Updated: All entry points (main.clj, sse_main.clj, figwheel_main.clj, shadow_main.clj) to configure logging
  • Updated: deps.edn - Added timbre, moved slf4j-nop to main deps, removed logback
  • Deleted: dev/logback.xml - No longer needed with Timbre

Configuration

Logging is now configured via options at entry points:

  • :log-file - Path to log file (default: .clojure-mcp/clojure-mcp.log)
  • :enable-logging? - Whether to enable logging (default: false)
  • :log-level - Minimum log level (default: :debug)

Test Results

All tests pass with zero logging noise: 293 tests, 2062 assertions, 0 failures

Summary by CodeRabbit

  • Chores
    • Migrated logging system to a new library with improved environment-specific configuration (development, production, testing)
    • Updated test infrastructure with simplified runner and automatic logging suppression for test execution
    • Removed legacy logging configuration files and streamlined dependency management for logging and web server components

✏️ Tip: You can customize this high-level summary in your review settings.

Bruce Hauman added 2 commits November 19, 2025 12:36
Replace clojure.tools.logging with taoensso.timbre for pure Clojure logging.

Changes:
- Create src/clojure_mcp/logging.clj with centralized Timbre configuration
- Add logging initialization to all main entry points (main.clj, sse_main.clj,
  figwheel_main.clj, shadow_main.clj)
- Update all 26 source files to use [taoensso.timbre :as log]
- Add test/clojure_mcp/test_helper.clj to suppress logging during tests
- Update :test alias in deps.edn to use -M flag with test helper
- Add helpful error message when using -X:test instead of -M:test
- Remove clojure.tools.logging and logback dependencies
- Add slf4j-nop to main deps to suppress Java library logging
- Delete dev/logback.xml (no longer needed)

Benefits:
- Pure Clojure logging solution (no Java dependencies)
- Simplified configuration
- Better REPL integration
- Clean test output with zero logging noise
- Consistent logging across all entry points
@coderabbitai
Copy link

coderabbitai bot commented Nov 20, 2025

Walkthrough

This pull request migrates the codebase from clojure.tools.logging to taoensso.timbre as the logging backend. It replaces logging imports across 30+ source files, introduces centralized logging configuration in a new logging.clj module, updates dependencies, and removes the old Logback configuration file.

Changes

Cohort / File(s) Summary
Dependency & Build Configuration
deps.edn
Removed org.clojure/tools.logging dependency; added taoensso/timbre and org.slf4j/slf4j-nop. Updated :test profile to use clojure-mcp.test-helper and added nrepl/nrepl. Replaced per-alias slf4j-nop deps with explicit web server component dependencies (jakarta.servlet-api, jetty-server, jetty-servlet) where needed.
Logging Infrastructure Removal
dev/logback.xml
Deleted entire file; removed legacy Logback configuration including RollingFileAppenders, root logger, and library-specific logger definitions.
New Centralized Logging Module
src/clojure_mcp/logging.clj
Added new namespace with configure-logging! function supporting :log-file, :enable-logging?, and :log-level options. Added convenience functions: configure-dev-logging!, configure-prod-logging!, configure-test-logging!, and suppress-logging-for-tests! for environment-based configuration.
Server Entry Points with Logging Setup
src/clojure_mcp/main.clj, src/clojure_mcp/main_examples/figwheel_main.clj, src/clojure_mcp/main_examples/shadow_main.clj, src/clojure_mcp/sse_main.clj
Updated to import clojure-mcp.logging and call logging/configure-logging! with extracted options before delegating to core builders. Logging-related keys (:log-file, :log-level, :enable-logging?) are dissoc'd before passing remaining opts to downstream handlers.
Test Helper
test/clojure_mcp/test_helper.clj
Added new namespace that suppresses logging during test runs and provides run-tests-with-exec to guide users toward correct -M:test invocation.
Logging Library Migration (Core Modules)
src/clojure_mcp/(agent/general_agent.clj, agent/langchain.clj, agent/langchain/chat_listener.clj, agent/langchain/model.clj, config.clj, core.clj, dialects.clj, nrepl.clj, nrepl_launcher.clj, sse_core.clj, tool_system.clj)
Replaced [clojure.tools.logging :as log] with [taoensso.timbre :as log] in namespace requires. No functional or control-flow changes.
Logging Library Migration (Tool Modules)
src/clojure_mcp/tools/(agent_tool_builder/core.clj, agent_tool_builder/file_changes.clj, agent_tool_builder/tool.clj, bash/core.clj, bash/tool.clj, eval/core.clj, figwheel/tool.clj, glob_files/core.clj, grep/core.clj, project/core.clj, scratch_pad/tool.clj, unified_clojure_edit/tool.clj, unified_read_file/file_timestamps.clj, unified_read_file/tool.clj)
Replaced [clojure.tools.logging :as log] with [taoensso.timbre :as log] in namespace requires across all tool modules. No functional or control-flow changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Repetitive changes across 30+ files: The majority of the diff consists of identical logging library import swaps, which are low-risk and easily verifiable in bulk.
  • New logging infrastructure: src/clojure_mcp/logging.clj introduces configuration logic with environment detection and conditional behavior that warrants careful review.
  • Entry point modifications: main.clj, example servers, and sse_main.clj add logging setup calls; verify that dissoc properly isolates logging options and that defaults are sensible.
  • Test setup: Confirm that test_helper.clj correctly suppresses logging during test runs and that the new test runner integration in deps.edn triggers it.

Poem

🐰 From tools.logging we hop away,
To Timbre's logs we now convey,
Config centralized, clean and bright,
Tests run silent through the night! 🌙
One library to log them all. ✨

Pre-merge checks and finishing touches

✅ 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 and concisely describes the main change: migrating the logging library from clojure.tools.logging to Timbre, which is the primary focus across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch migrate-to-timbre

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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.

@bhauman bhauman merged commit 5dae6ed into main Nov 20, 2025
1 of 2 checks passed
@bhauman bhauman deleted the migrate-to-timbre branch November 20, 2025 02:44
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

🧹 Nitpick comments (9)
src/clojure_mcp/main_examples/figwheel_main.clj (1)

40-46: LGTM: Proper logging configuration and option sanitization.

The logging setup correctly:

  • Configures logging before server startup
  • Provides sensible defaults (logging disabled by default, debug level)
  • Sanitizes options by removing logging-related keys before passing to core

Note: This pattern is duplicated in shadow_main.clj. Consider extracting a shared helper function if more entry points are added.

src/clojure_mcp/main_examples/shadow_main.clj (1)

86-92: LGTM: Consistent logging configuration pattern.

The logging setup follows the same pattern as figwheel_main.clj, properly configuring logging before server startup and sanitizing options.

Note: This configuration block is identical to the one in figwheel_main.clj (lines 40-46). Consider extracting a shared helper function if additional entry points are added.

test/clojure_mcp/test_helper.clj (1)

9-17: Consider sending the -X:test error message to STDERR and avoiding emoji

The guidance for incorrect -X:test usage is helpful, but you might want to:

  • Print to *err* instead of STDOUT.
  • Use plain text instead of an emoji for maximum portability in CI logs.

For example:

-(defn run-tests-with-exec
-  "Called when using -X:test (incorrect usage).
-   Prints helpful message directing user to use -M:test instead."
-  [& _args]
-  (println "\n⚠️  Error: The :test alias requires the -M flag, not -X")
-  (println "\nPlease run tests using:")
-  (println "  clojure -M:test")
-  (println "\nThe -M flag is required to suppress logging during test runs.")
-  (System/exit 1))
+(defn run-tests-with-exec
+  "Called when using -X:test (incorrect usage).
+   Prints helpful message directing user to use -M:test instead."
+  [& _args]
+  (binding [*out* *err*]
+    (println "\nWARNING: The :test alias requires the -M flag, not -X")
+    (println "\nPlease run tests using:")
+    (println "  clojure -M:test")
+    (println "\nThe -M flag is required to suppress logging during test runs."))
+  (System/exit 1))
src/clojure_mcp/sse_main.clj (1)

8-22: SSE entrypoint logging setup and opts sanitization look correct

Configuring logging up front with logging/configure-logging! and then passing (dissoc opts :log-file :log-level :enable-logging?) into build-and-start-mcp-server cleanly separates logging concerns from server options and matches the pattern in clojure-mcp.main/start-mcp-server.

If this pattern is repeated in several entrypoints (main, SSE, figwheel, shadow), consider a small helper like logging/configure-from-opts! to avoid drift across call sites over time.

src/clojure_mcp/main.clj (1)

3-6: Main entrypoint now cleanly configures logging before server startup

Using logging/configure-logging! with sane defaults and then stripping :log-file, :log-level, and :enable-logging? from opts before passing to core/build-and-start-mcp-server is a good separation of concerns and keeps the core API free of logging-specific keys.

Given this same pattern appears in clojure-mcp.sse-main (and likely the example mains), a small helper (e.g. logging/configure-from-opts!) could reduce duplication and make future logging option changes one-place.

Also applies to: 36-46

deps.edn (2)

38-67: MCP entrypoint aliases now consistently use exec-fn-based startup

The :mcp, :mcp-sse, :mcp-figwheel, and :mcp-shadow* aliases all delegate via :exec-fn to the appropriate start-*-mcp-server functions with minimal :exec-args, which pairs well with the new logging configuration logic in those entrypoints.

You might consider expanding the comments here to briefly mention the new logging-related opts (:log-file, :enable-logging?, :log-level) so users discover them from deps.edn alone.


108-116: :test alias wiring matches the new test helper behavior

The :test alias setup works nicely with clojure-mcp.test-helper:

  • -X:test invokes run-tests-with-exec via :exec-fn, which prints guidance and exits with a non-zero status.
  • -M:test follows :main-opts, first requiring clojure-mcp.test-helper (to suppress logging) and then running cognitect.test-runner.

The added :extra-deps ensure the runner and test tooling are on the classpath.

If you want to avoid duplicated nrepl/nrepl declarations, you could rely on the top-level :deps entry and drop it from :test’s :extra-deps, unless you specifically want to pin a different version for tests.

src/clojure_mcp/logging.clj (2)

33-42: Make Timbre config derive from default-config and simplify :ns-filter

configure-logging! currently calls timbre/set-config! with a minimal map that only defines :appenders. This replaces Timbre’s entire *config* and drops other defaults like :min-level, :ns-filter, :timestamp-opts, and :output-fn. It works as long as Timbre tolerates these as nil, but it’s brittle and bypasses future defaults and environment-based config merging. (taoensso.github.io)

Given this is the central logging entry point, it’d be more robust to start from timbre/default-config (or the existing *config*) and override only what you care about. That also lets you put :min-level and :ns-filter at the top level instead of per-appender.

For example:

-  (timbre/set-config!
-   {:appenders (if enable-logging?
-                 {:spit (assoc
-                         (timbre/spit-appender {:fname log-file})
-                         :enabled? enable-logging?
-                         :min-level (or log-level :report)
-                         :ns-filter (if enable-logging?
-                                      {:allow #{"clojure-mcp.*"}}
-                                      {:deny #{"*"}}))}
-                 {})}))
+  (timbre/set-config!
+   (assoc timbre/default-config
+          :min-level (or log-level :debug)
+          :ns-filter (if enable-logging?
+                       {:allow #{"clojure-mcp.*"}}
+                       {:deny  #{"*"}})
+          :appenders (if enable-logging?
+                       {:spit (assoc (timbre/spit-appender {:fname log-file})
+                                     :enabled? true)}
+                       {})))

This keeps Timbre’s standard behavior (output-fn, timestamp options, etc.) while still enforcing your namespace filter and appender choice. It also removes the redundant inner if enable-logging? on :ns-filter.


9-9: Clarify and/or harden default log file path handling

default-log-file points to ".clojure-mcp/clojure-mcp.log", while configure-dev-logging! writes to "logs/clojure-mcp.log". Neither path ensures that the parent directory exists before spit-appender tries to write, which can throw if the directory is missing.

Two possible follow-ups:

  • Explicitly document that callers must ensure the containing directory exists, or
  • Proactively create the parent directory when enable-logging? is true.

For example, you could (optionally) add a small helper invoked before timbre/spit-appender that (.mkdirs (io/file parent-dir)).

Also applies to: 48-50

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 818d0c9 and 969d273.

📒 Files selected for processing (33)
  • deps.edn (2 hunks)
  • dev/logback.xml (0 hunks)
  • src/clojure_mcp/agent/general_agent.clj (1 hunks)
  • src/clojure_mcp/agent/langchain.clj (1 hunks)
  • src/clojure_mcp/agent/langchain/chat_listener.clj (1 hunks)
  • src/clojure_mcp/agent/langchain/model.clj (1 hunks)
  • src/clojure_mcp/config.clj (1 hunks)
  • src/clojure_mcp/core.clj (1 hunks)
  • src/clojure_mcp/dialects.clj (1 hunks)
  • src/clojure_mcp/logging.clj (1 hunks)
  • src/clojure_mcp/main.clj (2 hunks)
  • src/clojure_mcp/main_examples/figwheel_main.clj (2 hunks)
  • src/clojure_mcp/main_examples/shadow_main.clj (2 hunks)
  • src/clojure_mcp/nrepl.clj (1 hunks)
  • src/clojure_mcp/nrepl_launcher.clj (1 hunks)
  • src/clojure_mcp/sse_core.clj (1 hunks)
  • src/clojure_mcp/sse_main.clj (1 hunks)
  • src/clojure_mcp/tool_system.clj (1 hunks)
  • src/clojure_mcp/tools/agent_tool_builder/core.clj (1 hunks)
  • src/clojure_mcp/tools/agent_tool_builder/file_changes.clj (1 hunks)
  • src/clojure_mcp/tools/agent_tool_builder/tool.clj (1 hunks)
  • src/clojure_mcp/tools/bash/core.clj (1 hunks)
  • src/clojure_mcp/tools/bash/tool.clj (1 hunks)
  • src/clojure_mcp/tools/eval/core.clj (1 hunks)
  • src/clojure_mcp/tools/figwheel/tool.clj (1 hunks)
  • src/clojure_mcp/tools/glob_files/core.clj (1 hunks)
  • src/clojure_mcp/tools/grep/core.clj (1 hunks)
  • src/clojure_mcp/tools/project/core.clj (1 hunks)
  • src/clojure_mcp/tools/scratch_pad/tool.clj (1 hunks)
  • src/clojure_mcp/tools/unified_clojure_edit/tool.clj (1 hunks)
  • src/clojure_mcp/tools/unified_read_file/file_timestamps.clj (1 hunks)
  • src/clojure_mcp/tools/unified_read_file/tool.clj (1 hunks)
  • test/clojure_mcp/test_helper.clj (1 hunks)
💤 Files with no reviewable changes (1)
  • dev/logback.xml
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{clj,cljc}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{clj,cljc}: Use :require with ns aliases for imports (e.g., [clojure.string :as string])
Include clear tool :description for LLM guidance
Validate inputs and provide helpful error messages in MCP tools
Return structured data with both result and error status in MCP tools
Maintain atom-based state for consistent service access in MCP tools

Files:

  • src/clojure_mcp/tools/agent_tool_builder/core.clj
  • src/clojure_mcp/core.clj
  • src/clojure_mcp/tools/glob_files/core.clj
  • src/clojure_mcp/tool_system.clj
  • src/clojure_mcp/agent/langchain.clj
  • src/clojure_mcp/agent/general_agent.clj
  • src/clojure_mcp/tools/bash/core.clj
  • src/clojure_mcp/main.clj
  • src/clojure_mcp/dialects.clj
  • src/clojure_mcp/tools/agent_tool_builder/file_changes.clj
  • src/clojure_mcp/main_examples/figwheel_main.clj
  • src/clojure_mcp/agent/langchain/chat_listener.clj
  • src/clojure_mcp/nrepl.clj
  • src/clojure_mcp/tools/agent_tool_builder/tool.clj
  • src/clojure_mcp/nrepl_launcher.clj
  • src/clojure_mcp/tools/figwheel/tool.clj
  • src/clojure_mcp/tools/unified_read_file/file_timestamps.clj
  • src/clojure_mcp/sse_core.clj
  • src/clojure_mcp/logging.clj
  • src/clojure_mcp/sse_main.clj
  • src/clojure_mcp/tools/grep/core.clj
  • src/clojure_mcp/tools/project/core.clj
  • src/clojure_mcp/agent/langchain/model.clj
  • src/clojure_mcp/tools/scratch_pad/tool.clj
  • src/clojure_mcp/tools/unified_read_file/tool.clj
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/tools/bash/tool.clj
  • src/clojure_mcp/tools/unified_clojure_edit/tool.clj
  • src/clojure_mcp/main_examples/shadow_main.clj
  • src/clojure_mcp/tools/eval/core.clj
**/*.{clj,cljc}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{clj,cljc}: Use kebab-case for vars/functions; end predicates with ? (e.g., is-top-level-form?)
Use try/catch with specific exception handling; use atom for tracking errors
Use 2-space indentation and maintain whitespace in edited forms
Align namespaces with directory structure (e.g., clojure-mcp.repl-tools)

Files:

  • src/clojure_mcp/tools/agent_tool_builder/core.clj
  • src/clojure_mcp/core.clj
  • src/clojure_mcp/tools/glob_files/core.clj
  • src/clojure_mcp/tool_system.clj
  • src/clojure_mcp/agent/langchain.clj
  • src/clojure_mcp/agent/general_agent.clj
  • src/clojure_mcp/tools/bash/core.clj
  • src/clojure_mcp/main.clj
  • src/clojure_mcp/dialects.clj
  • src/clojure_mcp/tools/agent_tool_builder/file_changes.clj
  • src/clojure_mcp/main_examples/figwheel_main.clj
  • src/clojure_mcp/agent/langchain/chat_listener.clj
  • src/clojure_mcp/nrepl.clj
  • src/clojure_mcp/tools/agent_tool_builder/tool.clj
  • src/clojure_mcp/nrepl_launcher.clj
  • src/clojure_mcp/tools/figwheel/tool.clj
  • src/clojure_mcp/tools/unified_read_file/file_timestamps.clj
  • src/clojure_mcp/sse_core.clj
  • src/clojure_mcp/logging.clj
  • src/clojure_mcp/sse_main.clj
  • test/clojure_mcp/test_helper.clj
  • src/clojure_mcp/tools/grep/core.clj
  • src/clojure_mcp/tools/project/core.clj
  • src/clojure_mcp/agent/langchain/model.clj
  • src/clojure_mcp/tools/scratch_pad/tool.clj
  • src/clojure_mcp/tools/unified_read_file/tool.clj
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/tools/bash/tool.clj
  • src/clojure_mcp/tools/unified_clojure_edit/tool.clj
  • src/clojure_mcp/main_examples/shadow_main.clj
  • src/clojure_mcp/tools/eval/core.clj
test/**/*.{clj,cljc}

📄 CodeRabbit inference engine (CLAUDE.md)

Use deftest with descriptive names; testing for subsections; is for assertions in tests

Files:

  • test/clojure_mcp/test_helper.clj
🧠 Learnings (8)
📚 Learning: 2025-08-02T20:23:28.499Z
Learnt from: CR
Repo: bhauman/clojure-mcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T20:23:28.499Z
Learning: Applies to src/**/*.{clj,cljc} : Return structured data with both result and error status in MCP tools

Applied to files:

  • src/clojure_mcp/core.clj
  • src/clojure_mcp/tool_system.clj
  • src/clojure_mcp/agent/langchain.clj
  • src/clojure_mcp/tools/bash/core.clj
  • src/clojure_mcp/main.clj
  • src/clojure_mcp/dialects.clj
  • test/clojure_mcp/test_helper.clj
  • src/clojure_mcp/tools/project/core.clj
  • src/clojure_mcp/tools/scratch_pad/tool.clj
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/tools/bash/tool.clj
  • src/clojure_mcp/tools/unified_clojure_edit/tool.clj
  • src/clojure_mcp/main_examples/shadow_main.clj
  • src/clojure_mcp/tools/eval/core.clj
  • deps.edn
📚 Learning: 2025-08-18T00:39:24.837Z
Learnt from: hugoduncan
Repo: bhauman/clojure-mcp PR: 86
File: src/clojure_mcp/subprocess.clj:0-0
Timestamp: 2025-08-18T00:39:24.837Z
Learning: In the clojure-mcp project, the user prefers to only parse stdout for nREPL port discovery in the subprocess.clj module, and explicitly does not want to parse stderr for port information.

Applied to files:

  • src/clojure_mcp/core.clj
  • src/clojure_mcp/tools/bash/core.clj
  • src/clojure_mcp/main.clj
  • src/clojure_mcp/dialects.clj
  • src/clojure_mcp/main_examples/figwheel_main.clj
  • src/clojure_mcp/sse_core.clj
  • src/clojure_mcp/sse_main.clj
  • src/clojure_mcp/tools/bash/tool.clj
  • src/clojure_mcp/main_examples/shadow_main.clj
  • deps.edn
📚 Learning: 2025-08-02T20:23:28.499Z
Learnt from: CR
Repo: bhauman/clojure-mcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T20:23:28.499Z
Learning: Applies to src/**/*.{clj,cljc} : Validate inputs and provide helpful error messages in MCP tools

Applied to files:

  • src/clojure_mcp/core.clj
  • src/clojure_mcp/tool_system.clj
  • src/clojure_mcp/agent/langchain.clj
  • src/clojure_mcp/tools/bash/core.clj
  • src/clojure_mcp/main.clj
  • src/clojure_mcp/dialects.clj
  • src/clojure_mcp/main_examples/figwheel_main.clj
  • test/clojure_mcp/test_helper.clj
  • src/clojure_mcp/tools/project/core.clj
  • src/clojure_mcp/tools/scratch_pad/tool.clj
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/tools/bash/tool.clj
  • src/clojure_mcp/tools/unified_clojure_edit/tool.clj
  • src/clojure_mcp/tools/eval/core.clj
📚 Learning: 2025-08-02T20:23:28.499Z
Learnt from: CR
Repo: bhauman/clojure-mcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T20:23:28.499Z
Learning: Applies to src/**/*.{clj,cljc} : Maintain atom-based state for consistent service access in MCP tools

Applied to files:

  • src/clojure_mcp/core.clj
  • src/clojure_mcp/agent/langchain.clj
  • src/clojure_mcp/tools/bash/core.clj
  • src/clojure_mcp/main.clj
  • src/clojure_mcp/dialects.clj
  • src/clojure_mcp/tools/agent_tool_builder/file_changes.clj
  • src/clojure_mcp/main_examples/figwheel_main.clj
  • src/clojure_mcp/sse_core.clj
  • src/clojure_mcp/sse_main.clj
  • test/clojure_mcp/test_helper.clj
  • src/clojure_mcp/tools/project/core.clj
  • src/clojure_mcp/agent/langchain/model.clj
  • src/clojure_mcp/tools/scratch_pad/tool.clj
  • src/clojure_mcp/tools/bash/tool.clj
  • src/clojure_mcp/main_examples/shadow_main.clj
  • deps.edn
📚 Learning: 2025-08-02T20:23:28.499Z
Learnt from: CR
Repo: bhauman/clojure-mcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T20:23:28.499Z
Learning: Applies to **/*.{clj,cljc} : Align namespaces with directory structure (e.g., `clojure-mcp.repl-tools`)

Applied to files:

  • src/clojure_mcp/core.clj
  • src/clojure_mcp/tools/agent_tool_builder/file_changes.clj
  • test/clojure_mcp/test_helper.clj
  • src/clojure_mcp/tools/project/core.clj
  • src/clojure_mcp/tools/scratch_pad/tool.clj
  • src/clojure_mcp/config.clj
  • src/clojure_mcp/tools/bash/tool.clj
  • src/clojure_mcp/tools/unified_clojure_edit/tool.clj
  • deps.edn
📚 Learning: 2025-08-02T20:23:28.499Z
Learnt from: CR
Repo: bhauman/clojure-mcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T20:23:28.499Z
Learning: Applies to src/**/*.{clj,cljc} : Include clear tool `:description` for LLM guidance

Applied to files:

  • src/clojure_mcp/tool_system.clj
  • src/clojure_mcp/tools/agent_tool_builder/file_changes.clj
  • test/clojure_mcp/test_helper.clj
  • src/clojure_mcp/tools/grep/core.clj
  • src/clojure_mcp/tools/scratch_pad/tool.clj
  • src/clojure_mcp/tools/unified_clojure_edit/tool.clj
  • src/clojure_mcp/tools/eval/core.clj
  • deps.edn
📚 Learning: 2025-08-02T20:23:28.499Z
Learnt from: CR
Repo: bhauman/clojure-mcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T20:23:28.499Z
Learning: Applies to src/**/*.{clj,cljc} : Use `:require` with ns aliases for imports (e.g., `[clojure.string :as string]`)

Applied to files:

  • src/clojure_mcp/tools/bash/core.clj
  • src/clojure_mcp/nrepl.clj
  • src/clojure_mcp/tools/unified_clojure_edit/tool.clj
  • src/clojure_mcp/tools/eval/core.clj
📚 Learning: 2025-08-02T20:23:28.499Z
Learnt from: CR
Repo: bhauman/clojure-mcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T20:23:28.499Z
Learning: Applies to test/**/*.{clj,cljc} : Use `deftest` with descriptive names; `testing` for subsections; `is` for assertions in tests

Applied to files:

  • test/clojure_mcp/test_helper.clj
🔇 Additional comments (31)
src/clojure_mcp/tools/unified_clojure_edit/tool.clj (1)

9-9: LGTM! Clean logging library migration.

The import change from clojure.tools.logging to taoensso.timbre is correct and maintains API compatibility. The log alias remains unchanged, so the existing log/info call at line 203 works without modification. This change aligns with the PR's systematic migration to Timbre across the codebase.

src/clojure_mcp/agent/langchain/model.clj (1)

5-5: Timbre import and log/* usages look correct and non-breaking

Switching the require to [taoensso.timbre :as log] keeps the log/info and log/warn call sites valid, including the (log/warn e (str ...)) pattern in get-tool-model, so behavior should carry over cleanly to the new backend while satisfying the aliasing guideline. As per coding guidelines.

Also applies to: 570-573

src/clojure_mcp/tools/agent_tool_builder/core.clj (1)

11-11: LGTM! Clean logging backend migration.

The switch from clojure.tools.logging to taoensso.timbre is consistent with the project-wide logging migration. Preserving the log alias ensures all existing logging calls remain compatible.

src/clojure_mcp/tools/bash/core.clj (1)

7-7: LGTM! Logging backend successfully migrated.

The Timbre migration is correctly applied with the preserved log alias. All existing logging calls (debug, warn, error) throughout the file remain compatible.

src/clojure_mcp/agent/langchain.clj (1)

5-5: LGTM! Logging backend migration applied correctly.

The switch to Timbre maintains the log alias, ensuring seamless compatibility with existing logging statements in the LangChain integration code.

src/clojure_mcp/nrepl_launcher.clj (1)

8-8: LGTM! Logging migration successful.

The Timbre backend swap is properly implemented. This launcher module's extensive logging (debug, info, warn, error) will continue to function correctly with the preserved log alias.

src/clojure_mcp/nrepl.clj (1)

7-7: LGTM! Logging backend updated correctly.

The Timbre migration maintains compatibility with the nREPL client's error and info logging. The preserved log alias ensures no changes are needed to the connection management code.

src/clojure_mcp/tools/bash/tool.clj (1)

9-9: LGTM! Logging backend migration complete.

The Timbre switch is correctly applied. The bash tool's error and debug logging will continue to work seamlessly with the preserved log alias.

src/clojure_mcp/tools/unified_read_file/file_timestamps.clj (1)

6-6: LGTM! Logging migration implemented correctly.

The Timbre backend swap maintains full compatibility with the file timestamp tracking logic. The preserved log alias ensures all debug, info, and warn calls continue to function properly.

src/clojure_mcp/agent/general_agent.clj (1)

5-5: LGTM! Logging backend successfully updated.

The Timbre migration is properly applied to the general agent module. Error logging for agent creation and chat operations will continue to work correctly with the preserved log alias.

src/clojure_mcp/tools/figwheel/tool.clj (1)

3-3: Clean logging backend migration.

The swap from clojure.tools.logging to taoensso.timbre is consistent with the project-wide migration. The log alias is preserved, so all existing logging calls continue to work without modification.

src/clojure_mcp/tools/glob_files/core.clj (1)

7-7: Clean logging backend migration.

The namespace change from clojure.tools.logging to taoensso.timbre is straightforward and consistent with the project-wide logging migration. All logging calls throughout the file continue to work via the preserved log alias.

src/clojure_mcp/tools/eval/core.clj (1)

9-9: Clean logging backend migration.

The logging namespace swap to taoensso.timbre maintains the log alias, ensuring all existing logging calls (such as Line 90's log/error) continue to function without modification.

src/clojure_mcp/agent/langchain/chat_listener.clj (1)

5-5: Clean logging backend migration.

The switch to taoensso.timbre is consistent with the project-wide migration. The log alias is preserved, ensuring all logging calls (including those in the logging-listener function) continue to work seamlessly.

src/clojure_mcp/core.clj (1)

5-5: Clean logging backend migration.

The migration to taoensso.timbre is well-executed. The preserved log alias ensures all logging calls throughout this core file (lines 94, 218, 231, 234, 260, 262, 284, etc.) continue to function without modification.

src/clojure_mcp/tools/agent_tool_builder/tool.clj (1)

8-8: Clean logging backend migration.

The namespace change to taoensso.timbre aligns with the project-wide migration. The log alias is preserved, maintaining compatibility with existing logging calls in the create-agent-tools function.

src/clojure_mcp/dialects.clj (1)

8-8: Clean logging backend migration.

The migration to taoensso.timbre is straightforward and consistent. The preserved log alias ensures existing logging calls (lines 85, 107) continue to work without modification.

src/clojure_mcp/tool_system.clj (1)

8-8: Clean logging backend migration.

The namespace swap to taoensso.timbre is consistent with the project-wide migration. The log alias is preserved, ensuring the error logging call (line 110) continues to work seamlessly.

src/clojure_mcp/config.clj (1)

7-7: LGTM: Clean logging backend migration.

The import swap from clojure.tools.logging to taoensso.timbre maintains the same log alias, ensuring all existing log calls remain unchanged and compatible.

src/clojure_mcp/sse_core.clj (1)

6-6: LGTM: Logging backend successfully migrated.

The Timbre import preserves the log alias, maintaining compatibility with all existing logging calls.

src/clojure_mcp/tools/unified_read_file/tool.clj (1)

13-13: LGTM: Consistent logging migration.

Import change aligns with the project-wide migration to Timbre while preserving existing log call syntax.

src/clojure_mcp/main_examples/figwheel_main.clj (1)

13-13: LGTM: Centralized logging integration.

The import of the new clojure-mcp.logging namespace enables centralized logging configuration for entry points.

src/clojure_mcp/tools/scratch_pad/tool.clj (1)

7-7: LGTM: Logging backend migrated successfully.

The import swap maintains the log alias, ensuring compatibility with all existing logging statements throughout the file.

src/clojure_mcp/main_examples/shadow_main.clj (1)

14-16: LGTM: Logging integration complete.

Both the centralized logging namespace and Timbre backend are properly imported for logging configuration and usage.

src/clojure_mcp/tools/grep/core.clj (1)

8-8: LGTM: Logging migration complete.

The import change aligns with the project-wide migration to Timbre, maintaining compatibility with all existing log calls.

src/clojure_mcp/tools/agent_tool_builder/file_changes.clj (1)

8-8: LGTM: Logging backend updated.

The import swap completes the migration to Timbre while preserving the log alias and existing logging calls.

test/clojure_mcp/test_helper.clj (1)

1-8: Test helper logging suppression is wired correctly

Requiring clojure-mcp.logging here and calling logging/configure-test-logging! at load time ensures tests run with logging suppressed regardless of how the test runner is invoked, which matches the new :test alias behavior.

deps.edn (2)

68-98: Dev aliases correctly mirror the main MCP entrypoints with dev/test paths

The dev aliases (:prompt-cli, :dev-mcp*) now consistently:

  • Add ["dev" "test"] to :extra-paths, and
  • Use the same start-*-mcp-server functions as the non-dev aliases,

which should give a predictable dev experience while still honoring the centralized logging configuration.


29-35: Logging migration verified—old backend fully removed, new stack correctly in place

Verification confirms the migration is complete:

  • Timbre 6.8.0 and slf4j-nop 2.0.16 are present in deps.edn (lines 29, 32)
  • No logback-classic, java-logging, log4j, or log4j2 in deps.edn
  • No logback.xml or logback-classic code references
  • No conflicting SLF4J bindings

The changes are correct as-is.

src/clojure_mcp/tools/project/core.clj (1)

12-12: Timbre logging alias swap verified as correct

The migration to [taoensso.timbre :as log] at line 12 is complete and consistent. The dependency is present in deps.edn (6.8.0), all 12+ existing log/debug and log/warn call sites throughout the file remain valid, and no old logging backend references persist in the codebase. The namespace declaration follows coding guidelines with proper :require formatting and ns aliases.

src/clojure_mcp/logging.clj (1)

44-63: Helper logging modes and test suppression look consistent

The dev/prod/test helpers and suppress-logging-for-tests! cleanly wrap configure-logging! and match the PR intent: simple dev file logging, and logging suppressed by default and in tests via env var or system property.

No functional issues spotted here.

Also applies to: 64-71

Comment on lines +14 to +18
Options:
- :log-file Path to log file (default: 'logs/clojure-mcp.log')
- :enable-logging? Whether to enable logging (default: true)
- :log-level Minimum log level (default: :debug)
Valid values: :trace :debug :info :warn :error :fatal :report
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix configure-logging! option docs to match actual defaults

The option docs and the implementation diverge:

  • Doc says :log-file default is 'logs/clojure-mcp.log', but :or uses default-log-file which is ".clojure-mcp/clojure-mcp.log".
  • Doc says :enable-logging? default is true, but the implementation defaults it to false.

Given this is a new public API, this mismatch will confuse users configuring logging from the CLI/entry points.

Consider updating the docstring to describe the real behavior:

-   - :log-file       Path to log file (default: 'logs/clojure-mcp.log')
-   - :enable-logging? Whether to enable logging (default: true)
-   - :log-level      Minimum log level (default: :debug)
+   - :log-file         Path to log file (default: '.clojure-mcp/clojure-mcp.log')
+   - :enable-logging?  Whether to enable logging (default: false)
+   - :log-level        Minimum log level when logging is enabled (default: :debug)

Also applies to: 29-32

🤖 Prompt for AI Agents
In src/clojure_mcp/logging.clj around lines 14-18 and 29-32, the docstring
defaults for :log-file and :enable-logging? do not match the implementation;
update the two documentation blocks to state the actual defaults (use
default-log-file value ".clojure-mcp/clojure-mcp.log" for :log-file and set
:enable-logging? default to false), and ensure the :log-level default text
remains correct (e.g., :debug) — or alternatively change the implementation to
match the previously documented defaults; pick one approach and make both doc
blocks consistent with the code.

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.

2 participants