The MCP server: kala.memory exposed as six tools over stdio.
The surface is the #43 lock: context / record / recall / read / history / turns, bare-named, one per memory op. The server owns the session — it installs the spine at boot and opens (or resumes) the configured session, so an agent's record needs no session argument and write provenance holds by construction. EDN at both edges: structure-bearing arguments arrive as EDN strings and every result is a readable-EDN string; kala and memory errors surface verbatim under the MCP isError flag. The transport is newline-delimited JSON-RPC 2.0 over stdio — a deliberate hand-rolled subset (initialize, tools/list, tools/call, ping), not the Java SDK: the subset is small and the artifact stays one-dependency light.
The protocol is a pure seam: handle takes a request map and returns the reply map (nil for notifications); serve! is the only line-reading loop. Nothing but protocol traffic ever reaches stdout — the server mutters to stderr or not at all.
The MCP server: kala.memory exposed as six tools over stdio. The surface is the #43 lock: context / record / recall / read / history / turns, bare-named, one per memory op. The server owns the session — it installs the spine at boot and opens (or resumes) the configured session, so an agent's record needs no session argument and write provenance holds by construction. EDN at both edges: structure-bearing arguments arrive as EDN strings and every result is a readable-EDN string; kala and memory errors surface verbatim under the MCP isError flag. The transport is newline-delimited JSON-RPC 2.0 over stdio — a deliberate hand-rolled subset (initialize, tools/list, tools/call, ping), not the Java SDK: the subset is small and the artifact stays one-dependency light. The protocol is a pure seam: handle takes a request map and returns the reply map (nil for notifications); serve! is the only line-reading loop. Nothing but protocol traffic ever reaches stdout — the server mutters to stderr or not at all.
(-main & [config-file])clojure -M:mcp [config.edn]
Config (all optional): {:conn {...}} names the connection — peer storage opts (e.g. {:storage :file :path "..."}) or client opts {:host :port :token} (ADR-0006: the shared token rides :connect); and {:session "id"} names the session to open or resume. No config means an in-memory store and a fresh session.
clojure -M:mcp [config.edn]
Config (all optional): {:conn {...}} names the connection — peer
storage opts (e.g. {:storage :file :path "..."}) or client opts
{:host :port :token} (ADR-0006: the shared token rides :connect); and
{:session "id"} names the session to open or resume. No config means
an in-memory store and a fresh session.(handle state {:keys [id method params]})One JSON-RPC request map in, the reply map out — nil for notifications. The whole server's behavior is testable here, with no stdio attached.
One JSON-RPC request map in, the reply map out — nil for notifications. The whole server's behavior is testable here, with no stdio attached.
(handle-line state line)One stdio line in, one reply line out (nil says nothing). Malformed JSON is a -32700 parse error — the id, if any was ever known, is null.
One stdio line in, one reply line out (nil says nothing). Malformed JSON is a -32700 parse error — the id, if any was ever known, is null.
(make-state conn session-id)Boot the memory side of the server: install the spine, open or resume the session. Public for the protocol-seam tests.
Boot the memory side of the server: install the spine, open or resume the session. Public for the protocol-seam tests.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |