@crowley/rag-mcp 1.0.5 → 1.0.6

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.
Files changed (49) hide show
  1. package/dist/annotations.d.ts +16 -0
  2. package/dist/annotations.js +158 -0
  3. package/dist/context-enrichment.js +7 -0
  4. package/dist/formatters.d.ts +2 -0
  5. package/dist/formatters.js +12 -0
  6. package/dist/index.js +46 -47
  7. package/dist/schemas.d.ts +97 -0
  8. package/dist/schemas.js +128 -0
  9. package/dist/tool-middleware.d.ts +40 -0
  10. package/dist/tool-middleware.js +216 -0
  11. package/dist/tool-registry.js +2 -1
  12. package/dist/tools/advanced.d.ts +2 -2
  13. package/dist/tools/advanced.js +200 -275
  14. package/dist/tools/agents.d.ts +2 -2
  15. package/dist/tools/agents.js +59 -78
  16. package/dist/tools/analytics.d.ts +2 -2
  17. package/dist/tools/analytics.js +170 -210
  18. package/dist/tools/architecture.d.ts +2 -2
  19. package/dist/tools/architecture.js +506 -669
  20. package/dist/tools/ask.d.ts +2 -2
  21. package/dist/tools/ask.js +164 -219
  22. package/dist/tools/cache.d.ts +2 -2
  23. package/dist/tools/cache.js +63 -82
  24. package/dist/tools/clustering.d.ts +2 -2
  25. package/dist/tools/clustering.js +154 -215
  26. package/dist/tools/confluence.d.ts +2 -2
  27. package/dist/tools/confluence.js +80 -116
  28. package/dist/tools/database.d.ts +2 -2
  29. package/dist/tools/database.js +303 -380
  30. package/dist/tools/feedback.d.ts +2 -2
  31. package/dist/tools/feedback.js +143 -184
  32. package/dist/tools/guidelines.d.ts +2 -2
  33. package/dist/tools/guidelines.js +123 -135
  34. package/dist/tools/indexing.d.ts +2 -2
  35. package/dist/tools/indexing.js +100 -108
  36. package/dist/tools/memory.d.ts +2 -2
  37. package/dist/tools/memory.js +299 -485
  38. package/dist/tools/pm.d.ts +2 -2
  39. package/dist/tools/pm.js +367 -615
  40. package/dist/tools/review.d.ts +2 -2
  41. package/dist/tools/review.js +142 -189
  42. package/dist/tools/search.d.ts +2 -2
  43. package/dist/tools/search.js +230 -305
  44. package/dist/tools/session.d.ts +2 -2
  45. package/dist/tools/session.js +288 -345
  46. package/dist/tools/suggestions.d.ts +2 -2
  47. package/dist/tools/suggestions.js +425 -512
  48. package/dist/types.d.ts +19 -2
  49. 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
+ }
@@ -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 result = await handler(args, ctx);
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);
@@ -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 { ToolModule } from "../types.js";
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): ToolModule;
9
+ export declare function createAdvancedTools(projectName: string): ToolSpec[];