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

Open
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.
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin fix-mcp-wrapper-tool-schemas:fix-mcp-wrapper-tool-schemas
git checkout fix-mcp-wrapper-tool-schemas
Sign in to join this conversation.