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
pull from: fix-mcp-wrapper-tool-schemas
merge into: :fix/bound-session-payload
:dev
:main
:v0-neuron
:neuron-branding-sweep
:docs/correspondence-and-ownership-2026-08-16
:fix/engram-is-canonical
:fix/graph-edges-no-canonical-clobber
:docs/architecture-2026-08-14-deep-night
:fix/mcp-wrapper-agentic-routing
:merge-pr154-v2
:merge-pr151-v2
:merge-pr150-v2
:merge-pr149-v2
:build-audit-1786832983
:fix-mcp-wrapper-tool-schemas
:docs-cognitive-architecture
:docs/session-2026-08-13-language-faculty
:docs/geo-operators-el-cutover-reversal-2026-08-13
:docs/engram-cognitive-architecture-2026-08-12
:engram-store-wiring
:el-route-decorators
:fix/bound-session-payload
:rebase/openai-tools-onto-main
:rebase/gate-state-key-reads-onto-main
:feat/gold-set-heldout
:feat/structural-audit
:feat/claim24-unfloored-semantic
:feat/executive-filter-recall
:feat/recall-through-activation
:chore/regen-soul-amalgam-20260807
:reconcile/hotfix-to-main-launch
:salvage/elh-state-20260704
:feat/plan-mode-endpoint
:fix/operator-identity-home-resolution
:fix/prevent-engram-corruption
:improve/recall-context-format
:improve/recall-context-dedup
:improve/recall-cross-session-continuity
:improve/recall-emotional-recall
:improve/recall-activation-seed
:improve/recall-recall-completeness
:improve/recall-temporal-precision
:improve/recall-engram-scoring
:improve/recall-recall-reliability
:docs/conversation-retrieval-design
No Reviewers
Labels
Clear labels
BETA-CRITICAL
blocks-public-beta
HELD
ORTHOGONAL
P0
POST-BETA
security
On the beta critical path — must resolve before ship
Must be fixed before any public beta
Blocked pending an external decision (counsel / dual sign-off)
Parallel workstream (testing/hardening) — safe to assign off critical path
Drop-everything severity
Important but not blocking the beta ship
Security vulnerability
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: neuron-technologies/neuron#150
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "fix-mcp-wrapper-tool-schemas"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Every Neuron MCP tool advertised an empty
inputSchema({"type":"object","properties":{}}). MCP clients therefore sent no arguments, so:inspectGraph,traverseGraph,searchGraph,retrieveKnowledge) ignoredentity_id/depth/query/limitand returned the full neighborhood — 480–775KB per call, over the transport's token limit. The documented traversalinspectGraph(entity_id=…, depth=1)did not deliver a bounded, targeted result.inspectGraphalso read only the legacymax_depth, so adeptharg was silently dropped.forget,linkEntities,evolveMemory,remember, …) had no way to receivenode_id/from_id+to_id/id+content— so they couldn't target a specific node/edge.Fix
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).inspectGraphnow honorsdepth(fell back tomax_depth),compact(default on),snip,k; resolvesnameroots via a provably-reassigning expression-if.traverseGraphacceptsentity_id(aliasstart_id) and defaultscompact=1so a depth-2 walk stays bounded (previously it sent no compact → full dump).retrieveKnowledgeforwardsid/keyplus optionaldepth/snip/k; keepscompact=1.compact_flag()reads the raw JSON token so an integer0,false, or"0"opts out correctly (json_get_stringcan't see an integer and would silently force compact back on).Builds on and preserves PR #149's relevance-ranked
compactprojection (kept on by default for graph neighborhoods).Proof (throwaway build over a COPY of the engram; live :7770/:7779/~/.neuron untouched)
tools/listnow 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):
inspectGraph(kn-10fa60db…, depth=1)inspectGraph(fcd0ebc2… deg=357)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;traverseGraphdefaultscompact=1.searchGraphhonorslimit(3 args → 3 results / 15KB; 15 → 15 results / 46KB); distinct queries → distinct results.retrieveKnowledgehonorsid(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 (atombstonesmarker 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
~/.neuronwere never touched. Base isfix/bound-session-payload(stacked on PR #149).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.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.Pull request closed