kotadb 2.1.0 → 2.2.0-next.20260204175832
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/package.json +6 -3
- package/src/cli/args.ts +105 -0
- package/src/cli.ts +72 -4
- package/src/db/migrations/005_workflow_contexts.sql +41 -0
- package/src/indexer/ast-parser.ts +43 -1
- package/src/mcp/server.ts +26 -56
- package/src/mcp/tools.ts +526 -120
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kotadb",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0-next.20260204175832",
|
|
4
4
|
"description": "Local-only code intelligence tool for CLI agents. SQLite-backed repository indexing and code search via MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"@asteasolutions/zod-to-openapi": "^8.4.0",
|
|
55
55
|
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
56
56
|
"@sentry/node": "^10.25.0",
|
|
57
|
-
"@typescript-eslint/parser": "
|
|
58
|
-
"@typescript-eslint/types": "
|
|
57
|
+
"@typescript-eslint/parser": "8.54.0",
|
|
58
|
+
"@typescript-eslint/types": "8.54.0",
|
|
59
59
|
"bcryptjs": "^2.4.3",
|
|
60
60
|
"chokidar": "^5.0.0",
|
|
61
61
|
"cors": "^2.8.6",
|
|
@@ -75,5 +75,8 @@
|
|
|
75
75
|
"lint-staged": "^16.2.4",
|
|
76
76
|
"supertest": "^7.1.4",
|
|
77
77
|
"typescript": "^5.9.3"
|
|
78
|
+
},
|
|
79
|
+
"overrides": {
|
|
80
|
+
"@typescript-eslint/types": "8.54.0"
|
|
78
81
|
}
|
|
79
82
|
}
|
package/src/cli/args.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI argument parsing utilities
|
|
3
|
+
*
|
|
4
|
+
* Extracted for testability. Used by main CLI entry point.
|
|
5
|
+
*
|
|
6
|
+
* @module cli/args
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Valid toolset tiers for MCP tool selection
|
|
11
|
+
* - default: 8 tools (core + sync)
|
|
12
|
+
* - core: 6 tools
|
|
13
|
+
* - memory: 14 tools (core + sync + memory)
|
|
14
|
+
* - full: 20 tools (all)
|
|
15
|
+
*/
|
|
16
|
+
export type ToolsetTier = "default" | "core" | "memory" | "full";
|
|
17
|
+
|
|
18
|
+
const VALID_TOOLSET_TIERS: ToolsetTier[] = ["default", "core", "memory", "full"];
|
|
19
|
+
|
|
20
|
+
export interface CliOptions {
|
|
21
|
+
port: number;
|
|
22
|
+
help: boolean;
|
|
23
|
+
version: boolean;
|
|
24
|
+
stdio: boolean;
|
|
25
|
+
toolset: ToolsetTier;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Type guard for valid toolset tier
|
|
30
|
+
*/
|
|
31
|
+
export function isValidToolsetTier(value: string): value is ToolsetTier {
|
|
32
|
+
return VALID_TOOLSET_TIERS.includes(value as ToolsetTier);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Parse CLI arguments into options object
|
|
37
|
+
*/
|
|
38
|
+
export function parseArgs(args: string[]): CliOptions {
|
|
39
|
+
const options: CliOptions = {
|
|
40
|
+
port: Number(process.env.PORT ?? 3000),
|
|
41
|
+
help: false,
|
|
42
|
+
version: false,
|
|
43
|
+
stdio: false,
|
|
44
|
+
toolset: "default",
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < args.length; i++) {
|
|
48
|
+
const arg = args[i];
|
|
49
|
+
if (arg === undefined) continue;
|
|
50
|
+
|
|
51
|
+
if (arg === "--help" || arg === "-h") {
|
|
52
|
+
options.help = true;
|
|
53
|
+
} else if (arg === "--version" || arg === "-v") {
|
|
54
|
+
options.version = true;
|
|
55
|
+
} else if (arg === "--stdio") {
|
|
56
|
+
options.stdio = true;
|
|
57
|
+
} else if (arg === "--port") {
|
|
58
|
+
const portStr = args[++i];
|
|
59
|
+
if (!portStr || Number.isNaN(Number(portStr))) {
|
|
60
|
+
process.stderr.write("Error: --port requires a valid number\n");
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
options.port = Number(portStr);
|
|
64
|
+
} else if (arg.startsWith("--port=")) {
|
|
65
|
+
const portStr = arg.split("=")[1];
|
|
66
|
+
if (portStr === undefined || Number.isNaN(Number(portStr))) {
|
|
67
|
+
process.stderr.write("Error: --port requires a valid number\n");
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
options.port = Number(portStr);
|
|
71
|
+
} else if (arg === "--toolset") {
|
|
72
|
+
const tierStr = args[++i];
|
|
73
|
+
if (!tierStr) {
|
|
74
|
+
process.stderr.write("Error: --toolset requires a tier value\n");
|
|
75
|
+
process.stderr.write("Valid tiers: default, core, memory, full\n");
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
if (!isValidToolsetTier(tierStr)) {
|
|
79
|
+
process.stderr.write(`Error: Invalid toolset tier '${tierStr}'\n`);
|
|
80
|
+
process.stderr.write("Valid tiers: default, core, memory, full\n");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
options.toolset = tierStr;
|
|
84
|
+
} else if (arg.startsWith("--toolset=")) {
|
|
85
|
+
const tierStr = arg.split("=")[1];
|
|
86
|
+
if (tierStr === undefined || tierStr === "") {
|
|
87
|
+
process.stderr.write("Error: --toolset requires a tier value\n");
|
|
88
|
+
process.stderr.write("Valid tiers: default, core, memory, full\n");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
if (!isValidToolsetTier(tierStr)) {
|
|
92
|
+
process.stderr.write(`Error: Invalid toolset tier '${tierStr}'\n`);
|
|
93
|
+
process.stderr.write("Valid tiers: default, core, memory, full\n");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
options.toolset = tierStr;
|
|
97
|
+
} else if (arg.startsWith("-") && arg !== "-") {
|
|
98
|
+
process.stderr.write(`Unknown option: ${arg}\n`);
|
|
99
|
+
process.stderr.write("Use --help for usage information\n");
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return options;
|
|
105
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* kotadb Start the MCP server (default port 3000)
|
|
10
10
|
* kotadb --stdio Start in stdio mode (for Claude Code integration)
|
|
11
11
|
* kotadb --port 4000 Start on custom port
|
|
12
|
+
* kotadb --toolset full Select tool tier (default, core, memory, full)
|
|
12
13
|
* kotadb --version Show version
|
|
13
14
|
* kotadb --help Show help
|
|
14
15
|
* kotadb deps Query dependency information for a file
|
|
@@ -25,11 +26,23 @@ import { fileURLToPath } from "node:url";
|
|
|
25
26
|
|
|
26
27
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
27
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Valid toolset tiers for MCP tool selection
|
|
31
|
+
* - default: 8 tools (core + sync)
|
|
32
|
+
* - core: 6 tools
|
|
33
|
+
* - memory: 14 tools (core + sync + memory)
|
|
34
|
+
* - full: 20 tools (all)
|
|
35
|
+
*/
|
|
36
|
+
export type ToolsetTier = "default" | "core" | "memory" | "full";
|
|
37
|
+
|
|
38
|
+
const VALID_TOOLSET_TIERS: ToolsetTier[] = ["default", "core", "memory", "full"];
|
|
39
|
+
|
|
28
40
|
interface CliOptions {
|
|
29
41
|
port: number;
|
|
30
42
|
help: boolean;
|
|
31
43
|
version: boolean;
|
|
32
44
|
stdio: boolean;
|
|
45
|
+
toolset: ToolsetTier;
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
function getVersion(): string {
|
|
@@ -70,6 +83,12 @@ COMMANDS:
|
|
|
70
83
|
OPTIONS:
|
|
71
84
|
--stdio Use stdio transport (for Claude Code integration)
|
|
72
85
|
--port <number> Port to listen on (default: 3000, env: PORT)
|
|
86
|
+
--toolset <tier> Select tool tier (default: default)
|
|
87
|
+
Tiers:
|
|
88
|
+
default 8 tools (core + sync)
|
|
89
|
+
core 6 tools (search, index, deps, impact)
|
|
90
|
+
memory 14 tools (core + sync + memory layer)
|
|
91
|
+
full 20 tools (all available tools)
|
|
73
92
|
--version, -v Show version number
|
|
74
93
|
--help, -h Show this help message
|
|
75
94
|
|
|
@@ -81,6 +100,8 @@ ENVIRONMENT VARIABLES:
|
|
|
81
100
|
|
|
82
101
|
EXAMPLES:
|
|
83
102
|
kotadb --stdio Start in stdio mode (for Claude Code)
|
|
103
|
+
kotadb --stdio --toolset full Start with all tools enabled
|
|
104
|
+
kotadb --stdio --toolset core Start with minimal core tools
|
|
84
105
|
kotadb Start HTTP server on port 3000
|
|
85
106
|
kotadb --port 4000 Start HTTP server on port 4000
|
|
86
107
|
kotadb deps --file src/db/client.ts Query deps for a file (text)
|
|
@@ -99,6 +120,17 @@ MCP CONFIGURATION (stdio mode - RECOMMENDED):
|
|
|
99
120
|
}
|
|
100
121
|
}
|
|
101
122
|
|
|
123
|
+
With toolset selection:
|
|
124
|
+
|
|
125
|
+
{
|
|
126
|
+
"mcpServers": {
|
|
127
|
+
"kotadb": {
|
|
128
|
+
"command": "bunx",
|
|
129
|
+
"args": ["kotadb@next", "--stdio", "--toolset", "full"]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
102
134
|
MCP CONFIGURATION (HTTP mode - legacy):
|
|
103
135
|
Add to your .mcp.json or Claude Code settings:
|
|
104
136
|
|
|
@@ -126,12 +158,17 @@ function printVersion(): void {
|
|
|
126
158
|
process.stdout.write(`kotadb v${version}\n`);
|
|
127
159
|
}
|
|
128
160
|
|
|
161
|
+
function isValidToolsetTier(value: string): value is ToolsetTier {
|
|
162
|
+
return VALID_TOOLSET_TIERS.includes(value as ToolsetTier);
|
|
163
|
+
}
|
|
164
|
+
|
|
129
165
|
function parseArgs(args: string[]): CliOptions {
|
|
130
166
|
const options: CliOptions = {
|
|
131
167
|
port: Number(process.env.PORT ?? 3000),
|
|
132
168
|
help: false,
|
|
133
169
|
version: false,
|
|
134
170
|
stdio: false,
|
|
171
|
+
toolset: "default",
|
|
135
172
|
};
|
|
136
173
|
|
|
137
174
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -158,6 +195,32 @@ function parseArgs(args: string[]): CliOptions {
|
|
|
158
195
|
process.exit(1);
|
|
159
196
|
}
|
|
160
197
|
options.port = Number(portStr);
|
|
198
|
+
} else if (arg === "--toolset") {
|
|
199
|
+
const tierStr = args[++i];
|
|
200
|
+
if (!tierStr) {
|
|
201
|
+
process.stderr.write("Error: --toolset requires a tier value\n");
|
|
202
|
+
process.stderr.write("Valid tiers: default, core, memory, full\n");
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
if (!isValidToolsetTier(tierStr)) {
|
|
206
|
+
process.stderr.write(`Error: Invalid toolset tier '${tierStr}'\n`);
|
|
207
|
+
process.stderr.write("Valid tiers: default, core, memory, full\n");
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
options.toolset = tierStr;
|
|
211
|
+
} else if (arg.startsWith("--toolset=")) {
|
|
212
|
+
const tierStr = arg.split("=")[1];
|
|
213
|
+
if (tierStr === undefined || tierStr === "") {
|
|
214
|
+
process.stderr.write("Error: --toolset requires a tier value\n");
|
|
215
|
+
process.stderr.write("Valid tiers: default, core, memory, full\n");
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
if (!isValidToolsetTier(tierStr)) {
|
|
219
|
+
process.stderr.write(`Error: Invalid toolset tier '${tierStr}'\n`);
|
|
220
|
+
process.stderr.write("Valid tiers: default, core, memory, full\n");
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
options.toolset = tierStr;
|
|
161
224
|
} else if (arg.startsWith("-") && arg !== "-") {
|
|
162
225
|
process.stderr.write(`Unknown option: ${arg}\n`);
|
|
163
226
|
process.stderr.write("Use --help for usage information\n");
|
|
@@ -168,7 +231,7 @@ function parseArgs(args: string[]): CliOptions {
|
|
|
168
231
|
return options;
|
|
169
232
|
}
|
|
170
233
|
|
|
171
|
-
async function runStdioMode(): Promise<void> {
|
|
234
|
+
async function runStdioMode(toolset: ToolsetTier): Promise<void> {
|
|
172
235
|
// Redirect logger to stderr in stdio mode
|
|
173
236
|
// This is CRITICAL - stdout is reserved for JSON-RPC protocol
|
|
174
237
|
const logger = createLogger({
|
|
@@ -178,11 +241,13 @@ async function runStdioMode(): Promise<void> {
|
|
|
178
241
|
|
|
179
242
|
logger.info("KotaDB MCP server starting in stdio mode", {
|
|
180
243
|
version: getVersion(),
|
|
244
|
+
toolset,
|
|
181
245
|
});
|
|
182
246
|
|
|
183
|
-
// Create MCP server with local-only context
|
|
247
|
+
// Create MCP server with local-only context and toolset
|
|
184
248
|
const context: McpServerContext = {
|
|
185
249
|
userId: "local", // Local-only mode uses fixed user ID
|
|
250
|
+
toolset,
|
|
186
251
|
};
|
|
187
252
|
const server = createMcpServer(context);
|
|
188
253
|
|
|
@@ -192,7 +257,7 @@ async function runStdioMode(): Promise<void> {
|
|
|
192
257
|
// Connect server to transport
|
|
193
258
|
await server.connect(transport);
|
|
194
259
|
|
|
195
|
-
logger.info("KotaDB MCP server connected via stdio");
|
|
260
|
+
logger.info("KotaDB MCP server connected via stdio", { toolset });
|
|
196
261
|
|
|
197
262
|
// Server lifecycle is managed by the transport
|
|
198
263
|
// Process will stay alive until stdin closes (when Claude Code terminates it)
|
|
@@ -234,7 +299,7 @@ async function main(): Promise<void> {
|
|
|
234
299
|
|
|
235
300
|
// Handle stdio mode
|
|
236
301
|
if (options.stdio) {
|
|
237
|
-
await runStdioMode();
|
|
302
|
+
await runStdioMode(options.toolset);
|
|
238
303
|
return; // runStdioMode() keeps process alive
|
|
239
304
|
}
|
|
240
305
|
|
|
@@ -247,6 +312,7 @@ async function main(): Promise<void> {
|
|
|
247
312
|
mode: envConfig.mode,
|
|
248
313
|
port: options.port,
|
|
249
314
|
localDbPath: envConfig.localDbPath,
|
|
315
|
+
toolset: options.toolset,
|
|
250
316
|
});
|
|
251
317
|
|
|
252
318
|
const app = createExpressApp();
|
|
@@ -256,6 +322,7 @@ async function main(): Promise<void> {
|
|
|
256
322
|
port: options.port,
|
|
257
323
|
mcp_endpoint: `http://localhost:${options.port}/mcp`,
|
|
258
324
|
health_endpoint: `http://localhost:${options.port}/health`,
|
|
325
|
+
toolset: options.toolset,
|
|
259
326
|
});
|
|
260
327
|
|
|
261
328
|
// Print user-friendly startup message
|
|
@@ -265,6 +332,7 @@ async function main(): Promise<void> {
|
|
|
265
332
|
process.stdout.write(` MCP Endpoint: http://localhost:${options.port}/mcp\n`);
|
|
266
333
|
process.stdout.write(` Health Check: http://localhost:${options.port}/health\n`);
|
|
267
334
|
process.stdout.write(` Database: ${envConfig.localDbPath}\n`);
|
|
335
|
+
process.stdout.write(` Toolset: ${options.toolset}\n`);
|
|
268
336
|
process.stdout.write(`\n`);
|
|
269
337
|
process.stdout.write(`Press Ctrl+C to stop\n`);
|
|
270
338
|
process.stdout.write(`\n`);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
-- SQLite Migration: Workflow Context Accumulation
|
|
2
|
+
--
|
|
3
|
+
-- Migration: 005_workflow_contexts
|
|
4
|
+
-- Issue: #144 - ADW context accumulation for inter-phase handoffs
|
|
5
|
+
-- Author: Claude Code
|
|
6
|
+
-- Date: 2026-02-04
|
|
7
|
+
--
|
|
8
|
+
-- This migration adds workflow context storage for ADW automation,
|
|
9
|
+
-- enabling context accumulation between workflow phases (analysis -> plan -> build -> improve).
|
|
10
|
+
-- Context is stored in the main KotaDB database for future MCP tool integration.
|
|
11
|
+
|
|
12
|
+
-- ============================================================================
|
|
13
|
+
-- 1. Workflow Contexts Table
|
|
14
|
+
-- ============================================================================
|
|
15
|
+
-- Stores curated context data for each workflow phase
|
|
16
|
+
|
|
17
|
+
CREATE TABLE IF NOT EXISTS workflow_contexts (
|
|
18
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
19
|
+
workflow_id TEXT NOT NULL, -- 'adw-123-20260204T120000'
|
|
20
|
+
phase TEXT NOT NULL, -- 'analysis' | 'plan' | 'build' | 'improve'
|
|
21
|
+
context_data TEXT NOT NULL, -- JSON blob
|
|
22
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
23
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
24
|
+
|
|
25
|
+
UNIQUE(workflow_id, phase),
|
|
26
|
+
CHECK (phase IN ('analysis', 'plan', 'build', 'improve'))
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
-- Index for workflow-scoped queries (primary access pattern)
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_workflow_contexts_workflow_id
|
|
31
|
+
ON workflow_contexts(workflow_id);
|
|
32
|
+
|
|
33
|
+
-- Index for time-based queries (debugging/monitoring)
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_workflow_contexts_created_at
|
|
35
|
+
ON workflow_contexts(created_at DESC);
|
|
36
|
+
|
|
37
|
+
-- ============================================================================
|
|
38
|
+
-- 2. Record Migration
|
|
39
|
+
-- ============================================================================
|
|
40
|
+
|
|
41
|
+
INSERT OR IGNORE INTO schema_migrations (name) VALUES ('005_workflow_contexts');
|
|
@@ -42,6 +42,24 @@ export interface ParseError {
|
|
|
42
42
|
column?: number;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Type guard to validate that an AST node is a valid Program.
|
|
47
|
+
* Provides runtime type validation to prevent version compatibility issues.
|
|
48
|
+
*
|
|
49
|
+
* @param ast - Unknown AST node to validate
|
|
50
|
+
* @returns true if ast is a valid Program node
|
|
51
|
+
*/
|
|
52
|
+
function isValidProgram(ast: unknown): ast is TSESTree.Program {
|
|
53
|
+
return (
|
|
54
|
+
ast !== null &&
|
|
55
|
+
typeof ast === "object" &&
|
|
56
|
+
"type" in ast &&
|
|
57
|
+
ast.type === "Program" &&
|
|
58
|
+
"body" in ast &&
|
|
59
|
+
Array.isArray(ast.body)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
45
63
|
/**
|
|
46
64
|
* Result of parsing a file, including partial AST recovery information.
|
|
47
65
|
*/
|
|
@@ -103,7 +121,7 @@ function createParseError(error: unknown): ParseError {
|
|
|
103
121
|
|
|
104
122
|
/**
|
|
105
123
|
* Parse a file with error-tolerant options enabled.
|
|
106
|
-
* Uses allowInvalidAST to attempt partial recovery.
|
|
124
|
+
* Uses allowInvalidAST to attempt partial recovery and validates result.
|
|
107
125
|
*/
|
|
108
126
|
function parseWithRecoveryOptions(filePath: string, content: string): TSESTree.Program | null {
|
|
109
127
|
try {
|
|
@@ -119,6 +137,18 @@ function parseWithRecoveryOptions(filePath: string, content: string): TSESTree.P
|
|
|
119
137
|
allowInvalidAST: true,
|
|
120
138
|
errorOnUnknownASTType: false,
|
|
121
139
|
});
|
|
140
|
+
|
|
141
|
+
// Validate the returned AST is actually a Program node
|
|
142
|
+
if (!isValidProgram(ast)) {
|
|
143
|
+
const astType = typeof ast === "object" && ast !== null && "type" in ast ? (ast as any).type : typeof ast;
|
|
144
|
+
logger.warn(`Parser returned invalid Program type for ${filePath}`, {
|
|
145
|
+
file_path: filePath,
|
|
146
|
+
ast_type: astType,
|
|
147
|
+
recovery: "failed_validation",
|
|
148
|
+
});
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
122
152
|
return ast;
|
|
123
153
|
} catch {
|
|
124
154
|
// Even with recovery options, parsing can still fail
|
|
@@ -159,6 +189,18 @@ export function parseFileWithRecovery(filePath: string, content: string): ParseR
|
|
|
159
189
|
tokens: true,
|
|
160
190
|
filePath,
|
|
161
191
|
});
|
|
192
|
+
|
|
193
|
+
// Validate the returned AST is actually a Program node
|
|
194
|
+
if (!isValidProgram(ast)) {
|
|
195
|
+
const astType = typeof ast === "object" && ast !== null && "type" in ast ? (ast as any).type : typeof ast;
|
|
196
|
+
logger.warn(`Parser returned invalid Program type for ${filePath}`, {
|
|
197
|
+
file_path: filePath,
|
|
198
|
+
ast_type: astType,
|
|
199
|
+
recovery: "failed_validation",
|
|
200
|
+
});
|
|
201
|
+
throw new Error(`Invalid AST type returned: expected Program, got ${astType}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
162
204
|
return {
|
|
163
205
|
ast,
|
|
164
206
|
errors: [],
|
package/src/mcp/server.ts
CHANGED
|
@@ -18,17 +18,14 @@ import {
|
|
|
18
18
|
GENERATE_TASK_CONTEXT_TOOL,
|
|
19
19
|
INDEX_REPOSITORY_TOOL,
|
|
20
20
|
LIST_RECENT_FILES_TOOL,
|
|
21
|
-
|
|
21
|
+
SEARCH_TOOL,
|
|
22
22
|
SEARCH_DEPENDENCIES_TOOL,
|
|
23
23
|
SYNC_EXPORT_TOOL,
|
|
24
24
|
SYNC_IMPORT_TOOL,
|
|
25
25
|
VALIDATE_IMPLEMENTATION_SPEC_TOOL,
|
|
26
26
|
// Memory Layer tools
|
|
27
|
-
SEARCH_DECISIONS_TOOL,
|
|
28
27
|
RECORD_DECISION_TOOL,
|
|
29
|
-
SEARCH_FAILURES_TOOL,
|
|
30
28
|
RECORD_FAILURE_TOOL,
|
|
31
|
-
SEARCH_PATTERNS_TOOL,
|
|
32
29
|
RECORD_INSIGHT_TOOL,
|
|
33
30
|
// Dynamic Expertise tools
|
|
34
31
|
GET_DOMAIN_KEY_FILES_TOOL,
|
|
@@ -40,27 +37,35 @@ import {
|
|
|
40
37
|
executeGenerateTaskContext,
|
|
41
38
|
executeIndexRepository,
|
|
42
39
|
executeListRecentFiles,
|
|
43
|
-
|
|
40
|
+
executeSearch,
|
|
44
41
|
executeSearchDependencies,
|
|
45
42
|
executeSyncExport,
|
|
46
43
|
executeSyncImport,
|
|
47
44
|
executeValidateImplementationSpec,
|
|
48
45
|
// Memory Layer execute functions
|
|
49
|
-
executeSearchDecisions,
|
|
50
46
|
executeRecordDecision,
|
|
51
|
-
executeSearchFailures,
|
|
52
47
|
executeRecordFailure,
|
|
53
|
-
executeSearchPatterns,
|
|
54
48
|
executeRecordInsight,
|
|
55
49
|
// Dynamic Expertise execute functions
|
|
56
50
|
executeGetDomainKeyFiles,
|
|
57
51
|
executeValidateExpertise,
|
|
58
52
|
executeSyncExpertise,
|
|
59
53
|
executeGetRecentPatterns,
|
|
54
|
+
// Tool filtering
|
|
55
|
+
filterToolsByTier,
|
|
60
56
|
} from "./tools";
|
|
61
57
|
|
|
62
58
|
const logger = createLogger({ module: "mcp-server" });
|
|
63
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Valid toolset tiers for MCP tool selection
|
|
62
|
+
* - default: 8 tools (core + sync)
|
|
63
|
+
* - core: 6 tools
|
|
64
|
+
* - memory: 14 tools (core + sync + memory)
|
|
65
|
+
* - full: 20 tools (all)
|
|
66
|
+
*/
|
|
67
|
+
export type ToolsetTier = "default" | "core" | "memory" | "full";
|
|
68
|
+
|
|
64
69
|
/**
|
|
65
70
|
* MCP Server context passed to tool handlers via closure
|
|
66
71
|
*
|
|
@@ -68,6 +73,7 @@ const logger = createLogger({ module: "mcp-server" });
|
|
|
68
73
|
*/
|
|
69
74
|
export interface McpServerContext {
|
|
70
75
|
userId: string;
|
|
76
|
+
toolset?: ToolsetTier;
|
|
71
77
|
}
|
|
72
78
|
|
|
73
79
|
/**
|
|
@@ -107,35 +113,20 @@ export function createMcpServer(context: McpServerContext): Server {
|
|
|
107
113
|
},
|
|
108
114
|
);
|
|
109
115
|
|
|
110
|
-
// Register tools/list handler -
|
|
116
|
+
// Register tools/list handler - filter by toolset tier
|
|
111
117
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
118
|
+
const tier = context.toolset || "default";
|
|
119
|
+
const filteredTools = filterToolsByTier(tier);
|
|
120
|
+
|
|
121
|
+
logger.debug("Listing MCP tools", {
|
|
122
|
+
tier,
|
|
123
|
+
tool_count: filteredTools.length
|
|
124
|
+
});
|
|
125
|
+
|
|
112
126
|
return {
|
|
113
|
-
tools:
|
|
114
|
-
SEARCH_CODE_TOOL,
|
|
115
|
-
INDEX_REPOSITORY_TOOL,
|
|
116
|
-
LIST_RECENT_FILES_TOOL,
|
|
117
|
-
SEARCH_DEPENDENCIES_TOOL,
|
|
118
|
-
ANALYZE_CHANGE_IMPACT_TOOL,
|
|
119
|
-
VALIDATE_IMPLEMENTATION_SPEC_TOOL,
|
|
120
|
-
SYNC_EXPORT_TOOL,
|
|
121
|
-
SYNC_IMPORT_TOOL,
|
|
122
|
-
GENERATE_TASK_CONTEXT_TOOL,
|
|
123
|
-
// Memory Layer tools
|
|
124
|
-
SEARCH_DECISIONS_TOOL,
|
|
125
|
-
RECORD_DECISION_TOOL,
|
|
126
|
-
SEARCH_FAILURES_TOOL,
|
|
127
|
-
RECORD_FAILURE_TOOL,
|
|
128
|
-
SEARCH_PATTERNS_TOOL,
|
|
129
|
-
RECORD_INSIGHT_TOOL,
|
|
130
|
-
// Dynamic Expertise tools
|
|
131
|
-
GET_DOMAIN_KEY_FILES_TOOL,
|
|
132
|
-
VALIDATE_EXPERTISE_TOOL,
|
|
133
|
-
SYNC_EXPERTISE_TOOL,
|
|
134
|
-
GET_RECENT_PATTERNS_TOOL,
|
|
135
|
-
],
|
|
127
|
+
tools: filteredTools,
|
|
136
128
|
};
|
|
137
129
|
});
|
|
138
|
-
|
|
139
130
|
// Register tools/call handler
|
|
140
131
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
141
132
|
const { name, arguments: toolArgs } = request.params;
|
|
@@ -146,8 +137,8 @@ export function createMcpServer(context: McpServerContext): Server {
|
|
|
146
137
|
|
|
147
138
|
try {
|
|
148
139
|
switch (name) {
|
|
149
|
-
case "
|
|
150
|
-
result = await
|
|
140
|
+
case "search":
|
|
141
|
+
result = await executeSearch(
|
|
151
142
|
toolArgs,
|
|
152
143
|
"", // requestId not used
|
|
153
144
|
context.userId,
|
|
@@ -202,13 +193,6 @@ export function createMcpServer(context: McpServerContext): Server {
|
|
|
202
193
|
);
|
|
203
194
|
break;
|
|
204
195
|
// Memory Layer tools
|
|
205
|
-
case "search_decisions":
|
|
206
|
-
result = await executeSearchDecisions(
|
|
207
|
-
toolArgs,
|
|
208
|
-
"", // requestId not used
|
|
209
|
-
context.userId,
|
|
210
|
-
);
|
|
211
|
-
break;
|
|
212
196
|
case "record_decision":
|
|
213
197
|
result = await executeRecordDecision(
|
|
214
198
|
toolArgs,
|
|
@@ -216,13 +200,6 @@ export function createMcpServer(context: McpServerContext): Server {
|
|
|
216
200
|
context.userId,
|
|
217
201
|
);
|
|
218
202
|
break;
|
|
219
|
-
case "search_failures":
|
|
220
|
-
result = await executeSearchFailures(
|
|
221
|
-
toolArgs,
|
|
222
|
-
"", // requestId not used
|
|
223
|
-
context.userId,
|
|
224
|
-
);
|
|
225
|
-
break;
|
|
226
203
|
case "record_failure":
|
|
227
204
|
result = await executeRecordFailure(
|
|
228
205
|
toolArgs,
|
|
@@ -230,13 +207,6 @@ export function createMcpServer(context: McpServerContext): Server {
|
|
|
230
207
|
context.userId,
|
|
231
208
|
);
|
|
232
209
|
break;
|
|
233
|
-
case "search_patterns":
|
|
234
|
-
result = await executeSearchPatterns(
|
|
235
|
-
toolArgs,
|
|
236
|
-
"", // requestId not used
|
|
237
|
-
context.userId,
|
|
238
|
-
);
|
|
239
|
-
break;
|
|
240
210
|
case "record_insight":
|
|
241
211
|
result = await executeRecordInsight(
|
|
242
212
|
toolArgs,
|