Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 18 additions & 33 deletions deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
org.clojure/data.json {:mvn/version "2.5.1"}
nrepl/nrepl {:mvn/version "1.3.1"}
org.clojure/tools.logging {:mvn/version "1.3.0"}
org.clojure/tools.cli {:mvn/version "1.1.230"}
org.clj-commons/pretty {:mvn/version "3.6.7"}

Expand All @@ -27,22 +26,22 @@
dev.langchain4j/langchain4j-anthropic {:mvn/version "1.8.0"}
dev.langchain4j/langchain4j-google-ai-gemini {:mvn/version "1.8.0"}

;; in order to use the stdio server you have to handle logging somehow
;; org.slf4j/slf4j-nop {:mvn/version "2.0.16"}
com.taoensso/timbre {:mvn/version "6.8.0"}

;; Suppress logging from Java libraries (MCP SDK, LangChain4j, etc.)
org.slf4j/slf4j-nop {:mvn/version "2.0.16"}

;; native Java diff library
io.github.java-diff-utils/java-diff-utils {:mvn/version "4.15"}}
:aliases

{:mcp
{:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"}}
:exec-fn clojure-mcp.main/start-mcp-server
{:exec-fn clojure-mcp.main/start-mcp-server
;; it needs an nrepl port to talk to
:exec-args {:port 7888}}

:mcp-sse
{:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"} ;; optional
jakarta.servlet/jakarta.servlet-api {:mvn/version "6.1.0"}
{:extra-deps {jakarta.servlet/jakarta.servlet-api {:mvn/version "6.1.0"}
org.eclipse.jetty/jetty-server {:mvn/version "11.0.20"}
org.eclipse.jetty/jetty-servlet {:mvn/version "11.0.20"}}
:exec-fn clojure-mcp.sse-main/start-sse-mcp-server
Expand All @@ -52,86 +51,72 @@
:mcp-sse-port 8078}}

:mcp-figwheel
{:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"}}
:exec-fn clojure-mcp.main-examples.figwheel-main/start-mcp-server
{:exec-fn clojure-mcp.main-examples.figwheel-main/start-mcp-server
:exec-args {:port 7888 :figwheel-build "dev"}}

:mcp-shadow
{:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"}}
:exec-fn clojure-mcp.main-examples.shadow-main/start-mcp-server
{:exec-fn clojure-mcp.main-examples.shadow-main/start-mcp-server
:exec-args {:port 7888 :shadow-build "app"}}

;; dual shadow and project nrepl setup
:mcp-shadow-dual
{:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"}}
:extra-paths ["dev" "test"]
{:extra-paths ["dev" "test"]
:exec-fn clojure-mcp.main-examples.shadow-main/start-mcp-server
;; it needs an nrepl port to talk to
:exec-args {:port 7888 :shadow-build "app" :shadow-port 7889}}

;; below are dev set ups that need a logback.xml file
;; below are dev set ups
:prompt-cli
{:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"}}
:main-opts ["-m" "clojure-mcp.prompt-cli"]}
{:main-opts ["-m" "clojure-mcp.prompt-cli"]}

:dev-mcp
{:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.14"}}
:extra-paths ["dev" "test"]
{:extra-paths ["dev" "test"]
:exec-fn clojure-mcp.main/start-mcp-server
;; it needs an nrepl port to talk to
:exec-args {:port 7888
;; test auto starting the repl
;; :start-nrepl-cmd ["clojure" "-M:nrepl"]
}}

;; DEV setup needs logback.xml
:dev-mcp-figwheel
{:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.14"}}
:extra-paths ["dev" "test"]
{:extra-paths ["dev" "test"]
:exec-fn clojure-mcp.main-examples.figwheel-main/start-mcp-server
;; it needs an nrepl port to talk to
:exec-args {:port 7888 :figwheel-build "dev"}}

;; DEV setup needs logback.xml
:dev-mcp-shadow
{:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.14"}}
:extra-paths ["dev" "test"]
{:extra-paths ["dev" "test"]
:exec-fn clojure-mcp.main-examples.shadow-main/start-mcp-server
;; it needs an nrepl port to talk to
:exec-args {:port 7888 :shadow-build "app"}}

:dev-mcp-shadow-dual
{:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.14"}}
:extra-paths ["dev" "test"]
{:extra-paths ["dev" "test"]
:exec-fn clojure-mcp.main-examples.shadow-main/start-mcp-server
;; it needs an nrepl port to talk to
:exec-args {:port 7888 :shadow-build "app" :shadow-port 7889}}

:nrepl {:extra-paths ["test" "dev"]
:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.14"}}
:main-opts ["-m" "nrepl.cmdline" "--port" "7888"]}

:dkr-nrepl {:extra-paths ["test" "dev"]
:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.14"}}
:main-opts ["-m" "nrepl.cmdline" "--port" "7888"
;; for Docker
"--bind" "0.0.0.0"]}

;; dev cycle
:test
{:extra-paths ["test" "dev"]
:exec-fn cognitect.test-runner/test
:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.14"}
org.clojure/test.check {:mvn/version "1.1.1"}
:exec-fn clojure-mcp.test-helper/run-tests-with-exec
:extra-deps {org.clojure/test.check {:mvn/version "1.1.1"}
nrepl/nrepl {:mvn/version "1.3.1"} ;; Add nrepl server for testing
io.github.cognitect-labs/test-runner
{:git/tag "v0.5.1" :git/sha "dfb30dd"}}
:main-opts ["-m" "cognitect.test-runner"]}
:main-opts ["-e" "(require 'clojure-mcp.test-helper)" "-m" "cognitect.test-runner"]}

:index
{:exec-fn clojure-mcp.code-indexer/map-project
:exec-args {}
:extra-deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"}}
;; Override with: clojure -X:index :dirs '["src" "lib"]' :include-tests true :out-file '"my-index.txt"'
}

Expand Down
57 changes: 0 additions & 57 deletions dev/logback.xml

This file was deleted.

2 changes: 1 addition & 1 deletion src/clojure_mcp/agent/general_agent.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"A generalized agent library that can be parameterized with system prompts,
context, tools, memory, and models."
(:require [clojure.string :as string]
[clojure.tools.logging :as log]
[taoensso.timbre :as log]
[clojure.java.io :as io]
[clojure-mcp.agent.langchain :as chain]
[clojure-mcp.tools.project.core :as project-core]
Expand Down
2 changes: 1 addition & 1 deletion src/clojure_mcp/agent/langchain.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
(:require
[clojure.data.json :as json]
[clojure-mcp.agent.langchain.schema :as schema]
[clojure.tools.logging :as log]
[taoensso.timbre :as log]
[clojure.string :as string]
[clojure.pprint])
(:import
Expand Down
2 changes: 1 addition & 1 deletion src/clojure_mcp/agent/langchain/chat_listener.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"Creates ChatModelListener instances from Clojure functions that work with EDN data"
(:require
[clojure-mcp.agent.langchain.message-conv :as msg-conv]
[clojure.tools.logging :as log])
[taoensso.timbre :as log])
(:import
[dev.langchain4j.model.chat.listener
ChatModelListener
Expand Down
2 changes: 1 addition & 1 deletion src/clojure_mcp/agent/langchain/model.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
(:require
[clojure-mcp.config.schema :as schema]
[clojure-mcp.config :as config]
[clojure.tools.logging :as log])
[taoensso.timbre :as log])
(:import
[dev.langchain4j.model.anthropic
AnthropicChatModel
Expand Down
2 changes: 1 addition & 1 deletion src/clojure_mcp/config.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[clojure-mcp.config.schema :as schema]
[clojure-mcp.utils.file :as file-utils]
[clojure.edn :as edn]
[clojure.tools.logging :as log]))
[taoensso.timbre :as log]))

(defn- relative-to [dir path]
(try
Expand Down
2 changes: 1 addition & 1 deletion src/clojure_mcp/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
(:require [clojure.data.json :as json]
[clojure.java.io :as io]
[clojure.spec.alpha :as s]
[clojure.tools.logging :as log]
[taoensso.timbre :as log]
[clojure-mcp.nrepl :as nrepl]
[clojure-mcp.config :as config]
[clojure-mcp.dialects :as dialects]
Expand Down
2 changes: 1 addition & 1 deletion src/clojure_mcp/dialects.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
and initialization sequences specific to each dialect."
(:require [clojure.edn :as edn]
[clojure.java.io :as io]
[clojure.tools.logging :as log]
[taoensso.timbre :as log]
[clojure-mcp.nrepl :as nrepl]
[clojure-mcp.utils.file :as file-utils]))

Expand Down
71 changes: 71 additions & 0 deletions src/clojure_mcp/logging.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
(ns clojure-mcp.logging
"Centralized logging configuration using Timbre.

This namespace provides functions to configure Timbre-based logging
for the Clojure MCP server with support for both development and
production modes."
(:require [taoensso.timbre :as timbre]))

(def default-log-file ".clojure-mcp/clojure-mcp.log")

(defn configure-logging!
"Configure Timbre logging with the given options.

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
Comment on lines +14 to +18
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.


Examples:

Development mode with full logging:
(configure-logging! {:log-file \"logs/clojure-mcp.log\"
:enable-logging? true
:log-level :debug})

Production mode with logging suppressed:
(configure-logging! {:enable-logging? false})"
[{:keys [log-file enable-logging? log-level]
:or {log-file default-log-file
enable-logging? false
log-level :debug}}]
(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 #{"*"}}))}
{})}))

(defn configure-dev-logging!
"Configure logging for development mode with debug level.
Convenience function that enables full debug logging to logs/clojure-mcp.log"
[]
(configure-logging! {:log-file "logs/clojure-mcp.log"
:enable-logging? true
:log-level :debug}))

(defn configure-prod-logging!
"Configure logging for production mode with all logging suppressed.
Convenience function that disables all logging."
[]
(configure-logging! {:enable-logging? false}))

(defn configure-test-logging!
"Configure logging for test mode with all logging suppressed.
Convenience function that disables all logging during tests."
[]
(configure-logging! {:enable-logging? false}))

(defn suppress-logging-for-tests!
"Automatically suppress logging if running in test mode.
Checks for CLOJURE_MCP_TEST environment variable or
clojure.mcp.test system property."
[]
(when (or (System/getenv "CLOJURE_MCP_TEST")
(System/getProperty "clojure.mcp.test"))
(configure-test-logging!)))
8 changes: 7 additions & 1 deletion src/clojure_mcp/main.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(ns clojure-mcp.main
(:require [clojure-mcp.core :as core]
[clojure-mcp.logging :as logging]
[clojure-mcp.prompts :as prompts]
[clojure-mcp.resources :as resources]
[clojure-mcp.tools :as tools]))
Expand Down Expand Up @@ -33,8 +34,13 @@
(tools/build-all-tools nrepl-client-atom))

(defn start-mcp-server [opts]
;; Configure logging before starting the server
(logging/configure-logging!
{:log-file (get opts :log-file logging/default-log-file)
:enable-logging? (get opts :enable-logging? false)
:log-level (get opts :log-level :debug)})
(core/build-and-start-mcp-server
opts
(dissoc opts :log-file :log-level :enable-logging?)
{:make-tools-fn make-tools
:make-prompts-fn make-prompts
:make-resources-fn make-resources}))
Expand Down
8 changes: 7 additions & 1 deletion src/clojure_mcp/main_examples/figwheel_main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
See the comments below for the required deps.edn configuration."
(:require
[clojure-mcp.core :as core]
[clojure-mcp.logging :as logging]
[clojure-mcp.main :as main]
[clojure-mcp.tools.figwheel.tool :as figwheel-tool]))

Expand All @@ -36,8 +37,13 @@
(figwheel-tool/figwheel-eval nrepl-client-atom {:figwheel-build (or figwheel-build "dev")})))

(defn start-mcp-server [opts]
;; Configure logging before starting the server
(logging/configure-logging!
{:log-file (get opts :log-file logging/default-log-file)
:enable-logging? (get opts :enable-logging? false)
:log-level (get opts :log-level :debug)})
(core/build-and-start-mcp-server
opts
(dissoc opts :log-file :log-level :enable-logging?)
{:make-tools-fn (fn [nrepl-client-atom working-directory]
(make-tools nrepl-client-atom working-directory opts))
:make-prompts-fn main/make-prompts
Expand Down
10 changes: 8 additions & 2 deletions src/clojure_mcp/main_examples/shadow_main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
- Dual connection: Connect to a separate Shadow CLJS nREPL server"
(:require
[clojure-mcp.core :as core]
[clojure-mcp.logging :as logging]
[clojure-mcp.nrepl :as nrepl]
[clojure.tools.logging :as log]
[taoensso.timbre :as log]
[clojure-mcp.main :as main]
[clojure-mcp.tools.eval.tool :as eval-tool]))

Expand Down Expand Up @@ -82,8 +83,13 @@ JavaScript interop is fully supported including `js/console.log`, `js/setTimeout
(shadow-eval-tool nrepl-client-atom config))))

(defn start-mcp-server [opts]
;; Configure logging before starting the server
(logging/configure-logging!
{:log-file (get opts :log-file logging/default-log-file)
:enable-logging? (get opts :enable-logging? false)
:log-level (get opts :log-level :debug)})
(core/build-and-start-mcp-server
opts
(dissoc opts :log-file :log-level :enable-logging?)
{:make-tools-fn (fn [nrepl-client-atom working-directory]
(make-tools nrepl-client-atom working-directory opts))
:make-prompts-fn main/make-prompts
Expand Down
Loading