(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].
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`.
(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).(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.(mcp-auth-error? e)True when e is an mcp-auth-error.
True when `e` is an `mcp-auth-error`.
(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.(mcp-identity ctx)What :authenticate returned (nil without it).
What :authenticate returned (nil without it).
(mcp-request ctx)The inbound Ring request.
The inbound Ring request.
(mcp-request-meta ctx)The JSON-RPC request's params._meta (nil when absent).
The JSON-RPC request's `params._meta` (nil when absent).
(mcp-session-id ctx)The Mcp-Session-Id of the request ("" if none).
The Mcp-Session-Id of the request ("" if none).
(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.(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).
(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.
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.
The SEP-2640 skills extension id advertised by server/discover.
The SEP-2640 skills extension id advertised by server/discover.
(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).
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 |