@crowley/rag-mcp 1.0.5 → 1.1.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/annotations.d.ts +16 -0
- package/dist/annotations.js +158 -0
- package/dist/context-enrichment.js +7 -0
- package/dist/formatters.d.ts +2 -0
- package/dist/formatters.js +12 -0
- package/dist/index.js +99 -47
- package/dist/schemas.d.ts +97 -0
- package/dist/schemas.js +128 -0
- package/dist/tool-middleware.d.ts +40 -0
- package/dist/tool-middleware.js +216 -0
- package/dist/tool-registry.js +2 -1
- package/dist/tools/advanced.d.ts +2 -2
- package/dist/tools/advanced.js +200 -275
- package/dist/tools/agents.d.ts +2 -2
- package/dist/tools/agents.js +59 -78
- package/dist/tools/analytics.d.ts +2 -2
- package/dist/tools/analytics.js +170 -210
- package/dist/tools/architecture.d.ts +2 -2
- package/dist/tools/architecture.js +506 -669
- package/dist/tools/ask.d.ts +2 -2
- package/dist/tools/ask.js +164 -219
- package/dist/tools/cache.d.ts +2 -2
- package/dist/tools/cache.js +63 -82
- package/dist/tools/clustering.d.ts +2 -2
- package/dist/tools/clustering.js +154 -215
- package/dist/tools/confluence.d.ts +2 -2
- package/dist/tools/confluence.js +80 -116
- package/dist/tools/database.d.ts +2 -2
- package/dist/tools/database.js +303 -380
- package/dist/tools/feedback.d.ts +2 -2
- package/dist/tools/feedback.js +143 -184
- package/dist/tools/guidelines.d.ts +2 -2
- package/dist/tools/guidelines.js +123 -135
- package/dist/tools/indexing.d.ts +2 -2
- package/dist/tools/indexing.js +100 -108
- package/dist/tools/memory.d.ts +2 -2
- package/dist/tools/memory.js +299 -485
- package/dist/tools/pm.d.ts +2 -2
- package/dist/tools/pm.js +367 -615
- package/dist/tools/quality.d.ts +8 -0
- package/dist/tools/quality.js +60 -0
- package/dist/tools/review.d.ts +2 -2
- package/dist/tools/review.js +142 -189
- package/dist/tools/search.d.ts +2 -2
- package/dist/tools/search.js +230 -305
- package/dist/tools/session.d.ts +2 -2
- package/dist/tools/session.js +288 -345
- package/dist/tools/suggestions.d.ts +2 -2
- package/dist/tools/suggestions.js +517 -512
- package/dist/types.d.ts +19 -2
- package/package.json +4 -2
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Middleware — standalone middleware functions for MCP tool handlers.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from ToolRegistry.handle() so that McpServer.registerTool()
|
|
5
|
+
* (Phase 3) can reuse the same pipeline:
|
|
6
|
+
* auto-session → enrichment.before → handler → enrichment.after → trackUsage
|
|
7
|
+
*
|
|
8
|
+
* During Phase 2 migration, ToolRegistry continues to use its own copy.
|
|
9
|
+
* Phase 3 replaces ToolRegistry with wrapHandler() + McpServer.registerTool().
|
|
10
|
+
*/
|
|
11
|
+
// ── Timeouts ────────────────────────────────────────────────
|
|
12
|
+
/** Default tool timeout in milliseconds */
|
|
13
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
14
|
+
/** Per-tool timeout overrides (ms) */
|
|
15
|
+
export const TOOL_TIMEOUTS = {
|
|
16
|
+
// Indexing / heavy analysis — up to 2 min
|
|
17
|
+
index_codebase: 120_000,
|
|
18
|
+
reindex_zero_downtime: 120_000,
|
|
19
|
+
cluster_code: 60_000,
|
|
20
|
+
find_duplicates: 60_000,
|
|
21
|
+
run_quality_gates: 60_000,
|
|
22
|
+
analyze_project_structure: 60_000,
|
|
23
|
+
estimate_feature: 60_000,
|
|
24
|
+
// Quick search — 15 s
|
|
25
|
+
search_codebase: 15_000,
|
|
26
|
+
hybrid_search: 15_000,
|
|
27
|
+
search_similar: 15_000,
|
|
28
|
+
search_graph: 15_000,
|
|
29
|
+
grouped_search: 15_000,
|
|
30
|
+
search_docs: 10_000,
|
|
31
|
+
find_symbol: 10_000,
|
|
32
|
+
// Memory / recall — 10 s
|
|
33
|
+
recall: 10_000,
|
|
34
|
+
remember: 10_000,
|
|
35
|
+
context_briefing: 15_000,
|
|
36
|
+
};
|
|
37
|
+
/** Race a promise against a timeout */
|
|
38
|
+
async function withTimeout(promise, ms, name) {
|
|
39
|
+
let timer;
|
|
40
|
+
const timeout = new Promise((_, reject) => {
|
|
41
|
+
timer = setTimeout(() => reject(new Error(`Tool '${name}' timed out after ${ms}ms`)), ms);
|
|
42
|
+
});
|
|
43
|
+
try {
|
|
44
|
+
return await Promise.race([promise, timeout]);
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// ── Constants ───────────────────────────────────────────────
|
|
51
|
+
/** Tools excluded from usage tracking (meta/admin, avoid recursion) */
|
|
52
|
+
export const TRACKING_EXCLUDE = new Set([
|
|
53
|
+
"get_tool_analytics",
|
|
54
|
+
"get_knowledge_gaps",
|
|
55
|
+
"analyze_usage_patterns",
|
|
56
|
+
"get_behavior_patterns",
|
|
57
|
+
"get_quality_metrics",
|
|
58
|
+
"get_cache_stats",
|
|
59
|
+
"get_prediction_stats",
|
|
60
|
+
"get_rag_guidelines",
|
|
61
|
+
]);
|
|
62
|
+
/** Session management tools — skip auto-session to avoid recursion */
|
|
63
|
+
export const SESSION_TOOLS = new Set([
|
|
64
|
+
"start_session",
|
|
65
|
+
"end_session",
|
|
66
|
+
"get_session_context",
|
|
67
|
+
]);
|
|
68
|
+
// ── Helpers ─────────────────────────────────────────────────
|
|
69
|
+
/** Summarize tool args into a short string for analytics */
|
|
70
|
+
export function summarizeInput(name, args) {
|
|
71
|
+
const q = args.query || args.question || args.feature || args.description || args.task || "";
|
|
72
|
+
if (q && typeof q === "string")
|
|
73
|
+
return q.slice(0, 200);
|
|
74
|
+
const content = args.content || args.code || args.diff || "";
|
|
75
|
+
if (content && typeof content === "string")
|
|
76
|
+
return content.slice(0, 100);
|
|
77
|
+
const file = args.file || args.filePath || args.currentFile || "";
|
|
78
|
+
if (file && typeof file === "string")
|
|
79
|
+
return file;
|
|
80
|
+
for (const v of Object.values(args)) {
|
|
81
|
+
if (typeof v === "string" && v.length > 0)
|
|
82
|
+
return v.slice(0, 150);
|
|
83
|
+
}
|
|
84
|
+
return name;
|
|
85
|
+
}
|
|
86
|
+
/** Count results from a tool response string */
|
|
87
|
+
export function countResults(result) {
|
|
88
|
+
if (result.includes("No results") ||
|
|
89
|
+
result.includes("No matches") ||
|
|
90
|
+
result.includes("not found"))
|
|
91
|
+
return 0;
|
|
92
|
+
const numbered = result.match(/^\d+\./gm);
|
|
93
|
+
if (numbered)
|
|
94
|
+
return numbered.length;
|
|
95
|
+
const bullets = result.match(/^[-*] /gm);
|
|
96
|
+
if (bullets)
|
|
97
|
+
return bullets.length;
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
// ── Session management ──────────────────────────────────────
|
|
101
|
+
/** Shared lock to prevent concurrent auto-session starts */
|
|
102
|
+
let autoSessionPromise = null;
|
|
103
|
+
/** Auto-start a session via the RAG API if none is active */
|
|
104
|
+
export async function ensureSession(ctx) {
|
|
105
|
+
if (ctx.activeSessionId)
|
|
106
|
+
return;
|
|
107
|
+
if (autoSessionPromise) {
|
|
108
|
+
await autoSessionPromise;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
autoSessionPromise = doAutoStartSession(ctx);
|
|
112
|
+
try {
|
|
113
|
+
await autoSessionPromise;
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
autoSessionPromise = null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function doAutoStartSession(ctx) {
|
|
120
|
+
try {
|
|
121
|
+
const response = await ctx.api.post("/api/session/start", {
|
|
122
|
+
projectName: ctx.projectName,
|
|
123
|
+
initialContext: "auto-started by MCP tool call",
|
|
124
|
+
});
|
|
125
|
+
const session = response.data?.session;
|
|
126
|
+
const sid = session?.sessionId || response.data?.sessionId;
|
|
127
|
+
if (sid) {
|
|
128
|
+
ctx.activeSessionId = sid;
|
|
129
|
+
}
|
|
130
|
+
// Fire-and-forget: ensure critical collections exist
|
|
131
|
+
ctx.api
|
|
132
|
+
.post("/api/ensure-collections", { projectName: ctx.projectName })
|
|
133
|
+
.catch(() => { });
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Silent — auto-session must never block tool execution
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// ── Usage tracking ──────────────────────────────────────────
|
|
140
|
+
/** Fire-and-forget usage tracking */
|
|
141
|
+
export function trackUsage(name, args, startTime, success, result, errorMessage, ctx) {
|
|
142
|
+
if (TRACKING_EXCLUDE.has(name))
|
|
143
|
+
return;
|
|
144
|
+
ctx.api
|
|
145
|
+
.post("/api/track-usage", {
|
|
146
|
+
projectName: ctx.projectName,
|
|
147
|
+
sessionId: ctx.activeSessionId,
|
|
148
|
+
toolName: name,
|
|
149
|
+
inputSummary: summarizeInput(name, args),
|
|
150
|
+
startTime,
|
|
151
|
+
resultCount: success ? countResults(result) : 0,
|
|
152
|
+
success,
|
|
153
|
+
errorMessage,
|
|
154
|
+
})
|
|
155
|
+
.catch(() => { });
|
|
156
|
+
}
|
|
157
|
+
// ── Error formatting ────────────────────────────────────────
|
|
158
|
+
/** Format an error caught during tool execution */
|
|
159
|
+
export function formatToolError(error, ctx) {
|
|
160
|
+
const err = error;
|
|
161
|
+
if (err.code === "ECONNREFUSED") {
|
|
162
|
+
return (`Error: Cannot connect to RAG API at ${ctx.api.defaults.baseURL}. Is it running?\n` +
|
|
163
|
+
`Start with: cd docker && docker-compose up -d`);
|
|
164
|
+
}
|
|
165
|
+
if (err.response) {
|
|
166
|
+
return `API Error (${err.response.status}): ${JSON.stringify(err.response.data)}`;
|
|
167
|
+
}
|
|
168
|
+
return `Error: ${err.message || String(error)}`;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Wrap a raw ToolHandler with the full middleware pipeline:
|
|
172
|
+
* auto-session → enrichment.before → handler → enrichment.after → trackUsage
|
|
173
|
+
*
|
|
174
|
+
* Returns a ToolHandler with the same signature, so it works both
|
|
175
|
+
* with the legacy ToolRegistry and the Phase 3 McpServer adapter.
|
|
176
|
+
*/
|
|
177
|
+
export function wrapHandler(name, handler, deps) {
|
|
178
|
+
return async (args, ctx) => {
|
|
179
|
+
// Auto-start session (skip for session management tools)
|
|
180
|
+
if (!SESSION_TOOLS.has(name)) {
|
|
181
|
+
await ensureSession(ctx);
|
|
182
|
+
}
|
|
183
|
+
const startTime = Date.now();
|
|
184
|
+
try {
|
|
185
|
+
// Before: auto-enrich context
|
|
186
|
+
const contextPrefix = ctx.enrichmentEnabled && deps.enricher
|
|
187
|
+
? await deps.enricher.before(name, args, ctx)
|
|
188
|
+
: null;
|
|
189
|
+
// Execute original handler (with timeout)
|
|
190
|
+
const timeoutMs = TOOL_TIMEOUTS[name] ?? DEFAULT_TIMEOUT_MS;
|
|
191
|
+
const result = await withTimeout(handler(args, ctx), timeoutMs, name);
|
|
192
|
+
// Extract text for tracking/enrichment
|
|
193
|
+
const text = typeof result === "string" ? result : result.text;
|
|
194
|
+
// After: track interaction (fire-and-forget)
|
|
195
|
+
if (deps.enricher) {
|
|
196
|
+
deps.enricher.after(name, args, text, ctx);
|
|
197
|
+
}
|
|
198
|
+
// Track usage (fire-and-forget)
|
|
199
|
+
trackUsage(name, args, startTime, true, text, undefined, ctx);
|
|
200
|
+
// Prepend context if available
|
|
201
|
+
if (contextPrefix) {
|
|
202
|
+
if (typeof result === "string") {
|
|
203
|
+
return contextPrefix + "\n\n" + result;
|
|
204
|
+
}
|
|
205
|
+
return { text: contextPrefix + "\n\n" + result.text, structured: result.structured };
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
const errorMessage = formatToolError(error, ctx);
|
|
211
|
+
// Track failed usage (fire-and-forget)
|
|
212
|
+
trackUsage(name, args, startTime, false, "", errorMessage, ctx);
|
|
213
|
+
return errorMessage;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
package/dist/tool-registry.js
CHANGED
|
@@ -149,7 +149,8 @@ export class ToolRegistry {
|
|
|
149
149
|
? await this.enricher.before(name, args, ctx)
|
|
150
150
|
: null;
|
|
151
151
|
// Execute original handler
|
|
152
|
-
const
|
|
152
|
+
const rawResult = await handler(args, ctx);
|
|
153
|
+
const result = typeof rawResult === "string" ? rawResult : rawResult.text;
|
|
153
154
|
// After: track interaction (fire-and-forget)
|
|
154
155
|
if (this.enricher) {
|
|
155
156
|
this.enricher.after(name, args, result, ctx);
|
package/dist/tools/advanced.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Advanced tools module - memory merging, code completion context,
|
|
3
3
|
* import suggestions, type context, and behavior patterns.
|
|
4
4
|
*/
|
|
5
|
-
import type {
|
|
5
|
+
import type { ToolSpec } from "../types.js";
|
|
6
6
|
/**
|
|
7
7
|
* Create the advanced tools module with project-specific descriptions.
|
|
8
8
|
*/
|
|
9
|
-
export declare function createAdvancedTools(projectName: string):
|
|
9
|
+
export declare function createAdvancedTools(projectName: string): ToolSpec[];
|