Skip to content

collectTools — gather decorated functions

Clojure (JVM) + cljgo · package net.clojars.muthuishere/toolnexus · SPEC §6 · clojure/src/toolnexus/native.cljc

Sweep a module or class and collect every function marked as a tool.

A vector. toolnexus.native/native-tool returns a plain map, so a namespace of tools is an ordinary def that names them all, and the “collection” is the thing you were going to write anyway:

(ns myapp.tools
(:require [clojure.string :as str]
[toolnexus.native :as native]))
(def upper
(native/native-tool
{:name "upper"
:description "Uppercase the text"
:input-schema {:type "object" :properties {:text {:type "string"}} :required ["text"]}
:run (fn [args] (str/upper-case (str (:text args))))}))
(def reverse-text
(native/native-tool
{:name "reverse_text"
:description "Reverse the text"
:input-schema {:type "object" :properties {:text {:type "string"}} :required ["text"]}
:run (fn [args] (str/reverse (str (:text args))))}))
(def all
"Every tool this namespace exports. One place to add to, one place to read."
[upper reverse-text])

Hand that vector to toolnexus.core/build under :tools, next to every other source:

(require '[toolnexus.core :as toolnexus]
'[myapp.tools :as mytools])
(def tk (toolnexus/build {:mcp "examples/mcp.json"
:skills "examples/skills"
:tools mytools/all}))
(toolnexus/tool-names tk)
;; => ["apply_patch" "bash" "edit" "glob" "grep" "question" "read" "reverse_text"
;; "skill" "todowrite" "upper" "webfetch" "write"]

If you really want the namespace scanned rather than listed, ns-publics will do it on the JVM — but it is host-specific reflection and this port keeps zero of that in the shared .cljc tree, so it would be your code and not the library’s, and it would not run on cljgo. The explicit vector is also the only version in which the tool list is a diff a reviewer can read.