kiri-mcp-server 0.3.0 → 0.4.1
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 +540 -255
- package/config/default.example.yml +2 -2
- package/config/scoring-profiles.yml +1 -1
- package/dist/config/default.example.yml +2 -2
- package/dist/config/scoring-profiles.yml +1 -1
- package/dist/package.json +3 -2
- package/dist/src/client/start-daemon.js +2 -2
- package/dist/src/client/start-daemon.js.map +1 -1
- package/dist/src/indexer/codeintel.d.ts.map +1 -1
- package/dist/src/indexer/codeintel.js +345 -1
- package/dist/src/indexer/codeintel.js.map +1 -1
- package/dist/src/server/fallbacks/degradeController.js +1 -1
- package/dist/src/server/handlers.js +5 -5
- package/dist/src/server/rpc.js +33 -33
- package/dist/src/server/scoring.d.ts +1 -1
- package/package.json +3 -2
|
@@ -453,7 +453,7 @@ export async function filesSearch(context, params) {
|
|
|
453
453
|
const { db, repoId } = context;
|
|
454
454
|
const { query } = params;
|
|
455
455
|
if (!query || query.trim().length === 0) {
|
|
456
|
-
throw new Error("
|
|
456
|
+
throw new Error("files_search requires a non-empty query. Provide a search keyword to continue.");
|
|
457
457
|
}
|
|
458
458
|
const limit = normalizeLimit(params.limit);
|
|
459
459
|
const hasFTS = context.features?.fts ?? false;
|
|
@@ -550,7 +550,7 @@ export async function filesSearch(context, params) {
|
|
|
550
550
|
export async function snippetsGet(context, params) {
|
|
551
551
|
const { db, repoId } = context;
|
|
552
552
|
if (!params.path) {
|
|
553
|
-
throw new Error("
|
|
553
|
+
throw new Error("snippets_get requires a file path. Specify a tracked text file path to continue.");
|
|
554
554
|
}
|
|
555
555
|
const rows = await db.all(`
|
|
556
556
|
SELECT f.path, f.lang, f.ext, f.is_binary, b.content
|
|
@@ -630,7 +630,7 @@ export async function contextBundle(context, params) {
|
|
|
630
630
|
const { db, repoId } = context;
|
|
631
631
|
const goal = params.goal?.trim() ?? "";
|
|
632
632
|
if (goal.length === 0) {
|
|
633
|
-
throw new Error("
|
|
633
|
+
throw new Error("context_bundle requires a non-empty goal. Describe your objective to receive context.");
|
|
634
634
|
}
|
|
635
635
|
const limit = normalizeBundleLimit(params.limit);
|
|
636
636
|
const artifacts = params.artifacts ?? {};
|
|
@@ -880,7 +880,7 @@ export async function contextBundle(context, params) {
|
|
|
880
880
|
export async function semanticRerank(context, params) {
|
|
881
881
|
const text = params.text?.trim() ?? "";
|
|
882
882
|
if (text.length === 0) {
|
|
883
|
-
throw new Error("
|
|
883
|
+
throw new Error("semantic_rerank requires non-empty text. Describe the intent to compute semantic similarity.");
|
|
884
884
|
}
|
|
885
885
|
if (!Array.isArray(params.candidates) || params.candidates.length === 0) {
|
|
886
886
|
return { candidates: [] };
|
|
@@ -948,7 +948,7 @@ export async function semanticRerank(context, params) {
|
|
|
948
948
|
export async function depsClosure(context, params) {
|
|
949
949
|
const { db, repoId } = context;
|
|
950
950
|
if (!params.path) {
|
|
951
|
-
throw new Error("
|
|
951
|
+
throw new Error("deps_closure requires a file path. Provide a tracked source file path to continue.");
|
|
952
952
|
}
|
|
953
953
|
const direction = params.direction ?? "outbound";
|
|
954
954
|
const maxDepth = params.max_depth ?? 3;
|
package/dist/src/server/rpc.js
CHANGED
|
@@ -8,7 +8,7 @@ const SERVER_INFO = {
|
|
|
8
8
|
};
|
|
9
9
|
const TOOL_DESCRIPTORS = [
|
|
10
10
|
{
|
|
11
|
-
name: "
|
|
11
|
+
name: "context_bundle",
|
|
12
12
|
description: "🎯 PRIMARY TOOL: Extracts relevant code context for a specific task or question.\n\n" +
|
|
13
13
|
"Use this tool as your first step for any code-related task. It intelligently finds and ranks relevant files and code snippets using keyword matching, dependency analysis, and semantic similarity.\n\n" +
|
|
14
14
|
"IMPORTANT: The 'goal' parameter MUST be a clear and specific description of your objective. Use concrete keywords, not abstract verbs.\n\n" +
|
|
@@ -82,7 +82,7 @@ const TOOL_DESCRIPTORS = [
|
|
|
82
82
|
},
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
|
-
name: "
|
|
85
|
+
name: "semantic_rerank",
|
|
86
86
|
description: "Re-rank a list of file candidates by semantic similarity to a query text. Uses structural embeddings to compute similarity scores and combines them with existing scores. Use as a REFINEMENT step after files.search or when you have a list of candidates and want to prioritize them by semantic relevance. Not needed with context.bundle (which already does semantic ranking internally). Returns candidates sorted by combined score (base + semantic similarity). Example: after getting 20 search results, rerank them by semantic similarity to 'user authentication flow' to surface the most contextually relevant files.",
|
|
87
87
|
inputSchema: {
|
|
88
88
|
type: "object",
|
|
@@ -108,7 +108,7 @@ const TOOL_DESCRIPTORS = [
|
|
|
108
108
|
},
|
|
109
109
|
},
|
|
110
110
|
{
|
|
111
|
-
name: "
|
|
111
|
+
name: "files_search",
|
|
112
112
|
description: "Search files by specific keywords or identifiers. Use when you know EXACT terms to search for: function names, class names, error messages, or code patterns.\n\n" +
|
|
113
113
|
"IMPORTANT: For broader exploration like 'understand feature X' or 'how does Y work', use context.bundle instead. This tool is for TARGETED searches with specific identifiers.\n\n" +
|
|
114
114
|
"✅ GOOD EXAMPLES (specific identifiers):\n" +
|
|
@@ -161,7 +161,7 @@ const TOOL_DESCRIPTORS = [
|
|
|
161
161
|
},
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
|
-
name: "
|
|
164
|
+
name: "snippets_get",
|
|
165
165
|
description: "Retrieve code snippets from a specific file path. Intelligently extracts relevant code sections using symbol boundaries (functions, classes, methods) when available. Use when you already know the exact file path and want to read its content efficiently without loading the entire file. Automatically selects appropriate snippet based on start_line or returns symbol-aligned chunks. Reduces token usage compared to reading full files. Use context.bundle instead if you don't know which file to read. Example: path='src/auth/login.ts' returns the most relevant function or class in that file.",
|
|
166
166
|
inputSchema: {
|
|
167
167
|
type: "object",
|
|
@@ -175,7 +175,7 @@ const TOOL_DESCRIPTORS = [
|
|
|
175
175
|
},
|
|
176
176
|
},
|
|
177
177
|
{
|
|
178
|
-
name: "
|
|
178
|
+
name: "deps_closure",
|
|
179
179
|
description: "Traverse the dependency graph from a starting file. Finds all files that depend on the target (inbound) or that the target depends on (outbound). Essential for impact analysis: understanding what breaks if you change a file, tracing import chains, or mapping module relationships. Returns nodes (files/packages) and edges (import statements) with depth levels. Use when: planning refactoring, understanding module boundaries, finding circular dependencies, or analyzing affected files. Example: path='src/utils.ts', direction='inbound' shows all files importing utils.ts. Set max_depth to limit traversal (default 3).",
|
|
180
180
|
inputSchema: {
|
|
181
181
|
type: "object",
|
|
@@ -417,17 +417,17 @@ export function validateJsonRpcRequest(payload) {
|
|
|
417
417
|
// Helper function to execute a tool by name
|
|
418
418
|
async function executeToolByName(toolName, toolParams, context, degrade, allowDegrade) {
|
|
419
419
|
switch (toolName) {
|
|
420
|
-
case "
|
|
420
|
+
case "context_bundle": {
|
|
421
421
|
const params = parseContextBundleParams(toolParams);
|
|
422
|
-
const handler = async () => await withSpan("
|
|
423
|
-
return await degrade.withResource(handler, "duckdb:
|
|
422
|
+
const handler = async () => await withSpan("context_bundle", async () => await contextBundle(context, params));
|
|
423
|
+
return await degrade.withResource(handler, "duckdb:context_bundle");
|
|
424
424
|
}
|
|
425
|
-
case "
|
|
425
|
+
case "semantic_rerank": {
|
|
426
426
|
const params = parseSemanticRerankParams(toolParams);
|
|
427
|
-
const handler = async () => await withSpan("
|
|
428
|
-
return await degrade.withResource(handler, "duckdb:
|
|
427
|
+
const handler = async () => await withSpan("semantic_rerank", async () => await semanticRerank(context, params));
|
|
428
|
+
return await degrade.withResource(handler, "duckdb:semantic_rerank");
|
|
429
429
|
}
|
|
430
|
-
case "
|
|
430
|
+
case "files_search": {
|
|
431
431
|
const params = parseFilesSearchParams(toolParams);
|
|
432
432
|
if (degrade.current.active && allowDegrade) {
|
|
433
433
|
return {
|
|
@@ -443,19 +443,19 @@ async function executeToolByName(toolName, toolParams, context, degrade, allowDe
|
|
|
443
443
|
};
|
|
444
444
|
}
|
|
445
445
|
else {
|
|
446
|
-
const handler = async () => await withSpan("
|
|
447
|
-
return await degrade.withResource(handler, "duckdb:
|
|
446
|
+
const handler = async () => await withSpan("files_search", async () => await filesSearch(context, params));
|
|
447
|
+
return await degrade.withResource(handler, "duckdb:files_search");
|
|
448
448
|
}
|
|
449
449
|
}
|
|
450
|
-
case "
|
|
450
|
+
case "snippets_get": {
|
|
451
451
|
const params = parseSnippetsGetParams(toolParams);
|
|
452
|
-
const handler = async () => await withSpan("
|
|
453
|
-
return await degrade.withResource(handler, "duckdb:
|
|
452
|
+
const handler = async () => await withSpan("snippets_get", async () => await snippetsGet(context, params));
|
|
453
|
+
return await degrade.withResource(handler, "duckdb:snippets_get");
|
|
454
454
|
}
|
|
455
|
-
case "
|
|
455
|
+
case "deps_closure": {
|
|
456
456
|
const params = parseDepsClosureParams(toolParams);
|
|
457
|
-
const handler = async () => await withSpan("
|
|
458
|
-
return await degrade.withResource(handler, "duckdb:
|
|
457
|
+
const handler = async () => await withSpan("deps_closure", async () => await depsClosure(context, params));
|
|
458
|
+
return await degrade.withResource(handler, "duckdb:deps_closure");
|
|
459
459
|
}
|
|
460
460
|
default:
|
|
461
461
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
@@ -546,31 +546,31 @@ export function createRpcHandler(dependencies) {
|
|
|
546
546
|
break;
|
|
547
547
|
}
|
|
548
548
|
// Legacy direct method invocation (backward compatibility)
|
|
549
|
-
case "
|
|
550
|
-
result = await executeToolByName("
|
|
549
|
+
case "context_bundle": {
|
|
550
|
+
result = await executeToolByName("context_bundle", payload.params, context, degrade, allowDegrade);
|
|
551
551
|
break;
|
|
552
552
|
}
|
|
553
|
-
case "
|
|
554
|
-
result = await executeToolByName("
|
|
553
|
+
case "semantic_rerank": {
|
|
554
|
+
result = await executeToolByName("semantic_rerank", payload.params, context, degrade, allowDegrade);
|
|
555
555
|
break;
|
|
556
556
|
}
|
|
557
|
-
case "
|
|
558
|
-
result = await executeToolByName("
|
|
557
|
+
case "files_search": {
|
|
558
|
+
result = await executeToolByName("files_search", payload.params, context, degrade, allowDegrade);
|
|
559
559
|
break;
|
|
560
560
|
}
|
|
561
|
-
case "
|
|
562
|
-
result = await executeToolByName("
|
|
561
|
+
case "snippets_get": {
|
|
562
|
+
result = await executeToolByName("snippets_get", payload.params, context, degrade, allowDegrade);
|
|
563
563
|
break;
|
|
564
564
|
}
|
|
565
|
-
case "
|
|
566
|
-
result = await executeToolByName("
|
|
565
|
+
case "deps_closure": {
|
|
566
|
+
result = await executeToolByName("deps_closure", payload.params, context, degrade, allowDegrade);
|
|
567
567
|
break;
|
|
568
568
|
}
|
|
569
569
|
default: {
|
|
570
570
|
return hasResponseId
|
|
571
571
|
? {
|
|
572
572
|
statusCode: 404,
|
|
573
|
-
response: errorResponse(payload.id, "Requested method is not available. Use tools/call, or legacy methods:
|
|
573
|
+
response: errorResponse(payload.id, "Requested method is not available. Use tools/call, or legacy methods: context_bundle, semantic_rerank, files_search, snippets_get, or deps_closure.", -32601),
|
|
574
574
|
}
|
|
575
575
|
: null;
|
|
576
576
|
}
|
|
@@ -601,8 +601,8 @@ export function createRpcHandler(dependencies) {
|
|
|
601
601
|
? {
|
|
602
602
|
statusCode: 503,
|
|
603
603
|
response: errorResponse(payload.id, degrade.current.reason
|
|
604
|
-
? `Backend degraded due to ${degrade.current.reason}. Only
|
|
605
|
-
: "Backend degraded. Only
|
|
604
|
+
? `Backend degraded due to ${degrade.current.reason}. Only files_search is operational.`
|
|
605
|
+
: "Backend degraded. Only files_search is operational."),
|
|
606
606
|
}
|
|
607
607
|
: null;
|
|
608
608
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kiri-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "KIRI context extraction platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@9.0.0",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"duckdb": "^1.1.0",
|
|
65
65
|
"gpt-tokenizer": "^3.2.0",
|
|
66
66
|
"tree-sitter": "^0.22.0",
|
|
67
|
+
"tree-sitter-php": "^0.22.8",
|
|
67
68
|
"tree-sitter-swift": "0.7.1",
|
|
68
69
|
"typescript": "^5.6.3",
|
|
69
70
|
"yaml": "^2.8.1",
|
|
@@ -77,8 +78,8 @@
|
|
|
77
78
|
"eslint": "^9.9.0",
|
|
78
79
|
"eslint-config-prettier": "^9.1.0",
|
|
79
80
|
"eslint-plugin-import": "^2.29.1",
|
|
80
|
-
"prettier": "^3.3.3",
|
|
81
81
|
"lint-staged": "^15.2.10",
|
|
82
|
+
"prettier": "^3.3.3",
|
|
82
83
|
"simple-git-hooks": "^2.10.0",
|
|
83
84
|
"tsx": "^4.16.5",
|
|
84
85
|
"vitest": "^2.0.5"
|