Liking cljdoc? Tell your friends :D

toolnexus.mcp-handler


decode-header-valueclj/s

(decode-header-value v)

An Mcp-Name header value with the =?base64?<std-base64>?= sentinel decoded (SPEC §2.3). [value ok?] — an absent / empty header is ["" false].

An Mcp-Name header value with the `=?base64?<std-base64>?=` sentinel decoded
(SPEC §2.3). [value ok?] — an absent / empty header is ["" false].
sourceraw docstring

implemented-versionsclj/s

MCP protocol versions whose wire this handler implements (ADR 0039/0040). 2026-07-28 is the stateless wire of SPEC §7C.2 and is served only when listed in :protocol-versions.

MCP protocol versions whose wire this handler implements (ADR 0039/0040).
2026-07-28 is the stateless wire of SPEC §7C.2 and is served only when listed
in `:protocol-versions`.
sourceraw docstring

load-mcp-skillsclj/s

(load-mcp-skills dir)

SPEC §7C.2 loadMcpSkills(dir) — every skill under dir (**/SKILL.md, any depth) as :list-skills entries {:name :frontmatter {:name :description} :files [{:path :text}]}. Frontmatter is parsed as in §3 (trimmed strings); a skill without a name is skipped. Files are every regular file under the skill directory that is valid UTF-8 (binary files are skipped — the wire is text), /-separated paths sorted by code point. A path reached THROUGH a symlink is skipped (koine's walk follows links; this compares each path with its real path, so a linked file or directory is never published).

SPEC §7C.2 `loadMcpSkills(dir)` — every skill under `dir` (`**/SKILL.md`, any
depth) as `:list-skills` entries {:name :frontmatter {:name :description}
:files [{:path :text}]}. Frontmatter is parsed as in §3 (trimmed strings); a
skill without a `name` is skipped. Files are every regular file under the
skill directory that is valid UTF-8 (binary files are skipped — the wire is
text), `/`-separated paths sorted by code point. A path reached THROUGH a
symlink is skipped (koine's walk follows links; this compares each path with
its real path, so a linked file or directory is never published).
sourceraw docstring

mcp-auth-errorclj/s

(mcp-auth-error status challenge)
(mcp-auth-error status challenge reason)

SPEC §7C.2 MCPAuthError: THROW this from any :authenticate hook to answer status (401|403; nil ⇒ 401) with WWW-Authenticate: challenge (a non-empty :www-authenticate result wins) and the body {"error":"unauthorized"}, on both wires. reason is the exception message and never reaches the wire.

SPEC §7C.2 `MCPAuthError`: THROW this from any `:authenticate` hook to answer
`status` (401|403; nil ⇒ 401) with `WWW-Authenticate: challenge` (a non-empty
`:www-authenticate` result wins) and the body `{"error":"unauthorized"}`,
on both wires. `reason` is the exception message and never reaches the wire.
sourceraw docstring

mcp-auth-error?clj/s

(mcp-auth-error? e)

True when e is an mcp-auth-error.

True when `e` is an `mcp-auth-error`.
sourceraw docstring

mcp-handlerclj/s

(mcp-handler tk)
(mcp-handler tk cfg)

SPEC §7C.1 toolkit.mcpHandler(cfg) — an embeddable streamable-HTTP MCP server. Returns {:handler (fn [ring-request] ring-response) …}; mount (:handler h) on any Ring stack and call (notify-tools-changed! h) when the tool set moves. Every cfg key is optional:

:name :title :version :instructions static serverInfo (defaults "toolnexus" / "0.1.0"; empty title omitted) :server-info (fn [ctx] {:name :title :version :instructions}) wins when set :protocol-versions newest first; entries outside implemented-versions dropped; default ["2025-06-18"]. Listing "2026-07-28" enables the stateless 2026 wire (SPEC §7C.2) — alone, or beside legacy versions on one mount :list-skills (fn [ctx] skills) — SEP-2640 skills extension on the 2026 wire; skills are {:name :frontmatter? :files [{:path :text}]} (load-mcp-skills builds them); nil ⇒ not advertised :authenticate (fn [ring-request] identity) — a THROW ⇒ 401; a thrown mcp-auth-error ⇒ its status + challenge (both wires). mcp-server-auth builds one (toolnexus.mcp-server-auth) :www-authenticate (fn [ring-request ex] header-string) :list-tools (fn [ctx] tools) — per request, for tools/list AND tools/call (a name outside it ⇒ -32602, never executed) :before-call (fn [ctx tool args] {:kind :allow|:deny|:confirm :message :result}) nil ⇒ allow; a throw ⇒ deny with its message :confirm-timeout-ms elicitation round trip bound (default 300000) :on-call (fn [event]) {:name :source :ms :is-error :err :result-bytes :decision :identity :session-id}; throws isolated :list-resources (fn [ctx]) / :read-resource (fn [ctx uri]) :list-prompts (fn [ctx]) / :get-prompt (fn [ctx name args]) :session-ids {:generate (fn [ctx]) :validate (fn [ctx id]) :terminate (fn [ctx id])} :stateless true — no session ids issued or checked; no elicitation :stateless-session-id returned on initialize in stateless mode, never checked :max-body-bytes POST cap (default 4 MiB ⇒ 413)

ctx (every hook, and every tool built with :context? true) is {:identity :request :session-id :meta} — see mcp-identity & co.

SPEC §7C.1 `toolkit.mcpHandler(cfg)` — an embeddable streamable-HTTP MCP
server. Returns `{:handler (fn [ring-request] ring-response) …}`; mount
`(:handler h)` on any Ring stack and call `(notify-tools-changed! h)` when the
tool set moves. Every cfg key is optional:

  :name :title :version :instructions   static serverInfo (defaults
                                        "toolnexus" / "0.1.0"; empty title omitted)
  :server-info (fn [ctx] {:name :title :version :instructions})   wins when set
  :protocol-versions  newest first; entries outside `implemented-versions`
                      dropped; default ["2025-06-18"]. Listing "2026-07-28"
                      enables the stateless 2026 wire (SPEC §7C.2) — alone,
                      or beside legacy versions on one mount
  :list-skills (fn [ctx] skills)  — SEP-2640 skills extension on the 2026
                      wire; skills are {:name :frontmatter? :files [{:path :text}]}
                      (`load-mcp-skills` builds them); nil ⇒ not advertised
  :authenticate (fn [ring-request] identity)  — a THROW ⇒ 401; a thrown
                      `mcp-auth-error` ⇒ its status + challenge (both wires).
                      `mcp-server-auth` builds one (toolnexus.mcp-server-auth)
  :www-authenticate (fn [ring-request ex] header-string)
  :list-tools (fn [ctx] tools)  — per request, for tools/list AND tools/call
                                (a name outside it ⇒ -32602, never executed)
  :before-call (fn [ctx tool args] {:kind :allow|:deny|:confirm :message :result})
                nil ⇒ allow; a throw ⇒ deny with its message
  :confirm-timeout-ms   elicitation round trip bound (default 300000)
  :on-call (fn [event])  {:name :source :ms :is-error :err :result-bytes
                          :decision :identity :session-id}; throws isolated
  :list-resources (fn [ctx]) / :read-resource (fn [ctx uri])
  :list-prompts (fn [ctx]) / :get-prompt (fn [ctx name args])
  :session-ids {:generate (fn [ctx]) :validate (fn [ctx id]) :terminate (fn [ctx id])}
  :stateless true  — no session ids issued or checked; no elicitation
  :stateless-session-id  returned on initialize in stateless mode, never checked
  :max-body-bytes  POST cap (default 4 MiB ⇒ 413)

ctx (every hook, and every tool built with `:context? true`) is
{:identity :request :session-id :meta} — see `mcp-identity` & co.
sourceraw docstring

mcp-identityclj/s

(mcp-identity ctx)

What :authenticate returned (nil without it).

What :authenticate returned (nil without it).
sourceraw docstring

mcp-requestclj/s

(mcp-request ctx)

The inbound Ring request.

The inbound Ring request.
sourceraw docstring

mcp-request-metaclj/s

(mcp-request-meta ctx)

The JSON-RPC request's params._meta (nil when absent).

The JSON-RPC request's `params._meta` (nil when absent).
sourceraw docstring

mcp-session-idclj/s

(mcp-session-id ctx)

The Mcp-Session-Id of the request ("" if none).

The Mcp-Session-Id of the request ("" if none).
sourceraw docstring

memory-session-idsclj/s

(memory-session-ids)

The default :session-ids: {:generate :validate :terminate} over an atom. A host plugs its own (signed ids, a DB) so any replica validates any session.

The default `:session-ids`: {:generate :validate :terminate} over an atom.
A host plugs its own (signed ids, a DB) so any replica validates any session.
sourceraw docstring

notify-tools-changed!clj/s

(notify-tools-changed! h)

Send notifications/tools/list_changed on every open GET stream. A stream whose queue already holds 16 events drops it rather than grow (Go parity: never block the host on a slow — or silently dead — stream).

Send notifications/tools/list_changed on every open GET stream. A stream
whose queue already holds 16 events drops it rather than grow (Go parity:
never block the host on a slow — or silently dead — stream).
sourceraw docstring

parse-skill-uriclj/s

(parse-skill-uri uri)

SPEC §2.7 containment for skill://<name>/<path>: [name rel] or throws ex-info whose message is the §7C.2 reason.

SPEC §2.7 containment for `skill://<name>/<path>`: [name rel] or throws
ex-info whose message is the §7C.2 reason.
sourceraw docstring

protocol-2026clj/s

The MCP 2026-07-28 wire (SPEC §7C.2) — opt-in only, never a default.

The MCP 2026-07-28 wire (SPEC §7C.2) — opt-in only, never a default.
sourceraw docstring

skills-extensionclj/s

The SEP-2640 skills extension id advertised by server/discover.

The SEP-2640 skills extension id advertised by server/discover.
sourceraw docstring

wire-toolclj/s

(wire-tool t)

The tools/list entry: name verbatim, description, inputSchema, outputSchema when set, annotations (:annotations verbatim; else derived from :hints; else omitted).

The tools/list entry: name verbatim, description, inputSchema, outputSchema
when set, annotations (`:annotations` verbatim; else derived from `:hints`;
else omitted).
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