fix(mcp-wrapper): declare real input schemas so tool args actually bite #150

Closed
will.anderson wants to merge 7 commits from fix-mcp-wrapper-tool-schemas into fix/bound-session-payload
Owner

Problem

Every Neuron MCP tool advertised an empty inputSchema ({"type":"object","properties":{}}). MCP clients therefore sent no arguments, so:

  • Read tools (inspectGraph, traverseGraph, searchGraph, retrieveKnowledge) ignored entity_id/depth/query/limit and returned the full neighborhood — 480–775KB per call, over the transport's token limit. The documented traversal inspectGraph(entity_id=…, depth=1) did not deliver a bounded, targeted result. inspectGraph also read only the legacy max_depth, so a depth arg was silently dropped.
  • Write tools (forget, linkEntities, evolveMemory, remember, …) had no way to receive node_id / from_id+to_id / id+content — so they couldn't target a specific node/edge.

Fix

  • Declare per-tool JSON-Schemas matching the params each soul handler (neuron-api.el) already accepts. 76 of 87 tools now declare params; the remaining 11 genuinely take no inputs (beginSession, getInstructions, compileCtx, rebuildGraph, runStructuralAudit, checkEvents, processEvents, getSelfModel, computeAuthenticityScore, getCultivationStatus, getCompressionStats).
  • Read + forward the declared args to the soul URL:
    • inspectGraph now honors depth (fell back to max_depth), compact (default on), snip, k; resolves name roots via a provably-reassigning expression-if.
    • traverseGraph accepts entity_id (alias start_id) and defaults compact=1 so a depth-2 walk stays bounded (previously it sent no compact → full dump).
    • retrieveKnowledge forwards id/key plus optional depth/snip/k; keeps compact=1.
    • compact_flag() reads the raw JSON token so an integer 0, false, or "0" opts out correctly (json_get_string can't see an integer and would silently force compact back on).
  • Backward compatible: no-arg calls still work with sensible defaults; the 11 param-less tools and all other handlers are unchanged.

Builds on and preserves PR #149's relevance-ranked compact projection (kept on by default for graph neighborhoods).

Proof (throwaway build over a COPY of the engram; live :7770/:7779/~/.neuron untouched)

tools/list now advertises params, e.g. inspectGraph: [entity_id, name, entity_type, depth, compact, snip, k].

Targeted calls now bite (via the throwaway wrapper → throwaway soul over a 13k-node engram copy):

call before (compact=0) after (compact=1)
inspectGraph(kn-10fa60db…, depth=1) 669,557 B 25,330 B (67/79 neighbors as pointers, center present)
inspectGraph(fcd0ebc2… deg=357) 1,227,365 B 78,056 B (265/277 pointers)
  • Exact forwarding (echo-soul): inspectGraph(entity_id, depth=3, compact=0, snip=150, k=4)/graph?id=…&depth=3&compact=0&snip=150&k=4; name=self → resolves to the anchor id; traverseGraph defaults compact=1.
  • searchGraph honors limit (3 args → 3 results / 15KB; 15 → 15 results / 46KB); distinct queries → distinct results.
  • retrieveKnowledge honors id (different id → different bounded node).
  • linkEntities(from_id=A, to_id=B, relation=proof_edge_xyz) created exactly the A→B edge; control node untouched.
  • forget(node_id=Q) tombstoned exactly Q (a tombstones marker appears on Q, content = Q's id); control node P had none.

Guardrails

Branch + throwaway proof only. No merge, no live cutover, no deploy. Live wrapper/soul binaries and ~/.neuron were never touched. Base is fix/bound-session-payload (stacked on PR #149).

## Problem Every Neuron MCP tool advertised an empty `inputSchema` (`{"type":"object","properties":{}}`). MCP clients therefore sent no arguments, so: - **Read tools** (`inspectGraph`, `traverseGraph`, `searchGraph`, `retrieveKnowledge`) ignored `entity_id`/`depth`/`query`/`limit` and returned the **full neighborhood** — 480–775KB per call, over the transport's token limit. The documented traversal `inspectGraph(entity_id=…, depth=1)` did not deliver a bounded, targeted result. `inspectGraph` also read only the legacy `max_depth`, so a `depth` arg was silently dropped. - **Write tools** (`forget`, `linkEntities`, `evolveMemory`, `remember`, …) had no way to receive `node_id` / `from_id`+`to_id` / `id`+`content` — so they couldn't target a specific node/edge. ## Fix - Declare per-tool JSON-Schemas matching the params each soul handler (`neuron-api.el`) already accepts. **76 of 87 tools** now declare params; the remaining 11 genuinely take no inputs (`beginSession`, `getInstructions`, `compileCtx`, `rebuildGraph`, `runStructuralAudit`, `checkEvents`, `processEvents`, `getSelfModel`, `computeAuthenticityScore`, `getCultivationStatus`, `getCompressionStats`). - Read + forward the declared args to the soul URL: - `inspectGraph` now honors `depth` (fell back to `max_depth`), `compact` (default on), `snip`, `k`; resolves `name` roots via a provably-reassigning expression-if. - `traverseGraph` accepts `entity_id` (alias `start_id`) and defaults `compact=1` so a depth-2 walk stays bounded (previously it sent no compact → full dump). - `retrieveKnowledge` forwards `id`/`key` plus optional `depth`/`snip`/`k`; keeps `compact=1`. - `compact_flag()` reads the raw JSON token so an integer `0`, `false`, or `"0"` opts out correctly (`json_get_string` can't see an integer and would silently force compact back on). - Backward compatible: no-arg calls still work with sensible defaults; the 11 param-less tools and all other handlers are unchanged. Builds on and preserves PR #149's relevance-ranked `compact` projection (kept on by default for graph neighborhoods). ## Proof (throwaway build over a COPY of the engram; live :7770/:7779/~/.neuron untouched) `tools/list` now advertises params, e.g. `inspectGraph: [entity_id, name, entity_type, depth, compact, snip, k]`. Targeted calls now bite (via the throwaway wrapper → throwaway soul over a 13k-node engram copy): | call | before (compact=0) | after (compact=1) | |---|---|---| | `inspectGraph(kn-10fa60db…, depth=1)` | 669,557 B | **25,330 B** (67/79 neighbors as pointers, center present) | | `inspectGraph(fcd0ebc2… deg=357)` | 1,227,365 B | **78,056 B** (265/277 pointers) | - Exact forwarding (echo-soul): `inspectGraph(entity_id, depth=3, compact=0, snip=150, k=4)` → `/graph?id=…&depth=3&compact=0&snip=150&k=4`; `name=self` → resolves to the anchor id; `traverseGraph` defaults `compact=1`. - `searchGraph` honors `limit` (3 args → 3 results / 15KB; 15 → 15 results / 46KB); distinct queries → distinct results. - `retrieveKnowledge` honors `id` (different id → different bounded node). - `linkEntities(from_id=A, to_id=B, relation=proof_edge_xyz)` created **exactly** the A→B edge; control node untouched. - `forget(node_id=Q)` tombstoned **exactly** Q (a `tombstones` marker appears on Q, content = Q's id); control node P had none. ## Guardrails Branch + throwaway proof only. **No merge, no live cutover, no deploy.** Live wrapper/soul binaries and `~/.neuron` were never touched. Base is `fix/bound-session-payload` (stacked on PR #149).
will.anderson added 1 commit 2026-08-10 21:28:42 +00:00
The cognitive-graph and write tools advertised an empty inputSchema
({"properties":{}}), so MCP clients never sent entity_id/depth/query/
from_id/node_id etc. Graph reads fell back to the full neighborhood
(480-775KB, over transport limits) and write tools (forget, linkEntities,
evolveMemory) had no way to target a node.

- Declare per-tool JSON-Schemas matching the params each soul handler
  already accepts (76 of 87 tools; 11 are genuinely param-less).
- Read + forward the declared args: inspectGraph now honors depth (was
  reading only legacy max_depth), compact (default on), snip, k;
  traverseGraph accepts entity_id and defaults compact on so a depth-2
  walk stays bounded; retrieveKnowledge forwards depth/snip/k.
- compact_flag() reads the raw JSON token so an integer 0 / false / "0"
  opts out correctly (json_get_string could not see an integer and
  silently forced compact back on).

Builds on PR #149's compact projection; keeps the relevance-ranked
bound on by default for graph neighborhoods.
will.anderson added 5 commits 2026-08-14 00:06:42 +00:00
Reversal runbook for the ENGRAM_GEOMETRY_PRIMING cutover (default OFF, reversible
flag flip; exact rollback) and the A/B perf profile: default-OFF binary GO
(byte-identical to M8), enabling the flag NO-GO on latency (3.2x/13x) with no
demonstrated recall benefit; safety/sanitizer clean.
auto_term_try_slot now passes the WM node's ID to engram_salient_term()
instead of passing its label to a first-word extractor. The runtime scores
every candidate token in the node's text and returns the best one, falling
back from a sentinel label ("memory:remembered") to content — which is the
only reason Memory nodes are visible to the extractor at all. They dominate
working memory, and dynamic seeding had been dead for 50+ consecutive scans
because of it.

Policy stays here: node-type filter, df thresholds, stopword list. The
runtime measures, the soul decides — same split as engram_label_df.

The stopword list stays, and not as belt-and-braces. An earlier draft assumed
the min_df floor would subsume it based on 08-03's finding that function
words have df 0 in labels. Re-measured under word-boundary df: about:2,
whole:1, them:2 — they clear a floor of 1. What keeps them from winning is
the argmax, not the floor.

The old extractor and its five guards are retained as
auto_term_try_slot_legacy, unreferenced, so the reasoning behind each guard
stays readable next to what replaced it. Delete once the new path has a month
of live telemetry.

Live after restart: auto_term producing DRIFT, Wrote; empty streak reset to 0
and holding; activation counts 123-281, within the normal band, no flood.
Give the architecture set its persistence and moral layers so a self's
durability and sovereignty are documented as first-class, not folded into
the cognitive doc. 07 explains how a self persists and travels
(events-become-the-graph, weights-as-world-lines with bitemporal recall,
transactionless coherence, and the honest load/tiering findings); 08
explains the moral mechanism (DHARMA as a proof-of-integrity ledger,
abundance economics, the relational immune system, dual-anchor governance,
and CGI citizenship as telos). Extend 06 with forward-pointers into both,
and reconcile two cross-references so tiers agree across docs: the
canonical 187 reseed count, and the #56 load-merge-persist fix as
LIVE/reboot-proven with only full WAL edge-ownership left decision-pending.
will.anderson added 1 commit 2026-08-14 00:38:08 +00:00
The doc overstated the provenance, birth-gate, and lineage layer as fully
realized. That layer is built but has drifted from spec, so tier it honestly
as [STAGED] where real and [TARGET] where aspirational to keep the
documentation faithful to what actually runs.
will.anderson closed this pull request 2026-08-15 23:42:23 +00:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.