Liking cljdoc? Tell your friends :D

toolnexus.serve


agent-cardclj/s

(agent-card cfg base skills)

§7B's Agent Card, with every default the spec names.

skills[] comes from the toolkit's SkillSource — NEVER from the tools — filtered to a2a.skills when given. The skill id is sanitized (§0.2); the skill name is not. provider is present ONLY when configured (absent, not null).

AMBIGUITY (§7B): unknown names in a2a.skills are undefined. §7C explicitly says unknown mcp.tools names are ignored; we ignore them here too, by symmetry — an untested asymmetry is exactly how six ports drift.

§7B's Agent Card, with every default the spec names.

`skills[]` comes from the toolkit's SkillSource — NEVER from the tools —
filtered to `a2a.skills` when given. The skill `id` is sanitized (§0.2); the
skill `name` is not. `provider` is present ONLY when configured (absent, not
null).

AMBIGUITY (§7B): unknown names in `a2a.skills` are undefined. §7C explicitly
says unknown `mcp.tools` names are ignored; we ignore them here too, by
symmetry — an untested asymmetry is exactly how six ports drift.
sourceraw docstring

as-mcp-serverclj/s

(as-mcp-server tk)
(as-mcp-server tk cfg)

SPEC §8C toolkit.asMcpServer(config?) — serve tk for a LOCAL agent to call, on the §7C server (same tool mapping; tool names verbatim, skill stays skill). cfg is the §7C MCPServeConfig {:name :version :tools}.

Listens on 127.0.0.1:<ephemeral>. Returns {:url "http://127.0.0.1:<port>/mcp" :token <64 hex> :close (fn [])}. Every request needs Authorization: Bearer <token> (else 401 + WWW-Authenticate: Bearer, compared in constant time); other paths 404; any method but POST 405. :close is idempotent. The token is fresh per call and never logged. The caller builds whatever mcpServers entry its agent accepts, e.g. for toolnexus.acp/connect:

{:type "http" :name "toolnexus" :url url :headers [{:name "Authorization" :value (str "Bearer " token)}]}

SPEC §8C `toolkit.asMcpServer(config?)` — serve `tk` for a LOCAL agent to
call, on the §7C server (same tool mapping; tool names verbatim, `skill`
stays `skill`). `cfg` is the §7C MCPServeConfig `{:name :version :tools}`.

Listens on 127.0.0.1:<ephemeral>. Returns
`{:url "http://127.0.0.1:<port>/mcp" :token <64 hex> :close (fn [])}`.
Every request needs `Authorization: Bearer <token>` (else 401 +
`WWW-Authenticate: Bearer`, compared in constant time); other paths 404;
any method but POST 405. `:close` is idempotent. The token is fresh per call
and never logged. The caller builds whatever `mcpServers` entry its agent
accepts, e.g. for `toolnexus.acp/connect`:

  {:type "http" :name "toolnexus" :url url
   :headers [{:name "Authorization" :value (str "Bearer " token)}]}
sourceraw docstring

exposed-toolsclj/s

(exposed-tools tk cfg)

The tools this MCP profile exposes: mcp.tools filtered to exactly those names, UNKNOWN NAMES IGNORED (§7C, explicit); omitted ⇒ every toolkit tool. Sorted, so two runtimes cannot disagree on order.

============================ KNOWN SPEC DEFECT ============================ §7C says only that mcp.tools filters the LIST. Ported literally, a tool excluded from tools/list is STILL CALLABLE through tools/call — which turns what every reader takes for an allowlist into a cosmetic filter, on the one surface (serve) whose whole job is exposing a toolkit to strangers.

This function is therefore AUTHORITATIVE FOR CALLS TOO: tools/call resolves the tool out of this same filtered set, so an excluded tool answers -32602 exactly like a tool that does not exist. Spike S21 made the same call. It is a deliberate, security-motivated deviation from a literal reading, it is reported upward, and §7C needs a sentence — not six ports each guessing.

The tools this MCP profile exposes: `mcp.tools` filtered to exactly those
names, UNKNOWN NAMES IGNORED (§7C, explicit); omitted ⇒ every toolkit tool.
Sorted, so two runtimes cannot disagree on order.

============================ KNOWN SPEC DEFECT ============================
§7C says only that `mcp.tools` filters the LIST. Ported literally, a tool
excluded from `tools/list` is STILL CALLABLE through `tools/call` — which
turns what every reader takes for an allowlist into a cosmetic filter, on the
one surface (`serve`) whose whole job is exposing a toolkit to strangers.

