关于 Modex: Model Context Protocol Server & Client Library in Clojure
Modex 是一个 Clojure 库,用于构建 MCP 服务与客户端,可为 AI 模型添加工具、资源和提示词。它直接使用 Clojure 实现,不依赖 Anthropic 的 Java SDK。项目面向 Clojure 开发者,目前以 stdio 传输为主。
主要功能
- 01使用原生 Clojure 实现 MCP 服务与客户端
- 02通过 tool 与 tools 宏定义工具及参数
- 03内置参数校验的工具调用(invoke-tool)
- 04基于 stdio 的 JSON-RPC 2.0 传输
- 05支持 nREPL 实时修改运行中的进程
适用场景
- 01将 Datomic 数据库的查询能力暴露给 Claude Desktop
- 02在 Claude Desktop 中以工具形式调用 Clojure 函数
- 03用 Clojure 快速搭建本地 MCP 服务原型
MCP 相关
Modex 可构建 MCP 服务,将工具暴露给 MCP 客户端,例如 Claude Desktop。它也包含客户端实现。项目基于 2024-11-05 版本的 MCP 规范,大部分兼容。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Modex:Clojure 中的模型上下文协议服务端与客户端库
Modex(MOdel + ContEXt)是一个 Clojure 库,可让你为 AI 添加新的工具、资源和提示词。
Modex 实现了 模型上下文协议 的(大部分)内容,可使用“原生” Clojure 构建 MCP 服务端和客户端。
由于它是原生 Clojure,你无需处理 Anthropic 的 MCP Java SDK。
Modex 实现了 2024-11-05 版 MCP 规范中的 stdio 传输,因此无需使用
mcp-proxy 之类的代理来在 SSE <=> stdio 之间进行转换。
Modex 实际运行截图
Claude Desktop 可以通过其 MCP 客户端与 Modex MCP 服务通信:
目录
示例工具
- Datomic MCP 使用 Modex 暴露 Datomic 工具,让模型能够在开发或生产环境中查询数据库架构和数据。
快速入门
git clone [email protected]:theronic/modex.gitcd modex./build.sh会在target/modex-mcp-0.2.2.jar构建一个 uberjar。- 打开 Claude Desktop 配置文件:
~/Library/Application\ Support/Claude/claude_desktop_config.json - 配置一个新的 MCP 服务,使其运行 uberjar 的_完整路径_:
{
"mcpServers": {
"modex-mcp-hello-world": {
"command": "java",
"args": ["-jar", "/Users/your-username/code/modex/target/modex-mcp-0.2.2.jar"]
}
},
"globalShortcut": ""
}
- 重启 Claude Desktop 以启用新的 MCP 服务和工具 :)(Cmd+R 刷新不会重新加载配置,只会重启工具)
- 告诉 Claude“运行 inc 工具并传入 123”,授权该工具,你应该会看到输出 124。
什么是 MCP?
MCP 可让你为 AI 模型添加工具、资源和提示词:
- 工具是它可以执行的操作,例如查询数据库(如 Datomic)。
- 资源是它可以读取的文件和数据,例如 PDF 银行对账单。
- 提示词是模板化的消息和工作流。
使用场景
datomic-mcp 使用 Modex 将我们的生产 Datomic 数据库暴露给 Claude Desktop 等 MCP 客户端。AI 模型会通过读取数据库架构并运行查询来检查服务器状态和 IP,从而智能地诊断生产环境中的支持请求;它可以尝试连接服务器,并比较集群中虚拟机的期望状态与实际状态。
我希望今后能使用 Modex 和其他 MCP 工具,将大部分重复出现的支持请求自动化。
Modex 能做什么?
完整示例
src/modex/mcp/core.clj 中有一个 MCP 服务示例,其中定义了一些基本工具。
你的 MCP 客户端(例如 Claude Desktop)可以连接到此服务,并使用其中暴露的工具为 AI 模型提供额外上下文。
数据结构
工具
在内部,工具就是一个带有若干 Parameter 参数的 Tool 记录:
(defrecord Tool [name doc args handler])(defrecord Parameter [name doc type required default])
不过,使用下面的 tool 和 tools 宏定义工具会更加方便。
使用 tool 宏描述单个工具:
tool 宏的作用类似于 defrecord,处理器定义接收一个参数映射,形式如 {:keys [arg1 arg2 ...]},但还可以带有 :type、:or 和 :doc 这几个额外的(可选)映射。这些元数据用于向 MCP 客户端描述工具。
- MCP 规范目前仅支持
:string和:number工具参数类型。 - 在
:or映射中出现的参数即为可选参数。 - 缺失的参数文档字符串默认使用参数名称字符串。
(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-tool 调用工具(含验证):
调用时使用参数映射,就像 MCP 客户端发起 tools/call 请求一样:
(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.
直接调用工具处理程序以跳过验证和错误处理:
(tools/invoke-handler (:handler add-tool) {:x 5 :y 6})
=> [11] ; note vector result to support multiple values.
使用 tools 宏定义工具集
tools 宏会为每个工具定义调用 tool 宏,并返回一个以工具名称(关键字)为键的工具映射:
(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." {})))))
创建 Modex MCP 服务和工具:
(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.
启动 MCP 服务
(server/start-server! my-mcp-server)
或者将其放入你的 -main 函数中。
协议
Modex 提供 AServer 协议,以及用于定义工具协议的 DSL,用来描述可公开工具、资源和提示词的 MCP 服务。
AServer 协议:
(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]))
详细分步说明
第 1 步:构建 Uberjar
运行之前,必须先构建。构建会生成一个 uberjar,类似于 Java 可执行文件。
clojure -T:build uber
或者运行执行此操作的辅助脚本:
./build.sh
(你可能需要运行 chmod +x build.sh)
第 2 步:打开 Claude Desktop 配置文件
打开 Claude Desktop 配置文件 claude_desktop_config.json。在 MacOS 上,该文件应位于:
~/Library/Application\ Support/Claude/claude_desktop_config.json
第 3 步:配置 MCP 服务
在 mcpServers 下添加一个条目,使其如下所示:
{
"mcpServers": {
"modex": {
"command": "java",
"args": ["-jar", "/Users/your-username/code/modex/target/modex-mcp-0.2.2.jar"]
}
},
"globalShortcut": ""
}
这会告知 Claude Desktop 有一个名为 modex 的工具,并且可以通过运行 java -jar /path/to/your/uber.jar 连接到它。
其工作方式是:本地 MCP 客户端(即 Claude Desktop)启动 MCP 服务进程,并通过 stdin/stdout 管道与其通信。
第 4 步:重启 Claude Desktop
现在,你应该可以询问 Claude“运行 foo”或“foo 会说什么?”,它会运行
foo 工具并回复“你好,AI!”。
实现
Modex 使用 Clojure 实现了 MCP 客户端和服务,并且 基本 符合 2024-11-05 MCP 规范。
消息采用 JSON-RPC 2.0 线格式编码。
消息有 3 种类型:
- 请求包含
{:keys [id method ?params]} - 响应包含
{:keys [id result ?error]} - 通知包含
{:keys [method ?params}
MCP 支持两种传输类型:
- stdio/stdout —— 已在 Modex 中实现。
- Server-Sent Events (SSE) —— 尚未实现。适用于受限网络
项目状态
- 测试通过
- 易用性(AServer / AClient 协议?)
- 工具
- 用于实时修改运行中进程的 nREPL
- 资源
- 提示词
- [in progress] SSE 支持
- [in progress] 流式 HTTP 支持(2025-03-26 MCP 规范)
设计原因
现有一个使用 SSE 的库 mcp-clj,因此需要通过 mcp-proxy 将 SSE 转发到 stdio,或将 stdio 转发到 SSE。我对此很不满,于是创建了 Modex。
常见问题
MCP 客户端(例如 Claude Desktop)连接时,我可以修改服务吗?
目前还不行,不过我很快会添加 nREPL,这样 Claude Desktop 连接到进程时,你就可以对更改进行求值,而不必重新构建 uberjar。
顺便说一下,我试过让它运行 clojure -M -m modex.mcp.server,但你无法设置 Claude Desktop 的工作目录。
因此,目前我会重新构建 uberjar 并重启 Claude Desktop。之后会修复。
感谢付费使用 Modex 的客户:
许可证
简而言之:
- 非商业用途免费:可免费使用、修改和分享,但需遵循 GPLv3,并保持开源。
- 商业用途:想将修改内容保密?一次性支付 $20,即可获得永久商业许可证。这笔费用用于支付我的 AI 令牌成本,让我能继续公开开发。
本工具采用 GNU 通用公共许可证 v3.0(GPLv3) 授权。您可以自由使用、修改和分发本工具,但任何衍生作品也必须采用 GPLv3 授权并开源。这样可确保社区能够持续免费使用本工具,同时要求对任何修改保持透明。
如果您希望在专有项目中使用或修改本工具,且不以 GPLv3 发布修改内容,则可以购买商业许可证。购买后,您可以将修改内容保密,用于个人或商业用途。 如需获取商业许可证,请通过 [email protected] 联系我。
作者
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。