@wrongstack/codebase-index-mcp 0.297.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/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/adapter.d.ts +28 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +435 -0
- package/dist/cli.js.map +7 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +231 -0
- package/dist/index.js.map +7 -0
- package/dist/policy.d.ts +10 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ECOSTACK TECHNOLOGY OÜ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @wrongstack/codebase-index-mcp
|
|
2
|
+
|
|
3
|
+
Expose WrongStack's project-scoped Codebase Index daemon to any MCP client.
|
|
4
|
+
The MCP process is only a protocol adapter: search, stats, graphs, and index
|
|
5
|
+
updates still go through the existing named-pipe/Unix-socket IPC service, so
|
|
6
|
+
the detached project daemon remains the single SQLite owner.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
wstack-codebase-index-mcp --project-root /absolute/path/to/project
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The default stdio surface is read-only:
|
|
15
|
+
|
|
16
|
+
- `codebase_search`
|
|
17
|
+
- `codebase_stats`
|
|
18
|
+
- `codebase_package_graph`
|
|
19
|
+
- `codebase_file_graph`
|
|
20
|
+
- `codebase_symbol_graph`
|
|
21
|
+
|
|
22
|
+
Add `--writable` to expose `codebase_index`, which can incrementally refresh
|
|
23
|
+
or fully rebuild the index:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
wstack-codebase-index-mcp --project-root /absolute/path/to/project --writable
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Loopback HTTP is also available:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
wstack-codebase-index-mcp --project-root /absolute/path/to/project --http --port 8767
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Non-loopback HTTP binds require `--token`; the shared MCP HTTP transport
|
|
36
|
+
rejects an unauthenticated public bind.
|
|
37
|
+
|
|
38
|
+
## MCP client configuration
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"mcpServers": {
|
|
43
|
+
"wrongstack-codebase-index": {
|
|
44
|
+
"command": "wstack-codebase-index-mcp",
|
|
45
|
+
"args": ["--project-root", "/absolute/path/to/project", "--writable"]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Context } from '@wrongstack/core/agent';
|
|
2
|
+
import type { Tool } from '@wrongstack/core/types';
|
|
3
|
+
import { MCPServer, type MCPServerToolHost } from '@wrongstack/mcp';
|
|
4
|
+
import { type CodebaseIndexMcpPolicyOptions } from './policy.js';
|
|
5
|
+
interface GraphBaseArgs {
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
indexDir?: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
interface FileGraphArgs extends GraphBaseArgs {
|
|
10
|
+
packageFilter: string;
|
|
11
|
+
}
|
|
12
|
+
interface SymbolGraphArgs extends GraphBaseArgs {
|
|
13
|
+
fileFilter: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CodebaseIndexMcpDependencies {
|
|
16
|
+
executeTool?: (tool: Tool, args: Record<string, unknown>, context: Context, signal: AbortSignal) => Promise<unknown>;
|
|
17
|
+
packageGraph?: (args: GraphBaseArgs) => Promise<unknown>;
|
|
18
|
+
fileGraph?: (args: FileGraphArgs) => Promise<unknown>;
|
|
19
|
+
symbolGraph?: (args: SymbolGraphArgs) => Promise<unknown>;
|
|
20
|
+
}
|
|
21
|
+
export interface CodebaseIndexMcpToolHostOptions extends CodebaseIndexMcpPolicyOptions {
|
|
22
|
+
indexDir?: string | undefined;
|
|
23
|
+
dependencies?: CodebaseIndexMcpDependencies | undefined;
|
|
24
|
+
}
|
|
25
|
+
export declare function createCodebaseIndexMcpToolHost(projectRoot: string, opts?: CodebaseIndexMcpToolHostOptions): MCPServerToolHost;
|
|
26
|
+
export declare function createCodebaseIndexMcpServer(projectRoot: string, opts?: CodebaseIndexMcpToolHostOptions): MCPServer;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAc,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EACL,SAAS,EAGT,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AASzB,OAAO,EACL,KAAK,6BAA6B,EAGnC,MAAM,aAAa,CAAC;AAGrB,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,UAAU,aAAc,SAAQ,aAAa;IAC3C,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,eAAgB,SAAQ,aAAa;IAC7C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,CACZ,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,WAAW,KAChB,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,+BAAgC,SAAQ,6BAA6B;IACpF,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,YAAY,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;CACzD;AAsHD,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,+BAAoC,GACzC,iBAAiB,CAoEnB;AAED,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,+BAAoC,GACzC,SAAS,CAeX"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface ParsedArgs {
|
|
3
|
+
projectRoot: string;
|
|
4
|
+
indexDir?: string | undefined;
|
|
5
|
+
transport: 'stdio' | 'http';
|
|
6
|
+
httpPort: number;
|
|
7
|
+
httpHost: string;
|
|
8
|
+
httpToken?: string | undefined;
|
|
9
|
+
writable: boolean;
|
|
10
|
+
help: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function printHelp(stdout: NodeJS.WriteStream): void;
|
|
13
|
+
export declare function parseArgs(argv: readonly string[]): ParsedArgs;
|
|
14
|
+
export declare function main(argv?: string[]): Promise<number>;
|
|
15
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAeA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,GAAG,IAAI,CAsB1D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CA8C7D;AAkBD,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuFxE"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { realpathSync } from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7
|
+
import { canonicalProjectRoot } from "@wrongstack/core/utils";
|
|
8
|
+
import { serveHttp, serveStdio } from "@wrongstack/mcp";
|
|
9
|
+
import {
|
|
10
|
+
checkCodebaseIndexServerHealth,
|
|
11
|
+
ensureCodebaseIndexServer,
|
|
12
|
+
resolveProjectIndexDaemonAvailability,
|
|
13
|
+
shutdownCodebaseIndexHost
|
|
14
|
+
} from "@wrongstack/tools/codebase-index";
|
|
15
|
+
|
|
16
|
+
// src/adapter.ts
|
|
17
|
+
import {
|
|
18
|
+
MCPServer
|
|
19
|
+
} from "@wrongstack/mcp";
|
|
20
|
+
import {
|
|
21
|
+
codebaseIndexTool,
|
|
22
|
+
codebaseSearchTool,
|
|
23
|
+
codebaseStatsTool,
|
|
24
|
+
fileGraphService,
|
|
25
|
+
packageGraphService,
|
|
26
|
+
symbolGraphService
|
|
27
|
+
} from "@wrongstack/tools/codebase-index";
|
|
28
|
+
|
|
29
|
+
// src/policy.ts
|
|
30
|
+
var CODEBASE_INDEX_READ_TOOLS = [
|
|
31
|
+
"codebase_search",
|
|
32
|
+
"codebase_stats",
|
|
33
|
+
"codebase_package_graph",
|
|
34
|
+
"codebase_file_graph",
|
|
35
|
+
"codebase_symbol_graph"
|
|
36
|
+
];
|
|
37
|
+
var CODEBASE_INDEX_WRITE_TOOLS = ["codebase_index"];
|
|
38
|
+
function selectCodebaseIndexMcpTools(opts = {}) {
|
|
39
|
+
return opts.writable === true ? [...CODEBASE_INDEX_READ_TOOLS, ...CODEBASE_INDEX_WRITE_TOOLS] : [...CODEBASE_INDEX_READ_TOOLS];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/version.ts
|
|
43
|
+
import { readFileSync } from "node:fs";
|
|
44
|
+
import { dirname, resolve } from "node:path";
|
|
45
|
+
import { fileURLToPath } from "node:url";
|
|
46
|
+
var here = dirname(fileURLToPath(import.meta.url));
|
|
47
|
+
var packagePath = resolve(here, "..", "package.json");
|
|
48
|
+
var cached;
|
|
49
|
+
function readServerInfo() {
|
|
50
|
+
if (cached) return cached;
|
|
51
|
+
try {
|
|
52
|
+
const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
53
|
+
cached = {
|
|
54
|
+
name: pkg.name ?? "@wrongstack/codebase-index-mcp",
|
|
55
|
+
version: pkg.version ?? "0.0.0"
|
|
56
|
+
};
|
|
57
|
+
} catch {
|
|
58
|
+
cached = { name: "@wrongstack/codebase-index-mcp", version: "0.0.0" };
|
|
59
|
+
}
|
|
60
|
+
return cached;
|
|
61
|
+
}
|
|
62
|
+
var SERVER_INFO = readServerInfo();
|
|
63
|
+
|
|
64
|
+
// src/adapter.ts
|
|
65
|
+
var GRAPH_SCHEMAS = {
|
|
66
|
+
codebase_package_graph: {
|
|
67
|
+
type: "object",
|
|
68
|
+
properties: {},
|
|
69
|
+
additionalProperties: false
|
|
70
|
+
},
|
|
71
|
+
codebase_file_graph: {
|
|
72
|
+
type: "object",
|
|
73
|
+
properties: {
|
|
74
|
+
package: {
|
|
75
|
+
type: "string",
|
|
76
|
+
description: "Package name or path fragment whose file dependency graph should be returned."
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
required: ["package"],
|
|
80
|
+
additionalProperties: false
|
|
81
|
+
},
|
|
82
|
+
codebase_symbol_graph: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
file: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Project-relative file path whose symbol dependency graph should be returned."
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
required: ["file"],
|
|
91
|
+
additionalProperties: false
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var TOOL_DESCRIPTIONS = {
|
|
95
|
+
codebase_search: "Search the project symbol index with SQLite FTS5 and BM25 ranking. Use this before broad filesystem exploration.",
|
|
96
|
+
codebase_stats: "Inspect the persisted project index health, freshness, symbol counts, language breakdown, and storage path.",
|
|
97
|
+
codebase_package_graph: "Return the project package dependency graph from the authoritative Codebase Index service.",
|
|
98
|
+
codebase_file_graph: "Return the file dependency graph for one package or package-path fragment.",
|
|
99
|
+
codebase_symbol_graph: "Return the symbol dependency graph for one project-relative source file.",
|
|
100
|
+
codebase_index: "Build or incrementally refresh the project Codebase Index. Hidden unless the server starts with --writable."
|
|
101
|
+
};
|
|
102
|
+
var BUILTIN_TOOLS = {
|
|
103
|
+
codebase_search: codebaseSearchTool,
|
|
104
|
+
codebase_stats: codebaseStatsTool,
|
|
105
|
+
codebase_index: codebaseIndexTool
|
|
106
|
+
};
|
|
107
|
+
function cloneToolSchema(name, tool) {
|
|
108
|
+
const schema = structuredClone(tool.inputSchema);
|
|
109
|
+
if (name === "codebase_search") {
|
|
110
|
+
const properties = schema.properties;
|
|
111
|
+
if (properties) delete properties["preferLsp"];
|
|
112
|
+
}
|
|
113
|
+
return schema;
|
|
114
|
+
}
|
|
115
|
+
function toolDescriptor(name) {
|
|
116
|
+
const builtin = BUILTIN_TOOLS[name];
|
|
117
|
+
const graphSchema = GRAPH_SCHEMAS[name];
|
|
118
|
+
if (!builtin && !graphSchema) throw new Error(`Codebase Index MCP: missing schema for ${name}`);
|
|
119
|
+
return {
|
|
120
|
+
name,
|
|
121
|
+
description: TOOL_DESCRIPTIONS[name],
|
|
122
|
+
inputSchema: builtin ? cloneToolSchema(name, builtin) : graphSchema
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function createContext(projectRoot, indexDir) {
|
|
126
|
+
return {
|
|
127
|
+
systemPrompt: [],
|
|
128
|
+
cwd: projectRoot,
|
|
129
|
+
projectRoot,
|
|
130
|
+
allowOutsideProjectRoot: false,
|
|
131
|
+
model: "codebase-index-mcp",
|
|
132
|
+
tools: [],
|
|
133
|
+
meta: {
|
|
134
|
+
source: "codebase-index-mcp",
|
|
135
|
+
...indexDir ? { codebaseIndexDir: indexDir } : {}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function nonEmptyString(value) {
|
|
140
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
141
|
+
}
|
|
142
|
+
function validateArgs(name, args) {
|
|
143
|
+
if (name === "codebase_search" && !nonEmptyString(args["query"])) {
|
|
144
|
+
return 'codebase_search requires a non-empty string "query"';
|
|
145
|
+
}
|
|
146
|
+
if (name === "codebase_file_graph" && !nonEmptyString(args["package"])) {
|
|
147
|
+
return 'codebase_file_graph requires a non-empty string "package"';
|
|
148
|
+
}
|
|
149
|
+
if (name === "codebase_symbol_graph" && !nonEmptyString(args["file"])) {
|
|
150
|
+
return 'codebase_symbol_graph requires a non-empty string "file"';
|
|
151
|
+
}
|
|
152
|
+
if (name === "codebase_index") {
|
|
153
|
+
if (args["force"] !== void 0 && typeof args["force"] !== "boolean") {
|
|
154
|
+
return 'codebase_index "force" must be a boolean';
|
|
155
|
+
}
|
|
156
|
+
if (args["langs"] !== void 0 && (!Array.isArray(args["langs"]) || !args["langs"].every((lang) => typeof lang === "string"))) {
|
|
157
|
+
return 'codebase_index "langs" must be an array of language strings';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
function createCodebaseIndexMcpToolHost(projectRoot, opts = {}) {
|
|
163
|
+
const selected = selectCodebaseIndexMcpTools(opts);
|
|
164
|
+
const allowed = new Set(selected);
|
|
165
|
+
const context = createContext(projectRoot, opts.indexDir);
|
|
166
|
+
const executeTool = opts.dependencies?.executeTool ?? (async (tool, args, ctx, signal) => await tool.execute(args, ctx, { signal }));
|
|
167
|
+
const getPackageGraph = opts.dependencies?.packageGraph ?? packageGraphService;
|
|
168
|
+
const getFileGraph = opts.dependencies?.fileGraph ?? fileGraphService;
|
|
169
|
+
const getSymbolGraph = opts.dependencies?.symbolGraph ?? symbolGraphService;
|
|
170
|
+
return {
|
|
171
|
+
listTools() {
|
|
172
|
+
return selected.map(toolDescriptor);
|
|
173
|
+
},
|
|
174
|
+
async callTool(name, args) {
|
|
175
|
+
if (!allowed.has(name)) {
|
|
176
|
+
return {
|
|
177
|
+
content: `Tool "${name}" is not exposed by this Codebase Index MCP server`,
|
|
178
|
+
isError: true
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const toolName = name;
|
|
182
|
+
const validationError = validateArgs(toolName, args);
|
|
183
|
+
if (validationError) return { content: validationError, isError: true };
|
|
184
|
+
try {
|
|
185
|
+
const builtin = BUILTIN_TOOLS[toolName];
|
|
186
|
+
if (builtin) {
|
|
187
|
+
const validate = builtin.validate;
|
|
188
|
+
if (typeof validate === "function") {
|
|
189
|
+
const errors = await validate(args);
|
|
190
|
+
if (Array.isArray(errors) && errors.length > 0) {
|
|
191
|
+
return { content: errors.join("\n"), isError: true };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const content = await executeTool(builtin, args, context, new AbortController().signal);
|
|
195
|
+
return { content, isError: false };
|
|
196
|
+
}
|
|
197
|
+
const base = {
|
|
198
|
+
projectRoot,
|
|
199
|
+
...opts.indexDir ? { indexDir: opts.indexDir } : {}
|
|
200
|
+
};
|
|
201
|
+
if (toolName === "codebase_package_graph") {
|
|
202
|
+
return { content: await getPackageGraph(base), isError: false };
|
|
203
|
+
}
|
|
204
|
+
if (toolName === "codebase_file_graph") {
|
|
205
|
+
return {
|
|
206
|
+
content: await getFileGraph({ ...base, packageFilter: String(args["package"]) }),
|
|
207
|
+
isError: false
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
content: await getSymbolGraph({ ...base, fileFilter: String(args["file"]) }),
|
|
212
|
+
isError: false
|
|
213
|
+
};
|
|
214
|
+
} catch (error) {
|
|
215
|
+
return {
|
|
216
|
+
content: error instanceof Error ? error.message : String(error),
|
|
217
|
+
isError: true
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function createCodebaseIndexMcpServer(projectRoot, opts = {}) {
|
|
224
|
+
return new MCPServer({
|
|
225
|
+
host: createCodebaseIndexMcpToolHost(projectRoot, opts),
|
|
226
|
+
serverInfo: { name: "wrongstack-codebase-index-mcp", version: SERVER_INFO.version },
|
|
227
|
+
prompts: [
|
|
228
|
+
{
|
|
229
|
+
name: "explore-codebase",
|
|
230
|
+
title: "Explore a project through Codebase Index",
|
|
231
|
+
description: "Check index readiness, then locate symbols and dependency relationships.",
|
|
232
|
+
arguments: [{ name: "query", description: "Symbol or concept to locate", required: true }],
|
|
233
|
+
template: "Use the Codebase Index MCP tools to explore {{query}}. Start with codebase_stats, use codebase_search before broad filesystem scans, and follow relevant package, file, or symbol graphs. If no persisted index exists and codebase_index is available, build it once and retry."
|
|
234
|
+
}
|
|
235
|
+
]
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// src/cli.ts
|
|
240
|
+
function printHelp(stdout) {
|
|
241
|
+
stdout.write(
|
|
242
|
+
[
|
|
243
|
+
`${SERVER_INFO.name} v${SERVER_INFO.version} \u2014 WrongStack Codebase Index MCP server`,
|
|
244
|
+
"",
|
|
245
|
+
"Usage:",
|
|
246
|
+
` ${SERVER_INFO.name} --project-root <path> [options]`,
|
|
247
|
+
"",
|
|
248
|
+
"Options:",
|
|
249
|
+
" --project-root <path> Project whose IPC-backed index should be served (required).",
|
|
250
|
+
" --index-dir <path> Override the project Codebase Index directory.",
|
|
251
|
+
" --stdio Use stdio transport (default).",
|
|
252
|
+
" --http Use HTTP transport.",
|
|
253
|
+
" --port <n> HTTP port (default 0 = ephemeral).",
|
|
254
|
+
" --host <h> HTTP bind host (default 127.0.0.1).",
|
|
255
|
+
" --token <t> Bearer token. Required for a non-loopback HTTP bind.",
|
|
256
|
+
" --writable Also expose codebase_index for incremental/full rebuilds.",
|
|
257
|
+
" -h, --help Show this message.",
|
|
258
|
+
"",
|
|
259
|
+
"The MCP process is an IPC client. The detached project daemon remains the only SQLite owner."
|
|
260
|
+
].join("\n") + "\n"
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
function parseArgs(argv) {
|
|
264
|
+
const parsed = {
|
|
265
|
+
projectRoot: "",
|
|
266
|
+
transport: "stdio",
|
|
267
|
+
httpPort: 0,
|
|
268
|
+
httpHost: "127.0.0.1",
|
|
269
|
+
writable: false,
|
|
270
|
+
help: false
|
|
271
|
+
};
|
|
272
|
+
for (let index = 0; index < argv.length; index++) {
|
|
273
|
+
const arg = argv[index];
|
|
274
|
+
switch (arg) {
|
|
275
|
+
case "--project-root":
|
|
276
|
+
parsed.projectRoot = path.resolve(argv[++index] ?? "");
|
|
277
|
+
break;
|
|
278
|
+
case "--index-dir":
|
|
279
|
+
parsed.indexDir = path.resolve(argv[++index] ?? "");
|
|
280
|
+
break;
|
|
281
|
+
case "--stdio":
|
|
282
|
+
parsed.transport = "stdio";
|
|
283
|
+
break;
|
|
284
|
+
case "--http":
|
|
285
|
+
parsed.transport = "http";
|
|
286
|
+
break;
|
|
287
|
+
case "--port":
|
|
288
|
+
parsed.httpPort = Number(argv[++index] ?? "") || 0;
|
|
289
|
+
break;
|
|
290
|
+
case "--host":
|
|
291
|
+
parsed.httpHost = argv[++index] ?? "127.0.0.1";
|
|
292
|
+
break;
|
|
293
|
+
case "--token":
|
|
294
|
+
parsed.httpToken = argv[++index];
|
|
295
|
+
break;
|
|
296
|
+
case "--writable":
|
|
297
|
+
parsed.writable = true;
|
|
298
|
+
break;
|
|
299
|
+
case "-h":
|
|
300
|
+
case "--help":
|
|
301
|
+
parsed.help = true;
|
|
302
|
+
break;
|
|
303
|
+
default:
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return parsed;
|
|
308
|
+
}
|
|
309
|
+
function availabilityError(availability) {
|
|
310
|
+
if (availability.kind === "available") return null;
|
|
311
|
+
if (availability.kind === "inline-requested") {
|
|
312
|
+
return "the Codebase Index daemon is disabled by WRONGSTACK_INDEX_INLINE or WRONGSTACK_INDEX_SERVER=0";
|
|
313
|
+
}
|
|
314
|
+
if (availability.kind === "missing-build") {
|
|
315
|
+
return "the @wrongstack/tools Codebase Index project-server build is missing";
|
|
316
|
+
}
|
|
317
|
+
return `the IPC endpoint is too long (${availability.byteLength}/${availability.maxBytes} bytes): ` + availability.endpoint;
|
|
318
|
+
}
|
|
319
|
+
async function main(argv = process.argv.slice(2)) {
|
|
320
|
+
const args = parseArgs(argv);
|
|
321
|
+
if (args.help) {
|
|
322
|
+
printHelp(process.stdout);
|
|
323
|
+
return 0;
|
|
324
|
+
}
|
|
325
|
+
if (!args.projectRoot) {
|
|
326
|
+
process.stderr.write(`${SERVER_INFO.name}: --project-root is required
|
|
327
|
+
`);
|
|
328
|
+
printHelp(process.stderr);
|
|
329
|
+
return 2;
|
|
330
|
+
}
|
|
331
|
+
const projectRoot = canonicalProjectRoot(args.projectRoot);
|
|
332
|
+
const availability = resolveProjectIndexDaemonAvailability(projectRoot, args.indexDir);
|
|
333
|
+
const unavailable = availabilityError(availability);
|
|
334
|
+
if (unavailable) {
|
|
335
|
+
process.stderr.write(`${SERVER_INFO.name}: cannot use project-scoped IPC: ${unavailable}
|
|
336
|
+
`);
|
|
337
|
+
return 3;
|
|
338
|
+
}
|
|
339
|
+
const startupLease = setInterval(() => {
|
|
340
|
+
}, 1e3);
|
|
341
|
+
try {
|
|
342
|
+
await ensureCodebaseIndexServer({
|
|
343
|
+
projectRoot,
|
|
344
|
+
...args.indexDir ? { indexDir: args.indexDir } : {},
|
|
345
|
+
watchExternal: false
|
|
346
|
+
});
|
|
347
|
+
const health = await checkCodebaseIndexServerHealth(projectRoot, args.indexDir);
|
|
348
|
+
if (health.status === "unresponsive") {
|
|
349
|
+
throw new Error("project server health check was unresponsive");
|
|
350
|
+
}
|
|
351
|
+
} catch (error) {
|
|
352
|
+
await shutdownCodebaseIndexHost();
|
|
353
|
+
process.stderr.write(
|
|
354
|
+
`${SERVER_INFO.name}: cannot attach to Codebase Index project server for ${projectRoot}: ${error instanceof Error ? error.message : String(error)}
|
|
355
|
+
`
|
|
356
|
+
);
|
|
357
|
+
return 3;
|
|
358
|
+
} finally {
|
|
359
|
+
clearInterval(startupLease);
|
|
360
|
+
}
|
|
361
|
+
const server = createCodebaseIndexMcpServer(projectRoot, {
|
|
362
|
+
writable: args.writable,
|
|
363
|
+
...args.indexDir ? { indexDir: args.indexDir } : {}
|
|
364
|
+
});
|
|
365
|
+
const policyText = `writable=${String(args.writable)}`;
|
|
366
|
+
if (args.transport === "http") {
|
|
367
|
+
try {
|
|
368
|
+
const handle = await serveHttp(server, {
|
|
369
|
+
port: args.httpPort,
|
|
370
|
+
host: args.httpHost,
|
|
371
|
+
...args.httpToken ? { token: args.httpToken } : {},
|
|
372
|
+
logger: { warn: (message) => process.stderr.write(`[codebase-index-mcp] ${message}
|
|
373
|
+
`) }
|
|
374
|
+
});
|
|
375
|
+
process.stderr.write(
|
|
376
|
+
`${SERVER_INFO.name}: ready at ${handle.url} \u2014 projectRoot=${projectRoot} transport=http ${policyText}${args.httpToken ? " [token auth]" : ""}
|
|
377
|
+
`
|
|
378
|
+
);
|
|
379
|
+
await new Promise((resolve3) => {
|
|
380
|
+
process.once("SIGINT", resolve3);
|
|
381
|
+
process.once("SIGTERM", resolve3);
|
|
382
|
+
});
|
|
383
|
+
await handle.close();
|
|
384
|
+
return 0;
|
|
385
|
+
} finally {
|
|
386
|
+
await shutdownCodebaseIndexHost();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
try {
|
|
390
|
+
const handle = serveStdio(server);
|
|
391
|
+
process.stderr.write(
|
|
392
|
+
`${SERVER_INFO.name}: ready on stdio \u2014 projectRoot=${projectRoot} transport=stdio ${policyText}
|
|
393
|
+
`
|
|
394
|
+
);
|
|
395
|
+
await handle.done;
|
|
396
|
+
return 0;
|
|
397
|
+
} finally {
|
|
398
|
+
await shutdownCodebaseIndexHost();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function isMainModule() {
|
|
402
|
+
const entry = process.argv[1];
|
|
403
|
+
if (!entry) return false;
|
|
404
|
+
const self = fileURLToPath2(import.meta.url);
|
|
405
|
+
const comparablePath = (value) => {
|
|
406
|
+
const normalized = path.resolve(value).replace(/^\\\\\?\\/, "");
|
|
407
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
408
|
+
};
|
|
409
|
+
if (comparablePath(entry) === comparablePath(self)) return true;
|
|
410
|
+
try {
|
|
411
|
+
return comparablePath(realpathSync(entry)) === comparablePath(realpathSync(self));
|
|
412
|
+
} catch {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (isMainModule()) {
|
|
417
|
+
main().then(
|
|
418
|
+
(code) => {
|
|
419
|
+
process.exitCode = code;
|
|
420
|
+
},
|
|
421
|
+
(error) => {
|
|
422
|
+
process.stderr.write(`${SERVER_INFO.name}: unexpected error
|
|
423
|
+
`);
|
|
424
|
+
process.stderr.write(error instanceof Error ? error.stack ?? error.message : String(error));
|
|
425
|
+
process.stderr.write("\n");
|
|
426
|
+
process.exitCode = 1;
|
|
427
|
+
}
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
export {
|
|
431
|
+
main,
|
|
432
|
+
parseArgs,
|
|
433
|
+
printHelp
|
|
434
|
+
};
|
|
435
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/cli.ts", "../src/adapter.ts", "../src/policy.ts", "../src/version.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\nimport { realpathSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { canonicalProjectRoot } from '@wrongstack/core/utils';\nimport { serveHttp, serveStdio } from '@wrongstack/mcp';\nimport {\n checkCodebaseIndexServerHealth,\n ensureCodebaseIndexServer,\n resolveProjectIndexDaemonAvailability,\n shutdownCodebaseIndexHost,\n} from '@wrongstack/tools/codebase-index';\nimport { createCodebaseIndexMcpServer } from './adapter.js';\nimport { SERVER_INFO } from './version.js';\n\nexport interface ParsedArgs {\n projectRoot: string;\n indexDir?: string | undefined;\n transport: 'stdio' | 'http';\n httpPort: number;\n httpHost: string;\n httpToken?: string | undefined;\n writable: boolean;\n help: boolean;\n}\n\nexport function printHelp(stdout: NodeJS.WriteStream): void {\n stdout.write(\n [\n `${SERVER_INFO.name} v${SERVER_INFO.version} \u2014 WrongStack Codebase Index MCP server`,\n '',\n 'Usage:',\n ` ${SERVER_INFO.name} --project-root <path> [options]`,\n '',\n 'Options:',\n ' --project-root <path> Project whose IPC-backed index should be served (required).',\n ' --index-dir <path> Override the project Codebase Index directory.',\n ' --stdio Use stdio transport (default).',\n ' --http Use HTTP transport.',\n ' --port <n> HTTP port (default 0 = ephemeral).',\n ' --host <h> HTTP bind host (default 127.0.0.1).',\n ' --token <t> Bearer token. Required for a non-loopback HTTP bind.',\n ' --writable Also expose codebase_index for incremental/full rebuilds.',\n ' -h, --help Show this message.',\n '',\n 'The MCP process is an IPC client. The detached project daemon remains the only SQLite owner.',\n ].join('\\n') + '\\n',\n );\n}\n\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n const parsed: ParsedArgs = {\n projectRoot: '',\n transport: 'stdio',\n httpPort: 0,\n httpHost: '127.0.0.1',\n writable: false,\n help: false,\n };\n\n for (let index = 0; index < argv.length; index++) {\n const arg = argv[index];\n switch (arg) {\n case '--project-root':\n parsed.projectRoot = path.resolve(argv[++index] ?? '');\n break;\n case '--index-dir':\n parsed.indexDir = path.resolve(argv[++index] ?? '');\n break;\n case '--stdio':\n parsed.transport = 'stdio';\n break;\n case '--http':\n parsed.transport = 'http';\n break;\n case '--port':\n parsed.httpPort = Number(argv[++index] ?? '') || 0;\n break;\n case '--host':\n parsed.httpHost = argv[++index] ?? '127.0.0.1';\n break;\n case '--token':\n parsed.httpToken = argv[++index];\n break;\n case '--writable':\n parsed.writable = true;\n break;\n case '-h':\n case '--help':\n parsed.help = true;\n break;\n default:\n break;\n }\n }\n return parsed;\n}\n\nfunction availabilityError(\n availability: ReturnType<typeof resolveProjectIndexDaemonAvailability>,\n): string | null {\n if (availability.kind === 'available') return null;\n if (availability.kind === 'inline-requested') {\n return 'the Codebase Index daemon is disabled by WRONGSTACK_INDEX_INLINE or WRONGSTACK_INDEX_SERVER=0';\n }\n if (availability.kind === 'missing-build') {\n return 'the @wrongstack/tools Codebase Index project-server build is missing';\n }\n return (\n `the IPC endpoint is too long (${availability.byteLength}/${availability.maxBytes} bytes): ` +\n availability.endpoint\n );\n}\n\nexport async function main(argv = process.argv.slice(2)): Promise<number> {\n const args = parseArgs(argv);\n if (args.help) {\n printHelp(process.stdout);\n return 0;\n }\n if (!args.projectRoot) {\n process.stderr.write(`${SERVER_INFO.name}: --project-root is required\\n`);\n printHelp(process.stderr);\n return 2;\n }\n\n const projectRoot = canonicalProjectRoot(args.projectRoot);\n const availability = resolveProjectIndexDaemonAvailability(projectRoot, args.indexDir);\n const unavailable = availabilityError(availability);\n if (unavailable) {\n process.stderr.write(`${SERVER_INFO.name}: cannot use project-scoped IPC: ${unavailable}\\n`);\n return 3;\n }\n\n // The shared IPC client's spawn-retry timers are intentionally unref'ed so\n // background callers do not keep a normal CLI alive. A standalone MCP\n // process has no other referenced handle before its transport starts, so it\n // needs a short startup lease while the first project daemon is elected.\n const startupLease = setInterval(() => {}, 1_000);\n try {\n await ensureCodebaseIndexServer({\n projectRoot,\n ...(args.indexDir ? { indexDir: args.indexDir } : {}),\n watchExternal: false,\n });\n const health = await checkCodebaseIndexServerHealth(projectRoot, args.indexDir);\n if (health.status === 'unresponsive') {\n throw new Error('project server health check was unresponsive');\n }\n } catch (error) {\n await shutdownCodebaseIndexHost();\n process.stderr.write(\n `${SERVER_INFO.name}: cannot attach to Codebase Index project server for ${projectRoot}: ${\n error instanceof Error ? error.message : String(error)\n }\\n`,\n );\n return 3;\n } finally {\n clearInterval(startupLease);\n }\n\n const server = createCodebaseIndexMcpServer(projectRoot, {\n writable: args.writable,\n ...(args.indexDir ? { indexDir: args.indexDir } : {}),\n });\n const policyText = `writable=${String(args.writable)}`;\n\n if (args.transport === 'http') {\n try {\n const handle = await serveHttp(server, {\n port: args.httpPort,\n host: args.httpHost,\n ...(args.httpToken ? { token: args.httpToken } : {}),\n logger: { warn: (message) => process.stderr.write(`[codebase-index-mcp] ${message}\\n`) },\n });\n process.stderr.write(\n `${SERVER_INFO.name}: ready at ${handle.url} \u2014 projectRoot=${projectRoot} transport=http ${policyText}${\n args.httpToken ? ' [token auth]' : ''\n }\\n`,\n );\n await new Promise<void>((resolve) => {\n process.once('SIGINT', resolve);\n process.once('SIGTERM', resolve);\n });\n await handle.close();\n return 0;\n } finally {\n await shutdownCodebaseIndexHost();\n }\n }\n\n try {\n const handle = serveStdio(server);\n process.stderr.write(\n `${SERVER_INFO.name}: ready on stdio \u2014 projectRoot=${projectRoot} transport=stdio ${policyText}\\n`,\n );\n await handle.done;\n return 0;\n } finally {\n await shutdownCodebaseIndexHost();\n }\n}\n\nfunction isMainModule(): boolean {\n const entry = process.argv[1];\n if (!entry) return false;\n const self = fileURLToPath(import.meta.url);\n const comparablePath = (value: string): string => {\n const normalized = path.resolve(value).replace(/^\\\\\\\\\\?\\\\/, '');\n return process.platform === 'win32' ? normalized.toLowerCase() : normalized;\n };\n if (comparablePath(entry) === comparablePath(self)) return true;\n try {\n return comparablePath(realpathSync(entry)) === comparablePath(realpathSync(self));\n } catch {\n return false;\n }\n}\n\nif (isMainModule()) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error) => {\n process.stderr.write(`${SERVER_INFO.name}: unexpected error\\n`);\n process.stderr.write(error instanceof Error ? (error.stack ?? error.message) : String(error));\n process.stderr.write('\\n');\n process.exitCode = 1;\n },\n );\n}\n", "import type { Context } from '@wrongstack/core/agent';\nimport type { JSONSchema, Tool } from '@wrongstack/core/types';\nimport {\n MCPServer,\n type MCPServerCallResult,\n type MCPServerTool,\n type MCPServerToolHost,\n} from '@wrongstack/mcp';\nimport {\n codebaseIndexTool,\n codebaseSearchTool,\n codebaseStatsTool,\n fileGraphService,\n packageGraphService,\n symbolGraphService,\n} from '@wrongstack/tools/codebase-index';\nimport {\n type CodebaseIndexMcpPolicyOptions,\n type CodebaseIndexMcpToolName,\n selectCodebaseIndexMcpTools,\n} from './policy.js';\nimport { SERVER_INFO } from './version.js';\n\ninterface GraphBaseArgs {\n projectRoot: string;\n indexDir?: string | undefined;\n}\n\ninterface FileGraphArgs extends GraphBaseArgs {\n packageFilter: string;\n}\n\ninterface SymbolGraphArgs extends GraphBaseArgs {\n fileFilter: string;\n}\n\nexport interface CodebaseIndexMcpDependencies {\n executeTool?: (\n tool: Tool,\n args: Record<string, unknown>,\n context: Context,\n signal: AbortSignal,\n ) => Promise<unknown>;\n packageGraph?: (args: GraphBaseArgs) => Promise<unknown>;\n fileGraph?: (args: FileGraphArgs) => Promise<unknown>;\n symbolGraph?: (args: SymbolGraphArgs) => Promise<unknown>;\n}\n\nexport interface CodebaseIndexMcpToolHostOptions extends CodebaseIndexMcpPolicyOptions {\n indexDir?: string | undefined;\n dependencies?: CodebaseIndexMcpDependencies | undefined;\n}\n\nconst GRAPH_SCHEMAS = {\n codebase_package_graph: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n codebase_file_graph: {\n type: 'object',\n properties: {\n package: {\n type: 'string',\n description:\n 'Package name or path fragment whose file dependency graph should be returned.',\n },\n },\n required: ['package'],\n additionalProperties: false,\n },\n codebase_symbol_graph: {\n type: 'object',\n properties: {\n file: {\n type: 'string',\n description: 'Project-relative file path whose symbol dependency graph should be returned.',\n },\n },\n required: ['file'],\n additionalProperties: false,\n },\n} as const satisfies Partial<Record<CodebaseIndexMcpToolName, Record<string, unknown>>>;\n\nconst TOOL_DESCRIPTIONS: Record<CodebaseIndexMcpToolName, string> = {\n codebase_search:\n 'Search the project symbol index with SQLite FTS5 and BM25 ranking. Use this before broad filesystem exploration.',\n codebase_stats:\n 'Inspect the persisted project index health, freshness, symbol counts, language breakdown, and storage path.',\n codebase_package_graph:\n 'Return the project package dependency graph from the authoritative Codebase Index service.',\n codebase_file_graph: 'Return the file dependency graph for one package or package-path fragment.',\n codebase_symbol_graph: 'Return the symbol dependency graph for one project-relative source file.',\n codebase_index:\n 'Build or incrementally refresh the project Codebase Index. Hidden unless the server starts with --writable.',\n};\n\nconst BUILTIN_TOOLS: Partial<Record<CodebaseIndexMcpToolName, Tool>> = {\n codebase_search: codebaseSearchTool,\n codebase_stats: codebaseStatsTool,\n codebase_index: codebaseIndexTool,\n};\n\nfunction cloneToolSchema(name: CodebaseIndexMcpToolName, tool: Tool): Record<string, unknown> {\n const schema = structuredClone(tool.inputSchema) as JSONSchema;\n if (name === 'codebase_search') {\n const properties = schema.properties as Record<string, unknown> | undefined;\n if (properties) delete properties['preferLsp'];\n }\n return schema as unknown as Record<string, unknown>;\n}\n\nfunction toolDescriptor(name: CodebaseIndexMcpToolName): MCPServerTool {\n const builtin = BUILTIN_TOOLS[name];\n const graphSchema = GRAPH_SCHEMAS[name as keyof typeof GRAPH_SCHEMAS];\n if (!builtin && !graphSchema) throw new Error(`Codebase Index MCP: missing schema for ${name}`);\n return {\n name,\n description: TOOL_DESCRIPTIONS[name],\n inputSchema: builtin ? cloneToolSchema(name, builtin) : graphSchema!,\n };\n}\n\nfunction createContext(projectRoot: string, indexDir?: string): Context {\n return {\n systemPrompt: [],\n cwd: projectRoot,\n projectRoot,\n allowOutsideProjectRoot: false,\n model: 'codebase-index-mcp',\n tools: [],\n meta: {\n source: 'codebase-index-mcp',\n ...(indexDir ? { codebaseIndexDir: indexDir } : {}),\n },\n } as unknown as Context;\n}\n\nfunction nonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction validateArgs(\n name: CodebaseIndexMcpToolName,\n args: Record<string, unknown>,\n): string | null {\n if (name === 'codebase_search' && !nonEmptyString(args['query'])) {\n return 'codebase_search requires a non-empty string \"query\"';\n }\n if (name === 'codebase_file_graph' && !nonEmptyString(args['package'])) {\n return 'codebase_file_graph requires a non-empty string \"package\"';\n }\n if (name === 'codebase_symbol_graph' && !nonEmptyString(args['file'])) {\n return 'codebase_symbol_graph requires a non-empty string \"file\"';\n }\n if (name === 'codebase_index') {\n if (args['force'] !== undefined && typeof args['force'] !== 'boolean') {\n return 'codebase_index \"force\" must be a boolean';\n }\n if (\n args['langs'] !== undefined &&\n (!Array.isArray(args['langs']) || !args['langs'].every((lang) => typeof lang === 'string'))\n ) {\n return 'codebase_index \"langs\" must be an array of language strings';\n }\n }\n return null;\n}\n\nexport function createCodebaseIndexMcpToolHost(\n projectRoot: string,\n opts: CodebaseIndexMcpToolHostOptions = {},\n): MCPServerToolHost {\n const selected = selectCodebaseIndexMcpTools(opts);\n const allowed = new Set<CodebaseIndexMcpToolName>(selected);\n const context = createContext(projectRoot, opts.indexDir);\n const executeTool =\n opts.dependencies?.executeTool ??\n (async (tool: Tool, args: Record<string, unknown>, ctx: Context, signal: AbortSignal) =>\n await tool.execute(args as never, ctx, { signal }));\n const getPackageGraph = opts.dependencies?.packageGraph ?? packageGraphService;\n const getFileGraph = opts.dependencies?.fileGraph ?? fileGraphService;\n const getSymbolGraph = opts.dependencies?.symbolGraph ?? symbolGraphService;\n\n return {\n listTools(): MCPServerTool[] {\n return selected.map(toolDescriptor);\n },\n\n async callTool(name: string, args: Record<string, unknown>): Promise<MCPServerCallResult> {\n if (!allowed.has(name as CodebaseIndexMcpToolName)) {\n return {\n content: `Tool \"${name}\" is not exposed by this Codebase Index MCP server`,\n isError: true,\n };\n }\n\n const toolName = name as CodebaseIndexMcpToolName;\n const validationError = validateArgs(toolName, args);\n if (validationError) return { content: validationError, isError: true };\n\n try {\n const builtin = BUILTIN_TOOLS[toolName];\n if (builtin) {\n const validate = builtin.validate;\n if (typeof validate === 'function') {\n const errors = await validate(args);\n if (Array.isArray(errors) && errors.length > 0) {\n return { content: errors.join('\\n'), isError: true };\n }\n }\n const content = await executeTool(builtin, args, context, new AbortController().signal);\n return { content, isError: false };\n }\n\n const base = {\n projectRoot,\n ...(opts.indexDir ? { indexDir: opts.indexDir } : {}),\n };\n if (toolName === 'codebase_package_graph') {\n return { content: await getPackageGraph(base), isError: false };\n }\n if (toolName === 'codebase_file_graph') {\n return {\n content: await getFileGraph({ ...base, packageFilter: String(args['package']) }),\n isError: false,\n };\n }\n return {\n content: await getSymbolGraph({ ...base, fileFilter: String(args['file']) }),\n isError: false,\n };\n } catch (error) {\n return {\n content: error instanceof Error ? error.message : String(error),\n isError: true,\n };\n }\n },\n };\n}\n\nexport function createCodebaseIndexMcpServer(\n projectRoot: string,\n opts: CodebaseIndexMcpToolHostOptions = {},\n): MCPServer {\n return new MCPServer({\n host: createCodebaseIndexMcpToolHost(projectRoot, opts),\n serverInfo: { name: 'wrongstack-codebase-index-mcp', version: SERVER_INFO.version },\n prompts: [\n {\n name: 'explore-codebase',\n title: 'Explore a project through Codebase Index',\n description: 'Check index readiness, then locate symbols and dependency relationships.',\n arguments: [{ name: 'query', description: 'Symbol or concept to locate', required: true }],\n template:\n 'Use the Codebase Index MCP tools to explore {{query}}. Start with codebase_stats, use codebase_search before broad filesystem scans, and follow relevant package, file, or symbol graphs. If no persisted index exists and codebase_index is available, build it once and retry.',\n },\n ],\n });\n}\n", "export const CODEBASE_INDEX_READ_TOOLS = [\n 'codebase_search',\n 'codebase_stats',\n 'codebase_package_graph',\n 'codebase_file_graph',\n 'codebase_symbol_graph',\n] as const;\n\nexport const CODEBASE_INDEX_WRITE_TOOLS = ['codebase_index'] as const;\n\nexport type CodebaseIndexMcpReadToolName = (typeof CODEBASE_INDEX_READ_TOOLS)[number];\nexport type CodebaseIndexMcpWriteToolName = (typeof CODEBASE_INDEX_WRITE_TOOLS)[number];\nexport type CodebaseIndexMcpToolName = CodebaseIndexMcpReadToolName | CodebaseIndexMcpWriteToolName;\n\nexport interface CodebaseIndexMcpPolicyOptions {\n writable?: boolean;\n}\n\nexport function selectCodebaseIndexMcpTools(\n opts: CodebaseIndexMcpPolicyOptions = {},\n): CodebaseIndexMcpToolName[] {\n return opts.writable === true\n ? [...CODEBASE_INDEX_READ_TOOLS, ...CODEBASE_INDEX_WRITE_TOOLS]\n : [...CODEBASE_INDEX_READ_TOOLS];\n}\n", "import { readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst here = dirname(fileURLToPath(import.meta.url));\nconst packagePath = resolve(here, '..', 'package.json');\n\ninterface MinimalPackage {\n name?: string;\n version?: string;\n}\n\nlet cached: { name: string; version: string } | undefined;\n\nfunction readServerInfo(): { name: string; version: string } {\n if (cached) return cached;\n try {\n const pkg = JSON.parse(readFileSync(packagePath, 'utf8')) as MinimalPackage;\n cached = {\n name: pkg.name ?? '@wrongstack/codebase-index-mcp',\n version: pkg.version ?? '0.0.0',\n };\n } catch {\n cached = { name: '@wrongstack/codebase-index-mcp', version: '0.0.0' };\n }\n return cached;\n}\n\nexport const SERVER_INFO = readServerInfo();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["fileURLToPath", "resolve", "fileURLToPath"]
|
|
7
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { type CodebaseIndexMcpDependencies, type CodebaseIndexMcpToolHostOptions, createCodebaseIndexMcpServer, createCodebaseIndexMcpToolHost, } from './adapter.js';
|
|
2
|
+
export { CODEBASE_INDEX_READ_TOOLS, CODEBASE_INDEX_WRITE_TOOLS, type CodebaseIndexMcpPolicyOptions, type CodebaseIndexMcpToolName, selectCodebaseIndexMcpTools, } from './policy.js';
|
|
3
|
+
export { SERVER_INFO } from './version.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACpC,4BAA4B,EAC5B,8BAA8B,GAC/B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,KAAK,6BAA6B,EAClC,KAAK,wBAAwB,EAC7B,2BAA2B,GAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// src/adapter.ts
|
|
2
|
+
import {
|
|
3
|
+
MCPServer
|
|
4
|
+
} from "@wrongstack/mcp";
|
|
5
|
+
import {
|
|
6
|
+
codebaseIndexTool,
|
|
7
|
+
codebaseSearchTool,
|
|
8
|
+
codebaseStatsTool,
|
|
9
|
+
fileGraphService,
|
|
10
|
+
packageGraphService,
|
|
11
|
+
symbolGraphService
|
|
12
|
+
} from "@wrongstack/tools/codebase-index";
|
|
13
|
+
|
|
14
|
+
// src/policy.ts
|
|
15
|
+
var CODEBASE_INDEX_READ_TOOLS = [
|
|
16
|
+
"codebase_search",
|
|
17
|
+
"codebase_stats",
|
|
18
|
+
"codebase_package_graph",
|
|
19
|
+
"codebase_file_graph",
|
|
20
|
+
"codebase_symbol_graph"
|
|
21
|
+
];
|
|
22
|
+
var CODEBASE_INDEX_WRITE_TOOLS = ["codebase_index"];
|
|
23
|
+
function selectCodebaseIndexMcpTools(opts = {}) {
|
|
24
|
+
return opts.writable === true ? [...CODEBASE_INDEX_READ_TOOLS, ...CODEBASE_INDEX_WRITE_TOOLS] : [...CODEBASE_INDEX_READ_TOOLS];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/version.ts
|
|
28
|
+
import { readFileSync } from "node:fs";
|
|
29
|
+
import { dirname, resolve } from "node:path";
|
|
30
|
+
import { fileURLToPath } from "node:url";
|
|
31
|
+
var here = dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
var packagePath = resolve(here, "..", "package.json");
|
|
33
|
+
var cached;
|
|
34
|
+
function readServerInfo() {
|
|
35
|
+
if (cached) return cached;
|
|
36
|
+
try {
|
|
37
|
+
const pkg = JSON.parse(readFileSync(packagePath, "utf8"));
|
|
38
|
+
cached = {
|
|
39
|
+
name: pkg.name ?? "@wrongstack/codebase-index-mcp",
|
|
40
|
+
version: pkg.version ?? "0.0.0"
|
|
41
|
+
};
|
|
42
|
+
} catch {
|
|
43
|
+
cached = { name: "@wrongstack/codebase-index-mcp", version: "0.0.0" };
|
|
44
|
+
}
|
|
45
|
+
return cached;
|
|
46
|
+
}
|
|
47
|
+
var SERVER_INFO = readServerInfo();
|
|
48
|
+
|
|
49
|
+
// src/adapter.ts
|
|
50
|
+
var GRAPH_SCHEMAS = {
|
|
51
|
+
codebase_package_graph: {
|
|
52
|
+
type: "object",
|
|
53
|
+
properties: {},
|
|
54
|
+
additionalProperties: false
|
|
55
|
+
},
|
|
56
|
+
codebase_file_graph: {
|
|
57
|
+
type: "object",
|
|
58
|
+
properties: {
|
|
59
|
+
package: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "Package name or path fragment whose file dependency graph should be returned."
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
required: ["package"],
|
|
65
|
+
additionalProperties: false
|
|
66
|
+
},
|
|
67
|
+
codebase_symbol_graph: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
file: {
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "Project-relative file path whose symbol dependency graph should be returned."
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
required: ["file"],
|
|
76
|
+
additionalProperties: false
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var TOOL_DESCRIPTIONS = {
|
|
80
|
+
codebase_search: "Search the project symbol index with SQLite FTS5 and BM25 ranking. Use this before broad filesystem exploration.",
|
|
81
|
+
codebase_stats: "Inspect the persisted project index health, freshness, symbol counts, language breakdown, and storage path.",
|
|
82
|
+
codebase_package_graph: "Return the project package dependency graph from the authoritative Codebase Index service.",
|
|
83
|
+
codebase_file_graph: "Return the file dependency graph for one package or package-path fragment.",
|
|
84
|
+
codebase_symbol_graph: "Return the symbol dependency graph for one project-relative source file.",
|
|
85
|
+
codebase_index: "Build or incrementally refresh the project Codebase Index. Hidden unless the server starts with --writable."
|
|
86
|
+
};
|
|
87
|
+
var BUILTIN_TOOLS = {
|
|
88
|
+
codebase_search: codebaseSearchTool,
|
|
89
|
+
codebase_stats: codebaseStatsTool,
|
|
90
|
+
codebase_index: codebaseIndexTool
|
|
91
|
+
};
|
|
92
|
+
function cloneToolSchema(name, tool) {
|
|
93
|
+
const schema = structuredClone(tool.inputSchema);
|
|
94
|
+
if (name === "codebase_search") {
|
|
95
|
+
const properties = schema.properties;
|
|
96
|
+
if (properties) delete properties["preferLsp"];
|
|
97
|
+
}
|
|
98
|
+
return schema;
|
|
99
|
+
}
|
|
100
|
+
function toolDescriptor(name) {
|
|
101
|
+
const builtin = BUILTIN_TOOLS[name];
|
|
102
|
+
const graphSchema = GRAPH_SCHEMAS[name];
|
|
103
|
+
if (!builtin && !graphSchema) throw new Error(`Codebase Index MCP: missing schema for ${name}`);
|
|
104
|
+
return {
|
|
105
|
+
name,
|
|
106
|
+
description: TOOL_DESCRIPTIONS[name],
|
|
107
|
+
inputSchema: builtin ? cloneToolSchema(name, builtin) : graphSchema
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function createContext(projectRoot, indexDir) {
|
|
111
|
+
return {
|
|
112
|
+
systemPrompt: [],
|
|
113
|
+
cwd: projectRoot,
|
|
114
|
+
projectRoot,
|
|
115
|
+
allowOutsideProjectRoot: false,
|
|
116
|
+
model: "codebase-index-mcp",
|
|
117
|
+
tools: [],
|
|
118
|
+
meta: {
|
|
119
|
+
source: "codebase-index-mcp",
|
|
120
|
+
...indexDir ? { codebaseIndexDir: indexDir } : {}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function nonEmptyString(value) {
|
|
125
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
126
|
+
}
|
|
127
|
+
function validateArgs(name, args) {
|
|
128
|
+
if (name === "codebase_search" && !nonEmptyString(args["query"])) {
|
|
129
|
+
return 'codebase_search requires a non-empty string "query"';
|
|
130
|
+
}
|
|
131
|
+
if (name === "codebase_file_graph" && !nonEmptyString(args["package"])) {
|
|
132
|
+
return 'codebase_file_graph requires a non-empty string "package"';
|
|
133
|
+
}
|
|
134
|
+
if (name === "codebase_symbol_graph" && !nonEmptyString(args["file"])) {
|
|
135
|
+
return 'codebase_symbol_graph requires a non-empty string "file"';
|
|
136
|
+
}
|
|
137
|
+
if (name === "codebase_index") {
|
|
138
|
+
if (args["force"] !== void 0 && typeof args["force"] !== "boolean") {
|
|
139
|
+
return 'codebase_index "force" must be a boolean';
|
|
140
|
+
}
|
|
141
|
+
if (args["langs"] !== void 0 && (!Array.isArray(args["langs"]) || !args["langs"].every((lang) => typeof lang === "string"))) {
|
|
142
|
+
return 'codebase_index "langs" must be an array of language strings';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
function createCodebaseIndexMcpToolHost(projectRoot, opts = {}) {
|
|
148
|
+
const selected = selectCodebaseIndexMcpTools(opts);
|
|
149
|
+
const allowed = new Set(selected);
|
|
150
|
+
const context = createContext(projectRoot, opts.indexDir);
|
|
151
|
+
const executeTool = opts.dependencies?.executeTool ?? (async (tool, args, ctx, signal) => await tool.execute(args, ctx, { signal }));
|
|
152
|
+
const getPackageGraph = opts.dependencies?.packageGraph ?? packageGraphService;
|
|
153
|
+
const getFileGraph = opts.dependencies?.fileGraph ?? fileGraphService;
|
|
154
|
+
const getSymbolGraph = opts.dependencies?.symbolGraph ?? symbolGraphService;
|
|
155
|
+
return {
|
|
156
|
+
listTools() {
|
|
157
|
+
return selected.map(toolDescriptor);
|
|
158
|
+
},
|
|
159
|
+
async callTool(name, args) {
|
|
160
|
+
if (!allowed.has(name)) {
|
|
161
|
+
return {
|
|
162
|
+
content: `Tool "${name}" is not exposed by this Codebase Index MCP server`,
|
|
163
|
+
isError: true
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const toolName = name;
|
|
167
|
+
const validationError = validateArgs(toolName, args);
|
|
168
|
+
if (validationError) return { content: validationError, isError: true };
|
|
169
|
+
try {
|
|
170
|
+
const builtin = BUILTIN_TOOLS[toolName];
|
|
171
|
+
if (builtin) {
|
|
172
|
+
const validate = builtin.validate;
|
|
173
|
+
if (typeof validate === "function") {
|
|
174
|
+
const errors = await validate(args);
|
|
175
|
+
if (Array.isArray(errors) && errors.length > 0) {
|
|
176
|
+
return { content: errors.join("\n"), isError: true };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const content = await executeTool(builtin, args, context, new AbortController().signal);
|
|
180
|
+
return { content, isError: false };
|
|
181
|
+
}
|
|
182
|
+
const base = {
|
|
183
|
+
projectRoot,
|
|
184
|
+
...opts.indexDir ? { indexDir: opts.indexDir } : {}
|
|
185
|
+
};
|
|
186
|
+
if (toolName === "codebase_package_graph") {
|
|
187
|
+
return { content: await getPackageGraph(base), isError: false };
|
|
188
|
+
}
|
|
189
|
+
if (toolName === "codebase_file_graph") {
|
|
190
|
+
return {
|
|
191
|
+
content: await getFileGraph({ ...base, packageFilter: String(args["package"]) }),
|
|
192
|
+
isError: false
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
content: await getSymbolGraph({ ...base, fileFilter: String(args["file"]) }),
|
|
197
|
+
isError: false
|
|
198
|
+
};
|
|
199
|
+
} catch (error) {
|
|
200
|
+
return {
|
|
201
|
+
content: error instanceof Error ? error.message : String(error),
|
|
202
|
+
isError: true
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function createCodebaseIndexMcpServer(projectRoot, opts = {}) {
|
|
209
|
+
return new MCPServer({
|
|
210
|
+
host: createCodebaseIndexMcpToolHost(projectRoot, opts),
|
|
211
|
+
serverInfo: { name: "wrongstack-codebase-index-mcp", version: SERVER_INFO.version },
|
|
212
|
+
prompts: [
|
|
213
|
+
{
|
|
214
|
+
name: "explore-codebase",
|
|
215
|
+
title: "Explore a project through Codebase Index",
|
|
216
|
+
description: "Check index readiness, then locate symbols and dependency relationships.",
|
|
217
|
+
arguments: [{ name: "query", description: "Symbol or concept to locate", required: true }],
|
|
218
|
+
template: "Use the Codebase Index MCP tools to explore {{query}}. Start with codebase_stats, use codebase_search before broad filesystem scans, and follow relevant package, file, or symbol graphs. If no persisted index exists and codebase_index is available, build it once and retry."
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
export {
|
|
224
|
+
CODEBASE_INDEX_READ_TOOLS,
|
|
225
|
+
CODEBASE_INDEX_WRITE_TOOLS,
|
|
226
|
+
SERVER_INFO,
|
|
227
|
+
createCodebaseIndexMcpServer,
|
|
228
|
+
createCodebaseIndexMcpToolHost,
|
|
229
|
+
selectCodebaseIndexMcpTools
|
|
230
|
+
};
|
|
231
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/adapter.ts", "../src/policy.ts", "../src/version.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@wrongstack/core/agent';\nimport type { JSONSchema, Tool } from '@wrongstack/core/types';\nimport {\n MCPServer,\n type MCPServerCallResult,\n type MCPServerTool,\n type MCPServerToolHost,\n} from '@wrongstack/mcp';\nimport {\n codebaseIndexTool,\n codebaseSearchTool,\n codebaseStatsTool,\n fileGraphService,\n packageGraphService,\n symbolGraphService,\n} from '@wrongstack/tools/codebase-index';\nimport {\n type CodebaseIndexMcpPolicyOptions,\n type CodebaseIndexMcpToolName,\n selectCodebaseIndexMcpTools,\n} from './policy.js';\nimport { SERVER_INFO } from './version.js';\n\ninterface GraphBaseArgs {\n projectRoot: string;\n indexDir?: string | undefined;\n}\n\ninterface FileGraphArgs extends GraphBaseArgs {\n packageFilter: string;\n}\n\ninterface SymbolGraphArgs extends GraphBaseArgs {\n fileFilter: string;\n}\n\nexport interface CodebaseIndexMcpDependencies {\n executeTool?: (\n tool: Tool,\n args: Record<string, unknown>,\n context: Context,\n signal: AbortSignal,\n ) => Promise<unknown>;\n packageGraph?: (args: GraphBaseArgs) => Promise<unknown>;\n fileGraph?: (args: FileGraphArgs) => Promise<unknown>;\n symbolGraph?: (args: SymbolGraphArgs) => Promise<unknown>;\n}\n\nexport interface CodebaseIndexMcpToolHostOptions extends CodebaseIndexMcpPolicyOptions {\n indexDir?: string | undefined;\n dependencies?: CodebaseIndexMcpDependencies | undefined;\n}\n\nconst GRAPH_SCHEMAS = {\n codebase_package_graph: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n codebase_file_graph: {\n type: 'object',\n properties: {\n package: {\n type: 'string',\n description:\n 'Package name or path fragment whose file dependency graph should be returned.',\n },\n },\n required: ['package'],\n additionalProperties: false,\n },\n codebase_symbol_graph: {\n type: 'object',\n properties: {\n file: {\n type: 'string',\n description: 'Project-relative file path whose symbol dependency graph should be returned.',\n },\n },\n required: ['file'],\n additionalProperties: false,\n },\n} as const satisfies Partial<Record<CodebaseIndexMcpToolName, Record<string, unknown>>>;\n\nconst TOOL_DESCRIPTIONS: Record<CodebaseIndexMcpToolName, string> = {\n codebase_search:\n 'Search the project symbol index with SQLite FTS5 and BM25 ranking. Use this before broad filesystem exploration.',\n codebase_stats:\n 'Inspect the persisted project index health, freshness, symbol counts, language breakdown, and storage path.',\n codebase_package_graph:\n 'Return the project package dependency graph from the authoritative Codebase Index service.',\n codebase_file_graph: 'Return the file dependency graph for one package or package-path fragment.',\n codebase_symbol_graph: 'Return the symbol dependency graph for one project-relative source file.',\n codebase_index:\n 'Build or incrementally refresh the project Codebase Index. Hidden unless the server starts with --writable.',\n};\n\nconst BUILTIN_TOOLS: Partial<Record<CodebaseIndexMcpToolName, Tool>> = {\n codebase_search: codebaseSearchTool,\n codebase_stats: codebaseStatsTool,\n codebase_index: codebaseIndexTool,\n};\n\nfunction cloneToolSchema(name: CodebaseIndexMcpToolName, tool: Tool): Record<string, unknown> {\n const schema = structuredClone(tool.inputSchema) as JSONSchema;\n if (name === 'codebase_search') {\n const properties = schema.properties as Record<string, unknown> | undefined;\n if (properties) delete properties['preferLsp'];\n }\n return schema as unknown as Record<string, unknown>;\n}\n\nfunction toolDescriptor(name: CodebaseIndexMcpToolName): MCPServerTool {\n const builtin = BUILTIN_TOOLS[name];\n const graphSchema = GRAPH_SCHEMAS[name as keyof typeof GRAPH_SCHEMAS];\n if (!builtin && !graphSchema) throw new Error(`Codebase Index MCP: missing schema for ${name}`);\n return {\n name,\n description: TOOL_DESCRIPTIONS[name],\n inputSchema: builtin ? cloneToolSchema(name, builtin) : graphSchema!,\n };\n}\n\nfunction createContext(projectRoot: string, indexDir?: string): Context {\n return {\n systemPrompt: [],\n cwd: projectRoot,\n projectRoot,\n allowOutsideProjectRoot: false,\n model: 'codebase-index-mcp',\n tools: [],\n meta: {\n source: 'codebase-index-mcp',\n ...(indexDir ? { codebaseIndexDir: indexDir } : {}),\n },\n } as unknown as Context;\n}\n\nfunction nonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction validateArgs(\n name: CodebaseIndexMcpToolName,\n args: Record<string, unknown>,\n): string | null {\n if (name === 'codebase_search' && !nonEmptyString(args['query'])) {\n return 'codebase_search requires a non-empty string \"query\"';\n }\n if (name === 'codebase_file_graph' && !nonEmptyString(args['package'])) {\n return 'codebase_file_graph requires a non-empty string \"package\"';\n }\n if (name === 'codebase_symbol_graph' && !nonEmptyString(args['file'])) {\n return 'codebase_symbol_graph requires a non-empty string \"file\"';\n }\n if (name === 'codebase_index') {\n if (args['force'] !== undefined && typeof args['force'] !== 'boolean') {\n return 'codebase_index \"force\" must be a boolean';\n }\n if (\n args['langs'] !== undefined &&\n (!Array.isArray(args['langs']) || !args['langs'].every((lang) => typeof lang === 'string'))\n ) {\n return 'codebase_index \"langs\" must be an array of language strings';\n }\n }\n return null;\n}\n\nexport function createCodebaseIndexMcpToolHost(\n projectRoot: string,\n opts: CodebaseIndexMcpToolHostOptions = {},\n): MCPServerToolHost {\n const selected = selectCodebaseIndexMcpTools(opts);\n const allowed = new Set<CodebaseIndexMcpToolName>(selected);\n const context = createContext(projectRoot, opts.indexDir);\n const executeTool =\n opts.dependencies?.executeTool ??\n (async (tool: Tool, args: Record<string, unknown>, ctx: Context, signal: AbortSignal) =>\n await tool.execute(args as never, ctx, { signal }));\n const getPackageGraph = opts.dependencies?.packageGraph ?? packageGraphService;\n const getFileGraph = opts.dependencies?.fileGraph ?? fileGraphService;\n const getSymbolGraph = opts.dependencies?.symbolGraph ?? symbolGraphService;\n\n return {\n listTools(): MCPServerTool[] {\n return selected.map(toolDescriptor);\n },\n\n async callTool(name: string, args: Record<string, unknown>): Promise<MCPServerCallResult> {\n if (!allowed.has(name as CodebaseIndexMcpToolName)) {\n return {\n content: `Tool \"${name}\" is not exposed by this Codebase Index MCP server`,\n isError: true,\n };\n }\n\n const toolName = name as CodebaseIndexMcpToolName;\n const validationError = validateArgs(toolName, args);\n if (validationError) return { content: validationError, isError: true };\n\n try {\n const builtin = BUILTIN_TOOLS[toolName];\n if (builtin) {\n const validate = builtin.validate;\n if (typeof validate === 'function') {\n const errors = await validate(args);\n if (Array.isArray(errors) && errors.length > 0) {\n return { content: errors.join('\\n'), isError: true };\n }\n }\n const content = await executeTool(builtin, args, context, new AbortController().signal);\n return { content, isError: false };\n }\n\n const base = {\n projectRoot,\n ...(opts.indexDir ? { indexDir: opts.indexDir } : {}),\n };\n if (toolName === 'codebase_package_graph') {\n return { content: await getPackageGraph(base), isError: false };\n }\n if (toolName === 'codebase_file_graph') {\n return {\n content: await getFileGraph({ ...base, packageFilter: String(args['package']) }),\n isError: false,\n };\n }\n return {\n content: await getSymbolGraph({ ...base, fileFilter: String(args['file']) }),\n isError: false,\n };\n } catch (error) {\n return {\n content: error instanceof Error ? error.message : String(error),\n isError: true,\n };\n }\n },\n };\n}\n\nexport function createCodebaseIndexMcpServer(\n projectRoot: string,\n opts: CodebaseIndexMcpToolHostOptions = {},\n): MCPServer {\n return new MCPServer({\n host: createCodebaseIndexMcpToolHost(projectRoot, opts),\n serverInfo: { name: 'wrongstack-codebase-index-mcp', version: SERVER_INFO.version },\n prompts: [\n {\n name: 'explore-codebase',\n title: 'Explore a project through Codebase Index',\n description: 'Check index readiness, then locate symbols and dependency relationships.',\n arguments: [{ name: 'query', description: 'Symbol or concept to locate', required: true }],\n template:\n 'Use the Codebase Index MCP tools to explore {{query}}. Start with codebase_stats, use codebase_search before broad filesystem scans, and follow relevant package, file, or symbol graphs. If no persisted index exists and codebase_index is available, build it once and retry.',\n },\n ],\n });\n}\n", "export const CODEBASE_INDEX_READ_TOOLS = [\n 'codebase_search',\n 'codebase_stats',\n 'codebase_package_graph',\n 'codebase_file_graph',\n 'codebase_symbol_graph',\n] as const;\n\nexport const CODEBASE_INDEX_WRITE_TOOLS = ['codebase_index'] as const;\n\nexport type CodebaseIndexMcpReadToolName = (typeof CODEBASE_INDEX_READ_TOOLS)[number];\nexport type CodebaseIndexMcpWriteToolName = (typeof CODEBASE_INDEX_WRITE_TOOLS)[number];\nexport type CodebaseIndexMcpToolName = CodebaseIndexMcpReadToolName | CodebaseIndexMcpWriteToolName;\n\nexport interface CodebaseIndexMcpPolicyOptions {\n writable?: boolean;\n}\n\nexport function selectCodebaseIndexMcpTools(\n opts: CodebaseIndexMcpPolicyOptions = {},\n): CodebaseIndexMcpToolName[] {\n return opts.writable === true\n ? [...CODEBASE_INDEX_READ_TOOLS, ...CODEBASE_INDEX_WRITE_TOOLS]\n : [...CODEBASE_INDEX_READ_TOOLS];\n}\n", "import { readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst here = dirname(fileURLToPath(import.meta.url));\nconst packagePath = resolve(here, '..', 'package.json');\n\ninterface MinimalPackage {\n name?: string;\n version?: string;\n}\n\nlet cached: { name: string; version: string } | undefined;\n\nfunction readServerInfo(): { name: string; version: string } {\n if (cached) return cached;\n try {\n const pkg = JSON.parse(readFileSync(packagePath, 'utf8')) as MinimalPackage;\n cached = {\n name: pkg.name ?? '@wrongstack/codebase-index-mcp',\n version: pkg.version ?? '0.0.0',\n };\n } catch {\n cached = { name: '@wrongstack/codebase-index-mcp', version: '0.0.0' };\n }\n return cached;\n}\n\nexport const SERVER_INFO = readServerInfo();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const CODEBASE_INDEX_READ_TOOLS: readonly ['codebase_search', 'codebase_stats', 'codebase_package_graph', 'codebase_file_graph', 'codebase_symbol_graph'];
|
|
2
|
+
export declare const CODEBASE_INDEX_WRITE_TOOLS: readonly ['codebase_index'];
|
|
3
|
+
export type CodebaseIndexMcpReadToolName = (typeof CODEBASE_INDEX_READ_TOOLS)[number];
|
|
4
|
+
export type CodebaseIndexMcpWriteToolName = (typeof CODEBASE_INDEX_WRITE_TOOLS)[number];
|
|
5
|
+
export type CodebaseIndexMcpToolName = CodebaseIndexMcpReadToolName | CodebaseIndexMcpWriteToolName;
|
|
6
|
+
export interface CodebaseIndexMcpPolicyOptions {
|
|
7
|
+
writable?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function selectCodebaseIndexMcpTools(opts?: CodebaseIndexMcpPolicyOptions): CodebaseIndexMcpToolName[];
|
|
10
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,YACpC,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,CACf,CAAC;AAEX,eAAO,MAAM,0BAA0B,YAAI,gBAAgB,CAAU,CAAC;AAEtE,MAAM,MAAM,4BAA4B,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AACtF,MAAM,MAAM,6BAA6B,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AACxF,MAAM,MAAM,wBAAwB,GAAG,4BAA4B,GAAG,6BAA6B,CAAC;AAEpG,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,2BAA2B,CACzC,IAAI,GAAE,6BAAkC,GACvC,wBAAwB,EAAE,CAI5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,WAAW;UAdW,MAAM;aAAW,MAAM;CAcf,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wrongstack/codebase-index-mcp",
|
|
3
|
+
"version": "0.297.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "WrongStack Codebase Index as an MCP server, backed by the existing project-scoped IPC daemon.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/WrongStack/WrongStack.git",
|
|
9
|
+
"directory": "packages/codebase-index-mcp"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/WrongStack/WrongStack#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/WrongStack/WrongStack/issues"
|
|
14
|
+
},
|
|
15
|
+
"author": "ECOSTACK TECHNOLOGY OÜ",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"bin": {
|
|
20
|
+
"wstack-codebase-index-mcp": "./dist/cli.js"
|
|
21
|
+
},
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@wrongstack/mcp": "0.297.0",
|
|
34
|
+
"@wrongstack/tools": "0.297.0",
|
|
35
|
+
"@wrongstack/core": "0.297.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^26.1.1",
|
|
39
|
+
"typescript": "^7.0.2",
|
|
40
|
+
"vitest": "^4.1.10"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "node ../../scripts/build-package.mjs",
|
|
47
|
+
"typecheck": "tsc --noEmit -p tsconfig.test.json",
|
|
48
|
+
"test": "echo \"Run @wrongstack/codebase-index-mcp tests from the workspace root: pnpm exec vitest run packages/codebase-index-mcp/tests\"",
|
|
49
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
|
|
50
|
+
}
|
|
51
|
+
}
|