# Creating Addons **Status**: Stable (2026-02-15) **See also**: [ADR-0007](ADR-0007-hive-addons-architecture) | [Classpath Discovery](Addon-Classpath-Discovery) ## Overview hive-mcp includes a **deps-new template** that scaffolds a complete addon project with IAddon protocol implementation, classpath manifest, tests, and documentation. One command gives you a working addon ready to extend. ## Quick Start ### Generate a new addon project ```bash # Using local hive-mcp checkout: clojure -Sdeps '{:deps {hive-mcp {:local/root "/path/to/hive-mcp"}}}' \ -Tnew create :template hive-agi/addon :name com.example/my-addon # Using the published release (Clojars): clojure -Sdeps '{:deps {io.github.hive-agi/hive-mcp {:mvn/version "0.19.0"}}}' \ -Tnew create :template hive-agi/addon :name com.example/my-addon ``` Check the [releases page](https://github.com/hive-agi/hive-mcp/releases) for the current version. Remember the addon itself must **not** depend on hive-mcp at runtime — see [[Core-Engine]]; the dependency above exists only so `-Tnew` can find the template. This generates: ``` my-addon/ +-- deps.edn # Dependencies (hive-mcp + dev tools) +-- .hive-project.edn # Hive project descriptor +-- README.md # Getting started guide +-- src/com/example/ | +-- addon.clj # IAddon implementation (defrecord) +-- test/com/example/ | +-- addon_test.clj # 12 unit tests covering full lifecycle +-- resources/META-INF/hive-addons/ +-- my-addon.edn # Classpath manifest (auto-discovered) ``` ### Start developing ```bash cd my-addon # Update deps.edn to point at your local hive-mcp: # io.github.hive-agi/hive-mcp {:local/root "../hive-mcp"} # Start REPL clojure -M:dev:nrepl ``` ### Verify in REPL ```clojure (require '[com.example.addon :as addon]) (require '[hive-mcp.addons.protocol :as proto]) (def a (addon/->addon)) (proto/addon-id a) ;=> "my-addon" (proto/initialize! a {}) ;=> {:success? true} (proto/tools a) ;=> [{:name "hello" ...}] (proto/health a) ;=> {:status :ok :details {...}} ``` ## The IAddon Protocol Every addon implements `hive-mcp.addons.protocol/IAddon` (8 methods): ```clojure (defprotocol IAddon (addon-id [this]) ;; Unique string ID (e.g., "my-addon") (addon-type [this]) ;; :native | :mcp-bridge | :external (capabilities [this]) ;; #{:tools :schema :resources :prompts :mcp-bridge :health-reporting} (initialize! [this config]) ;; Start services, return {:success? bool :errors [...]} (shutdown! [this]) ;; Release resources (tools [this]) ;; Return seq of MCP tool definitions (schema-extensions [this]) ;; Return DataScript schema additions (or {}) (health [this])) ;; Return {:status :ok|:degraded|:down :details {...}} ``` ### Addon Types | Type | Use case | Example | |------|----------|---------| | `:native` | Clojure code in same JVM | lsp-mcp, scc-mcp, clj-kondo-mcp | | `:mcp-bridge` | Proxy to external MCP server via stdio/sse | haystack bridge | | `:external` | Non-MCP external integrations (REST, CLI) | Custom API adapters | ## Adding Tools Edit `addon.clj` and add entries to the `tool-defs` vector: ```clojure (def ^:private tool-defs [{:name "my-tool" :description "What my tool does" :inputSchema {:type "object" :properties {"param" {:type "string" :description "Input parameter"}} :required ["param"]} :handler handle-my-tool}]) ``` Handlers receive keyword-ized params and return MCP content items: ```clojure (defn- handle-my-tool [{:keys [param]}] {:type "text" :text (str "Result: " param)}) ``` ## The Manifest The classpath manifest at `resources/META-INF/hive-addons/.edn` is what makes auto-discovery work. The template generates one automatically: ```edn {:addon/id "my-addon" :addon/type :native :addon/version "0.1.0" :addon/init-ns "com.example.addon" :addon/init-fn "init-as-addon!" :addon/config {} :addon/capabilities #{:tools} :addon/dependencies #{} ;; Other addon IDs that must load first :addon/description "My addon description" :addon/author "Your Name" :addon/license "AGPL-3.0-or-later"} ``` **Required fields**: `:addon/id`, `:addon/type`, `:addon/init-ns`, `:addon/init-fn` Config values support `${ENV_VAR}` expansion (e.g., `{:api-key "${MY_API_KEY}"}`). ## How Discovery Works At JVM startup, hive-mcp: 1. **Scans classpath** for `META-INF/hive-addons/*.edn` files across all JARs and directories 2. **Validates** each manifest against a Malli schema 3. **Topological sorts** by `:addon/dependencies` (Kahn's algorithm) 4. **Calls** `init-as-addon!` on each addon's init namespace 5. **Registers** the returned IAddon record into the addon registry 6. **Initializes** the addon (starts services, registers tools) Zero changes to hive-mcp core code needed. ## Composability Principles - **Never modify another addon's core** to extend it. Plug a new brick via IAddon instead. - **Supertool pattern**: Register a tool under the SAME NAME as a core tool to override it (last-write-wins in the tool registry). - **Schema extensions via `register-schema!`** augment existing tool schemas (Open/Closed Principle). - **Extension registry**: Use `ext/get-extension` and `ext/contribute-commands!` for cross-addon collaboration. ## Deployment ### As a deps.edn dependency The consumer just adds your addon to their classpath: ```edn {:deps {io.github.hive-agi/hive-mcp {:git/tag "v0.12.0" :git/sha "..."} com.example/my-addon {:local/root "../my-addon"}}} ``` ### Docker / Uberjar Each addon's `META-INF/hive-addons/.edn` has a unique filename, so no collisions when merged into an uberjar. ### K8s runtime injection Mount addon JARs without rebuilding images: ```yaml env: - name: JAVA_TOOL_OPTIONS value: "-cp /app/lib/*:/addons/*" volumeMounts: - name: addon-jars mountPath: /addons ``` ## MCP Bridge Addons For addons that proxy external MCP servers, implement both `IAddon` and `IMcpBridge`: ```clojure (defprotocol IMcpBridge (bridge-connect! [this config]) (bridge-disconnect! [this]) (bridge-call-tool [this tool-name params]) (bridge-list-tools [this])) ``` Set manifest type to `:mcp-bridge` and add `:mcp-bridge` to capabilities. See `hive-mcp.addons.stdio_bridge` for a reference implementation. ## Existing Addons (Reference) | Addon | Type | What it does | Source | |-------|------|--------------|--------| | `lsp-mcp` | `:native` | Clojure-LSP bridge contributing analysis commands | [github.com/hive-agi/lsp-mcp](https://github.com/hive-agi/lsp-mcp) | | `scc-mcp` | `:native` | Code complexity metrics via scc | [github.com/hive-agi/scc-mcp](https://github.com/hive-agi/scc-mcp) | | `clj-kondo-mcp` | `:native` | Clojure linting via clj-kondo | [github.com/hive-agi/clj-kondo-mcp](https://github.com/hive-agi/clj-kondo-mcp) | | `emacs-addon` | `:native` | Emacs buffer/editor integration via emacsclient | bundled in hive-mcp | Study `lsp-mcp` or `scc-mcp` for real-world examples of the IAddon lifecycle, tool registration, and classpath manifest patterns. ## Setting Up Addons (Walkthrough) This section walks through cloning an existing addon and wiring it into your hive-mcp instance. We'll use `scc-mcp` as the example, but the same steps apply to any addon. ### 1. Clone addon repos alongside hive-mcp Addons are sibling directories to your hive-mcp checkout. A typical workspace looks like: ``` ~/projects/ +-- hive-mcp/ # core engine (AGPL) +-- lsp-mcp/ # Clojure-LSP addon +-- scc-mcp/ # code complexity addon +-- clj-kondo-mcp/ # linting addon +-- my-addon/ # your own addon ``` Clone whichever addons you want: ```bash cd ~/projects git clone https://github.com/hive-agi/lsp-mcp.git git clone https://github.com/hive-agi/scc-mcp.git git clone https://github.com/hive-agi/clj-kondo-mcp.git ``` ### 2. Add addons to hive-mcp's classpath via deps.edn Edit your hive-mcp `deps.edn` (or a `:local` alias) to include addon directories: ```edn {:deps {io.github.hive-agi/scc-mcp {:local/root "../scc-mcp"} io.github.hive-agi/lsp-mcp {:local/root "../lsp-mcp"} io.github.hive-agi/clj-kondo-mcp {:local/root "../clj-kondo-mcp"}}} ``` That's it. When you start hive-mcp, these directories are added to the JVM classpath. ### 3. Why this works: classpath manifest discovery Each addon ships a small EDN file at a well-known path: ``` scc-mcp/ +-- resources/ +-- META-INF/ +-- hive-addons/ +-- scc-mcp.edn <- classpath manifest ``` The JVM classpath merges `resources/` directories from all dependencies. At startup, hive-mcp calls: ```clojure (.getResources (ClassLoader/getSystemClassLoader) "META-INF/hive-addons") ``` This returns **every** `META-INF/hive-addons/` directory across all JARs and local paths on the classpath. The scanner reads all `*.edn` files it finds, validates them, topologically sorts by `:addon/dependencies`, and initializes each addon in order. This is the same mechanism Java's `ServiceLoader` uses with `META-INF/services/`, and how SLF4J, JDBC drivers, and Spring Boot auto-configuration discover implementations at runtime. ### 4. The reify pattern: manifest to live IAddon Each manifest points to an init function: ```edn ;; scc-mcp/resources/META-INF/hive-addons/scc-mcp.edn {:addon/id "scc-mcp" :addon/type :native :addon/init-ns "scc-mcp.init" :addon/init-fn "init-as-addon!"} ``` At startup, hive-mcp: 1. **Resolves** the namespace: `(require 'scc-mcp.init)` 2. **Calls** the init function: `(scc-mcp.init/init-as-addon!)` 3. The init function returns an **IAddon `defrecord`** instance — a concrete reification of the protocol 4. hive-mcp **registers** the record in the addon registry 5. The addon's `tools` method is called, and its MCP tools become available ```clojure ;; What happens inside init-as-addon! (simplified): (defrecord SccAddon [config] proto/IAddon (addon-id [_] "scc-mcp") (tools [_] [{:name "scc_analyze" :handler handle-analyze ...}]) ...) (defn init-as-addon! [] ;; Register the IAddon record, return confirmation (let [addon (->SccAddon {})] (proto/initialize! addon {}) {:registered ["scc-mcp"] :total 1})) ``` The key insight: **the protocol is defined in hive-mcp (open), the implementation lives in the addon (separate repo)**. Adding an addon to the classpath is the only integration step — no hive-mcp code changes, no configuration files to edit, no import statements to add. ### 5. Verify it loaded After starting hive-mcp, check that your addon was discovered: ```clojure ;; In REPL or via MCP tool call: (require '[hive-mcp.addons.loader :as loader]) (loader/loaded-addons) ;=> ["scc-mcp" "lsp-mcp" "clj-kondo-mcp" ...] ``` Or use the MCP health tool to see addon status. ## Template Source The deps-new template lives at: ``` hive-mcp/resources/hive-agi/addon/ +-- template.edn # Transform rules (src, test, resources mapping) +-- root/ +-- deps.edn # Template for generated deps.edn +-- .hive-project.edn # Template for hive project descriptor +-- README.md # Template for generated README +-- src/addon.clj # Template for IAddon implementation +-- test/addon_test.clj # Template for tests (12 test cases) +-- resources/META-INF/hive-addons/addon-manifest.edn ``` ## Related - [[Addon-Classpath-Discovery]] -- Technical details of the discovery mechanism - [[ADR-0007-hive-addons-architecture]] -- Architecture decision record - [[Ecosystem]] -- Broader hive-mcp ecosystem and open source strategy