SkillAgentSearch skills...

Modex

Modex is a Clojure MCP Library to augment your AI models with Tools, Resources & Prompts using Clojure (Model Context Protocol). Implements MCP Server & Client.

Install / Use

/learn @theronic/Modex
About this skill

Quality Score

0/100

Supported Platforms

Claude Code
Cursor

README

Modex: Model Context Protocol Server & Client Library in Clojure

Modex (MOdel + ContEXt) is a Clojure library that lets you augment your AI with new tools, resources and prompts.

Modex implements (most of) the Model Context Protocol to build MCP Servers & Clients in 'native' Clojure.

Because it's native Clojure, you don't need to deal with Anthropic's MCP Java SDK.

Modex implements the stdio transport in the 2024-11-05 MCP spec, so no need for a proxy like mcp-proxy to translate between SSE <=> stdio or vice versa.

Screenshot of Modex in Action

Claude Desktop can talk to a Modex MCP Server via its MCP client:

<img width="650" alt="image" src="https://github.com/user-attachments/assets/ef83b8da-1816-48c0-aba6-47b4b5623f7a" />

Table of Contents

  1. Quickstart
  2. What is MCP?
  3. What can Modex do?
  4. Detailed Step-by-Step Instructions
  5. Implementation
  6. Project Status
  7. Rationale
  8. FAQ
  9. Licence

Example Tools

  • Datomic MCP uses Modex to expose Datomic tools so your models can query DB schema and data in dev or prod.

Quickstart

  1. git clone git@github.com:theronic/modex.git
  2. cd modex
  3. ./build.sh builds an uberjar at target/modex-mcp-0.2.2.jar.
  4. Open your Claude Desktop Config at ~/Library/Application\ Support/Claude/claude_desktop_config.json
  5. Configure a new MCP Server that will run the uberjar at its full path:
{
  "mcpServers": {
    "modex-mcp-hello-world": {
      "command": "java",
      "args": ["-jar", "/Users/your-username/code/modex/target/modex-mcp-0.2.2.jar"]
    }
  },
  "globalShortcut": ""
}
  1. Restart Claude Desktop to activate your new MCP Server + tools :) (Cmd+R refresh does not reload config, only restarts tools)
  2. Tell Claude to "run the inc tool with 123", authorize the tool and you should see an output of 124.

What is MCP?

MCP lets you augment your AI models with Tools, Resources & Prompts:

  • Tools are things it can do, like query a database (e.g. Datomic).
  • Resources are files and data it can read, like PDF bank statements.
  • Prompts are templated messages and workflows.

Use Cases

Modex is used by datomic-mcp, which exposes our production Datomic databases to an MCP client like Claude Desktop. The AI model intelligently diagnoses support queries in production by reading our database schema and running queries that checks server state & IPs, so it can try to reach it and compare the desired state of VMs against the actual state in our clusters.

Over time, I hope to automate the bulk of our recurring support queries using Modex + other MCP tools.

What can Modex do?

Full Example

There is an MCP server example in src/modex/mcp/core.clj that defines an MCP server with some basic tools.

Your MCP client (e.g. Claude Desktop) can connect to this server and use exposed tools to provide additional context to your AI models.

Data Structures

Tools

Internally, a tool is just Tool record with several Parameter arguments:

  • (defrecord Tool [name doc args handler])
  • (defrecord Parameter [name doc type required default])

However, it is more convenient to define tools using the tool & tools macros below.

Describe a single tool with the tool macro:

The tool macro acts like defrecord, where the handler definition takes a map of arguments ala {:keys [arg1 arg2 ...]} but with additional (optional) maps for :type, :or & :doc. This metadata is used to describe the tool to the MCP Client.

  • The MCP spec currently only supports :string & :number tool parameter types.
  • Presence in the :or map implies optionality.
  • Missing parameter docstrings default to parameter name string.
