graph-indexer 3.0.1 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +456 -0
- package/README.md +61 -8
- package/SECURITY.md +35 -20
- package/bin/graph-indexer.mjs +46 -5
- package/integrations/claude-code/.claude-plugin/plugin.json +1 -1
- package/integrations/claude-code/agents/code-structure.md +0 -3
- package/integrations/claude-code/skills/setup/SKILL.md +26 -0
- package/integrations/claude-code-local/.claude-plugin/plugin.json +9 -0
- package/integrations/{claude-code → claude-code-local}/.mcp.json +1 -1
- package/integrations/claude-code-local/README.md +10 -0
- package/integrations/claude-code-local/agents/code-structure.md +22 -0
- package/integrations/{claude-code → claude-code-local}/hooks/gi-hook.mjs +15 -4
- package/integrations/opencode/graph-indexer.js +10 -3
- package/package.json +1 -1
- package/src/cli/helper.mjs +15 -1
- package/src/cli/hook.mjs +124 -40
- package/src/cli/init.mjs +32 -5
- package/src/cli/resident.mjs +19 -4
- package/src/index/discover.mjs +52 -30
- package/src/index/indexer.mjs +78 -42
- package/src/index/modules.mjs +75 -2
- package/src/index/parse-worker.mjs +12 -0
- package/src/index/parsepool.mjs +73 -0
- package/src/index/resolver.mjs +362 -23
- package/src/mcp/server.mjs +43 -13
- package/src/mcp/tools.mjs +418 -26
- package/src/parse/arity.mjs +39 -2
- package/src/parse/extract.mjs +269 -45
- package/src/parse/lang/ecma.mjs +2 -0
- package/src/parse/lang/go.mjs +2 -0
- package/src/parse/lang/jvm.mjs +33 -0
- package/src/parse/lang/markdown.mjs +92 -0
- package/src/parse/lang/python.mjs +43 -0
- package/src/parse/lang/rust.mjs +215 -15
- package/src/parse/lang/sfc.mjs +126 -0
- package/src/parse/languages.mjs +9 -2
- package/src/query/check.mjs +49 -13
- package/src/query/facts.mjs +3 -2
- package/src/query/injection-spring.mjs +406 -0
- package/src/query/injection.mjs +174 -0
- package/src/query/intel.mjs +85 -15
- package/src/query/issue.mjs +156 -0
- package/src/query/orm.mjs +288 -0
- package/src/query/read.mjs +6 -1
- package/src/query/report.mjs +53 -0
- package/src/query/routes.mjs +142 -0
- package/src/query/showcase.mjs +59 -0
- package/src/query/textsearch.mjs +30 -9
- package/src/search/search.mjs +85 -17
- package/src/search/semantic.mjs +201 -0
- package/src/search/vectors.mjs +122 -0
- package/src/store/db.mjs +33 -4
- package/src/util/git.mjs +60 -11
- package/src/util/paths.mjs +10 -3
- package/vendor/grammars/README.md +47 -0
- package/vendor/grammars/kotlin.wasm.gz +0 -0
- package/vendor/grammars/manifest.json +4 -4
- /package/integrations/{claude-code → claude-code-local}/hooks/hooks.json +0 -0
package/src/mcp/server.mjs
CHANGED
|
@@ -10,6 +10,32 @@
|
|
|
10
10
|
import readline from 'node:readline';
|
|
11
11
|
import { TOOLS, LEGACY_TOOLS, SERVER_INSTRUCTIONS, callTool } from './tools.mjs';
|
|
12
12
|
|
|
13
|
+
const MAX_ITEMS = 100; // an array argument with no maxItems of its own
|
|
14
|
+
const MAX_STRING = 200_000; // a string argument (an issue pasted as a query is long, not this long)
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The arguments as the tool's schema bounds them: numbers clamped to minimum/maximum, arrays cut
|
|
18
|
+
* to maxItems (else MAX_ITEMS), strings to MAX_STRING. A client is not trusted to respect the schema,
|
|
19
|
+
* and `depth: 1e9` or ten thousand queries would otherwise hold the server.
|
|
20
|
+
*/
|
|
21
|
+
export function boundArgs(schema, raw) {
|
|
22
|
+
const args = raw && typeof raw === 'object' && !Array.isArray(raw) ? { ...raw } : {};
|
|
23
|
+
const props = schema?.properties ?? {};
|
|
24
|
+
const str = (v) => (typeof v === 'string' && v.length > MAX_STRING ? v.slice(0, MAX_STRING) : v);
|
|
25
|
+
for (const [k, v] of Object.entries(args)) {
|
|
26
|
+
const p = props[k];
|
|
27
|
+
if (typeof v === 'number' && p && (p.type === 'integer' || p.type === 'number')) {
|
|
28
|
+
let n = Number.isFinite(v) ? v : (p.default ?? p.minimum ?? 0);
|
|
29
|
+
if (p.type === 'integer') n = Math.trunc(n);
|
|
30
|
+
if (p.minimum != null) n = Math.max(p.minimum, n);
|
|
31
|
+
if (p.maximum != null) n = Math.min(p.maximum, n);
|
|
32
|
+
args[k] = n;
|
|
33
|
+
} else if (Array.isArray(v)) args[k] = v.slice(0, p?.maxItems ?? MAX_ITEMS).map(str);
|
|
34
|
+
else args[k] = str(v);
|
|
35
|
+
}
|
|
36
|
+
return args;
|
|
37
|
+
}
|
|
38
|
+
|
|
13
39
|
export const SUPPORTED_VERSIONS = ['2026-07-28', '2025-11-25', '2025-06-18', '2025-03-26', '2024-11-05'];
|
|
14
40
|
const LATEST_HANDSHAKE = '2025-11-25';
|
|
15
41
|
const META_VERSION = 'io.modelcontextprotocol/protocolVersion';
|
|
@@ -64,13 +90,17 @@ export class McpServer {
|
|
|
64
90
|
this.#error(id, -32022, `Unsupported protocol version: ${reqVersion}`, { supported: SUPPORTED_VERSIONS, requested: reqVersion });
|
|
65
91
|
return;
|
|
66
92
|
}
|
|
93
|
+
// 2026-07-28 results say whether they are complete (or need more input from the client);
|
|
94
|
+
// a client of that version ignores a result without it
|
|
95
|
+
const stateless = this.#requestVersion(params) === '2026-07-28' || method === 'server/discover';
|
|
96
|
+
const done = (res) => this.#result(id, stateless ? { resultType: 'complete', ...res } : res);
|
|
67
97
|
try {
|
|
68
98
|
switch (method) {
|
|
69
99
|
case 'initialize': {
|
|
70
100
|
const requested = params?.protocolVersion;
|
|
71
101
|
const version = SUPPORTED_VERSIONS.includes(requested) && requested !== '2026-07-28' ? requested : LATEST_HANDSHAKE;
|
|
72
102
|
this.negotiated = version;
|
|
73
|
-
|
|
103
|
+
done({
|
|
74
104
|
protocolVersion: version,
|
|
75
105
|
capabilities: { tools: { listChanged: false } },
|
|
76
106
|
serverInfo: { ...this.info, title: 'graph-indexer — code graph & search' },
|
|
@@ -79,7 +109,7 @@ export class McpServer {
|
|
|
79
109
|
return;
|
|
80
110
|
}
|
|
81
111
|
case 'server/discover':
|
|
82
|
-
|
|
112
|
+
done({
|
|
83
113
|
supportedVersions: SUPPORTED_VERSIONS,
|
|
84
114
|
capabilities: { tools: { listChanged: false } },
|
|
85
115
|
instructions: SERVER_INSTRUCTIONS,
|
|
@@ -89,22 +119,22 @@ export class McpServer {
|
|
|
89
119
|
});
|
|
90
120
|
return;
|
|
91
121
|
case 'ping':
|
|
92
|
-
|
|
122
|
+
done({});
|
|
93
123
|
return;
|
|
94
124
|
case 'tools/list': {
|
|
95
125
|
const res = { tools: TOOLS.map(({ name, title, description, inputSchema, annotations, _meta }) => ({ name, title, description, inputSchema, annotations, ...(_meta ? { _meta } : {}) })) };
|
|
96
126
|
if (this.#requestVersion(params) === '2026-07-28') Object.assign(res, { ttlMs: 3_600_000, cacheScope: 'private' });
|
|
97
|
-
|
|
127
|
+
done(res);
|
|
98
128
|
return;
|
|
99
129
|
}
|
|
100
130
|
case 'tools/call': {
|
|
101
131
|
const name = params?.name;
|
|
102
132
|
const tool = TOOLS.find(t => t.name === name) ?? LEGACY_TOOLS.find(t => t.name === name);
|
|
103
133
|
if (!tool) { this.#error(id, -32602, `Unknown tool: ${name}`); return; }
|
|
104
|
-
const args = params?.arguments
|
|
134
|
+
const args = boundArgs(tool.inputSchema, params?.arguments);
|
|
105
135
|
const missing = (tool.inputSchema.required ?? []).filter(k => args[k] === undefined || args[k] === null || args[k] === '');
|
|
106
136
|
if (missing.length) {
|
|
107
|
-
|
|
137
|
+
done({ content: [{ type: 'text', text: `Missing required argument(s): ${missing.join(', ')}.` }], isError: true });
|
|
108
138
|
return;
|
|
109
139
|
}
|
|
110
140
|
this.inflight++;
|
|
@@ -112,18 +142,18 @@ export class McpServer {
|
|
|
112
142
|
const note = await this.#awaitReady();
|
|
113
143
|
await this.intel.ensureFresh();
|
|
114
144
|
const text = await callTool(this.intel, name, args);
|
|
115
|
-
|
|
145
|
+
done({ content: [{ type: 'text', text: note ? `${note}\n${text}` : text }] });
|
|
116
146
|
} catch (err) {
|
|
117
147
|
this.log(`tool ${name} failed: ${err.stack || err.message}`);
|
|
118
|
-
|
|
148
|
+
done({ content: [{ type: 'text', text: `graph-indexer error in ${name}: ${err.message}` }], isError: true });
|
|
119
149
|
} finally { this.inflight--; }
|
|
120
150
|
return;
|
|
121
151
|
}
|
|
122
|
-
case 'resources/list':
|
|
123
|
-
case 'resources/templates/list':
|
|
124
|
-
case 'prompts/list':
|
|
125
|
-
case 'logging/setLevel':
|
|
126
|
-
case 'completion/complete':
|
|
152
|
+
case 'resources/list': done({ resources: [] }); return;
|
|
153
|
+
case 'resources/templates/list': done({ resourceTemplates: [] }); return;
|
|
154
|
+
case 'prompts/list': done({ prompts: [] }); return;
|
|
155
|
+
case 'logging/setLevel': done({}); return;
|
|
156
|
+
case 'completion/complete': done({ completion: { values: [], hasMore: false } }); return;
|
|
127
157
|
default:
|
|
128
158
|
this.#error(id, -32601, `Method not found: ${method}`);
|
|
129
159
|
}
|