mindgraph-mcp 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -1
- package/dist/cli.js +341 -33
- package/dist/index.js +143 -23
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -174,7 +174,7 @@ and never block the coding session.
|
|
|
174
174
|
|
|
175
175
|
## What You Get
|
|
176
176
|
|
|
177
|
-
**
|
|
177
|
+
**11 tools** covering the full knowledge-graph workflow (**13** in the coding
|
|
178
178
|
profile):
|
|
179
179
|
|
|
180
180
|
| Tool | Purpose |
|
|
@@ -185,6 +185,7 @@ profile):
|
|
|
185
185
|
| `mindgraph_plan` | Plans, tasks, procedures, governance policies, risk assessments, executions |
|
|
186
186
|
| `mindgraph_retrieve` | Context retrieval with bounded graph expansion, search, min-cost traversal, document index. Read results return as compact rendered text (labels, uids, summaries, epistemic status tags, relationships, traversal depth/cost); set `max_output_chars` for a hard whole-item character budget, or pass `format: "json"` for the raw server response |
|
|
187
187
|
| `mindgraph_memory` | Read-only M0 memory workflow: inspect honest integration status, retrieve bounded topic context, or recover authoritative task-first resume/continuity context. Returns model-ready text plus a structured envelope with scope, hashes, trace, budget, freshness, and warnings |
|
|
188
|
+
| `mindgraph_remember` | Small-text fast path: `remember` stores one fact/preference/decision synchronously and it is BM25- and vector-searchable on return; a stable `custom_id` makes re-sends an upsert of the same memory. `forget` reversibly removes by uid or custom_id, with `dry_run` previewing the affected edge uids |
|
|
188
189
|
| `mindgraph_series_query` | Bounded, read-only dense-measurement queries: list an entity's Series, inspect latest values, page a time window, or calculate calendar aggregates |
|
|
189
190
|
| `mindgraph_ingest` | Chunk / document / session ingestion with LLM-powered extraction. `job_status` without an id renders the 20 most recent jobs (`format: "json"` for the full list) |
|
|
190
191
|
| `mindgraph_synthesize` | Project-scoped cross-document synthesis — mine signals (rendered as sections since 0.17.0), spawn Article-generation jobs |
|
|
@@ -300,3 +301,17 @@ npm run dev # tsup --watch
|
|
|
300
301
|
## License
|
|
301
302
|
|
|
302
303
|
MIT
|
|
304
|
+
|
|
305
|
+
### Engine failures and retries
|
|
306
|
+
|
|
307
|
+
Tool failures carry `isError: true`; `code`, `status`, and optional `retriable`
|
|
308
|
+
are preserved in both the JSON text and structured content. Lease-conflict fields
|
|
309
|
+
remain available to hooks. A failed retrieval is not an empty successful result.
|
|
310
|
+
Explicit `retriable: false` stops automatic retries, including index maintenance.
|
|
311
|
+
Other 503 responses retry only reviewed reads or atomically keyed work operations.
|
|
312
|
+
|
|
313
|
+
This adoption branch pins the TypeScript SDK to immutable source commit
|
|
314
|
+
`02bad10728836bf55129c08efabf71386432deee` so installs and CI exercise the same
|
|
315
|
+
retry implementation. Git installation builds the SDK through its `prepare` hook.
|
|
316
|
+
Replace this source pin and regenerate the lockfile only after a registry release
|
|
317
|
+
containing that implementation is verified; older SDK releases retry all 503s.
|
package/dist/cli.js
CHANGED
|
@@ -27,25 +27,127 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
|
|
29
29
|
// node_modules/mindgraph/dist/index.mjs
|
|
30
|
+
function errorFields(body) {
|
|
31
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return {};
|
|
32
|
+
const fields = body;
|
|
33
|
+
return {
|
|
34
|
+
...typeof fields.code === "string" ? { code: fields.code } : {},
|
|
35
|
+
...typeof fields.retriable === "boolean" ? { retriable: fields.retriable } : {}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function canRetryRequest(method, path8, body) {
|
|
39
|
+
if (method === "GET" || method === "HEAD") return true;
|
|
40
|
+
if (method !== "POST") return false;
|
|
41
|
+
if (READ_POSTS.has(path8)) return true;
|
|
42
|
+
const fields = body && typeof body === "object" && !Array.isArray(body) ? body : {};
|
|
43
|
+
if (typeof fields.action !== "string") return false;
|
|
44
|
+
if (Object.prototype.hasOwnProperty.call(READ_ACTIONS, path8) && READ_ACTIONS[path8].includes(fields.action)) return true;
|
|
45
|
+
return path8 === "/agent/plan" && IDEMPOTENT_WORK.has(fields.action) && typeof fields.idempotency_key === "string" && fields.idempotency_key.trim().length > 0;
|
|
46
|
+
}
|
|
47
|
+
function permitsRetry(fields) {
|
|
48
|
+
return fields.retriable !== false && ![
|
|
49
|
+
"query_memory_budget_exceeded",
|
|
50
|
+
"query_timeout",
|
|
51
|
+
"query_cancelled",
|
|
52
|
+
"vector_index_rebuilding"
|
|
53
|
+
].includes(fields.code ?? "");
|
|
54
|
+
}
|
|
55
|
+
function retryDelayMs(header, backoff, attempt) {
|
|
56
|
+
const hint = Number(header);
|
|
57
|
+
return Number.isFinite(hint) && hint > 0 ? Math.min(hint * 1e3, 1e4) : Math.min(backoff * 2 ** Math.min(attempt, 32), 1e4);
|
|
58
|
+
}
|
|
30
59
|
function seg(value) {
|
|
31
60
|
return encodeURIComponent(String(value));
|
|
32
61
|
}
|
|
62
|
+
function pathSteps(response) {
|
|
63
|
+
const wrapped = response && typeof response === "object" && !Array.isArray(response) ? response : void 0;
|
|
64
|
+
const raw = wrapped?.steps ?? response;
|
|
65
|
+
if (!Array.isArray(raw)) return [];
|
|
66
|
+
return raw.flatMap((value) => {
|
|
67
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return [];
|
|
68
|
+
const step = value;
|
|
69
|
+
const taggedName = (tagged) => {
|
|
70
|
+
if (typeof tagged === "string") return tagged;
|
|
71
|
+
if (!tagged || typeof tagged !== "object" || Array.isArray(tagged)) return null;
|
|
72
|
+
const custom = tagged.Custom;
|
|
73
|
+
return typeof custom === "string" ? custom : null;
|
|
74
|
+
};
|
|
75
|
+
return [{
|
|
76
|
+
...step,
|
|
77
|
+
node_type: taggedName(step.node_type) ?? "Unknown",
|
|
78
|
+
edge_type: taggedName(step.edge_type)
|
|
79
|
+
}];
|
|
80
|
+
});
|
|
81
|
+
}
|
|
33
82
|
function createRequestId() {
|
|
34
83
|
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
35
84
|
return globalThis.crypto.randomUUID();
|
|
36
85
|
}
|
|
37
86
|
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
38
87
|
}
|
|
39
|
-
var MindGraphError, MindGraph;
|
|
88
|
+
var READ_POSTS, READ_ACTIONS, IDEMPOTENT_WORK, MindGraphError, MindGraph;
|
|
40
89
|
var init_dist = __esm({
|
|
41
90
|
"node_modules/mindgraph/dist/index.mjs"() {
|
|
42
91
|
"use strict";
|
|
92
|
+
READ_POSTS = /* @__PURE__ */ new Set([
|
|
93
|
+
"/search",
|
|
94
|
+
"/retrieve/context",
|
|
95
|
+
"/nodes/batch",
|
|
96
|
+
"/edges/batch",
|
|
97
|
+
"/subgraph",
|
|
98
|
+
"/embeddings/search",
|
|
99
|
+
"/embeddings/search-text",
|
|
100
|
+
"/ontology/query",
|
|
101
|
+
"/ontology/query/structured",
|
|
102
|
+
"/ontology/objects/search"
|
|
103
|
+
]);
|
|
104
|
+
READ_ACTIONS = {
|
|
105
|
+
"/retrieve": [
|
|
106
|
+
"text",
|
|
107
|
+
"semantic",
|
|
108
|
+
"hybrid",
|
|
109
|
+
"active_goals",
|
|
110
|
+
"open_questions",
|
|
111
|
+
"preferences",
|
|
112
|
+
"weak_claims",
|
|
113
|
+
"pending_approvals",
|
|
114
|
+
"unresolved_contradictions",
|
|
115
|
+
"merge_candidates",
|
|
116
|
+
"stale_derivations",
|
|
117
|
+
"curation_counts",
|
|
118
|
+
"layer",
|
|
119
|
+
"recent"
|
|
120
|
+
],
|
|
121
|
+
"/traverse": ["chain", "top_k_paths", "neighborhood", "path", "subgraph"],
|
|
122
|
+
"/reality/series": ["window", "aggregate", "latest", "list_for_entity", "batch_latest", "batch_aggregate"],
|
|
123
|
+
"/intent/deliberation": ["get_open"],
|
|
124
|
+
"/action/risk": ["get_assessments"],
|
|
125
|
+
"/action/skill": ["get", "list"],
|
|
126
|
+
"/memory/config": ["get_preferences", "get_policies"],
|
|
127
|
+
"/memory/sync": ["status"],
|
|
128
|
+
"/agent/plan": ["get_plan", "resume_work"],
|
|
129
|
+
"/agent/governance": ["get_pending", "check"],
|
|
130
|
+
"/agent/execution": ["get_executions"],
|
|
131
|
+
"/evolve": ["history", "snapshot"]
|
|
132
|
+
};
|
|
133
|
+
IDEMPOTENT_WORK = /* @__PURE__ */ new Set([
|
|
134
|
+
"claim_task",
|
|
135
|
+
"heartbeat",
|
|
136
|
+
"start_iteration",
|
|
137
|
+
"checkpoint_iteration",
|
|
138
|
+
"block_task",
|
|
139
|
+
"complete_task",
|
|
140
|
+
"abandon_iteration"
|
|
141
|
+
]);
|
|
43
142
|
MindGraphError = class extends Error {
|
|
44
143
|
constructor(message, status, body) {
|
|
45
144
|
super(message);
|
|
46
145
|
this.status = status;
|
|
47
146
|
this.body = body;
|
|
48
147
|
this.name = "MindGraphError";
|
|
148
|
+
const fields = errorFields(body);
|
|
149
|
+
this.code = fields.code;
|
|
150
|
+
this.retriable = fields.retriable;
|
|
49
151
|
}
|
|
50
152
|
};
|
|
51
153
|
MindGraph = class {
|
|
@@ -63,6 +165,18 @@ var init_dist = __esm({
|
|
|
63
165
|
this.telemetrySurface = config.telemetrySurface;
|
|
64
166
|
this.maxRetries = config.maxRetries ?? 3;
|
|
65
167
|
this.retryBackoffMs = config.retryBackoffMs ?? 1e3;
|
|
168
|
+
if (!Number.isSafeInteger(this.maxRetries) || this.maxRetries < 0) {
|
|
169
|
+
throw new RangeError("maxRetries must be a non-negative safe integer");
|
|
170
|
+
}
|
|
171
|
+
if (!Number.isFinite(this.retryBackoffMs) || this.retryBackoffMs < 0) {
|
|
172
|
+
throw new RangeError("retryBackoffMs must be finite and non-negative");
|
|
173
|
+
}
|
|
174
|
+
if (config.timeoutMs !== void 0) {
|
|
175
|
+
if (!Number.isFinite(config.timeoutMs) || config.timeoutMs <= 0) {
|
|
176
|
+
throw new RangeError("timeoutMs must be a positive finite number of milliseconds");
|
|
177
|
+
}
|
|
178
|
+
this.timeoutMs = config.timeoutMs;
|
|
179
|
+
}
|
|
66
180
|
}
|
|
67
181
|
// ---- HTTP helpers ----
|
|
68
182
|
async request(method, path8, body) {
|
|
@@ -79,9 +193,14 @@ var init_dist = __esm({
|
|
|
79
193
|
if (body !== void 0) {
|
|
80
194
|
init.body = JSON.stringify(body);
|
|
81
195
|
}
|
|
196
|
+
const retrySafe = canRetryRequest(
|
|
197
|
+
method,
|
|
198
|
+
path8,
|
|
199
|
+
typeof init.body === "string" ? JSON.parse(init.body) : void 0
|
|
200
|
+
);
|
|
82
201
|
let lastError;
|
|
83
202
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
84
|
-
const res = await
|
|
203
|
+
const res = await this.fetchWithDeadline(url, init, method, path8);
|
|
85
204
|
if (!res.ok) {
|
|
86
205
|
const text22 = await res.text().catch(() => "");
|
|
87
206
|
let parsed;
|
|
@@ -95,10 +214,9 @@ var init_dist = __esm({
|
|
|
95
214
|
res.status,
|
|
96
215
|
parsed
|
|
97
216
|
);
|
|
98
|
-
if (res.status === 503 && attempt < this.maxRetries) {
|
|
217
|
+
if (res.status === 503 && retrySafe && permitsRetry(err5) && attempt < this.maxRetries) {
|
|
99
218
|
lastError = err5;
|
|
100
|
-
const
|
|
101
|
-
const delay = Number.isFinite(retryAfterSecs) && retryAfterSecs > 0 ? Math.min(retryAfterSecs * 1e3, 1e4) : this.retryBackoffMs * 2 ** attempt;
|
|
219
|
+
const delay = retryDelayMs(res.headers.get("retry-after"), this.retryBackoffMs, attempt);
|
|
102
220
|
await new Promise((r) => setTimeout(r, delay));
|
|
103
221
|
continue;
|
|
104
222
|
}
|
|
@@ -110,6 +228,33 @@ var init_dist = __esm({
|
|
|
110
228
|
}
|
|
111
229
|
throw lastError;
|
|
112
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* One HTTP attempt. With `timeoutMs` set, the attempt is aborted at the
|
|
233
|
+
* deadline and surfaces as a non-retriable `MindGraphError` (`code:
|
|
234
|
+
* "timeout"`, `status: 0`). Without it the request is sent unchanged — no
|
|
235
|
+
* AbortSignal is attached, preserving the pre-0.16 behaviour.
|
|
236
|
+
*/
|
|
237
|
+
async fetchWithDeadline(url, init, method, path8) {
|
|
238
|
+
if (this.timeoutMs === void 0) {
|
|
239
|
+
return fetch(url, init);
|
|
240
|
+
}
|
|
241
|
+
const controller = new AbortController();
|
|
242
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
243
|
+
try {
|
|
244
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
245
|
+
} catch (error2) {
|
|
246
|
+
if (controller.signal.aborted) {
|
|
247
|
+
throw new MindGraphError(
|
|
248
|
+
`${method} ${path8} timed out after ${this.timeoutMs}ms`,
|
|
249
|
+
0,
|
|
250
|
+
{ error: "timeout", code: "timeout", retriable: false }
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
throw error2;
|
|
254
|
+
} finally {
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
113
258
|
get(path8) {
|
|
114
259
|
return this.request("GET", path8);
|
|
115
260
|
}
|
|
@@ -359,6 +504,40 @@ var init_dist = __esm({
|
|
|
359
504
|
async memorySync(req) {
|
|
360
505
|
return this.post("/memory/sync", req);
|
|
361
506
|
}
|
|
507
|
+
// ---- Memory (fast path) ----
|
|
508
|
+
/**
|
|
509
|
+
* Store a small piece of text as a memory, synchronously. The node is
|
|
510
|
+
* BM25- and vector-searchable when this resolves (`searchable` says which).
|
|
511
|
+
* Pass `custom_id` to make re-sends an upsert of the same node.
|
|
512
|
+
*/
|
|
513
|
+
async remember(text2, options = {}) {
|
|
514
|
+
return this.post("/memory/remember", { text: text2, ...options });
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Reversibly remove a memory by `uid` or `custom_id` (tombstone plus its
|
|
518
|
+
* connected edges). `dry_run: true` previews the affected edge uids first.
|
|
519
|
+
* Undo with `restore(uid)` and `evolve({ action: "restore_edge", uid })`.
|
|
520
|
+
*/
|
|
521
|
+
async forget(target, options = {}) {
|
|
522
|
+
return this.post("/memory/forget", { ...target, ...options });
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Operator guidance for what agents should remember into a Space; surfaced
|
|
526
|
+
* on every `remember()` response and on `retrieveContext()`. Empty clears it.
|
|
527
|
+
*/
|
|
528
|
+
async setRememberInstructions(text2, options = {}) {
|
|
529
|
+
return this.post("/memory/config", {
|
|
530
|
+
action: "set_remember_instructions",
|
|
531
|
+
text: text2,
|
|
532
|
+
...options
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
async getRememberInstructions(options = {}) {
|
|
536
|
+
return this.post("/memory/config", {
|
|
537
|
+
action: "get_remember_instructions",
|
|
538
|
+
...options
|
|
539
|
+
});
|
|
540
|
+
}
|
|
362
541
|
// ---- Agent Layer ----
|
|
363
542
|
async plan(req) {
|
|
364
543
|
return this.post("/agent/plan", req);
|
|
@@ -581,7 +760,7 @@ var init_dist = __esm({
|
|
|
581
760
|
start_uid: uid,
|
|
582
761
|
max_depth: maxDepth
|
|
583
762
|
});
|
|
584
|
-
return r
|
|
763
|
+
return pathSteps(r);
|
|
585
764
|
}
|
|
586
765
|
async neighborhood(uid, maxDepth = 1) {
|
|
587
766
|
const r = await this.post("/traverse", {
|
|
@@ -589,7 +768,7 @@ var init_dist = __esm({
|
|
|
589
768
|
start_uid: uid,
|
|
590
769
|
max_depth: maxDepth
|
|
591
770
|
});
|
|
592
|
-
return r
|
|
771
|
+
return pathSteps(r);
|
|
593
772
|
}
|
|
594
773
|
async subgraph(uid, opts) {
|
|
595
774
|
return this.post("/subgraph", { start_uids: [uid], ...opts });
|
|
@@ -960,11 +1139,19 @@ var init_dist = __esm({
|
|
|
960
1139
|
/**
|
|
961
1140
|
* Create a domain object by hand (auto-approved). Returns the created node
|
|
962
1141
|
* uid + the audit proposal id. Throws 409 if an object of the same type +
|
|
963
|
-
* canonical_name already exists, unless `allow_duplicate` is set.
|
|
1142
|
+
* canonical_name already exists, unless `allow_duplicate` is set. The
|
|
1143
|
+
* schema's identity key is always enforced.
|
|
964
1144
|
*/
|
|
965
1145
|
async createDomainObject(req) {
|
|
966
1146
|
return this.post("/v1/ontology/objects", req);
|
|
967
1147
|
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Schema-validated authored update with optimistic concurrency. Identity
|
|
1150
|
+
* fields are immutable; create and explicitly merge when identity changes.
|
|
1151
|
+
*/
|
|
1152
|
+
async updateDomainObject(uid, req) {
|
|
1153
|
+
return this.patch(`/v1/ontology/objects/${seg(uid)}`, req);
|
|
1154
|
+
}
|
|
968
1155
|
async linkDomainObjects(req) {
|
|
969
1156
|
return this.post("/ontology/relation", { action: "create", ...req });
|
|
970
1157
|
}
|
|
@@ -1787,6 +1974,22 @@ function conflictState(e) {
|
|
|
1787
1974
|
}
|
|
1788
1975
|
return lifted;
|
|
1789
1976
|
}
|
|
1977
|
+
function toolError(e, fallbackCode) {
|
|
1978
|
+
const body = e instanceof MindGraphError && e.body && typeof e.body === "object" && !Array.isArray(e.body) ? e.body : {};
|
|
1979
|
+
const code = typeof body.code === "string" ? body.code : fallbackCode;
|
|
1980
|
+
const payload = {
|
|
1981
|
+
error: errorDetail(e),
|
|
1982
|
+
...conflictState(e),
|
|
1983
|
+
...e instanceof MindGraphError ? { status: e.status } : {},
|
|
1984
|
+
...code !== void 0 ? { code } : {},
|
|
1985
|
+
...typeof body.retriable === "boolean" ? { retriable: body.retriable } : {}
|
|
1986
|
+
};
|
|
1987
|
+
return {
|
|
1988
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
1989
|
+
structuredContent: payload,
|
|
1990
|
+
isError: true
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1790
1993
|
var CONFLICT_STATE_KEYS;
|
|
1791
1994
|
var init_error_detail = __esm({
|
|
1792
1995
|
"src/error-detail.ts"() {
|
|
@@ -1994,7 +2197,7 @@ async function handleCodeTool(client2, args, adapter = new CodegraphAdapter({ cw
|
|
|
1994
2197
|
if (cause instanceof UnknownRepositoryError) {
|
|
1995
2198
|
return err("unknown_repository", cause.message);
|
|
1996
2199
|
}
|
|
1997
|
-
return
|
|
2200
|
+
return toolError(cause, "code_tool_failed");
|
|
1998
2201
|
}
|
|
1999
2202
|
}
|
|
2000
2203
|
async function attachCodeRefsToToolResult(client2, result, args, adapter) {
|
|
@@ -2738,7 +2941,7 @@ async function handleSyncTool(client2, args) {
|
|
|
2738
2941
|
}
|
|
2739
2942
|
return ok2(await remote.memorySync(request));
|
|
2740
2943
|
} catch (error2) {
|
|
2741
|
-
return
|
|
2944
|
+
return toolError(error2, "sync_failed");
|
|
2742
2945
|
}
|
|
2743
2946
|
}
|
|
2744
2947
|
async function scanRepository(remote, repository, requested, provider, agentId) {
|
|
@@ -4179,6 +4382,9 @@ async function handleTool(client2, name, args, memoryConfig = {}) {
|
|
|
4179
4382
|
case "mindgraph_memory":
|
|
4180
4383
|
result = await handleMemoryTool(client2, args, memoryConfig);
|
|
4181
4384
|
break;
|
|
4385
|
+
case "mindgraph_remember":
|
|
4386
|
+
result = await handleRemember(client2, args);
|
|
4387
|
+
break;
|
|
4182
4388
|
case "mindgraph_series_query":
|
|
4183
4389
|
result = await handleSeriesQuery(client2, args);
|
|
4184
4390
|
break;
|
|
@@ -4211,19 +4417,7 @@ async function handleTool(client2, name, args, memoryConfig = {}) {
|
|
|
4211
4417
|
].includes(action);
|
|
4212
4418
|
return attach ? await attachCodeRefsToToolResult(client2, result, args) : result;
|
|
4213
4419
|
} catch (e) {
|
|
4214
|
-
|
|
4215
|
-
if (Object.keys(lifted).length > 0) {
|
|
4216
|
-
return {
|
|
4217
|
-
content: [
|
|
4218
|
-
{
|
|
4219
|
-
type: "text",
|
|
4220
|
-
text: JSON.stringify({ error: errorDetail(e), ...lifted })
|
|
4221
|
-
}
|
|
4222
|
-
],
|
|
4223
|
-
isError: true
|
|
4224
|
-
};
|
|
4225
|
-
}
|
|
4226
|
-
return err3(errorDetail(e));
|
|
4420
|
+
return toolError(e);
|
|
4227
4421
|
}
|
|
4228
4422
|
}
|
|
4229
4423
|
async function handleSeriesQuery(client2, args) {
|
|
@@ -4247,6 +4441,56 @@ async function handleSeriesQuery(client2, args) {
|
|
|
4247
4441
|
await client2.series(args)
|
|
4248
4442
|
);
|
|
4249
4443
|
}
|
|
4444
|
+
async function handleRemember(client2, args) {
|
|
4445
|
+
const {
|
|
4446
|
+
action,
|
|
4447
|
+
text: text2,
|
|
4448
|
+
custom_id,
|
|
4449
|
+
label,
|
|
4450
|
+
uid,
|
|
4451
|
+
dry_run,
|
|
4452
|
+
cascade,
|
|
4453
|
+
reason,
|
|
4454
|
+
space_uid,
|
|
4455
|
+
on_near_duplicate,
|
|
4456
|
+
props,
|
|
4457
|
+
agent_id,
|
|
4458
|
+
// Adapter-owned; consumed locally, never sent to the API.
|
|
4459
|
+
invocation_context: _invocationContext,
|
|
4460
|
+
...rest
|
|
4461
|
+
} = args;
|
|
4462
|
+
void _invocationContext;
|
|
4463
|
+
void rest;
|
|
4464
|
+
switch (action) {
|
|
4465
|
+
case "remember": {
|
|
4466
|
+
if (typeof text2 !== "string" || !text2.trim()) {
|
|
4467
|
+
return err3("remember requires non-empty text");
|
|
4468
|
+
}
|
|
4469
|
+
const options = {};
|
|
4470
|
+
if (typeof custom_id === "string" && custom_id.trim()) options.custom_id = custom_id.trim();
|
|
4471
|
+
if (typeof label === "string" && label.trim()) options.label = label;
|
|
4472
|
+
if (typeof space_uid === "string" && space_uid.trim()) options.space_uid = space_uid;
|
|
4473
|
+
if (on_near_duplicate === "reuse" || on_near_duplicate === "create") {
|
|
4474
|
+
options.on_near_duplicate = on_near_duplicate;
|
|
4475
|
+
}
|
|
4476
|
+
if (props && typeof props === "object") options.props = props;
|
|
4477
|
+
if (typeof agent_id === "string") options.agent_id = agent_id;
|
|
4478
|
+
return ok3(await client2.remember(text2, options));
|
|
4479
|
+
}
|
|
4480
|
+
case "forget": {
|
|
4481
|
+
const target = typeof uid === "string" && uid.trim() ? { uid: uid.trim() } : typeof custom_id === "string" && custom_id.trim() ? { custom_id: custom_id.trim() } : null;
|
|
4482
|
+
if (!target) return err3("forget requires uid or custom_id");
|
|
4483
|
+
const options = {};
|
|
4484
|
+
if (dry_run === true) options.dry_run = true;
|
|
4485
|
+
if (typeof cascade === "boolean") options.cascade = cascade;
|
|
4486
|
+
if (typeof reason === "string" && reason.trim()) options.reason = reason;
|
|
4487
|
+
if (typeof agent_id === "string") options.agent_id = agent_id;
|
|
4488
|
+
return ok3(await client2.forget(target, options));
|
|
4489
|
+
}
|
|
4490
|
+
default:
|
|
4491
|
+
return err3(`Unknown remember action: ${String(action)}`);
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4250
4494
|
async function handleCapture(client2, args) {
|
|
4251
4495
|
const {
|
|
4252
4496
|
action,
|
|
@@ -6430,6 +6674,66 @@ var init_tools = __esm({
|
|
|
6430
6674
|
required: ["action"]
|
|
6431
6675
|
}
|
|
6432
6676
|
},
|
|
6677
|
+
{
|
|
6678
|
+
name: "mindgraph_remember",
|
|
6679
|
+
description: "Small-text memory fast path. 'remember' stores one fact, preference, decision or note synchronously; it is BM25- and vector-searchable the moment the call returns (the response says which). Pass a stable custom_id (e.g. 'pref:theme', 'deploy:target') so re-sending the same key UPDATES the same memory instead of creating a duplicate \u2014 that is the idempotency contract; without custom_id an exact duplicate is reused. 'forget' reversibly removes a memory by uid or custom_id (tombstone plus connected edges): call it with dry_run=true first to see the edge uids it would remove, then without. Undo with mindgraph_capture-independent server actions /evolve restore and restore_edge. Use mindgraph_capture for typed entities, sources and skills, and mindgraph_ingest for documents longer than a few paragraphs.",
|
|
6680
|
+
inputSchema: {
|
|
6681
|
+
type: "object",
|
|
6682
|
+
properties: {
|
|
6683
|
+
action: {
|
|
6684
|
+
type: "string",
|
|
6685
|
+
enum: ["remember", "forget"],
|
|
6686
|
+
description: "remember = store/upsert one small text; forget = reversible removal"
|
|
6687
|
+
},
|
|
6688
|
+
text: {
|
|
6689
|
+
type: "string",
|
|
6690
|
+
description: "remember: the memory text (\u2264 8 KiB). Use mindgraph_ingest for longer content."
|
|
6691
|
+
},
|
|
6692
|
+
custom_id: {
|
|
6693
|
+
type: "string",
|
|
6694
|
+
description: "Caller-owned key. remember: re-sending it edits the same memory (version bump, history kept). forget: the memory to remove."
|
|
6695
|
+
},
|
|
6696
|
+
label: {
|
|
6697
|
+
type: "string",
|
|
6698
|
+
description: "remember: optional short title; defaults to the first line of text"
|
|
6699
|
+
},
|
|
6700
|
+
uid: {
|
|
6701
|
+
type: "string",
|
|
6702
|
+
description: "forget: node uid to remove (alternative to custom_id)"
|
|
6703
|
+
},
|
|
6704
|
+
dry_run: {
|
|
6705
|
+
type: "boolean",
|
|
6706
|
+
description: "forget: preview the affected edge uids without changing anything"
|
|
6707
|
+
},
|
|
6708
|
+
cascade: {
|
|
6709
|
+
type: "boolean",
|
|
6710
|
+
description: "forget: also tombstone connected edges (default true)"
|
|
6711
|
+
},
|
|
6712
|
+
reason: {
|
|
6713
|
+
type: "string",
|
|
6714
|
+
description: "forget: why (recorded on the tombstone)"
|
|
6715
|
+
},
|
|
6716
|
+
space_uid: {
|
|
6717
|
+
type: "string",
|
|
6718
|
+
description: "remember: explicit target Space (default: the org space)"
|
|
6719
|
+
},
|
|
6720
|
+
on_near_duplicate: {
|
|
6721
|
+
type: "string",
|
|
6722
|
+
enum: ["reuse", "create"],
|
|
6723
|
+
description: "remember without custom_id: on an exact duplicate, reuse the existing memory (default) or create anyway"
|
|
6724
|
+
},
|
|
6725
|
+
props: {
|
|
6726
|
+
type: "object",
|
|
6727
|
+
description: "remember: extra Observation props"
|
|
6728
|
+
},
|
|
6729
|
+
agent_id: {
|
|
6730
|
+
type: "string",
|
|
6731
|
+
description: "Agent identifier (default: configured agent)"
|
|
6732
|
+
}
|
|
6733
|
+
},
|
|
6734
|
+
required: ["action"]
|
|
6735
|
+
}
|
|
6736
|
+
},
|
|
6433
6737
|
MEMORY_TOOL,
|
|
6434
6738
|
SYNC_TOOL,
|
|
6435
6739
|
CODE_TOOL
|
|
@@ -6605,13 +6909,14 @@ async function handleGeneratedTool(client2, desc, args) {
|
|
|
6605
6909
|
return err4(`unknown generated tool mapping: ${desc.maps_to}`);
|
|
6606
6910
|
}
|
|
6607
6911
|
} catch (e) {
|
|
6608
|
-
return
|
|
6912
|
+
return toolError(e);
|
|
6609
6913
|
}
|
|
6610
6914
|
}
|
|
6611
6915
|
var ok4, rendered, err4, CACHE_TTL_MS, FAILURE_COOLDOWN_MS, cache, retryNotBefore, EMPTY, DuplicateGeneratedToolError, STRUCTURED_QUERY_PASSTHROUGH;
|
|
6612
6916
|
var init_generated_tools = __esm({
|
|
6613
6917
|
"src/generated-tools.ts"() {
|
|
6614
6918
|
"use strict";
|
|
6919
|
+
init_error_detail();
|
|
6615
6920
|
init_render();
|
|
6616
6921
|
ok4 = (data) => ({
|
|
6617
6922
|
// Compact on purpose — pretty-printing doubled the token cost.
|
|
@@ -6671,6 +6976,7 @@ function unsupportedResponse(status, body) {
|
|
|
6671
6976
|
function toolMutability(toolName, action) {
|
|
6672
6977
|
if (toolName === "mindgraph_memory") return "read";
|
|
6673
6978
|
if (toolName === "mindgraph_retrieve") return "read";
|
|
6979
|
+
if (toolName === "mindgraph_remember") return "write";
|
|
6674
6980
|
if (toolName === "mindgraph_series_query") return "read";
|
|
6675
6981
|
if (toolName === "mindgraph_plan") {
|
|
6676
6982
|
return action && PLAN_READ_ACTIONS.has(action) ? "read" : "write";
|
|
@@ -7021,7 +7327,7 @@ async function main() {
|
|
|
7021
7327
|
const transport = new import_stdio.StdioServerTransport();
|
|
7022
7328
|
await server.connect(transport);
|
|
7023
7329
|
console.error(
|
|
7024
|
-
`MindGraph MCP server v${"0.
|
|
7330
|
+
`MindGraph MCP server v${"0.21.0"} running on stdio (${BASE_URL})`
|
|
7025
7331
|
);
|
|
7026
7332
|
}
|
|
7027
7333
|
var import_server, import_stdio, import_types, import_node_path6, API_KEY, BASE_URL, AGENT_ID, ORG_ID, PROFILE, HARNESS, client, INSTRUCTIONS, RUNNER_REFRESH, HOOK_SKEW_NOTE, server, GOVERNANCE_CONFIG, MEMORY_RUNTIME_CONFIG, PROMPTS;
|
|
@@ -7073,11 +7379,13 @@ var init_src = __esm({
|
|
|
7073
7379
|
|
|
7074
7380
|
**Answer from the bounded result.** Treat superseded, refuted, or out-of-validity items as warnings, not current facts. Retrieval proves only that the server returned context; it does not prove that a host automatically injected or used it.
|
|
7075
7381
|
|
|
7382
|
+
**Respect failed tool results.** An isError result is a failed operation, not evidence that the graph has no matches. Preserve its code and retry guidance. If retriable is false, do not automatically repeat the unchanged call or silently substitute another retrieval mode. Explain the failure; a narrower query or a later user-requested retry is a separate decision.
|
|
7383
|
+
|
|
7076
7384
|
**Preserve selectively after material durable change.** Use the existing typed write tool for a fact, correction, decision, work-state transition, or reusable lesson. Do not write ephemeral conversation, routine mechanics, unsupported guesses, or information already represented accurately. An explicit no-write is the correct outcome when nothing durable changed.
|
|
7077
7385
|
|
|
7078
7386
|
## Topic retrieval details
|
|
7079
7387
|
|
|
7080
|
-
Topic context is graph-only by default. Set \`include_chunks: true\` only for source text needed for quotes, citations, or missing detail. Query with a few proper nouns or technical terms rather than a full sentence. If keyword retrieval
|
|
7388
|
+
Topic context is graph-only by default. Set \`include_chunks: true\` only for source text needed for quotes, citations, or missing detail. Query with a few proper nouns or technical terms rather than a full sentence. If keyword retrieval succeeds but returns no matches, use \`mindgraph_retrieve\` with \`semantic\` or \`hybrid\`; use \`document_index\` to inspect ingested sources.
|
|
7081
7389
|
|
|
7082
7390
|
## Comprehensive read tools
|
|
7083
7391
|
|
|
@@ -7136,7 +7444,7 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
7136
7444
|
}
|
|
7137
7445
|
RUNNER_REFRESH = (() => {
|
|
7138
7446
|
try {
|
|
7139
|
-
return refreshHookRunner("0.
|
|
7447
|
+
return refreshHookRunner("0.21.0", import_node_path6.default.join(__dirname, "cli.js"));
|
|
7140
7448
|
} catch {
|
|
7141
7449
|
return void 0;
|
|
7142
7450
|
}
|
|
@@ -7150,12 +7458,12 @@ Capture knowledge when the user shares something worth remembering:
|
|
|
7150
7458
|
}
|
|
7151
7459
|
})();
|
|
7152
7460
|
console.error(
|
|
7153
|
-
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.
|
|
7461
|
+
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.21.0"}` + (refreshedSettings.length > 0 ? `; refreshed owned hook entries in ${refreshedSettings.join(", ")}` : "")
|
|
7154
7462
|
);
|
|
7155
7463
|
}
|
|
7156
7464
|
HOOK_SKEW_NOTE = (() => {
|
|
7157
7465
|
try {
|
|
7158
|
-
return versionSkewNote("0.
|
|
7466
|
+
return versionSkewNote("0.21.0");
|
|
7159
7467
|
} catch {
|
|
7160
7468
|
return void 0;
|
|
7161
7469
|
}
|
|
@@ -7169,7 +7477,7 @@ ${HOOK_SKEW_NOTE}`;
|
|
|
7169
7477
|
server = new import_server.Server(
|
|
7170
7478
|
{
|
|
7171
7479
|
name: "mindgraph",
|
|
7172
|
-
version: "0.
|
|
7480
|
+
version: "0.21.0"
|
|
7173
7481
|
},
|
|
7174
7482
|
{
|
|
7175
7483
|
capabilities: {
|
|
@@ -7194,7 +7502,7 @@ ${HOOK_SKEW_NOTE}`;
|
|
|
7194
7502
|
}
|
|
7195
7503
|
};
|
|
7196
7504
|
MEMORY_RUNTIME_CONFIG = {
|
|
7197
|
-
serverVersion: "0.
|
|
7505
|
+
serverVersion: "0.21.0",
|
|
7198
7506
|
baseUrl: BASE_URL,
|
|
7199
7507
|
profile: PROFILE,
|
|
7200
7508
|
harness: HARNESS,
|
|
@@ -8961,7 +9269,7 @@ function withHooksFlag() {
|
|
|
8961
9269
|
}
|
|
8962
9270
|
function finishCodeInstall(apiKey, baseUrl, withHooks, agentId) {
|
|
8963
9271
|
if (withHooks) {
|
|
8964
|
-
const runner = installHookRunner(__filename, void 0, "0.
|
|
9272
|
+
const runner = installHookRunner(__filename, void 0, "0.21.0");
|
|
8965
9273
|
console.log(`Installed pinned hook runner at ${runner}`);
|
|
8966
9274
|
const result = installClaudeHooks("user");
|
|
8967
9275
|
console.log(
|
|
@@ -9276,7 +9584,7 @@ ${total} skill(s) synced.`);
|
|
|
9276
9584
|
if (hookHarness !== "claude-code" && hookHarness !== "codex") {
|
|
9277
9585
|
throw new Error("--harness must be claude-code or codex");
|
|
9278
9586
|
}
|
|
9279
|
-
const runner = installHookRunner(__filename, void 0, "0.
|
|
9587
|
+
const runner = installHookRunner(__filename, void 0, "0.21.0");
|
|
9280
9588
|
console.log(`Installed pinned hook runner at ${runner}`);
|
|
9281
9589
|
const result = hookHarness === "codex" ? installCodexHooks(scope, projectDir) : installClaudeHooks(scope, projectDir);
|
|
9282
9590
|
console.log(
|
package/dist/index.js
CHANGED
|
@@ -89,6 +89,22 @@ function conflictState(e) {
|
|
|
89
89
|
}
|
|
90
90
|
return lifted;
|
|
91
91
|
}
|
|
92
|
+
function toolError(e, fallbackCode) {
|
|
93
|
+
const body = e instanceof import_mindgraph.MindGraphError && e.body && typeof e.body === "object" && !Array.isArray(e.body) ? e.body : {};
|
|
94
|
+
const code = typeof body.code === "string" ? body.code : fallbackCode;
|
|
95
|
+
const payload = {
|
|
96
|
+
error: errorDetail(e),
|
|
97
|
+
...conflictState(e),
|
|
98
|
+
...e instanceof import_mindgraph.MindGraphError ? { status: e.status } : {},
|
|
99
|
+
...code !== void 0 ? { code } : {},
|
|
100
|
+
...typeof body.retriable === "boolean" ? { retriable: body.retriable } : {}
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
104
|
+
structuredContent: payload,
|
|
105
|
+
isError: true
|
|
106
|
+
};
|
|
107
|
+
}
|
|
92
108
|
|
|
93
109
|
// src/codegraph.ts
|
|
94
110
|
var import_node_child_process = require("child_process");
|
|
@@ -1086,7 +1102,7 @@ async function handleCodeTool(client2, args, adapter = new CodegraphAdapter({ cw
|
|
|
1086
1102
|
if (cause instanceof UnknownRepositoryError) {
|
|
1087
1103
|
return err("unknown_repository", cause.message);
|
|
1088
1104
|
}
|
|
1089
|
-
return
|
|
1105
|
+
return toolError(cause, "code_tool_failed");
|
|
1090
1106
|
}
|
|
1091
1107
|
}
|
|
1092
1108
|
async function attachCodeRefsToToolResult(client2, result, args, adapter) {
|
|
@@ -1558,7 +1574,7 @@ async function handleSyncTool(client2, args) {
|
|
|
1558
1574
|
}
|
|
1559
1575
|
return ok2(await remote.memorySync(request));
|
|
1560
1576
|
} catch (error2) {
|
|
1561
|
-
return
|
|
1577
|
+
return toolError(error2, "sync_failed");
|
|
1562
1578
|
}
|
|
1563
1579
|
}
|
|
1564
1580
|
async function scanRepository(remote, repository, requested, provider, agentId) {
|
|
@@ -3919,6 +3935,66 @@ var TOOLS = [
|
|
|
3919
3935
|
required: ["action"]
|
|
3920
3936
|
}
|
|
3921
3937
|
},
|
|
3938
|
+
{
|
|
3939
|
+
name: "mindgraph_remember",
|
|
3940
|
+
description: "Small-text memory fast path. 'remember' stores one fact, preference, decision or note synchronously; it is BM25- and vector-searchable the moment the call returns (the response says which). Pass a stable custom_id (e.g. 'pref:theme', 'deploy:target') so re-sending the same key UPDATES the same memory instead of creating a duplicate \u2014 that is the idempotency contract; without custom_id an exact duplicate is reused. 'forget' reversibly removes a memory by uid or custom_id (tombstone plus connected edges): call it with dry_run=true first to see the edge uids it would remove, then without. Undo with mindgraph_capture-independent server actions /evolve restore and restore_edge. Use mindgraph_capture for typed entities, sources and skills, and mindgraph_ingest for documents longer than a few paragraphs.",
|
|
3941
|
+
inputSchema: {
|
|
3942
|
+
type: "object",
|
|
3943
|
+
properties: {
|
|
3944
|
+
action: {
|
|
3945
|
+
type: "string",
|
|
3946
|
+
enum: ["remember", "forget"],
|
|
3947
|
+
description: "remember = store/upsert one small text; forget = reversible removal"
|
|
3948
|
+
},
|
|
3949
|
+
text: {
|
|
3950
|
+
type: "string",
|
|
3951
|
+
description: "remember: the memory text (\u2264 8 KiB). Use mindgraph_ingest for longer content."
|
|
3952
|
+
},
|
|
3953
|
+
custom_id: {
|
|
3954
|
+
type: "string",
|
|
3955
|
+
description: "Caller-owned key. remember: re-sending it edits the same memory (version bump, history kept). forget: the memory to remove."
|
|
3956
|
+
},
|
|
3957
|
+
label: {
|
|
3958
|
+
type: "string",
|
|
3959
|
+
description: "remember: optional short title; defaults to the first line of text"
|
|
3960
|
+
},
|
|
3961
|
+
uid: {
|
|
3962
|
+
type: "string",
|
|
3963
|
+
description: "forget: node uid to remove (alternative to custom_id)"
|
|
3964
|
+
},
|
|
3965
|
+
dry_run: {
|
|
3966
|
+
type: "boolean",
|
|
3967
|
+
description: "forget: preview the affected edge uids without changing anything"
|
|
3968
|
+
},
|
|
3969
|
+
cascade: {
|
|
3970
|
+
type: "boolean",
|
|
3971
|
+
description: "forget: also tombstone connected edges (default true)"
|
|
3972
|
+
},
|
|
3973
|
+
reason: {
|
|
3974
|
+
type: "string",
|
|
3975
|
+
description: "forget: why (recorded on the tombstone)"
|
|
3976
|
+
},
|
|
3977
|
+
space_uid: {
|
|
3978
|
+
type: "string",
|
|
3979
|
+
description: "remember: explicit target Space (default: the org space)"
|
|
3980
|
+
},
|
|
3981
|
+
on_near_duplicate: {
|
|
3982
|
+
type: "string",
|
|
3983
|
+
enum: ["reuse", "create"],
|
|
3984
|
+
description: "remember without custom_id: on an exact duplicate, reuse the existing memory (default) or create anyway"
|
|
3985
|
+
},
|
|
3986
|
+
props: {
|
|
3987
|
+
type: "object",
|
|
3988
|
+
description: "remember: extra Observation props"
|
|
3989
|
+
},
|
|
3990
|
+
agent_id: {
|
|
3991
|
+
type: "string",
|
|
3992
|
+
description: "Agent identifier (default: configured agent)"
|
|
3993
|
+
}
|
|
3994
|
+
},
|
|
3995
|
+
required: ["action"]
|
|
3996
|
+
}
|
|
3997
|
+
},
|
|
3922
3998
|
MEMORY_TOOL,
|
|
3923
3999
|
SYNC_TOOL,
|
|
3924
4000
|
CODE_TOOL
|
|
@@ -4004,6 +4080,9 @@ async function handleTool(client2, name, args, memoryConfig = {}) {
|
|
|
4004
4080
|
case "mindgraph_memory":
|
|
4005
4081
|
result = await handleMemoryTool(client2, args, memoryConfig);
|
|
4006
4082
|
break;
|
|
4083
|
+
case "mindgraph_remember":
|
|
4084
|
+
result = await handleRemember(client2, args);
|
|
4085
|
+
break;
|
|
4007
4086
|
case "mindgraph_series_query":
|
|
4008
4087
|
result = await handleSeriesQuery(client2, args);
|
|
4009
4088
|
break;
|
|
@@ -4036,19 +4115,7 @@ async function handleTool(client2, name, args, memoryConfig = {}) {
|
|
|
4036
4115
|
].includes(action);
|
|
4037
4116
|
return attach ? await attachCodeRefsToToolResult(client2, result, args) : result;
|
|
4038
4117
|
} catch (e) {
|
|
4039
|
-
|
|
4040
|
-
if (Object.keys(lifted).length > 0) {
|
|
4041
|
-
return {
|
|
4042
|
-
content: [
|
|
4043
|
-
{
|
|
4044
|
-
type: "text",
|
|
4045
|
-
text: JSON.stringify({ error: errorDetail(e), ...lifted })
|
|
4046
|
-
}
|
|
4047
|
-
],
|
|
4048
|
-
isError: true
|
|
4049
|
-
};
|
|
4050
|
-
}
|
|
4051
|
-
return err3(errorDetail(e));
|
|
4118
|
+
return toolError(e);
|
|
4052
4119
|
}
|
|
4053
4120
|
}
|
|
4054
4121
|
async function handleSeriesQuery(client2, args) {
|
|
@@ -4072,6 +4139,56 @@ async function handleSeriesQuery(client2, args) {
|
|
|
4072
4139
|
await client2.series(args)
|
|
4073
4140
|
);
|
|
4074
4141
|
}
|
|
4142
|
+
async function handleRemember(client2, args) {
|
|
4143
|
+
const {
|
|
4144
|
+
action,
|
|
4145
|
+
text: text2,
|
|
4146
|
+
custom_id,
|
|
4147
|
+
label,
|
|
4148
|
+
uid,
|
|
4149
|
+
dry_run,
|
|
4150
|
+
cascade,
|
|
4151
|
+
reason,
|
|
4152
|
+
space_uid,
|
|
4153
|
+
on_near_duplicate,
|
|
4154
|
+
props,
|
|
4155
|
+
agent_id,
|
|
4156
|
+
// Adapter-owned; consumed locally, never sent to the API.
|
|
4157
|
+
invocation_context: _invocationContext,
|
|
4158
|
+
...rest
|
|
4159
|
+
} = args;
|
|
4160
|
+
void _invocationContext;
|
|
4161
|
+
void rest;
|
|
4162
|
+
switch (action) {
|
|
4163
|
+
case "remember": {
|
|
4164
|
+
if (typeof text2 !== "string" || !text2.trim()) {
|
|
4165
|
+
return err3("remember requires non-empty text");
|
|
4166
|
+
}
|
|
4167
|
+
const options = {};
|
|
4168
|
+
if (typeof custom_id === "string" && custom_id.trim()) options.custom_id = custom_id.trim();
|
|
4169
|
+
if (typeof label === "string" && label.trim()) options.label = label;
|
|
4170
|
+
if (typeof space_uid === "string" && space_uid.trim()) options.space_uid = space_uid;
|
|
4171
|
+
if (on_near_duplicate === "reuse" || on_near_duplicate === "create") {
|
|
4172
|
+
options.on_near_duplicate = on_near_duplicate;
|
|
4173
|
+
}
|
|
4174
|
+
if (props && typeof props === "object") options.props = props;
|
|
4175
|
+
if (typeof agent_id === "string") options.agent_id = agent_id;
|
|
4176
|
+
return ok3(await client2.remember(text2, options));
|
|
4177
|
+
}
|
|
4178
|
+
case "forget": {
|
|
4179
|
+
const target = typeof uid === "string" && uid.trim() ? { uid: uid.trim() } : typeof custom_id === "string" && custom_id.trim() ? { custom_id: custom_id.trim() } : null;
|
|
4180
|
+
if (!target) return err3("forget requires uid or custom_id");
|
|
4181
|
+
const options = {};
|
|
4182
|
+
if (dry_run === true) options.dry_run = true;
|
|
4183
|
+
if (typeof cascade === "boolean") options.cascade = cascade;
|
|
4184
|
+
if (typeof reason === "string" && reason.trim()) options.reason = reason;
|
|
4185
|
+
if (typeof agent_id === "string") options.agent_id = agent_id;
|
|
4186
|
+
return ok3(await client2.forget(target, options));
|
|
4187
|
+
}
|
|
4188
|
+
default:
|
|
4189
|
+
return err3(`Unknown remember action: ${String(action)}`);
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4075
4192
|
async function handleCapture(client2, args) {
|
|
4076
4193
|
const {
|
|
4077
4194
|
action,
|
|
@@ -5346,7 +5463,7 @@ async function handleGeneratedTool(client2, desc, args) {
|
|
|
5346
5463
|
return err4(`unknown generated tool mapping: ${desc.maps_to}`);
|
|
5347
5464
|
}
|
|
5348
5465
|
} catch (e) {
|
|
5349
|
-
return
|
|
5466
|
+
return toolError(e);
|
|
5350
5467
|
}
|
|
5351
5468
|
}
|
|
5352
5469
|
|
|
@@ -5398,6 +5515,7 @@ var ONTOLOGY_READ_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
5398
5515
|
function toolMutability(toolName, action) {
|
|
5399
5516
|
if (toolName === "mindgraph_memory") return "read";
|
|
5400
5517
|
if (toolName === "mindgraph_retrieve") return "read";
|
|
5518
|
+
if (toolName === "mindgraph_remember") return "write";
|
|
5401
5519
|
if (toolName === "mindgraph_series_query") return "read";
|
|
5402
5520
|
if (toolName === "mindgraph_plan") {
|
|
5403
5521
|
return action && PLAN_READ_ACTIONS.has(action) ? "read" : "write";
|
|
@@ -5958,11 +6076,13 @@ var INSTRUCTIONS = `You have access to a persistent knowledge graph via MindGrap
|
|
|
5958
6076
|
|
|
5959
6077
|
**Answer from the bounded result.** Treat superseded, refuted, or out-of-validity items as warnings, not current facts. Retrieval proves only that the server returned context; it does not prove that a host automatically injected or used it.
|
|
5960
6078
|
|
|
6079
|
+
**Respect failed tool results.** An isError result is a failed operation, not evidence that the graph has no matches. Preserve its code and retry guidance. If retriable is false, do not automatically repeat the unchanged call or silently substitute another retrieval mode. Explain the failure; a narrower query or a later user-requested retry is a separate decision.
|
|
6080
|
+
|
|
5961
6081
|
**Preserve selectively after material durable change.** Use the existing typed write tool for a fact, correction, decision, work-state transition, or reusable lesson. Do not write ephemeral conversation, routine mechanics, unsupported guesses, or information already represented accurately. An explicit no-write is the correct outcome when nothing durable changed.
|
|
5962
6082
|
|
|
5963
6083
|
## Topic retrieval details
|
|
5964
6084
|
|
|
5965
|
-
Topic context is graph-only by default. Set \`include_chunks: true\` only for source text needed for quotes, citations, or missing detail. Query with a few proper nouns or technical terms rather than a full sentence. If keyword retrieval
|
|
6085
|
+
Topic context is graph-only by default. Set \`include_chunks: true\` only for source text needed for quotes, citations, or missing detail. Query with a few proper nouns or technical terms rather than a full sentence. If keyword retrieval succeeds but returns no matches, use \`mindgraph_retrieve\` with \`semantic\` or \`hybrid\`; use \`document_index\` to inspect ingested sources.
|
|
5966
6086
|
|
|
5967
6087
|
## Comprehensive read tools
|
|
5968
6088
|
|
|
@@ -6021,7 +6141,7 @@ if (PROFILE === "coding") {
|
|
|
6021
6141
|
}
|
|
6022
6142
|
var RUNNER_REFRESH = (() => {
|
|
6023
6143
|
try {
|
|
6024
|
-
return refreshHookRunner("0.
|
|
6144
|
+
return refreshHookRunner("0.21.0", import_node_path5.default.join(__dirname, "cli.js"));
|
|
6025
6145
|
} catch {
|
|
6026
6146
|
return void 0;
|
|
6027
6147
|
}
|
|
@@ -6035,12 +6155,12 @@ if (RUNNER_REFRESH?.refreshed) {
|
|
|
6035
6155
|
}
|
|
6036
6156
|
})();
|
|
6037
6157
|
console.error(
|
|
6038
|
-
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.
|
|
6158
|
+
`[mindgraph-mcp] refreshed pinned hook runner ${RUNNER_REFRESH.runnerVersion ? `v${RUNNER_REFRESH.runnerVersion}` : "(pre-sidecar)"} \u2192 v${"0.21.0"}` + (refreshedSettings.length > 0 ? `; refreshed owned hook entries in ${refreshedSettings.join(", ")}` : "")
|
|
6039
6159
|
);
|
|
6040
6160
|
}
|
|
6041
6161
|
var HOOK_SKEW_NOTE = (() => {
|
|
6042
6162
|
try {
|
|
6043
|
-
return versionSkewNote("0.
|
|
6163
|
+
return versionSkewNote("0.21.0");
|
|
6044
6164
|
} catch {
|
|
6045
6165
|
return void 0;
|
|
6046
6166
|
}
|
|
@@ -6054,7 +6174,7 @@ ${HOOK_SKEW_NOTE}`;
|
|
|
6054
6174
|
var server = new import_server.Server(
|
|
6055
6175
|
{
|
|
6056
6176
|
name: "mindgraph",
|
|
6057
|
-
version: "0.
|
|
6177
|
+
version: "0.21.0"
|
|
6058
6178
|
},
|
|
6059
6179
|
{
|
|
6060
6180
|
capabilities: {
|
|
@@ -6079,7 +6199,7 @@ var GOVERNANCE_CONFIG = {
|
|
|
6079
6199
|
}
|
|
6080
6200
|
};
|
|
6081
6201
|
var MEMORY_RUNTIME_CONFIG = {
|
|
6082
|
-
serverVersion: "0.
|
|
6202
|
+
serverVersion: "0.21.0",
|
|
6083
6203
|
baseUrl: BASE_URL,
|
|
6084
6204
|
profile: PROFILE,
|
|
6085
6205
|
harness: HARNESS,
|
|
@@ -6281,7 +6401,7 @@ async function main() {
|
|
|
6281
6401
|
const transport = new import_stdio.StdioServerTransport();
|
|
6282
6402
|
await server.connect(transport);
|
|
6283
6403
|
console.error(
|
|
6284
|
-
`MindGraph MCP server v${"0.
|
|
6404
|
+
`MindGraph MCP server v${"0.21.0"} running on stdio (${BASE_URL})`
|
|
6285
6405
|
);
|
|
6286
6406
|
}
|
|
6287
6407
|
main().catch((error2) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mindgraph-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "MCP server for MindGraph — connect Claude Desktop, Claude Code, and any MCP client to your knowledge graph",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
35
|
-
"mindgraph": "^0.
|
|
35
|
+
"mindgraph": "^0.16.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^22.0.0",
|