
Clojure
STDIOClojure MCP server enabling AI-powered REPL-driven development with intelligent editing tools
Clojure MCP server enabling AI-powered REPL-driven development with intelligent editing tools
⚠️ Alpha Software - Work in Progress
Clojure MCP connects AI models to your Clojure development environment, enabling a remarkable REPL-driven development experience powered by large language models (LLMs).
Clojure MCP transforms LLMs into:
With Clojure MCP alone you can turn an LLM into a powerful Clojure REPL and coding assistant.
LLMs excel in the Clojure REPL: Current LLMs are unarguably fantastic Clojure REPL assistants that perform evaluations quickly and much more effectively than you can imagine. Ask anyone who has experienced this and they will tell you that the LLMs are performing much better in the Clojure REPL than they would have imagined. Additionally, we must remember that the form and maintainability of ephemeral code DOES NOT MATTER.
Buttery Smooth Clojure Editing: With current editing tools, LLMs still struggle with the parenthesis. Clojure MCP has a different take on editing that increases edit acceptance rates significantly. Clojure MCP lints code coming in, fixes parenthesis if possible, uses clj-rewrite to apply syntax aware patches, and then lints and formats the final result. This is a powerful editing pipeline that vastly outperforms when it comes to editing Clojure Code.
Together these two features along with a set of other Clojure aware tools create a new and unique LLM development experience that you probably should try at least once to understand how transformational it is.
There is a story that Clojure developers may have come to believe. The story that LLMs are overwhelmingly trained on more mainstream languages and as a result those languages have the upper hand when it comes to LLM assisted coding. I'm here to tell you that this is just not true.
LLMs can definitely write Clojure. However, our the secret weapon is the REPL and the fast focused feedback loop that it offers.
IMHO Clojure is an overwhemingly excellent langauge for LLM assisted development. All it needed was bit of a bridge... and this is what I've tried to create with ClojureMCP.
This project implements an MCP server that connects AI models to a Clojure nREPL, and Specialized Clojure editing tools enabling a unique Clojure develop experience.
Clojure MCP provides a superset of the tools that Claude Code uses, so you can use it to work on Clojure without any other tools.
I highly recommend using ClojureMCP with Claude Desktop to start. It's more attractive and there are no api charges!. Claude Desktop, also let's you have quick access to your own prompts and other resources provided by the clojure-mcp server. Having a stack of your own prompts available in a UI menu is very convenient.
Claude Desktop also let's you see the complete reasoning and tool execution chain which is very helpful for understanding how the LLM interacts with the tools. Seeing the explicit reasoning and actions is invaluable for learning how to work with LLMs as coding assistants.
If you use the built in Agent tools you will accumulate API charges.
For Clojurists an LLM assisted REPL is the killer application.
LLMs can:
Additionally, in some LLM clients (including Claude Desktop), you can control which tools are available to the model at any given moment so you can easily remove the ability to edit files and restrict the model to the REPL tool and force the use of the REPL.
These tools are designed to work with the latest LLM models. For the best experience with sexp editing and Clojure-specific tooling, we recommend:
I highly recommend Claude 4 if you want to see long autonomous agentic action chains.
The pattern-based structural editing tools require high model performance, so using one of these recommended models will significantly improve your experience.
I personally use Claude 4 Opus for almost everything, and I'm subscribed to Anthropic's $100US/month 5x Max plan.
The Clojure MCP tools are intentionally designed as a cohesive "action space" for Clojure development, rather than a collection of independent utilities. This design approach offers several key advantages:
The tools maintain state about file read/write operations to ensure safety.
When tools work together as a system, they can:
While you can use these tools alongside Claude Code and other code assistants with their own tooling, I recommend trying the Clojure MCP tools independently first to experience their full capabilities. Here's why:
Potential Conflicts:
Getting the Full Benefits:
Once you're comfortable with the Clojure MCP toolset, you can make informed decisions about whether to use it exclusively or integrate it with other code assistants and development tools based on your specific workflow needs.
grep
and glob_files
performanceSetting up ClojureMCP can be challenging as it is currently in alpha and not optimized for quick installation. This guide will walk you through the process step by step.
7888
in your projectclojure-mcp
to your ~/.clojure/deps.edn
clojure-mcp
as an MCP server in Claude Desktop or other MCP clients.gitignore
.Note: This setup verifies that all components work together. You can customize specific configuration details (like port numbers) after confirming the basic setup works.
In the Clojure project where you want AI assistance, you'll need to ensure you can start an nREPL server on port 7888
(you can use any port).
Add an :nrepl
alias to your project's deps.edn
:
{ ;; ... your project dependencies ... :aliases { ;; nREPL server for AI to connect to ;; Include all paths you want available for development :nrepl {:extra-paths ["test"] :extra-deps {nrepl/nrepl {:mvn/version "1.3.1"}} ;; this allows nrepl to interrupt runaway repl evals :jvm-opts ["-Djdk.attach.allowAttachSelf"] :main-opts ["-m" "nrepl.cmdline" "--port" "7888"]}}}
Verify the configuration:
$ clojure -M:nrepl
You should see the nREPL server start on port 7888
.
Start an nREPL server with:
$ lein repl :headless :port 7888
Add clojure-mcp
as an alias in your ~/.clojure/deps.edn
:
{:aliases {:mcp {:deps {org.slf4j/slf4j-nop {:mvn/version "2.0.16"} ;; Required for stdio server com.bhauman/clojure-mcp {:git/url "https://github.com/bhauman/clojure-mcp.git" :git/tag "v0.1.6-alpha" :git/sha "4ad62f4"}} :exec-fn clojure-mcp.main/start-mcp-server :exec-args {:port 7888}}}}
Finding the Latest Version: Visit https://github.com/bhauman/clojure-mcp/commits/main for the latest commit SHA, or clone the repo and run
git log --oneline -1
.
⚠️ Important: You must have an nREPL server running on port 7888
before starting clojure-mcp
.
First, start your nREPL server in your project directory:
$ clojure -M:nrepl # or for Leiningen: $ lein repl :headless :port 7888
Then, in a new terminal, start clojure-mcp
:
$ clojure -X:mcp :port 7888
You should see JSON-RPC output like this:
{"jsonrpc":"2.0","method":"notifications/tools/list_changed"} {"jsonrpc":"2.0","method":"notifications/tools/list_changed"} {"jsonrpc":"2.0","method":"notifications/resources/list_changed"} {"jsonrpc":"2.0","method":"notifications/prompts/list_changed"}
Connection Refused Error:
Execution error (ConnectException) at sun.nio.ch.Net/connect0 (Net.java:-2).
Connection refused
This means clojure-mcp
couldn't connect to your nREPL server. Ensure:
Extraneous Output:
If you see output other than JSON-RPC messages, it's likely due to clojure-mcp
being included in a larger environment. Ensure clojure-mcp
runs with its own isolated dependencies.
clojure-mcp
in your project's dependencies. It should run separately with its own deps. Always use :deps
(not :extra-deps
) in its alias.The MCP server accepts the following command-line arguments via clojure -X:mcp
:
Argument | Type | Description | Default | Example |
---|---|---|---|---|
:port | integer | nREPL server port to connect to | 7888 | :port 7889 |
:host | string | nREPL server host | "localhost" | :host "192.168.1.10" |
This is often the most challenging part—ensuring the application's launch environment has the correct PATH and environment variables.
Pick the shell executable that will most likely pick up your environment config:
If you are using Bash find the explicit bash
executable path:
$ which bash /opt/homebrew/bin/bash
If you are using Z Shell find the explicit zsh
executable path:
$ which zsh /bin/zsh
Now we're going to use this explicit shell path in the command
parameter in the Claude Desktop configuration as seen below.
Create or edit ~/Library/Application\ Support/Claude/claude_desktop_config.json
:
{ "mcpServers": { "clojure-mcp": { "command": "/opt/homebrew/bin/bash", "args": [ "-c", "clojure -X:mcp :port 7888" ] } } }
Start nREPL in your target project:
cd /path/to/your/project clojure -M:nrepl
Look for: nREPL server started on port 7888...
Restart Claude Desktop (required after configuration changes)
Verify Connection: In Claude Desktop, click the +
button in the chat area. You should see "Add from clojure-mcp" in the menu. It's important to note that it may take a few moments for this to show up.
If there was an error please see the Troubleshooting Tips. If it connected go see the Starting a new conversation section.
If Claude Desktop can't run the clojure
command:
which clojure
works in a fresh terminalIf you continue to have issues, consider consulting with AI assistants (Claude, ChatGPT, Gemini) about the specific PATH configuration for your system setup.
If the above claude_desktop_config.json
doesn't work, it's most
likely that the PATH
environment variable is setup incorrectly to
find clojure
and java
.
Depending on your setup you can fix this directly by altering the PATH
environment variable:
{ "mcpServers": { "clojure-mcp": { "command": "/opt/homebrew/bin/bash", "args": [ "-c", "export PATH=/opt/homebrew/bin:$PATH; exec clojure -X:mcp :port 7888" ] } } }
/opt/homebrew/bin
/usr/local/bin
/home/username/.nix-profile/bin
or /nix/var/nix/profiles/default/bin
/usr/bin:/usr/local/bin
These are some examples to give you a way to debug a failed ClojureMCP startup.
Examine the environment:
{ "mcpServers": { "clojure-mcp": { "command": "/opt/homebrew/bin/bash", "args": [ "-c", "echo $PATH > /Users/bruce/claude-desktop-path.txt" ] } } }
Capture ClojureMCP output:
{ "mcpServers": { "clojure-mcp": { "command": "/opt/homebrew/bin/bash", "args": [ "-c", "clojure -X:mcp :port 7888 | tee /Users/bruce/clojure-mcp-stdout.log" ] } } }
If you need to source environment variables (like API keys see LLM API Keys) :
{ "mcpServers": { "clojure-mcp": { "command": "/bin/sh", "args": [ "-c", "source ~/.my-llm-api-keys.sh && PATH=/Users/username/.nix-profile/bin:$PATH && clojure -X:mcp :port 7888" ] } } }
See the Wiki for information on setting up other MCP clients.
Once everything is set up I'd suggest starting a new chat in Claude.
The first thing you are going to want to do is initialize context about the Clojure project in the conversation attached to the nREPL.
In Claude Desktop click the +
tools and optionally add
PROJECT_SUMMARY.md
- (have the LLM create this) see belowClojure Project Info
- which introspects the nREPL connected projectLLM_CODE_STYLE.md
- Which is your personal coding style instructions (copy the one in this repo to the root of your project)clojure_repl_system_prompt
- instructions on how to code - cribbed a bunch from Clod CodeThen start the chat.
I would start by stating a problem and then chatting with the LLM to interactively design a solution. You can ask Claude to "propose" a solution to a problem.
Iterate on that a bit then have it either:
A. code and validate the idea in the REPL.
Don't underestimate LLMs abilities to use the REPL! Current LLMs are absolutely fantastic at using the Clojure REPL.
B. ask the LLM to make the changes to the source code and then have it validate the code in the REPL after file editing.
C. ask to run the tests. D. ask to commit the changes.
Make a branch and have the LLM commit often so that it doesn't ruin good work by going in a bad direction.
This project includes a workflow for maintaining an LLM-friendly PROJECT_SUMMARY.md
that helps assistants quickly understand the codebase structure.
Creating the Summary: To generate or update the PROJECT_SUMMARY.md file, use the MCP prompt in the +
> clojure-mcp
menu create-project-summary
. This prompt will:
Using the Summary: When starting a new conversation with an assistant:
Keeping It Updated: At the end of a productive session where new features or components were added:
create-project-summary
prompt againThis workflow creates a virtuous cycle where each session builds on the accumulated knowledge of previous sessions, making the assistant increasingly effective as your project evolves.
The Clojure MCP server provides a pair of prompts that enable
conversation continuity across chat sessions using the scratch_pad
tool. By default, data is stored in memory only for the current session.
To persist summaries across server restarts, you must enable scratch pad
persistence using the configuration options described in the scratch pad section.
The system uses two complementary prompts:
chat-session-summarize
: Creates a summary of the current conversation
chat_session_key
parameter (defaults to "chat_session_summary"
)chat-session-resume
: Restores context from a previous conversation
clojure_inspect_project
for current project statechat_session_key
parameter (defaults to "chat_session_summary"
)Ending a Session:
chat-session-summarize
promptStarting a New Session:
chat-session-resume
promptYou can maintain multiple parallel conversation contexts by using custom keys:
# For feature development
chat-session-summarize with key "feature-auth-system"
# For bug fixing
chat-session-summarize with key "debug-memory-leak"
# Resume specific context
chat-session-resume with key "feature-auth-system"
This enables switching between different development contexts while maintaining the full state of each conversation thread.
The chat summarization feature complements the PROJECT_SUMMARY.md by capturing conversation-specific context and decisions that haven't yet been formalized into project documentation.
ClojureMCP works seamlessly with shadow-cljs for ClojureScript development. Here's how to set it up:
Start your shadow-cljs server with an nREPL port:
# Start shadow-cljs (it will use port 9000 by default, or configure in shadow-cljs.edn) npx shadow-cljs watch app
Configure Claude Desktop or other client to connect to the the shadow-cljs nREPL port:
{
"mcpServers": {
"clojure-mcp": {
"command": "/bin/sh",
"args": [
"-c",
"PATH=/opt/homebrew/bin:$PATH && clojure -X:mcp :port 9000"
]
}
}
}
OR change the shadow port to 7888 (or whatever port you have configured) and leave your client config as is.
Switch to ClojureScript REPL in Claude Desktop:
Once Claude Desktop is connected, prompt Claude to evaluate:
(shadow/repl :app)
Replace :app
with your actual build ID from shadow-cljs.edn
.
All set! Now all clojure_eval
calls will be routed to your ClojureScript REPL, allowing you to:
To exit the ClojureScript REPL and return to Clojure, have Claude evaluate:
:cljs/quit
:app
, :main
, :test
, etc.) based on your shadow-cljs.edn
configurationThis integration gives you the full power of ClojureMCP's REPL-driven development workflow for ClojureScript projects!
This is NOT required to use the Clojure MCP server.
IMPORTANT: if you have the following API keys set in your environment, then ClojureMCP will make calls to them when you use the
dispatch_agent
,architect
andcode_critique
tools. These calls will incur API charges.
There are a few MCP tools provided that are agents unto themselves and they need API keys to function.
To use the agent tools, you'll need API keys from one or more of these providers:
GEMINI_API_KEY
- For Google Gemini models
dispatch_agent
, architect
, code_critique
OPENAI_API_KEY
- For GPT models
dispatch_agent
, architect
, code_critique
ANTHROPIC_API_KEY
- For Claude models
dispatch_agent
Option 1: Export in your shell
export ANTHROPIC_API_KEY="your-anthropic-api-key-here" export OPENAI_API_KEY="your-openai-api-key-here" export GEMINI_API_KEY="your-gemini-api-key-here"
Option 2: Add to your shell profile (.bashrc
, .zshrc
, etc.)
# Add these lines to your shell profile export ANTHROPIC_API_KEY="your-anthropic-api-key-here" export OPENAI_API_KEY="your-openai-api-key-here" export GEMINI_API_KEY="your-gemini-api-key-here"
When setting up Claude Desktop, ensure it can access your environment variables by updating your config.
Personally I source
them right in bash command:
{ "mcpServers": { "clojure-mcp": { "command": "/bin/sh", "args": [ "-c", "source ~/.api_credentials.sh && PATH=/your/bin/path:$PATH && clojure -X:mcp" ] } } }
Note: The agent tools will work with any available API key. You don't need all three - just set up the ones you have access to. The tools will automatically select from available models. For now the ANTHROPIC API is limited to the displatch_agent.
This tool has a learning curve. You may in practice have to remind the LLM to develop in the REPL. You may also have to remind the LLM to use the
clojure_edit
family of tools which have linters build in to prevent unbalanced parens and the like.
The default tools included in main.clj
are organized by category to support different workflows:
Tool Name | Description | Example Usage |
---|---|---|
LS | Returns a recursive tree view of files and directories | Exploring project structure |
read_file | Smart file reader with pattern-based exploration for Clojure files | Reading files with collapsed view, pattern matching |
grep | Fast content search using regular expressions | Finding files containing specific patterns |
glob_files | Pattern-based file finding | Finding files by name patterns like *.clj |
think | Log thoughts for complex reasoning and brainstorming | Planning approaches, organizing thoughts |
Tool Name | Description | Example Usage |
---|---|---|
clojure_eval | Evaluates Clojure code in the current namespace | Testing expressions like (+ 1 2) |
bash | Execute shell commands on the host system | Running tests, git commands, file operations |
Tool Name | Description | Example Usage |
---|---|---|
clojure_edit | Structure-aware editing of Clojure forms | Replacing/inserting functions, handling defmethod |
clojure_edit_replace_sexp | Modify expressions within functions | Changing specific s-expressions |
file_edit | Edit files by replacing text strings | Simple text replacements |
file_write | Write complete files with safety checks | Creating new files, overwriting with validation |
Tool Name | Description | Example Usage |
---|---|---|
dispatch_agent | Launch agents with read-only tools for complex searches | Multi-step file exploration and analysis |
architect | Technical planning and implementation guidance | System design, architecture decisions |
Tool Name | Description | Example Usage |
---|---|---|
scratch_pad | Persistent workspace for structured data storage | Task tracking, planning, inter-tool communication with optional file persistence (disabled by default) |
code_critique | Interactive code review and improvement suggestions | Iterative code quality improvement |
read_file
)name_pattern
to find functions by name, content_pattern
to search content"area :rectangle"
or vector dispatchesclojure_edit
)clojure_eval
)bash
)dispatch_agent
)scratch_pad
)set_path
, get_path
, delete_path
for precise data manipulationDefault Behavior (Memory-Only): By default, the scratch pad operates in memory only. Data persists during the session but is lost when the MCP server stops.
Enabling Persistence:
Add to .clojure-mcp/config.edn
:
{:scratch-pad-load true ; false by default :scratch-pad-file "workspace.edn"} ; defaults to "scratch_pad.edn"
Persistence Details:
.clojure-mcp/
directory within your projectClojureMCP is designed to be highly customizable. During the alpha phase, creating your own custom MCP server is the primary way to configure the system for your specific needs.
You can customize:
The customization approach is both easy and empowering - you're essentially building your own personalized AI development companion.
📖 Complete Customization Documentation
For a quick start: Creating Your Own Custom MCP Server - This is where most users should begin.
The Clojure MCP server supports minimal project-specific configuration
through a .clojure-mcp/config.edn
file in your project's root
directory. This configuration provides security controls and
customization options for the MCP server.
Create a .clojure-mcp/config.edn
file in your project root:
your-project/
├── .clojure-mcp/
│ └── config.edn
├── src/
├── deps.edn
└── ...
allowed-directories
Controls which directories the MCP tools can access for security. Paths can be relative (resolved from project root) or absolute.
emacs-notify
Boolean flag to enable Emacs integration notifications.
Emacs notify is only a toy for now... it switches focuses on the file being edited and highlights changes as they are happening. There are probably much better ways to handle this with auto-revert and existing emacs libraries.
Prerequisites for Emacs Integration:
emacsclient
must be available in your system PATHM-x server-start
or add (server-start)
to your init file)cljfmt
Boolean flag to enable/disable cljfmt formatting in editing pipelines (default: true
). When disabled, file edits preserve the original formatting without applying cljfmt.
Available values:
true
(default) - Applies cljfmt formatting to all edited filesfalse
- Disables formatting, preserving exact whitespace and formattingWhen to use each setting:
true
- Best for maintaining consistent code style across your projectfalse
- Useful when working with files that have specific formatting requirements or when you want to preserve manual formattingbash-over-nrepl
Boolean flag to control bash command execution mode (default: true
). This setting determines whether bash commands are executed over the nREPL connection or locally on the MCP server.
Available values:
true
(default) - Execute bash commands over nREPL connection with isolated sessionfalse
- Execute bash commands locally in the Clojure MCP server processWhen to use each setting:
true
- Best for most development scenarios, as it allows you to only sandbox the nrepl server processfalse
- Useful when the nREPL server is not a Clojure process, i.e. CLJS, Babashka, ScittleTechnical details:
true
, bash commands run in a separate nREPL sessionwrite-file-guard
Controls the file timestamp tracking behavior (default: :full-read
). This setting determines when file editing is allowed based on read operations.
Available values:
:full-read
(default) - Only full reads (collapsed: false
) update timestamps. This is the safest option, ensuring the AI sees complete file content before editing.:partial-read
- Both full and collapsed reads update timestamps. Allows editing after collapsed reads, providing more convenience with slightly less safety.false
- Disables timestamp checking entirely. Files can be edited without any read requirement. Use with caution!When to use each setting:
:full-read
- Best for team environments or when working with files that may be modified externally:partial-read
- Good for solo development when you want faster workflows but still want protection against external modificationsfalse
- Only for rapid prototyping or when you're certain no external modifications will occurThe timestamp tracking system prevents accidental overwrites when files are modified by external processes (other developers, editors, git operations, etc.).
scratch-pad-load
Boolean flag to automatically load the scratch pad on startup (default: false
).
Available values:
false
(default) - Scratch pad is saved to disk but not loaded on startuptrue
- Loads existing data on startupWhen to use each setting:
false
- Best for temporary planning and session-only datatrue
- When you want data to persist across sessions and server restartsscratch-pad-file
Filename for scratch pad persistence (default: "scratch_pad.edn"
).
Configuration:
.clojure-mcp/
directory{:allowed-directories ["." "src" "test" "resources" "dev" "/absolute/path/to/shared/code" "../sibling-project"] :emacs-notify false :write-file-guard :full-read :cljfmt true :bash-over-nrepl true :scratch-pad-load false ; Default: false :scratch-pad-file "scratch_pad.edn"}
Path Resolution:
"src"
, "../other-project"
) are resolved relative to your project root"/home/user/shared"
) are used as-isSecurity:
Default Behavior:
{:allowed-directories ["." "src" "test" "dev" "resources" "docs"] :write-file-guard :full-read :cljfmt true :bash-over-nrepl true :scratch-pad-load false ; Memory-only scratch pad :scratch-pad-file "scratch_pad.edn"}
{:allowed-directories ["." "../shared-utils" "../common-config" "/home/user/reference-code"] :write-file-guard :partial-read :cljfmt true :bash-over-nrepl true :scratch-pad-load true ; Enable file persistence :scratch-pad-file "workspace.edn"}
{:allowed-directories ["src" "test"] :write-file-guard :full-read :cljfmt false ; Preserve original formatting :bash-over-nrepl false ; Use local execution only :scratch-pad-load false ; No persistence :scratch-pad-file "scratch_pad.edn"}
Note: Configuration is loaded when the MCP server starts. Restart the server after making configuration changes.
# Run tests clojure -X:test # Run specific test clojure -X:test :dirs '["test"]' :include '"repl_tools_test"' # Run linter clojure -M:lint
The core philosophy of this project is that:
GNU Affero General Public License v3.0
Copyright (c) 2025 Bruce Hauman
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.
This license ensures the project remains open source while preventing commercial exploitation without contribution back to the community.