@crowley/rag-mcp 1.5.0 → 1.6.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/dist/__tests__/tool-middleware.test.js +51 -51
- package/dist/__tests__/tools/memory.test.js +78 -63
- package/dist/api-client.d.ts +49 -2
- package/dist/api-client.js +139 -7
- package/dist/connection-pool.d.ts +15 -0
- package/dist/connection-pool.js +24 -0
- package/dist/context-enrichment.js +5 -3
- package/dist/formatters.js +12 -8
- package/dist/http-transport.d.ts +15 -0
- package/dist/http-transport.js +109 -0
- package/dist/index.js +27 -4
- package/dist/schemas.js +3 -12
- package/dist/tool-middleware.js +13 -8
- package/dist/tool-registry.js +11 -4
- package/dist/tools/advanced.js +64 -19
- package/dist/tools/agents.js +42 -13
- package/dist/tools/analytics.js +17 -5
- package/dist/tools/architecture.js +115 -31
- package/dist/tools/ask.js +23 -8
- package/dist/tools/cache.js +12 -3
- package/dist/tools/clustering.js +53 -17
- package/dist/tools/confluence.js +26 -8
- package/dist/tools/database.js +87 -24
- package/dist/tools/feedback.js +22 -6
- package/dist/tools/guidelines.js +15 -2
- package/dist/tools/indexing.js +34 -8
- package/dist/tools/memory.js +196 -39
- package/dist/tools/pm.js +38 -11
- package/dist/tools/quality.js +7 -2
- package/dist/tools/review.js +25 -7
- package/dist/tools/search.js +92 -31
- package/dist/tools/session.js +58 -26
- package/dist/tools/suggestions.js +75 -22
- package/dist/types.d.ts +2 -2
- package/dist/validation-hooks.js +27 -11
- package/package.json +2 -2
package/dist/tools/search.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Search tools module - codebase search, similarity search, grouped/hybrid search,
|
|
3
3
|
* documentation search, and project statistics.
|
|
4
4
|
*/
|
|
5
|
-
import { formatCodeResults, formatNavigationResults, truncate } from "../formatters.js";
|
|
5
|
+
import { formatCodeResults, formatNavigationResults, truncate, } from "../formatters.js";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { TOOL_ANNOTATIONS } from "../annotations.js";
|
|
8
8
|
/**
|
|
@@ -15,15 +15,30 @@ export function createSearchTools(projectName) {
|
|
|
15
15
|
description: `Search the ${projectName} codebase. Returns file locations, symbols, and graph connections. Use Read tool to view the actual code at returned locations.`,
|
|
16
16
|
schema: z.object({
|
|
17
17
|
query: z.string().describe("Search query for finding code"),
|
|
18
|
-
limit: z.coerce
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
limit: z.coerce
|
|
19
|
+
.number()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("Max results to return (default: 5)"),
|
|
22
|
+
language: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Filter by language (typescript, python, vue, etc.)"),
|
|
26
|
+
path: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Filter by path pattern (e.g., 'src/modules/*')"),
|
|
30
|
+
layer: z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Filter by architectural layer (api, service, util, model, middleware, test, parser, types, config, other)"),
|
|
34
|
+
service: z
|
|
35
|
+
.string()
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("Filter by service/class name (e.g., 'EmbeddingService')"),
|
|
23
38
|
}),
|
|
24
39
|
annotations: TOOL_ANNOTATIONS["search_codebase"],
|
|
25
40
|
handler: async (args, ctx) => {
|
|
26
|
-
const { query, limit = 5, language, path, layer, service } = args;
|
|
41
|
+
const { query, limit = 5, language, path, layer, service, } = args;
|
|
27
42
|
const response = await ctx.api.post("/api/search", {
|
|
28
43
|
collection: `${ctx.collectionPrefix}codebase`,
|
|
29
44
|
query,
|
|
@@ -43,7 +58,10 @@ export function createSearchTools(projectName) {
|
|
|
43
58
|
description: "Find code similar to a given snippet.",
|
|
44
59
|
schema: z.object({
|
|
45
60
|
code: z.string().describe("Code snippet to find similar code for"),
|
|
46
|
-
limit: z.coerce
|
|
61
|
+
limit: z.coerce
|
|
62
|
+
.number()
|
|
63
|
+
.optional()
|
|
64
|
+
.describe("Max results (default: 5)"),
|
|
47
65
|
}),
|
|
48
66
|
annotations: TOOL_ANNOTATIONS["search_similar"],
|
|
49
67
|
handler: async (args, ctx) => {
|
|
@@ -65,17 +83,30 @@ export function createSearchTools(projectName) {
|
|
|
65
83
|
description: `Search ${projectName} codebase grouped by file. Returns file locations with symbols and connections. Use Read tool to view the actual code.`,
|
|
66
84
|
schema: z.object({
|
|
67
85
|
query: z.string().describe("Search query"),
|
|
68
|
-
groupBy: z
|
|
69
|
-
|
|
86
|
+
groupBy: z
|
|
87
|
+
.string()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe("Field to group by (default: 'file')"),
|
|
90
|
+
limit: z.coerce
|
|
91
|
+
.number()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("Max groups to return (default: 10)"),
|
|
70
94
|
language: z.string().optional().describe("Filter by language"),
|
|
71
|
-
layer: z
|
|
95
|
+
layer: z
|
|
96
|
+
.string()
|
|
97
|
+
.optional()
|
|
98
|
+
.describe("Filter by architectural layer (api, service, util, etc.)"),
|
|
72
99
|
service: z.string().optional().describe("Filter by service/class name"),
|
|
73
100
|
}),
|
|
74
101
|
annotations: TOOL_ANNOTATIONS["grouped_search"],
|
|
75
102
|
handler: async (args, ctx) => {
|
|
76
|
-
const { query, groupBy = "file", limit = 10, language, layer, service } = args;
|
|
77
|
-
const filters = {
|
|
78
|
-
|
|
103
|
+
const { query, groupBy = "file", limit = 10, language, layer, service, } = args;
|
|
104
|
+
const filters = {
|
|
105
|
+
language,
|
|
106
|
+
layer,
|
|
107
|
+
service,
|
|
108
|
+
};
|
|
109
|
+
const hasFilters = Object.values(filters).some((v) => v !== undefined);
|
|
79
110
|
const response = await ctx.api.post("/api/search-grouped", {
|
|
80
111
|
collection: `${ctx.collectionPrefix}codebase`,
|
|
81
112
|
query,
|
|
@@ -97,17 +128,30 @@ export function createSearchTools(projectName) {
|
|
|
97
128
|
description: `Hybrid search combining keyword matching and semantic similarity for ${projectName}. Returns file locations with symbols and connections. Use Read tool to view code.`,
|
|
98
129
|
schema: z.object({
|
|
99
130
|
query: z.string().describe("Search query"),
|
|
100
|
-
limit: z.coerce
|
|
101
|
-
|
|
131
|
+
limit: z.coerce
|
|
132
|
+
.number()
|
|
133
|
+
.optional()
|
|
134
|
+
.describe("Max results (default: 10)"),
|
|
135
|
+
semanticWeight: z.coerce
|
|
136
|
+
.number()
|
|
137
|
+
.optional()
|
|
138
|
+
.describe("Weight for semantic vs keyword (0-1, default: 0.7)"),
|
|
102
139
|
language: z.string().optional().describe("Filter by language"),
|
|
103
|
-
layer: z
|
|
140
|
+
layer: z
|
|
141
|
+
.string()
|
|
142
|
+
.optional()
|
|
143
|
+
.describe("Filter by architectural layer (api, service, util, etc.)"),
|
|
104
144
|
service: z.string().optional().describe("Filter by service/class name"),
|
|
105
145
|
}),
|
|
106
146
|
annotations: TOOL_ANNOTATIONS["hybrid_search"],
|
|
107
147
|
handler: async (args, ctx) => {
|
|
108
|
-
const { query, limit = 10, semanticWeight = 0.7, language, layer, service } = args;
|
|
109
|
-
const filters = {
|
|
110
|
-
|
|
148
|
+
const { query, limit = 10, semanticWeight = 0.7, language, layer, service, } = args;
|
|
149
|
+
const filters = {
|
|
150
|
+
language,
|
|
151
|
+
layer,
|
|
152
|
+
service,
|
|
153
|
+
};
|
|
154
|
+
const hasFilters = Object.values(filters).some((v) => v !== undefined);
|
|
111
155
|
const response = await ctx.api.post("/api/search-hybrid", {
|
|
112
156
|
collection: `${ctx.collectionPrefix}codebase`,
|
|
113
157
|
query,
|
|
@@ -128,7 +172,10 @@ export function createSearchTools(projectName) {
|
|
|
128
172
|
description: `Search documentation in the ${projectName} project.`,
|
|
129
173
|
schema: z.object({
|
|
130
174
|
query: z.string().describe("Search query"),
|
|
131
|
-
limit: z.coerce
|
|
175
|
+
limit: z.coerce
|
|
176
|
+
.number()
|
|
177
|
+
.optional()
|
|
178
|
+
.describe("Max results (default: 5)"),
|
|
132
179
|
}),
|
|
133
180
|
annotations: TOOL_ANNOTATIONS["search_docs"],
|
|
134
181
|
handler: async (args, ctx) => {
|
|
@@ -143,8 +190,7 @@ export function createSearchTools(projectName) {
|
|
|
143
190
|
return "No documentation found for this query.";
|
|
144
191
|
}
|
|
145
192
|
return results
|
|
146
|
-
.map((r) => `**${r.file}**\n` +
|
|
147
|
-
truncate(r.content, 500))
|
|
193
|
+
.map((r) => `**${r.file}**\n` + truncate(r.content, 500))
|
|
148
194
|
.join("\n\n---\n\n");
|
|
149
195
|
},
|
|
150
196
|
},
|
|
@@ -192,9 +238,17 @@ export function createSearchTools(projectName) {
|
|
|
192
238
|
name: "find_symbol",
|
|
193
239
|
description: `Find a function, class, type, or interface by name in ${projectName}. Fast symbol lookup without full-text search.`,
|
|
194
240
|
schema: z.object({
|
|
195
|
-
symbol: z
|
|
196
|
-
|
|
197
|
-
|
|
241
|
+
symbol: z
|
|
242
|
+
.string()
|
|
243
|
+
.describe("Symbol name to find (function, class, type, etc.)"),
|
|
244
|
+
kind: z
|
|
245
|
+
.string()
|
|
246
|
+
.optional()
|
|
247
|
+
.describe("Filter by kind: function, class, interface, type, enum, const"),
|
|
248
|
+
limit: z.coerce
|
|
249
|
+
.number()
|
|
250
|
+
.optional()
|
|
251
|
+
.describe("Max results (default: 10)"),
|
|
198
252
|
}),
|
|
199
253
|
outputSchema: z.object({
|
|
200
254
|
symbols: z.array(z.object({
|
|
@@ -209,7 +263,7 @@ export function createSearchTools(projectName) {
|
|
|
209
263
|
}),
|
|
210
264
|
annotations: TOOL_ANNOTATIONS["find_symbol"],
|
|
211
265
|
handler: async (args, ctx) => {
|
|
212
|
-
const { symbol, kind, limit = 10 } = args;
|
|
266
|
+
const { symbol, kind, limit = 10, } = args;
|
|
213
267
|
const response = await ctx.api.post("/api/find-symbol", {
|
|
214
268
|
projectName: ctx.projectName,
|
|
215
269
|
symbol,
|
|
@@ -246,12 +300,18 @@ export function createSearchTools(projectName) {
|
|
|
246
300
|
description: `Search ${projectName} codebase with graph expansion. Returns file locations plus connected files via import/call relationships. Use Read tool to view code.`,
|
|
247
301
|
schema: z.object({
|
|
248
302
|
query: z.string().describe("Search query"),
|
|
249
|
-
limit: z.coerce
|
|
250
|
-
|
|
303
|
+
limit: z.coerce
|
|
304
|
+
.number()
|
|
305
|
+
.optional()
|
|
306
|
+
.describe("Max direct results (default: 5)"),
|
|
307
|
+
expandHops: z.coerce
|
|
308
|
+
.number()
|
|
309
|
+
.optional()
|
|
310
|
+
.describe("Number of graph hops to expand (default: 1)"),
|
|
251
311
|
}),
|
|
252
312
|
annotations: TOOL_ANNOTATIONS["search_graph"],
|
|
253
313
|
handler: async (args, ctx) => {
|
|
254
|
-
const { query, limit = 5, expandHops = 1 } = args;
|
|
314
|
+
const { query, limit = 5, expandHops = 1, } = args;
|
|
255
315
|
const response = await ctx.api.post("/api/search-graph", {
|
|
256
316
|
collection: `${ctx.collectionPrefix}codebase`,
|
|
257
317
|
query,
|
|
@@ -260,7 +320,8 @@ export function createSearchTools(projectName) {
|
|
|
260
320
|
mode: "navigate",
|
|
261
321
|
});
|
|
262
322
|
const { results, graphExpanded, expandedFiles } = response.data;
|
|
263
|
-
if ((!results || results.length === 0) &&
|
|
323
|
+
if ((!results || results.length === 0) &&
|
|
324
|
+
(!graphExpanded || graphExpanded.length === 0)) {
|
|
264
325
|
return "No results found.";
|
|
265
326
|
}
|
|
266
327
|
let output = "";
|
package/dist/tools/session.js
CHANGED
|
@@ -15,7 +15,10 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
15
15
|
name: "summarize_context",
|
|
16
16
|
description: `Summarize the current working context for ${projectName}. Shows recently used tools, active features, recent queries, and suggested next steps.`,
|
|
17
17
|
schema: z.object({
|
|
18
|
-
sessionId: z
|
|
18
|
+
sessionId: z
|
|
19
|
+
.string()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("Session ID to get context for. If omitted, returns the latest context."),
|
|
19
22
|
}),
|
|
20
23
|
annotations: TOOL_ANNOTATIONS["summarize_context"],
|
|
21
24
|
handler: async (args, ctx) => {
|
|
@@ -26,16 +29,12 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
26
29
|
let result = `**Context Summary for ${ctx.projectName}**\n\n`;
|
|
27
30
|
if (data.recentTools && data.recentTools.length > 0) {
|
|
28
31
|
result += `**Recently Used Tools:**\n`;
|
|
29
|
-
result += data.recentTools
|
|
30
|
-
.map((t) => `- ${t}`)
|
|
31
|
-
.join("\n");
|
|
32
|
+
result += data.recentTools.map((t) => `- ${t}`).join("\n");
|
|
32
33
|
result += "\n\n";
|
|
33
34
|
}
|
|
34
35
|
if (data.activeFeatures && data.activeFeatures.length > 0) {
|
|
35
36
|
result += `**Active Features:**\n`;
|
|
36
|
-
result += data.activeFeatures
|
|
37
|
-
.map((f) => `- ${f}`)
|
|
38
|
-
.join("\n");
|
|
37
|
+
result += data.activeFeatures.map((f) => `- ${f}`).join("\n");
|
|
39
38
|
result += "\n\n";
|
|
40
39
|
}
|
|
41
40
|
if (data.recentQueries && data.recentQueries.length > 0) {
|
|
@@ -61,7 +60,10 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
61
60
|
description: `Summarize changes made during a session for ${projectName}. Shows what was modified, tools used, and key actions taken.`,
|
|
62
61
|
schema: z.object({
|
|
63
62
|
sessionId: z.string().describe("Session ID to summarize changes for."),
|
|
64
|
-
includeCode: z
|
|
63
|
+
includeCode: z
|
|
64
|
+
.boolean()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe("Whether to include code snippets in the summary (default: false)."),
|
|
65
67
|
}),
|
|
66
68
|
annotations: TOOL_ANNOTATIONS["summarize_changes"],
|
|
67
69
|
handler: async (args, ctx) => {
|
|
@@ -102,7 +104,10 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
102
104
|
name: "analyze_usage_patterns",
|
|
103
105
|
description: `Analyze tool usage patterns for ${projectName}. Shows common workflows, detected patterns, and recommendations for improving productivity.`,
|
|
104
106
|
schema: z.object({
|
|
105
|
-
days: z.coerce
|
|
107
|
+
days: z.coerce
|
|
108
|
+
.number()
|
|
109
|
+
.optional()
|
|
110
|
+
.describe("Number of days to analyze (default: 7)."),
|
|
106
111
|
}),
|
|
107
112
|
annotations: TOOL_ANNOTATIONS["analyze_usage_patterns"],
|
|
108
113
|
handler: async (args, ctx) => {
|
|
@@ -147,7 +152,9 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
147
152
|
schema: z.object({}),
|
|
148
153
|
annotations: TOOL_ANNOTATIONS["get_developer_profile"],
|
|
149
154
|
handler: async (_args, ctx) => {
|
|
150
|
-
const response = await ctx.api.get(`/api/developer-profile`, {
|
|
155
|
+
const response = await ctx.api.get(`/api/developer-profile`, {
|
|
156
|
+
headers: { "X-Project-Name": ctx.projectName },
|
|
157
|
+
});
|
|
151
158
|
const p = response.data;
|
|
152
159
|
if (!p.totalToolCalls) {
|
|
153
160
|
return "No usage data yet. Use tools to build your developer profile.";
|
|
@@ -155,22 +162,33 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
155
162
|
let result = `**Developer Profile** (${p.totalSessions} sessions, ${p.totalToolCalls} tool calls)\n\n`;
|
|
156
163
|
if (p.frequentFiles.length > 0) {
|
|
157
164
|
result += "**Frequent Files:**\n";
|
|
158
|
-
result += p.frequentFiles
|
|
165
|
+
result += p.frequentFiles
|
|
166
|
+
.slice(0, 10)
|
|
167
|
+
.map((f) => `- ${f.file} (${f.count}x)`)
|
|
168
|
+
.join("\n");
|
|
159
169
|
result += "\n\n";
|
|
160
170
|
}
|
|
161
171
|
if (p.preferredTools.length > 0) {
|
|
162
172
|
result += "**Preferred Tools:**\n";
|
|
163
|
-
result += p.preferredTools
|
|
173
|
+
result += p.preferredTools
|
|
174
|
+
.slice(0, 8)
|
|
175
|
+
.map((t) => `- ${t.tool}: ${t.count}x (avg ${Math.round(t.avgDurationMs)}ms)`)
|
|
176
|
+
.join("\n");
|
|
164
177
|
result += "\n\n";
|
|
165
178
|
}
|
|
166
179
|
if (p.peakHours.length > 0) {
|
|
167
180
|
result += "**Peak Hours:** ";
|
|
168
|
-
result += p.peakHours
|
|
181
|
+
result += p.peakHours
|
|
182
|
+
.map((h) => `${h.hour}:00 (${h.count})`)
|
|
183
|
+
.join(", ");
|
|
169
184
|
result += "\n\n";
|
|
170
185
|
}
|
|
171
186
|
if (p.commonPatterns.length > 0) {
|
|
172
187
|
result += "**Common Patterns:**\n";
|
|
173
|
-
result += p.commonPatterns
|
|
188
|
+
result += p.commonPatterns
|
|
189
|
+
.slice(0, 5)
|
|
190
|
+
.map((q) => `- "${truncate(q, 60)}"`)
|
|
191
|
+
.join("\n");
|
|
174
192
|
result += "\n";
|
|
175
193
|
}
|
|
176
194
|
return result;
|
|
@@ -180,9 +198,18 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
180
198
|
name: "start_session",
|
|
181
199
|
description: `Start a new working session for ${projectName}. Tracks tool usage, file changes, and learnings throughout the session.`,
|
|
182
200
|
schema: z.object({
|
|
183
|
-
sessionId: z
|
|
184
|
-
|
|
185
|
-
|
|
201
|
+
sessionId: z
|
|
202
|
+
.string()
|
|
203
|
+
.optional()
|
|
204
|
+
.describe("Custom session ID. If omitted, one will be generated."),
|
|
205
|
+
initialContext: z
|
|
206
|
+
.string()
|
|
207
|
+
.optional()
|
|
208
|
+
.describe("Description of what this session is about (e.g., 'fixing auth bug', 'adding new API endpoint')."),
|
|
209
|
+
resumeFrom: z
|
|
210
|
+
.string()
|
|
211
|
+
.optional()
|
|
212
|
+
.describe("Session ID to resume from. Carries over context from the previous session."),
|
|
186
213
|
}),
|
|
187
214
|
annotations: TOOL_ANNOTATIONS["start_session"],
|
|
188
215
|
handler: async (args, ctx) => {
|
|
@@ -212,9 +239,7 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
212
239
|
}
|
|
213
240
|
if (initialFiles && initialFiles.length > 0) {
|
|
214
241
|
result += `\n**Initial Files:**\n`;
|
|
215
|
-
result += initialFiles
|
|
216
|
-
.map((f) => `- ${f}`)
|
|
217
|
-
.join("\n");
|
|
242
|
+
result += initialFiles.map((f) => `- ${f}`).join("\n");
|
|
218
243
|
result += "\n";
|
|
219
244
|
}
|
|
220
245
|
// Include prefetch stats if available
|
|
@@ -259,9 +284,7 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
259
284
|
}
|
|
260
285
|
if (data.activeFeatures && data.activeFeatures.length > 0) {
|
|
261
286
|
result += `\n**Active Features:**\n`;
|
|
262
|
-
result += data.activeFeatures
|
|
263
|
-
.map((f) => `- ${f}`)
|
|
264
|
-
.join("\n");
|
|
287
|
+
result += data.activeFeatures.map((f) => `- ${f}`).join("\n");
|
|
265
288
|
result += "\n";
|
|
266
289
|
}
|
|
267
290
|
if (data.pendingLearnings && data.pendingLearnings.length > 0) {
|
|
@@ -283,9 +306,18 @@ export function createSessionTools(projectName, sharedCtx) {
|
|
|
283
306
|
description: `End a working session for ${projectName}. Saves a summary and optionally extracts learnings for future sessions.`,
|
|
284
307
|
schema: z.object({
|
|
285
308
|
sessionId: z.string().describe("Session ID to end."),
|
|
286
|
-
summary: z
|
|
287
|
-
|
|
288
|
-
|
|
309
|
+
summary: z
|
|
310
|
+
.string()
|
|
311
|
+
.optional()
|
|
312
|
+
.describe("Summary of what was accomplished during the session."),
|
|
313
|
+
autoSaveLearnings: z
|
|
314
|
+
.boolean()
|
|
315
|
+
.optional()
|
|
316
|
+
.describe("Automatically save detected learnings to memory (default: true)."),
|
|
317
|
+
feedback: z
|
|
318
|
+
.string()
|
|
319
|
+
.optional()
|
|
320
|
+
.describe("Optional feedback about the session (e.g., 'productive', 'too many context switches')."),
|
|
289
321
|
}),
|
|
290
322
|
annotations: TOOL_ANNOTATIONS["end_session"],
|
|
291
323
|
handler: async (args, ctx) => {
|
|
@@ -86,7 +86,10 @@ export function createSuggestionTools(projectName) {
|
|
|
86
86
|
description: `REQUIRED before code changes. Parallel lookup of recall + search + patterns + ADRs + graph for ${projectName}. One call replaces 5 separate RAG lookups.`,
|
|
87
87
|
schema: z.object({
|
|
88
88
|
task: z.string().describe("What you will implement/change"),
|
|
89
|
-
files: z
|
|
89
|
+
files: z
|
|
90
|
+
.array(z.string())
|
|
91
|
+
.optional()
|
|
92
|
+
.describe("Files you plan to modify"),
|
|
90
93
|
}),
|
|
91
94
|
annotations: TOOL_ANNOTATIONS["context_briefing"],
|
|
92
95
|
handler: async (args, ctx) => {
|
|
@@ -176,7 +179,9 @@ export function createSuggestionTools(projectName) {
|
|
|
176
179
|
if (patterns.length > 0) {
|
|
177
180
|
result += `## Patterns (${patterns.length})\n`;
|
|
178
181
|
for (const p of patterns) {
|
|
179
|
-
const name = p.memory?.metadata?.patternName ||
|
|
182
|
+
const name = p.memory?.metadata?.patternName ||
|
|
183
|
+
p.memory?.relatedTo ||
|
|
184
|
+
"Pattern";
|
|
180
185
|
result += `- **${name}**: ${truncate(p.memory?.content || "", 120)}\n`;
|
|
181
186
|
}
|
|
182
187
|
result += "\n";
|
|
@@ -191,7 +196,9 @@ export function createSuggestionTools(projectName) {
|
|
|
191
196
|
result += "\n";
|
|
192
197
|
}
|
|
193
198
|
const graphResults = graphRes?.data?.results || graphRes?.data?.directResults || [];
|
|
194
|
-
const connectedFiles = graphRes?.data?.connectedFiles ||
|
|
199
|
+
const connectedFiles = graphRes?.data?.connectedFiles ||
|
|
200
|
+
graphRes?.data?.expandedResults ||
|
|
201
|
+
[];
|
|
195
202
|
if (graphResults.length > 0 || connectedFiles.length > 0) {
|
|
196
203
|
result += `## Dependencies\n`;
|
|
197
204
|
for (const g of graphResults) {
|
|
@@ -203,7 +210,8 @@ export function createSuggestionTools(projectName) {
|
|
|
203
210
|
result += "\n";
|
|
204
211
|
}
|
|
205
212
|
if (result.endsWith(`# Context Briefing: ${task}\n\n`)) {
|
|
206
|
-
result +=
|
|
213
|
+
result +=
|
|
214
|
+
"_No relevant context found. Proceed with implementation._\n";
|
|
207
215
|
}
|
|
208
216
|
return result;
|
|
209
217
|
},
|
|
@@ -213,8 +221,14 @@ export function createSuggestionTools(projectName) {
|
|
|
213
221
|
description: `Intelligent task routing for ${projectName}. LLM analyzes your task and runs only the needed lookups (2-5 of 7 available) in parallel. More efficient than context_briefing for narrow tasks.`,
|
|
214
222
|
schema: z.object({
|
|
215
223
|
task: z.string().describe("What you will implement/change"),
|
|
216
|
-
files: z
|
|
217
|
-
|
|
224
|
+
files: z
|
|
225
|
+
.array(z.string())
|
|
226
|
+
.optional()
|
|
227
|
+
.describe("Files you plan to modify"),
|
|
228
|
+
intent: z
|
|
229
|
+
.enum(["code", "research", "debug", "review", "architecture"])
|
|
230
|
+
.optional()
|
|
231
|
+
.describe("Task intent for better routing"),
|
|
218
232
|
}),
|
|
219
233
|
annotations: TOOL_ANNOTATIONS["context_briefing"], // Same annotations as context_briefing
|
|
220
234
|
handler: async (args, ctx) => {
|
|
@@ -232,9 +246,18 @@ export function createSuggestionTools(projectName) {
|
|
|
232
246
|
name: "get_contextual_suggestions",
|
|
233
247
|
description: `Get contextual suggestions based on current work context for ${projectName}. Returns relevant suggestions, triggers, and related memories.`,
|
|
234
248
|
schema: z.object({
|
|
235
|
-
currentFile: z
|
|
236
|
-
|
|
237
|
-
|
|
249
|
+
currentFile: z
|
|
250
|
+
.string()
|
|
251
|
+
.optional()
|
|
252
|
+
.describe("Currently active file path"),
|
|
253
|
+
currentCode: z
|
|
254
|
+
.string()
|
|
255
|
+
.optional()
|
|
256
|
+
.describe("Currently selected or visible code"),
|
|
257
|
+
recentFiles: z
|
|
258
|
+
.array(z.string())
|
|
259
|
+
.optional()
|
|
260
|
+
.describe("Recently opened file paths"),
|
|
238
261
|
task: z.string().optional().describe("Current task description"),
|
|
239
262
|
}),
|
|
240
263
|
annotations: TOOL_ANNOTATIONS["get_contextual_suggestions"],
|
|
@@ -288,13 +311,22 @@ export function createSuggestionTools(projectName) {
|
|
|
288
311
|
name: "suggest_related_code",
|
|
289
312
|
description: `Find code related to a given file or snippet in ${projectName}. Shows similar implementations and related modules.`,
|
|
290
313
|
schema: z.object({
|
|
291
|
-
file: z
|
|
292
|
-
|
|
293
|
-
|
|
314
|
+
file: z
|
|
315
|
+
.string()
|
|
316
|
+
.optional()
|
|
317
|
+
.describe("File path to find related code for"),
|
|
318
|
+
code: z
|
|
319
|
+
.string()
|
|
320
|
+
.optional()
|
|
321
|
+
.describe("Code snippet to find related code for"),
|
|
322
|
+
limit: z.coerce
|
|
323
|
+
.number()
|
|
324
|
+
.optional()
|
|
325
|
+
.describe("Max results (default: 5)"),
|
|
294
326
|
}),
|
|
295
327
|
annotations: TOOL_ANNOTATIONS["suggest_related_code"],
|
|
296
328
|
handler: async (args, ctx) => {
|
|
297
|
-
const { file, code, limit = 5 } = args;
|
|
329
|
+
const { file, code, limit = 5, } = args;
|
|
298
330
|
const response = await ctx.api.post("/api/code/related", {
|
|
299
331
|
projectName: ctx.projectName,
|
|
300
332
|
file,
|
|
@@ -315,7 +347,10 @@ export function createSuggestionTools(projectName) {
|
|
|
315
347
|
result += ` | Line ${r.line}`;
|
|
316
348
|
result += "\n";
|
|
317
349
|
if (r.content || r.code) {
|
|
318
|
-
result +=
|
|
350
|
+
result +=
|
|
351
|
+
"```\n" +
|
|
352
|
+
truncate(r.content || r.code, PREVIEW.MEDIUM) +
|
|
353
|
+
"\n```\n";
|
|
319
354
|
}
|
|
320
355
|
result += "\n";
|
|
321
356
|
}
|
|
@@ -371,7 +406,10 @@ export function createSuggestionTools(projectName) {
|
|
|
371
406
|
schema: z.object({
|
|
372
407
|
file: z.string().optional().describe("File to suggest tests for"),
|
|
373
408
|
code: z.string().optional().describe("Code to suggest tests for"),
|
|
374
|
-
framework: z
|
|
409
|
+
framework: z
|
|
410
|
+
.string()
|
|
411
|
+
.optional()
|
|
412
|
+
.describe("Test framework preference (jest, mocha, pytest, etc.)"),
|
|
375
413
|
}),
|
|
376
414
|
annotations: TOOL_ANNOTATIONS["suggest_tests"],
|
|
377
415
|
handler: async (args, ctx) => {
|
|
@@ -401,7 +439,8 @@ export function createSuggestionTools(projectName) {
|
|
|
401
439
|
if (t.coverage)
|
|
402
440
|
result += `**Coverage:** ${t.coverage}\n`;
|
|
403
441
|
if (t.content || t.code) {
|
|
404
|
-
result +=
|
|
442
|
+
result +=
|
|
443
|
+
"```\n" + truncate(t.content || t.code, PREVIEW.LONG) + "\n```\n";
|
|
405
444
|
}
|
|
406
445
|
result += "\n";
|
|
407
446
|
}
|
|
@@ -461,10 +500,21 @@ export function createSuggestionTools(projectName) {
|
|
|
461
500
|
description: "Configure Claude Code for RAG integration. Creates/updates .mcp.json, adds RAG instructions to CLAUDE.md, and configures permissions. Call after index_codebase on a new project.",
|
|
462
501
|
schema: z.object({
|
|
463
502
|
projectPath: z.string().describe("Absolute path to project root"),
|
|
464
|
-
projectName: z
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
503
|
+
projectName: z
|
|
504
|
+
.string()
|
|
505
|
+
.describe("Project name in Qdrant (collection prefix)"),
|
|
506
|
+
ragApiUrl: z
|
|
507
|
+
.string()
|
|
508
|
+
.optional()
|
|
509
|
+
.describe("RAG API URL (default: from MCP env)"),
|
|
510
|
+
ragApiKey: z
|
|
511
|
+
.string()
|
|
512
|
+
.optional()
|
|
513
|
+
.describe("RAG API key (default: from MCP env)"),
|
|
514
|
+
updateClaudeMd: z
|
|
515
|
+
.boolean()
|
|
516
|
+
.optional()
|
|
517
|
+
.describe("Add RAG section to CLAUDE.md (default: true)"),
|
|
468
518
|
}),
|
|
469
519
|
annotations: TOOL_ANNOTATIONS["setup_project"],
|
|
470
520
|
handler: async (args, ctx) => {
|
|
@@ -524,7 +574,9 @@ After completing significant changes:
|
|
|
524
574
|
changes.push("CLAUDE.md — RAG section already exists, skipped");
|
|
525
575
|
}
|
|
526
576
|
else {
|
|
527
|
-
claudeMd = claudeMd
|
|
577
|
+
claudeMd = claudeMd
|
|
578
|
+
? claudeMd.trimEnd() + "\n" + ragSection
|
|
579
|
+
: `# CLAUDE.md\n${ragSection}`;
|
|
528
580
|
fs.writeFileSync(claudeMdPath, claudeMd);
|
|
529
581
|
changes.push("CLAUDE.md — added RAG Integration section");
|
|
530
582
|
}
|
|
@@ -563,7 +615,8 @@ After completing significant changes:
|
|
|
563
615
|
indexInfo = `\n## Index Status\n- **Vectors:** ${data.vectorCount ?? "N/A"}\n- **Status:** ${data.status || "unknown"}\n`;
|
|
564
616
|
}
|
|
565
617
|
catch {
|
|
566
|
-
indexInfo =
|
|
618
|
+
indexInfo =
|
|
619
|
+
"\n## Index Status\n_Not indexed yet. Run `index_codebase` first._\n";
|
|
567
620
|
}
|
|
568
621
|
let result = `# Project Setup: ${targetProject}\n\n`;
|
|
569
622
|
result += `## Files Updated\n`;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared types for the MCP server tool modules.
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type { ApiClient } from "./api-client.js";
|
|
5
5
|
import type { z } from "zod";
|
|
6
6
|
import type { ToolAnnotations } from "./annotations.js";
|
|
7
7
|
/** MCP tool input schema shape (raw JSON Schema) */
|
|
@@ -19,7 +19,7 @@ export interface ToolDefinition {
|
|
|
19
19
|
}
|
|
20
20
|
/** Context passed to every tool handler */
|
|
21
21
|
export interface ToolContext {
|
|
22
|
-
api:
|
|
22
|
+
api: ApiClient;
|
|
23
23
|
projectName: string;
|
|
24
24
|
projectPath: string;
|
|
25
25
|
collectionPrefix: string;
|