@kage-core/kage-graph-mcp 1.1.5 → 1.1.7
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 +12 -8
- package/dist/index.js +39 -1
- package/dist/kernel.js +42 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -158,6 +158,11 @@ ranking: text, graph, path/type/tag, freshness, quality, feedback, and a vector
|
|
|
158
158
|
placeholder for future local or external embedding providers. Current fallback
|
|
159
159
|
is deterministic text plus graph retrieval.
|
|
160
160
|
|
|
161
|
+
`kage_context` is the primary MCP entrypoint for agents. It validates repo
|
|
162
|
+
memory, recalls relevant packets, and returns code/knowledge graph context in
|
|
163
|
+
one call. Agents should use it at task start instead of loading separate
|
|
164
|
+
`kage_validate`, `kage_recall`, `kage_code_graph`, and `kage_graph` schemas.
|
|
165
|
+
|
|
161
166
|
`kage daemon start` exposes the optional local REST runtime on
|
|
162
167
|
`127.0.0.1:3111`:
|
|
163
168
|
|
|
@@ -203,6 +208,7 @@ confidence, and token-savings metrics connect.
|
|
|
203
208
|
|
|
204
209
|
Local repo tools:
|
|
205
210
|
|
|
211
|
+
- `kage_context`
|
|
206
212
|
- `kage_recall`
|
|
207
213
|
- `kage_code_graph`
|
|
208
214
|
- `kage_metrics`
|
|
@@ -288,14 +294,12 @@ Minimum policy:
|
|
|
288
294
|
|
|
289
295
|
```md
|
|
290
296
|
Before code changes or repo-specific answers:
|
|
291
|
-
1. Call `
|
|
292
|
-
2.
|
|
293
|
-
3.
|
|
294
|
-
4.
|
|
295
|
-
5.
|
|
296
|
-
6.
|
|
297
|
-
7. Before merge, call `kage_pr_check`.
|
|
298
|
-
8. Never publish or promote org/global memory automatically.
|
|
297
|
+
1. Call `kage_context` with `project_dir` and the user task as `query`.
|
|
298
|
+
2. Capture reusable learnings with `kage_learn` or `kage_capture`.
|
|
299
|
+
3. After meaningful file changes, call `kage_refresh`.
|
|
300
|
+
4. Before finishing changed-file tasks, call `kage_propose_from_diff` or `kage_pr_summarize`.
|
|
301
|
+
5. Before merge, call `kage_pr_check`.
|
|
302
|
+
6. Never publish or promote org/global memory automatically.
|
|
299
303
|
```
|
|
300
304
|
|
|
301
305
|
Run `kage setup verify-agent --agent codex --project <repo>` after setup. The
|
package/dist/index.js
CHANGED
|
@@ -54,9 +54,25 @@ function arrayArg(value) {
|
|
|
54
54
|
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
55
55
|
return [];
|
|
56
56
|
}
|
|
57
|
-
const server = new index_js_1.Server({ name: "kage-graph", version: "1.1.
|
|
57
|
+
const server = new index_js_1.Server({ name: "kage-graph", version: "1.1.7" }, { capabilities: { tools: {} } });
|
|
58
58
|
function listTools() {
|
|
59
59
|
return [
|
|
60
|
+
{
|
|
61
|
+
// Combined entry-point tool: validate + recall + code_graph + graph in one call.
|
|
62
|
+
// Agents should load this schema first (one ToolSearch) instead of loading four
|
|
63
|
+
// separate deferred schemas. Cuts session start from 4 schema loads to 1.
|
|
64
|
+
name: "kage_context",
|
|
65
|
+
description: "Primary kage entry point. Validates memory health, recalls relevant packets, and queries both the code graph and knowledge graph — all in one call. Call this at the start of every task instead of calling kage_validate, kage_recall, kage_code_graph, and kage_graph separately.",
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: "object",
|
|
68
|
+
properties: {
|
|
69
|
+
project_dir: { type: "string", description: "Absolute path to the project root" },
|
|
70
|
+
query: { type: "string", description: "The task or question — used for both memory recall and code graph search" },
|
|
71
|
+
limit: { type: "number", description: "Max memory packets to return (default 5)" },
|
|
72
|
+
},
|
|
73
|
+
required: ["project_dir", "query"],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
60
76
|
{
|
|
61
77
|
name: "kage_search",
|
|
62
78
|
description: "Search the kage community knowledge graph for gotchas, patterns, configs, and architectural decisions across auth, database, payments, deployment, frontend, testing, and more. Returns node summaries ranked by relevance.",
|
|
@@ -608,6 +624,28 @@ async function callTool(name, args) {
|
|
|
608
624
|
content: [{ type: "text", text: content }],
|
|
609
625
|
};
|
|
610
626
|
}
|
|
627
|
+
if (name === "kage_context") {
|
|
628
|
+
const projectDir = String(args?.project_dir ?? "");
|
|
629
|
+
const query = String(args?.query ?? "");
|
|
630
|
+
const limit = Number(args?.limit ?? 5);
|
|
631
|
+
// validate
|
|
632
|
+
const validation = (0, kernel_js_1.validateProject)(projectDir);
|
|
633
|
+
const validationText = validation.ok
|
|
634
|
+
? "Memory healthy."
|
|
635
|
+
: `Warnings: ${validation.warnings.join("; ")}`;
|
|
636
|
+
// recall (memory + code graph + knowledge graph combined)
|
|
637
|
+
const recallResult = (0, kernel_js_1.recall)(projectDir, query, limit, false);
|
|
638
|
+
// graph facts on top of recall
|
|
639
|
+
const graphResult = (0, kernel_js_1.queryGraph)(projectDir, query, 5);
|
|
640
|
+
const sections = [
|
|
641
|
+
recallResult.context_block,
|
|
642
|
+
graphResult.context_block ? `\n## Graph Facts\n${graphResult.context_block}` : "",
|
|
643
|
+
`\n_${validationText}_`,
|
|
644
|
+
].filter(Boolean).join("");
|
|
645
|
+
return {
|
|
646
|
+
content: [{ type: "text", text: sections }],
|
|
647
|
+
};
|
|
648
|
+
}
|
|
611
649
|
if (name === "kage_recall") {
|
|
612
650
|
const result = (0, kernel_js_1.recall)(String(args?.project_dir ?? ""), String(args?.query ?? ""), Number(args?.limit ?? 5), Boolean(args?.explain));
|
|
613
651
|
return {
|
package/dist/kernel.js
CHANGED
|
@@ -151,12 +151,11 @@ This repo uses Kage as an automatic memory harness for coding agents.
|
|
|
151
151
|
|
|
152
152
|
Before making code changes, answering repo-specific implementation questions, debugging failures, or proposing architecture:
|
|
153
153
|
|
|
154
|
-
1. Call \`
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
6. Prefer repo memory over public/community memory when they conflict.
|
|
154
|
+
1. Call \`kage_context\` with \`project_dir\` and the task as \`query\`.
|
|
155
|
+
This validates memory, recalls relevant packets, and queries both the code graph
|
|
156
|
+
and knowledge graph in one call — replacing the old four-step validate/recall/code_graph/graph sequence.
|
|
157
|
+
2. Use returned memory only when it is relevant, source-backed, and not stale.
|
|
158
|
+
3. Prefer repo memory over public/community memory when they conflict.
|
|
160
159
|
|
|
161
160
|
Do this without waiting for the user to ask. Kage should feel like ambient repo memory, not a manual search command.
|
|
162
161
|
|
|
@@ -217,17 +216,13 @@ If recalled memory materially helped, call \`kage_feedback\` with \`helpful\`.
|
|
|
217
216
|
|
|
218
217
|
For normal coding tasks:
|
|
219
218
|
|
|
220
|
-
1. \`
|
|
221
|
-
2.
|
|
222
|
-
3. \`
|
|
223
|
-
4. \`
|
|
224
|
-
5.
|
|
225
|
-
6. \`kage_learn\` for concrete learnings
|
|
226
|
-
7. \`kage_refresh\` after meaningful file changes
|
|
227
|
-
8. \`kage_pr_summarize\` or \`kage_propose_from_diff\` before the final response to create repo-local change memory
|
|
228
|
-
9. \`kage_pr_check\` before final handoff or merge readiness claims
|
|
219
|
+
1. \`kage_context\` — validate + recall + code graph + knowledge graph in one call
|
|
220
|
+
2. Work on the task
|
|
221
|
+
3. \`kage_learn\` for concrete learnings
|
|
222
|
+
4. \`kage_refresh\` after meaningful file changes
|
|
223
|
+
5. \`kage_propose_from_diff\` before the final response to create repo-local change memory
|
|
229
224
|
|
|
230
|
-
For quick factual questions, \`
|
|
225
|
+
For quick factual questions, \`kage_context\` alone is enough. For status or demo requests, call \`kage_metrics\`.
|
|
231
226
|
${AGENTS_POLICY_END}
|
|
232
227
|
`;
|
|
233
228
|
const STOPWORDS = new Set([
|
|
@@ -340,6 +335,9 @@ function repoKey(projectDir) {
|
|
|
340
335
|
}
|
|
341
336
|
return slugify((0, node_path_1.basename)(projectDir));
|
|
342
337
|
}
|
|
338
|
+
function repoDisplayName(projectDir) {
|
|
339
|
+
return (0, node_path_1.basename)((0, node_path_1.resolve)(projectDir));
|
|
340
|
+
}
|
|
343
341
|
function makePacketId(projectDir, type, title, suffix) {
|
|
344
342
|
const raw = suffix ? `${title}-${suffix}` : title;
|
|
345
343
|
return `repo:${repoKey(projectDir)}:${type}:${slugify(raw)}`;
|
|
@@ -580,7 +578,9 @@ function evaluateMemoryQuality(projectDir, packet) {
|
|
|
580
578
|
risks,
|
|
581
579
|
duplicate_candidates: duplicates,
|
|
582
580
|
stale_reasons: staleReasons,
|
|
583
|
-
|
|
581
|
+
// Tokens an agent saves by reading this packet instead of the files it references.
|
|
582
|
+
// Approximated as the token size of the files it grounds to (or the packet body if no paths).
|
|
583
|
+
estimated_tokens_saved: Math.max(20, estimateTokens(packet.body)),
|
|
584
584
|
};
|
|
585
585
|
}
|
|
586
586
|
function evaluateMemoryAdmission(projectDir, packet) {
|
|
@@ -934,14 +934,14 @@ function createRepoOverviewPacket(projectDir) {
|
|
|
934
934
|
const readmePath = (0, node_path_1.join)(projectDir, "README.md");
|
|
935
935
|
if (!(0, node_fs_1.existsSync)(packagePath) && !(0, node_fs_1.existsSync)(readmePath))
|
|
936
936
|
return null;
|
|
937
|
-
let title = `${(
|
|
937
|
+
let title = `${repoDisplayName(projectDir)} repo overview`;
|
|
938
938
|
const tags = ["repo", "overview"];
|
|
939
939
|
const bodyParts = [];
|
|
940
940
|
const paths = ["root"];
|
|
941
941
|
const stack = [];
|
|
942
942
|
if ((0, node_fs_1.existsSync)(packagePath)) {
|
|
943
943
|
const pkg = readJson(packagePath);
|
|
944
|
-
title = `${String(pkg.name ?? (
|
|
944
|
+
title = `${String(pkg.name ?? repoDisplayName(projectDir))} repo overview`;
|
|
945
945
|
const scripts = pkg.scripts && typeof pkg.scripts === "object" ? Object.keys(pkg.scripts) : [];
|
|
946
946
|
const deps = {
|
|
947
947
|
...pkg.dependencies,
|
|
@@ -1053,8 +1053,8 @@ function createRepoStructurePacket(projectDir) {
|
|
|
1053
1053
|
].filter(Boolean).join("\n");
|
|
1054
1054
|
return {
|
|
1055
1055
|
schema_version: exports.PACKET_SCHEMA_VERSION,
|
|
1056
|
-
id: makePacketId(projectDir, "repo_map", `${(
|
|
1057
|
-
title: `${(
|
|
1056
|
+
id: makePacketId(projectDir, "repo_map", `${repoDisplayName(projectDir)} repo structure`, "auto-structure"),
|
|
1057
|
+
title: `${repoDisplayName(projectDir)} repo structure`,
|
|
1058
1058
|
summary: summarize(body),
|
|
1059
1059
|
body,
|
|
1060
1060
|
type: "repo_map",
|
|
@@ -1086,7 +1086,18 @@ function createRepoStructurePacket(projectDir) {
|
|
|
1086
1086
|
}
|
|
1087
1087
|
function upsertGeneratedPacket(projectDir, packet) {
|
|
1088
1088
|
const dir = packetsDir(projectDir);
|
|
1089
|
-
const
|
|
1089
|
+
const entries = loadPacketEntriesFromDir(dir);
|
|
1090
|
+
const generatedKind = packet.tags.includes("overview") ? "overview" : packet.tags.includes("structure") ? "structure" : null;
|
|
1091
|
+
for (const entry of entries) {
|
|
1092
|
+
if (generatedKind &&
|
|
1093
|
+
entry.packet.id !== packet.id &&
|
|
1094
|
+
entry.packet.type === packet.type &&
|
|
1095
|
+
entry.packet.quality?.reviewer === "kage-indexer" &&
|
|
1096
|
+
entry.packet.tags.includes(generatedKind)) {
|
|
1097
|
+
(0, node_fs_1.unlinkSync)(entry.path);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
const existing = entries.find((entry) => entry.packet.id === packet.id)?.packet;
|
|
1090
1101
|
if (existing && existing.quality?.reviewer !== "kage-indexer")
|
|
1091
1102
|
return;
|
|
1092
1103
|
if (existing) {
|
|
@@ -2906,8 +2917,13 @@ function kageMetrics(projectDir) {
|
|
|
2906
2917
|
const duplicatePairs = allPackets.reduce((sum, packet) => sum + duplicateCandidates(projectDir, packet).length, 0);
|
|
2907
2918
|
const indexedSourceTokens = Math.ceil(sourceFiles.reduce((sum, file) => sum + file.size_bytes, 0) / 4);
|
|
2908
2919
|
const memoryTokens = allPackets.reduce((sum, packet) => sum + estimateTokens(packetText(packet)), 0);
|
|
2920
|
+
// Estimated size of a typical recall response: structured packet summaries + code graph
|
|
2921
|
+
// slice, capped at ~1 800 tokens. This is what actually reaches the agent per recall call.
|
|
2909
2922
|
const recallContextTokens = Math.max(250, Math.min(1800, codeGraph.symbols.length * 12 + codeGraph.routes.length * 10 + knowledgeGraph.edges.length * 14 + 180));
|
|
2910
|
-
|
|
2923
|
+
// Honest saving: tokens an agent would spend reading all source files minus tokens a
|
|
2924
|
+
// targeted recall costs. Only meaningful when an agent would otherwise read everything.
|
|
2925
|
+
// memoryTokens is storage cost, not context sent — excluded from this calculation.
|
|
2926
|
+
const tokensSaved = Math.max(0, indexedSourceTokens - recallContextTokens);
|
|
2911
2927
|
const readinessScore = Math.max(0, Math.min(100, Math.round(coverage * 0.35 +
|
|
2912
2928
|
percent(evidenceBackedEdges, knowledgeGraph.edges.length) * 0.25 +
|
|
2913
2929
|
(approvedPackets > 0 ? 20 : 0) +
|
|
@@ -3213,7 +3229,7 @@ function kageMetricsShallow(projectDir) {
|
|
|
3213
3229
|
estimated_indexed_source_tokens: indexedSourceTokens,
|
|
3214
3230
|
estimated_memory_tokens: memoryTokens,
|
|
3215
3231
|
estimated_recall_context_tokens: recallContextTokens,
|
|
3216
|
-
estimated_tokens_saved_per_recall: Math.max(0, indexedSourceTokens
|
|
3232
|
+
estimated_tokens_saved_per_recall: Math.max(0, indexedSourceTokens - recallContextTokens),
|
|
3217
3233
|
},
|
|
3218
3234
|
harness: {
|
|
3219
3235
|
policy_installed: (0, node_fs_1.existsSync)((0, node_path_1.join)(projectDir, "AGENTS.md")),
|
|
@@ -3528,10 +3544,8 @@ fi
|
|
|
3528
3544
|
if [[ -z "$POLICY" ]]; then
|
|
3529
3545
|
POLICY="This repo uses Kage as an automatic memory harness for coding agents.
|
|
3530
3546
|
Before making code changes or answering implementation questions:
|
|
3531
|
-
1. Call
|
|
3532
|
-
2.
|
|
3533
|
-
3. Call kage_code_graph for file, symbol, route, test, or dependency questions.
|
|
3534
|
-
4. Call kage_graph for decisions, bugs, workflows, and conventions.
|
|
3547
|
+
1. Call kage_context with project_dir and the user task as query.
|
|
3548
|
+
2. Use returned memory only when it is relevant, source-backed, and not stale.
|
|
3535
3549
|
When you learn something reusable: kage_learn.
|
|
3536
3550
|
After meaningful file changes: kage_refresh.
|
|
3537
3551
|
Before finishing a task that changed files: kage_pr_summarize or kage_propose_from_diff, then kage_pr_check.
|