@grec0/memory-bank-mcp 0.2.6 → 0.2.8

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.
@@ -5,6 +5,9 @@
5
5
  */
6
6
  import { databaseManager } from './database.js';
7
7
  import * as crypto from 'crypto';
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import * as os from 'os';
8
11
  // ============================================================================
9
12
  // Agent Board SQLite Implementation
10
13
  // ============================================================================
@@ -20,6 +23,7 @@ export class AgentBoardSqlite {
20
23
  * Register a new agent for this project.
21
24
  * Automatically deactivates any previous active agent.
22
25
  * The MCP generates the hash suffix - client only provides base ID.
26
+ * Also syncs project keywords/responsibilities from registry to SQLite.
23
27
  */
24
28
  registerAgent(baseAgentId, sessionId) {
25
29
  const db = databaseManager.getConnection();
@@ -29,6 +33,23 @@ export class AgentBoardSqlite {
29
33
  // Generate session ID if not provided
30
34
  const effectiveSessionId = sessionId || crypto.randomUUID();
31
35
  const now = new Date().toISOString();
36
+ // Get project metadata from registry (keywords, responsibilities) - sync read
37
+ let keywords = [];
38
+ let responsibilities = [];
39
+ try {
40
+ const registryPath = path.join(os.homedir(), '.memorybank', 'global_registry.json');
41
+ if (fs.existsSync(registryPath)) {
42
+ const registryData = JSON.parse(fs.readFileSync(registryPath, 'utf-8'));
43
+ const project = registryData.projects?.find((p) => p.projectId === this.projectId);
44
+ if (project) {
45
+ keywords = project.keywords || [];
46
+ responsibilities = project.responsibilities || [];
47
+ }
48
+ }
49
+ }
50
+ catch (e) {
51
+ // Registry not available, continue without metadata
52
+ }
32
53
  return databaseManager.transaction(() => {
33
54
  // Deactivate any currently active agents for this project
34
55
  db.prepare(`
@@ -36,11 +57,11 @@ export class AgentBoardSqlite {
36
57
  SET status = 'INACTIVE', last_heartbeat = ?
37
58
  WHERE project_id = ? AND status = 'ACTIVE'
38
59
  `).run(now, this.projectId);
39
- // Insert new agent as ACTIVE
60
+ // Insert new agent as ACTIVE with project metadata
40
61
  db.prepare(`
41
- INSERT INTO agents (id, project_id, session_id, status, focus, last_heartbeat)
42
- VALUES (?, ?, ?, 'ACTIVE', '-', ?)
43
- `).run(fullAgentId, this.projectId, effectiveSessionId, now);
62
+ INSERT INTO agents (id, project_id, session_id, status, focus, last_heartbeat, keywords, responsibilities)
63
+ VALUES (?, ?, ?, 'ACTIVE', '-', ?, ?, ?)
64
+ `).run(fullAgentId, this.projectId, effectiveSessionId, now, JSON.stringify(keywords), JSON.stringify(responsibilities));
44
65
  // Log the registration
45
66
  this.logMessage(fullAgentId, `Agent registered and activated`);
46
67
  return { agentId: fullAgentId, sessionId: effectiveSessionId };
@@ -7,7 +7,7 @@ import Database from 'better-sqlite3';
7
7
  import * as path from 'path';
8
8
  import * as os from 'os';
9
9
  import * as fs from 'fs';
10
- const SCHEMA_VERSION = 2; // v2: Added orchestrator_logs table
10
+ const SCHEMA_VERSION = 3; // v2: Added orchestrator_logs table, v3: Added keywords/responsibilities to agents
11
11
  /**
12
12
  * SQL Schema for Agent Board
13
13
  */
@@ -21,6 +21,8 @@ CREATE TABLE IF NOT EXISTS agents (
21
21
  status TEXT NOT NULL DEFAULT 'ACTIVE', -- ACTIVE, INACTIVE
22
22
  focus TEXT DEFAULT '-', -- Current task/file being worked on
23
23
  last_heartbeat TEXT NOT NULL, -- ISO timestamp of last activity
24
+ keywords TEXT, -- JSON array of project keywords (synced from registry)
25
+ responsibilities TEXT, -- JSON array of project responsibilities (synced from registry)
24
26
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
25
27
  PRIMARY KEY (id, project_id)
26
28
  );
@@ -180,6 +182,26 @@ class DatabaseManager {
180
182
  console.error(`[Database] Migrating schema from v${currentVersion} to v${SCHEMA_VERSION}`);
181
183
  // Run schema creation (IF NOT EXISTS makes it safe)
182
184
  this.db.exec(SCHEMA_SQL);
185
+ // v3 migration: Add keywords and responsibilities columns to agents table
186
+ if (currentVersion < 3) {
187
+ try {
188
+ // Check if columns already exist
189
+ const tableInfo = this.db.prepare("PRAGMA table_info(agents)").all();
190
+ const hasKeywords = tableInfo.some(col => col.name === 'keywords');
191
+ const hasResponsibilities = tableInfo.some(col => col.name === 'responsibilities');
192
+ if (!hasKeywords) {
193
+ this.db.exec('ALTER TABLE agents ADD COLUMN keywords TEXT');
194
+ console.error('[Database] Added keywords column to agents table');
195
+ }
196
+ if (!hasResponsibilities) {
197
+ this.db.exec('ALTER TABLE agents ADD COLUMN responsibilities TEXT');
198
+ console.error('[Database] Added responsibilities column to agents table');
199
+ }
200
+ }
201
+ catch (alterError) {
202
+ console.error(`[Database] Warning during v3 migration: ${alterError.message}`);
203
+ }
204
+ }
183
205
  // Record/update schema version
184
206
  this.db.prepare('INSERT OR REPLACE INTO schema_version (version) VALUES (?)').run(SCHEMA_VERSION);
185
207
  console.error(`[Database] Schema initialized at v${SCHEMA_VERSION}`);
@@ -1,2 +1,2 @@
1
1
  // Version of the MCP Kanban server
2
- export const VERSION = "0.2.5";
2
+ export const VERSION = "0.2.8";
@@ -41,28 +41,26 @@ function buildProjectsContext(projects, currentProjectId) {
41
41
  return context;
42
42
  }
43
43
  /**
44
- * Tools available to the orchestrator for verification
44
+ * Tools available to the orchestrator for verification (Responses API format)
45
45
  */
46
46
  const ORCHESTRATOR_TOOLS = [
47
47
  {
48
48
  type: "function",
49
- function: {
50
- name: "semantic_search",
51
- description: "Search for code semantically in a specific project. Use this to verify if code already exists, where implementations are located, or to understand project structure before routing decisions.",
52
- parameters: {
53
- type: "object",
54
- properties: {
55
- projectId: {
56
- type: "string",
57
- description: "The project ID to search in",
58
- },
59
- query: {
60
- type: "string",
61
- description: "Natural language query describing what you're looking for (e.g., 'UserDTO class', 'authentication service', 'database connection')",
62
- },
49
+ name: "semantic_search",
50
+ description: "Search for code semantically in a specific project. Use this to verify if code already exists, where implementations are located, or to understand project structure before routing decisions.",
51
+ parameters: {
52
+ type: "object",
53
+ properties: {
54
+ projectId: {
55
+ type: "string",
56
+ description: "The project ID to search in",
57
+ },
58
+ query: {
59
+ type: "string",
60
+ description: "Natural language query describing what you're looking for (e.g., 'UserDTO class', 'authentication service', 'database connection')",
63
61
  },
64
- required: ["projectId", "query"],
65
62
  },
63
+ required: ["projectId", "query"],
66
64
  },
67
65
  },
68
66
  ];
@@ -227,21 +225,18 @@ export async function routeTaskTool(params, indexManager) {
227
225
  warning: 'AI routing unavailable. Proceeding without validation.',
228
226
  };
229
227
  }
230
- // Model used for routing (needed for logging both success and error cases)
231
- const model = process.env.MEMORYBANK_ROUTING_MODEL || "gpt-4o";
228
+ // Model and reasoning config (use same as project knowledge service)
229
+ const model = process.env.MEMORYBANK_REASONING_MODEL || "gpt-5-mini";
230
+ const reasoningEffort = process.env.MEMORYBANK_REASONING_EFFORT || "medium";
232
231
  try {
233
232
  const client = new OpenAI({ apiKey });
234
233
  const prompt = ROUTING_PROMPT
235
234
  .replace('{projectsContext}', projectsContext)
236
235
  .replace('{currentProject}', projectId)
237
236
  .replace('{taskDescription}', taskDescription);
238
- console.error(`Calling AI orchestrator with tool access (${model})...`);
239
- // Initialize conversation
240
- const messages = [
241
- {
242
- role: "system",
243
- content: "You are a Task Routing Orchestrator. Analyze tasks and route them to appropriate projects. You can use semantic_search to verify where code exists before making decisions. Always respond with JSON after your analysis.",
244
- },
237
+ console.error(`Calling AI orchestrator with Responses API (${model}, effort: ${reasoningEffort})...`);
238
+ // Build initial input for Responses API
239
+ const input = [
245
240
  {
246
241
  role: "user",
247
242
  content: prompt,
@@ -254,42 +249,67 @@ export async function routeTaskTool(params, indexManager) {
254
249
  while (iterations < maxIterations) {
255
250
  iterations++;
256
251
  console.error(` Iteration ${iterations}/${maxIterations}`);
257
- const response = await client.chat.completions.create({
252
+ // Call Responses API with reasoning
253
+ const response = await client.responses.create({
258
254
  model,
259
- messages,
255
+ reasoning: {
256
+ effort: reasoningEffort,
257
+ },
258
+ instructions: "You are a Task Routing Orchestrator. Analyze tasks and route them to appropriate projects. You can use semantic_search to verify where code exists before making decisions. Always respond with JSON after your analysis.",
259
+ input,
260
260
  tools: ORCHESTRATOR_TOOLS,
261
261
  tool_choice: "auto",
262
- max_tokens: 4000,
262
+ max_output_tokens: 8000,
263
263
  });
264
- const message = response.choices[0]?.message;
265
- if (!message) {
266
- console.error(` No message in response`);
267
- break;
264
+ // Process output items from Responses API
265
+ let hasToolCalls = false;
266
+ const toolCalls = [];
267
+ for (const item of response.output || []) {
268
+ if (item.type === "function_call") {
269
+ hasToolCalls = true;
270
+ toolCalls.push({
271
+ id: item.call_id,
272
+ name: item.name,
273
+ arguments: item.arguments,
274
+ });
275
+ }
276
+ else if (item.type === "message" && item.content) {
277
+ // Extract text content from message
278
+ for (const contentItem of item.content) {
279
+ if (contentItem.type === "output_text") {
280
+ finalResponse = contentItem.text;
281
+ }
282
+ }
283
+ }
268
284
  }
269
- // Check if there are tool calls
270
- if (message.tool_calls && message.tool_calls.length > 0) {
271
- console.error(` Model requested ${message.tool_calls.length} tool call(s)`);
272
- // Add assistant message with tool calls
273
- messages.push(message);
274
- // Execute each tool call
275
- for (const toolCall of message.tool_calls) {
276
- const toolName = toolCall.function.name;
277
- const toolArgs = JSON.parse(toolCall.function.arguments);
278
- const toolResult = await executeToolCall(toolName, toolArgs, allProjects, indexManager);
279
- // Add tool result to messages
280
- messages.push({
281
- role: "tool",
282
- tool_call_id: toolCall.id,
283
- content: toolResult,
285
+ if (hasToolCalls) {
286
+ console.error(` Model requested ${toolCalls.length} tool call(s)`);
287
+ // Execute each tool call and add results to input
288
+ for (const toolCall of toolCalls) {
289
+ const toolArgs = JSON.parse(toolCall.arguments);
290
+ const toolResult = await executeToolCall(toolCall.name, toolArgs, allProjects, indexManager);
291
+ // Add function call and result to input for next iteration
292
+ input.push({
293
+ type: "function_call",
294
+ call_id: toolCall.id,
295
+ name: toolCall.name,
296
+ arguments: toolCall.arguments,
297
+ });
298
+ input.push({
299
+ type: "function_call_output",
300
+ call_id: toolCall.id,
301
+ output: toolResult,
284
302
  });
285
303
  }
286
304
  }
287
- else {
288
- // No tool calls, this is the final response
289
- finalResponse = message.content;
305
+ else if (finalResponse) {
290
306
  console.error(` Final response received`);
291
307
  break;
292
308
  }
309
+ else {
310
+ console.error(` No response or tool calls`);
311
+ break;
312
+ }
293
313
  }
294
314
  if (!finalResponse) {
295
315
  console.error(` No final response after ${iterations} iterations`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grec0/memory-bank-mcp",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "MCP server for semantic code indexing with Memory Bank - AI-powered codebase understanding",
5
5
  "license": "MIT",
6
6
  "author": "@grec0",