The six MCP verb tools — assert, unassert, unassert-handle, query,
argue, matching — the write-and-read surface an MCP client reaches a fork KB through.
Each verb is a map → map function: JSON-shaped input (string keys, EDN values
carried as strings) → a Clojure result map the transport serializes to JSON.
Errors are maps with :mcp-error true, never thrown — the transport layer
decides how to encode them (a JSON-RPC error, an MCP error content block, etc.).
Fork injection. Every verb receives the fork KB through the dynamic var
*mcp-kb*, which the MCP server binds per request. The verbs never see the
base KB directly; the fork's overlay isolates their writes.
Strength cap. An MCP client may assert at :default only — never
:monotonic. The cap is enforced here, before the call reaches vaelii.core,
so a client cannot promote a belief past the fork's own defeat semantics.
EDN coercion. Sentence, goal, and context arguments arrive as JSON strings
holding EDN s-expressions. Parsed with clojure.edn/read-string (never
read-string) — EDN has no reader-eval, so a client's output cannot execute
code.
Wire format. Results are Clojure maps serialized to JSON by the transport. Handles are longs. Bindings are maps of string keys to EDN-string values.
The six MCP verb tools — `assert`, `unassert`, `unassert-handle`, `query`, `argue`, `matching` — the write-and-read surface an MCP client reaches a fork KB through. Each verb is a map → map function: JSON-shaped input (string keys, EDN values carried as strings) → a Clojure result map the transport serializes to JSON. Errors are maps with `:mcp-error true`, never thrown — the transport layer decides how to encode them (a JSON-RPC error, an MCP error content block, etc.). **Fork injection.** Every verb receives the fork KB through the dynamic var `*mcp-kb*`, which the MCP server binds per request. The verbs never see the base KB directly; the fork's overlay isolates their writes. **Strength cap.** An MCP client may assert at `:default` only — never `:monotonic`. The cap is enforced here, before the call reaches `vaelii.core`, so a client cannot promote a belief past the fork's own defeat semantics. **EDN coercion.** Sentence, goal, and context arguments arrive as JSON strings holding EDN s-expressions. Parsed with `clojure.edn/read-string` (never `read-string`) — EDN has no reader-eval, so a client's output cannot execute code. **Wire format.** Results are Clojure maps serialized to JSON by the transport. Handles are longs. Bindings are maps of string keys to EDN-string values.
Authority lock bound by the dispatcher. Held around fence-check + mutation to prevent revocation from slipping between authorization and effect. C3: authorize before mutating — don't trust a rollback path under partial failure. nil outside an MCP request (standalone verb calls skip locking).
Authority lock bound by the dispatcher. Held around fence-check + mutation to prevent revocation from slipping between authorization and effect. C3: authorize before mutating — don't trust a rollback path under partial failure. nil outside an MCP request (standalone verb calls skip locking).
Fencing callback bound by the dispatcher. Called before every KB mutation (assert, retract) to verify the session's authority generation hasn't changed. Throws if the permit is stale — preventing a revoked/retired principal from committing a write that started before revocation but lands after.
nil outside an MCP request (standalone verb calls skip fencing). The dispatcher binds this to a closure that checks session/permit-valid? against the permit acquired at admission time.
Fencing callback bound by the dispatcher. Called before every KB mutation (assert, retract) to verify the session's authority generation hasn't changed. Throws if the permit is stale — preventing a revoked/retired principal from committing a write that started before revocation but lands after. nil outside an MCP request (standalone verb calls skip fencing). The dispatcher binds this to a closure that checks session/permit-valid? against the permit acquired at admission time.
The fork KB the MCP server binds per request. Every verb reads it; assert and
unassert write to its overlay. nil outside an MCP request.
The fork KB the MCP server binds per request. Every verb reads it; assert and unassert write to its overlay. `nil` outside an MCP request.
(dispatch verb-name input)Dispatch a verb call. verb-name is the wire name (a string), input is the
JSON object (string keys). Returns the result map or an error map — never throws.
Fail-closed on unknown arguments: any input key outside the verb's published schema is rejected before the verb runs. Silently ignoring an argument would let a caller believe an option took effect when it did not.
Dispatch a verb call. `verb-name` is the wire name (a string), `input` is the JSON object (string keys). Returns the result map or an error map — never throws. Fail-closed on unknown arguments: any input key outside the verb's published schema is rejected before the verb runs. Silently ignoring an argument would let a caller believe an option took effect when it did not.
Rows matching examines when the caller names no limit.
Rows `matching` examines when the caller names no `limit`.
The largest limit matching accepts.
The largest `limit` `matching` accepts.
Wire names of the verbs that never mutate the fork. The dispatcher records their successful completions with effect "none".
Wire names of the verbs that never mutate the fork. The dispatcher records their successful completions with effect "none".
The six verb schemas in MCP tool-list format.
The six verb schemas in MCP tool-list format.
(verb-argue input)Four-valued epistemic status of a closed (ground) goal.
Input: {"closed_goal" "(dog Muffet)" "context" "CxWell"} Output: {:verdict "true" :for_justification {...} :against_justification nil}
A "false" verdict has one of two grounds, told apart by
against_justification's :kind: a provable denial (not G) is
"inference", its tree the denial's justification; a stored G that a
placed nogood defeats (argue's :defeated-by, e.g. a :default filler
of a functional predicate beside a :monotonic one) is "defeat", its
tree the engine's defeat reports — each with :loser, :winners
({:handle :sentence :context :defeat-class :rules}, stored claims
carrying :provenance) and :placed-in, the contexts the nogood is placed
in. A stated denial wins the side when both are there. A conjunction's
against side is derived, so it stays "inference"; a defeated conjunct's
entry in its tree is that conjunct's "defeat" justification.
Four-valued epistemic status of a closed (ground) goal.
Input: {"closed_goal" "(dog Muffet)" "context" "CxWell"}
Output: {:verdict "true" :for_justification {...} :against_justification nil}
A "false" verdict has one of two grounds, told apart by
`against_justification`'s `:kind`: a provable denial `(not G)` is
`"inference"`, its tree the denial's justification; a stored G that a
placed nogood defeats (`argue`'s `:defeated-by`, e.g. a `:default` filler
of a `functional` predicate beside a `:monotonic` one) is `"defeat"`, its
tree the engine's defeat reports — each with `:loser`, `:winners`
(`{:handle :sentence :context :defeat-class :rules}`, stored claims
carrying `:provenance`) and `:placed-in`, the contexts the nogood is placed
in. A stated denial wins the side when both are there. A conjunction's
against side is derived, so it stays `"inference"`; a defeated conjunct's
entry in its tree is that conjunct's `"defeat"` justification.(verb-assert input)Assert a sentence in a context. Strength is capped at :default.
Input: {"sentence" "(dog Muffet)" "context" "CxWell"} Output: {:handle 42 :already_there false}
Assert a sentence in a context. Strength is capped at `:default`.
Input: {"sentence" "(dog Muffet)" "context" "CxWell"}
Output: {:handle 42 :already_there false}(verb-matching input)Stored, believed sentexes matching a single-literal pattern in a context —
a literal match against what is stored (asserted or rule-derived), with no
inference and no subtype expansion. A read: no write fence, no mutation;
it sees exactly what the bound fork sees, like query.
limit bounds the stored matches examined: the engine's lazy seq is cut
with take before it is realized, so an open pattern cannot walk the whole
store. truncated is true when more matches existed beyond the limit.
asserted_only then keeps only premises, so with it a truncated answer can
hold fewer than limit rows.
Input: {"pattern" "(likes ?x Bacon)" "context" "CxWell" "asserted_only" false "limit" 100} Output: {:rows [{:sentence "(likes Muffet Bacon)" :context "CxWell" :handle 42 :asserted true :provenance {...}}] :count 1 :truncated false}
Stored, believed sentexes matching a single-literal pattern in a context —
a literal match against what is stored (asserted or rule-derived), with no
inference and no subtype expansion. A read: no write fence, no mutation;
it sees exactly what the bound fork sees, like `query`.
`limit` bounds the stored matches examined: the engine's lazy seq is cut
with `take` before it is realized, so an open pattern cannot walk the whole
store. `truncated` is true when more matches existed beyond the limit.
`asserted_only` then keeps only premises, so with it a truncated answer can
hold fewer than `limit` rows.
Input: {"pattern" "(likes ?x Bacon)" "context" "CxWell"
"asserted_only" false "limit" 100}
Output: {:rows [{:sentence "(likes Muffet Bacon)" :context "CxWell"
:handle 42 :asserted true :provenance {...}}]
:count 1 :truncated false}(verb-query input)Answer a goal in a context.
Input: {"goal" "(dog ?x)" "context" "CxWell" "include_justification" true} Output: {:answers [{:bindings {"?x" "Muffet"} :justification nil}]}
Answer a goal in a context.
Input: {"goal" "(dog ?x)" "context" "CxWell" "include_justification" true}
Output: {:answers [{:bindings {"?x" "Muffet"} :justification nil}]}(verb-unassert input)Belief-state postcondition: ensure sentence is not believed from context. Finds all visible handles and excepts each.
Input: {"sentence" "(dog Muffet)" "context" "CxWell"} Output: {:excepting_handles [101 102]}
Belief-state postcondition: ensure sentence is not believed from context.
Finds all visible handles and excepts each.
Input: {"sentence" "(dog Muffet)" "context" "CxWell"}
Output: {:excepting_handles [101 102]}(verb-unassert-handle input)Identity withdrawal of one specific handle.
Input: {"sentex_handle" 42} Output: {:excepting_handle 101} or {:excepting_handle nil}
Identity withdrawal of one specific handle.
Input: {"sentex_handle" 42}
Output: {:excepting_handle 101} or {:excepting_handle nil}The six MCP verbs, keyed by their wire name.
The six MCP verbs, keyed by their wire name.
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 |