This function is therefore AUTHORITATIVE FOR CALLS TOO: `tools/call` resolves
the tool out of this same filtered set, so an excluded tool answers -32602
exactly like a tool that does not exist. Spike S21 made the same call. It is a
deliberate, security-motivated deviation from a literal reading, it is
reported upward, and §7C needs a sentence — not six ports each guessing.
sourceraw docstring

file-storeclj/s

(file-store dir)

§7B "file:<dir>" — one <id>.json per task.

§7B `"file:<dir>"` — one `<id>.json` per task.
sourceraw docstring

memory-storeclj/s

(memory-store)

The default store. A store is a plain map of two closures — not a protocol, not a record: those are the two things guaranteed to differ across hosts.

The default store. A store is a plain map of two closures — not a protocol,
not a record: those are the two things guaranteed to differ across hosts.
sourceraw docstring

part->content-blockclj/s

(part->content-block part)

SPEC §7C + §1B — one ContentPart as its MCP content block.

image/audio carrying bytes map to the SDK's own image/audio content; anything URL-backed becomes a resource_link (an MCP link is a uri, and a part that is already a url has no bytes to embed); a file carrying bytes becomes an embedded resource with the blob. Nothing is dropped — the reverse of toolnexus.mcp/collect-parts, so a toolkit served over MCP and consumed over MCP round-trips.

SPEC §7C + §1B — one ContentPart as its MCP content block.

`image`/`audio` carrying bytes map to the SDK's own image/audio content;
anything URL-backed becomes a `resource_link` (an MCP link is a uri, and a part
that is already a url has no bytes to embed); a `file` carrying bytes becomes an
embedded resource with the blob. Nothing is dropped — the reverse of
`toolnexus.mcp/collect-parts`, so a toolkit served over MCP and consumed over
MCP round-trips.
sourceraw docstring

resolve-storeclj/s

(resolve-store store)

§7B resolveStore(store?): nil | "memory" ⇒ in-memory (default); "file:<dir>" ⇒ a file store; anything else is used as-is.

§7B `resolveStore(store?)`: nil | "memory" ⇒ in-memory (default);
"file:<dir>" ⇒ a file store; anything else is used as-is.
sourceraw docstring

serveclj/s

(serve tk {:keys [port host a2a mcp skills store on-task on-call] :as opts})

SPEC §7B/§7C toolkit.serve(addr, {client, a2a?, mcp?, onTask?, onCall?}).

(serve tk {:port 0 :a2a {…} :mcp {…} :skills … :run f})

opts :port :host passed to koine.server (:port 0 ⇒ an OS-assigned port) :a2a §7B profile map, or nil/absent ⇒ NO A2A routes :mcp §7C profile map, or nil/absent ⇒ NO /mcp :skills the SkillSource the Agent Card advertises :client/:run the fulfilment (see run-fn-of) :store §7B TaskStore (see resolve-store) :on-task fires on a terminal Task state :on-call fires per inbound tools/call

Returns a ServeHandle: {:url :port :stop! :store :handle}. stop! is also available as a fn of the handle.

SPEC §7B/§7C `toolkit.serve(addr, {client, a2a?, mcp?, onTask?, onCall?})`.

  (serve tk {:port 0 :a2a {…} :mcp {…} :skills … :run f})

opts
  :port :host   passed to koine.server (`:port 0` ⇒ an OS-assigned port)
  :a2a          §7B profile map, or nil/absent ⇒ NO A2A routes
  :mcp          §7C profile map, or nil/absent ⇒ NO /mcp
  :skills       the SkillSource the Agent Card advertises
  :client/:run  the fulfilment (see `run-fn-of`)
  :store        §7B TaskStore (see `resolve-store`)
  :on-task      fires on a terminal Task state
  :on-call      fires per inbound `tools/call`

Returns a ServeHandle: `{:url :port :stop! :store :handle}`. `stop!` is also
available as a fn of the handle.
sourceraw docstring

stop!clj/s

(stop! handle)

Shut a ServeHandle down. Idempotent, like koine's.

Shut a ServeHandle down. Idempotent, like koine's.
sourceraw docstring

tool-result->mcpclj/s

(tool-result->mcp r)

SPEC §1 + §7C — a ToolResult as the MCP CallToolResult, the shape mcp-handler (§7C.1) emits: output → one text block (when :structured is set and output is empty, the JSON of :structured is that text, as the MCP spec asks), §1B parts follow, isError only when true, structuredContent only when :structured is set, _meta only when :meta is set.

SPEC §1 + §7C — a ToolResult as the MCP CallToolResult, the shape
`mcp-handler` (§7C.1) emits: output → one text block (when `:structured` is
set and output is empty, the JSON of `:structured` is that text, as the MCP
spec asks), §1B parts follow, `isError` only when true, `structuredContent`
only when `:structured` is set, `_meta` only when `:meta` is set.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close