(require '[modex.mcp.tools :as tools])

(def add-tool
  (tools/tool
    ; feels like defrecord.
    (add [{:keys [x y]
           :type {x :number
                  y :number}
           :or   {y 0} ; y is optional due to its presence in the :or map.
           :doc  {x "First number"
                  y "Second number"}}]
         [(+ x y)]))) ; tools should return a vector (to support multiple values).

Invoke a Tool with invoke-tool incl. validation:

Invocation uses a map of arguments like an MCP client would for a tools/call request:

(tools/invoke-tool add-tool {:x 5 :y 6}) ; Modex will map these arguments and call the handler.
=> {:success true, :results [11]} ; note :results is vector to support multiple values.

Invoke a tool handler directly to skip validation & error-handling:

(tools/invoke-handler (:handler add-tool) {:x 5 :y 6})
=> [11] ; note vector result to support multiple values.

Define a Toolset with tools macro

The tools macro just calls the tool macro for each tool definition and returns a map of tools keyed on tool name (keyword):

(def my-tools
  "Define your tools here."
  (tools/tools
    (greet
      "Greets a person by name." ; tools can have a docstring
      [{:keys [first-name last-name]
        :doc {first-name "A person's first name."
              last-name  "A person's last name (optional)."}
        :type {first-name :string
               last-name  :string}
        :or {last-name nil}}] ; last-name is optional, implied by presence in `:or` map.
      ; tools should return collection.
      [(str "Hello from Modex, "
            (if last-name ; args can be optional
              (str first-name " " last-name)
              first-name) "!")])
    
    (add
      "Adds two numbers."
      ; Tool handler args also support deprecated vector arg-style,
      ; but this is superseded by the newer map-destructuring style:
      [^{:type :number :doc "First number to add."} a
       ^{:type :number :doc "Second number to add."} b]
      [(+ a b)])

    (subtract
      "Subtracts two numbers (- a b)"
      [^{:type :number :doc "First number."} a
       ^{:type :number :doc "Second number."} b]
      [(- a b)])

    (error-handling
      "This tool throws intentionally. Modex will handle errors for you."
      []
      (throw (ex-info "Modex will handle exceptions." {})))))

Create a Modex MCP Server + tools:

(require '[modex.mcp.server :as server])
(def my-mcp-server
  "Here we create a reified instance of AServer. Only tools are presently supported."
  (server/->server
    {:name       "Modex MCP Server"
     :version    "0.0.2"
     :initialize (fn [_init-params] ; init-params, but may contain client capabilities in future.
                   "Do long-running setup & blocking I/O here, like connecting to prod database.")
     :tools      my-tools
     :prompts    nil    ; Prompts are WIP.
     :resources  nil})) ; Resources are WIP.

Start your MCP Server

(server/start-server! my-mcp-server)

Or put that in your -main function.

Protocols

Modex exposes an AServer protocol and a DSL to define tools protocols that describe MCP servers, which expose tools, resources & prompts.

AServer Protocol:

(defprotocol AServer
  (protocol-version [this])
  
  (server-name [this])
  (version [this])

  (capabilities [this])
  
  (initialize [this _init-params]) ; init-params is empty for now, but may contain client capabilities in future.

  (list-tools [this])
  (call-tool [this tool-name arg-map])

  (list-resources [this])
  (list-prompts [this]))

Detailed Step-by-Step Instructions

Step 1: Build the Uberjar

Before you can run it, you have to build it first. The build outputs an uberjar, which is like a Java executable.

clojure -T:build uber

or run the helper which does that:

./build.sh

(you might need to run chmod +x build.sh)

Step 2: Open Claude Desktop Config

Open your Claude Desktop Configuration file, claude_desktop_config.json, which on MacOS should be at:

~/Library/Application\ Support/Claude/claude_desktop_config.json

Step 3: Configure your MCP Server

Add an element under mcpServers so it looks like this:

{
  "mcpServers": {
    "modex": {
      "command": "java",
      "args": ["-jar", "/Users/your-username/code/modex/target/modex-mcp-0.2.2.jar"]
    }
  },
  "globalShortcut": ""
}

This tells Claude Desktop there is a tool named modex and it can connect to by running java -jar /path/to/your/uber.jar.

The way this works is that your local MCP Client (i.e. Claude Desktop), starts your MCP server process and communicates with it via stdin/stdout pipes.

Step 4: Restart Claude Desktop

You should now be able to ask Claude "run foo", or "what does foo say?" and it will run the foo tool and reply with the response, "Hello, AI!".

Implementation

Modex implements an MCP client & server in Clojure that is mostly compliant with the 2024-11-05 MCP Spec.

Messages are encoded using the JSON-RPC 2.0 wire format.

There are 3 message types:

  • Requests have {:keys [id method ?params]}
  • Responses have {:keys [id result ?error]}
  • Notifications have {:keys [method ?params}

MCP supports two transport types:

  • [x] stdio/stdout – implemented in Modex.
  • [ ] Server-Sent Events (SSE) – not implemented yet. Useful for restricted networks

Project Status

  • [x] Passing tests
  • [x] Ergonomics (AServer / AClient protocol?)
  • [x] Tools
  • [x] nREPL for live changes to running process
  • [ ] Resources
  • [ ] Prompts
  • [in progress] SSE support
  • [in progress] Streaming HTTP Support (2025-03-26 MCP spec)

Rationale

There is an existing library [mcp-clj](https://github.com/hugodun

Related Skills

View on GitHub
GitHub Stars112
CategoryDevelopment
Updated15d ago
Forks11

Languages

Clojure

Security Score

85/100

Audited on Mar 15, 2026

No findings