@crowley/rag-mcp 1.0.1 → 1.0.2

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.
@@ -7,8 +7,16 @@ export declare class ToolRegistry {
7
7
  private tools;
8
8
  private handlers;
9
9
  private enricher?;
10
+ private autoSessionPromise;
10
11
  /** Set the context enricher */
11
12
  setEnricher(enricher: ContextEnricher): void;
13
+ /**
14
+ * Ensure an active session exists before handling a tool call.
15
+ * Skips for session management tools. Handles post-end_session restart.
16
+ */
17
+ private ensureSession;
18
+ /** Start an auto-session via the RAG API */
19
+ private doAutoStartSession;
12
20
  /** Register a tool module */
13
21
  register(module: ToolModule): void;
14
22
  /** Get all registered tool definitions */
@@ -12,6 +12,12 @@ const TRACKING_EXCLUDE = new Set([
12
12
  "get_prediction_stats",
13
13
  "get_rag_guidelines",
14
14
  ]);
15
+ /** Session management tools — skip auto-session to avoid recursion */
16
+ const SESSION_TOOLS = new Set([
17
+ "start_session",
18
+ "end_session",
19
+ "get_session_context",
20
+ ]);
15
21
  /** Summarize tool args into a short string for analytics */
16
22
  function summarizeInput(name, args) {
17
23
  // Common patterns: query, question, content, feature, code, file
@@ -48,10 +54,54 @@ export class ToolRegistry {
48
54
  tools = [];
49
55
  handlers = new Map();
50
56
  enricher;
57
+ autoSessionPromise = null;
51
58
  /** Set the context enricher */
52
59
  setEnricher(enricher) {
53
60
  this.enricher = enricher;
54
61
  }
62
+ /**
63
+ * Ensure an active session exists before handling a tool call.
64
+ * Skips for session management tools. Handles post-end_session restart.
65
+ */
66
+ async ensureSession(ctx) {
67
+ if (ctx.activeSessionId)
68
+ return;
69
+ // If already starting, wait for it
70
+ if (this.autoSessionPromise) {
71
+ await this.autoSessionPromise;
72
+ return;
73
+ }
74
+ this.autoSessionPromise = this.doAutoStartSession(ctx);
75
+ try {
76
+ await this.autoSessionPromise;
77
+ }
78
+ finally {
79
+ this.autoSessionPromise = null;
80
+ }
81
+ }
82
+ /** Start an auto-session via the RAG API */
83
+ async doAutoStartSession(ctx) {
84
+ try {
85
+ const response = await ctx.api.post("/api/session/start", {
86
+ projectName: ctx.projectName,
87
+ initialContext: "auto-started by MCP tool call",
88
+ });
89
+ const session = response.data?.session;
90
+ const sid = session?.sessionId || response.data?.sessionId;
91
+ if (sid) {
92
+ ctx.activeSessionId = sid;
93
+ }
94
+ // Fire-and-forget: ensure critical collections exist
95
+ ctx.api
96
+ .post("/api/ensure-collections", { projectName: ctx.projectName })
97
+ .catch(() => {
98
+ // Silent — must never break tool execution
99
+ });
100
+ }
101
+ catch {
102
+ // Silent — auto-session must never block tool execution
103
+ }
104
+ }
55
105
  /** Register a tool module */
56
106
  register(module) {
57
107
  this.tools.push(...module.tools);
@@ -88,6 +138,10 @@ export class ToolRegistry {
88
138
  if (!handler) {
89
139
  return `Unknown tool: ${name}`;
90
140
  }
141
+ // Auto-start session on first tool call (skip for session management tools)
142
+ if (!SESSION_TOOLS.has(name)) {
143
+ await this.ensureSession(ctx);
144
+ }
91
145
  const startTime = Date.now();
92
146
  try {
93
147
  // Before: auto-enrich context
@@ -270,26 +270,32 @@ export function createSessionTools(projectName, sharedCtx) {
270
270
  resumeFrom,
271
271
  });
272
272
  const data = response.data;
273
+ const session = data.session;
274
+ // Extract fields — API returns { session: { sessionId, startedAt, ... } }
275
+ const sid = session?.sessionId || data.sessionId;
276
+ const started = session?.startedAt || data.started;
277
+ const resumedFrom = session?.metadata?.resumedFrom || data.resumedFrom;
278
+ const initialFiles = session?.currentFiles || data.initialFiles;
273
279
  // Update shared context with active session ID
274
- if (sharedCtx && data.sessionId) {
275
- sharedCtx.activeSessionId = data.sessionId;
280
+ if (sharedCtx && sid) {
281
+ sharedCtx.activeSessionId = sid;
276
282
  }
277
283
  let result = `**Session Started**\n\n`;
278
- result += `- **Session ID:** ${data.sessionId}\n`;
279
- result += `- **Started:** ${data.started}\n`;
280
- if (data.resumedFrom) {
281
- result += `- **Resumed From:** ${data.resumedFrom}\n`;
284
+ result += `- **Session ID:** ${sid}\n`;
285
+ result += `- **Started:** ${started}\n`;
286
+ if (resumedFrom) {
287
+ result += `- **Resumed From:** ${resumedFrom}\n`;
282
288
  }
283
- if (data.initialFiles && data.initialFiles.length > 0) {
289
+ if (initialFiles && initialFiles.length > 0) {
284
290
  result += `\n**Initial Files:**\n`;
285
- result += data.initialFiles
291
+ result += initialFiles
286
292
  .map((f) => `- ${f}`)
287
293
  .join("\n");
288
294
  result += "\n";
289
295
  }
290
296
  // Include prefetch stats if available
291
- if (data.session?.metadata?.prefetchStats) {
292
- const pf = data.session.metadata.prefetchStats;
297
+ if (session?.metadata?.prefetchStats) {
298
+ const pf = session.metadata.prefetchStats;
293
299
  result += `\n**Predictive Prefetch:** ${pf.prefetchedCount ?? 0} resources prefetched\n`;
294
300
  }
295
301
  // Include briefing if available (Sprint E)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowley/rag-mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Universal RAG MCP Server for any project",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",