secondbrainos-mcp-server 1.1.0 → 1.2.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.
Files changed (2) hide show
  1. package/build/index.js +194 -48
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -30,19 +30,24 @@ class SecondBrainOSServer {
30
30
  this.functionMap.set(operation.operationId, func);
31
31
  }
32
32
  });
33
- // Initialize workflow name-to-ID map
33
+ // Initialize maps and cache
34
34
  this.workflowNameToId = new Map();
35
- // Discover runPromptChain path from the OpenAPI schema
35
+ this.agentNameToId = new Map();
36
+ this.cachedAgents = null;
37
+ // Discover service paths from the OpenAPI schema
36
38
  this.runPromptChainPath = null;
39
+ this.getAIAgentsSchemaPath = null;
37
40
  if (initialSchema.paths) {
38
41
  for (const [path, pathItem] of Object.entries(initialSchema.paths)) {
39
42
  for (const operation of Object.values(pathItem)) {
40
43
  if (operation.operationId === 'runPromptChain') {
41
44
  this.runPromptChainPath = path;
42
- break;
45
+ }
46
+ if (operation.operationId === 'getAIAgentsSchema') {
47
+ this.getAIAgentsSchemaPath = path;
43
48
  }
44
49
  }
45
- if (this.runPromptChainPath)
50
+ if (this.runPromptChainPath && this.getAIAgentsSchemaPath)
46
51
  break;
47
52
  }
48
53
  }
@@ -181,66 +186,112 @@ class SecondBrainOSServer {
181
186
  throw error;
182
187
  }
183
188
  });
184
- // List available prompts (user's workflows)
189
+ // List available prompts (user's workflows + agents)
185
190
  this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
186
- if (!this.runPromptChainPath) {
187
- return { prompts: [] };
188
- }
189
- try {
190
- const data = await this.callRunPromptChain('', '');
191
- const workflows = data.workflows || [];
192
- // Populate name-to-ID map
193
- this.workflowNameToId.clear();
194
- for (const wf of workflows) {
195
- if (wf.name && wf.workflow_id) {
196
- this.workflowNameToId.set(wf.name, wf.workflow_id);
191
+ const prompts = [];
192
+ // Fetch workflows as prompts
193
+ if (this.runPromptChainPath) {
194
+ try {
195
+ const data = await this.callRunPromptChain('', '');
196
+ const workflows = data.workflows || [];
197
+ this.workflowNameToId.clear();
198
+ for (const wf of workflows) {
199
+ if (wf.name && wf.workflow_id) {
200
+ this.workflowNameToId.set(wf.name, wf.workflow_id);
201
+ }
202
+ }
203
+ for (const wf of workflows) {
204
+ prompts.push({
205
+ name: wf.name || wf.workflow_id,
206
+ description: wf.description || wf.name,
207
+ arguments: [
208
+ {
209
+ name: "user_input",
210
+ description: "Optional context or input to guide the workflow execution",
211
+ required: false
212
+ }
213
+ ]
214
+ });
197
215
  }
198
216
  }
199
- return {
200
- prompts: workflows.map((wf) => ({
201
- name: wf.name || wf.workflow_id,
202
- description: wf.description || wf.name,
203
- arguments: [
204
- {
205
- name: "user_input",
206
- description: "Optional context or input to guide the workflow execution",
207
- required: false
208
- }
209
- ]
210
- }))
211
- };
217
+ catch (error) {
218
+ console.error('Failed to fetch workflows for prompts/list:', error);
219
+ }
212
220
  }
213
- catch (error) {
214
- console.error('Failed to fetch workflows for prompts/list:', error);
215
- return { prompts: [] };
221
+ // Fetch agents as prompts
222
+ if (this.getAIAgentsSchemaPath) {
223
+ try {
224
+ const agents = await this.fetchAndEnrichAgents();
225
+ this.agentNameToId.clear();
226
+ for (const agent of agents) {
227
+ if (agent.name && agent.id) {
228
+ const agentPromptName = `[Agent] ${agent.name}`;
229
+ this.agentNameToId.set(agentPromptName, agent.id);
230
+ prompts.push({
231
+ name: agentPromptName,
232
+ description: agent.description || agent.name,
233
+ arguments: [
234
+ {
235
+ name: "user_input",
236
+ description: "Optional context or input to guide the agent",
237
+ required: false
238
+ }
239
+ ]
240
+ });
241
+ }
242
+ }
243
+ }
244
+ catch (error) {
245
+ console.error('Failed to fetch agents for prompts/list:', error);
246
+ }
216
247
  }
248
+ return { prompts };
217
249
  });
218
- // Get a specific prompt (workflow's prompt chain)
250
+ // Get a specific prompt (workflow prompt chain or agent document)
219
251
  this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
220
252
  const promptName = request.params.name;
221
- const workflowId = this.workflowNameToId.get(promptName) || promptName;
222
253
  const userInput = request.params.arguments?.user_input;
223
- // Fetch workflow details to get prompt IDs
224
- const workflowData = await this.callRunPromptChain('workflow', workflowId);
225
- const promptIds = workflowData.prompt_id || [];
254
+ // Check if this is an agent prompt
255
+ const agentId = this.agentNameToId.get(promptName);
256
+ if (agentId) {
257
+ return this.buildAgentPrompt(agentId, userInput);
258
+ }
259
+ // Otherwise treat as a workflow prompt
260
+ const workflowId = this.workflowNameToId.get(promptName) || promptName;
261
+ // Fetch workflow metadata from the workflows list
262
+ const workflowsData = await this.callRunPromptChain('', '');
263
+ const workflowMeta = (workflowsData.workflows || []).find((wf) => wf.workflow_id === workflowId);
264
+ const workflowDetail = await this.callRunPromptChain('workflow', workflowId);
265
+ const promptIds = workflowDetail.prompt_id || [];
226
266
  if (promptIds.length === 0) {
227
267
  throw new McpError(ErrorCode.InvalidRequest, `No prompts found for workflow: ${workflowId}`);
228
268
  }
229
- // Fetch each prompt's instructions
230
- const promptResults = await Promise.all(promptIds.map((promptId) => this.callRunPromptChain('prompt', promptId)));
231
- // Sort by order and build messages
269
+ // Fetch prompt metadata (no instructions)
270
+ const promptResults = await Promise.all(promptIds.map(async (promptId) => {
271
+ const promptData = await this.callRunPromptChain('prompt', promptId);
272
+ return {
273
+ id: promptId,
274
+ name: promptData.name,
275
+ order: promptData.order,
276
+ description: promptData.description || ''
277
+ };
278
+ }));
232
279
  const sortedPrompts = promptResults.sort((a, b) => (a.order || 0) - (b.order || 0));
233
- const messages = [];
234
- for (const prompt of sortedPrompts) {
235
- messages.push({
280
+ const workflowDocument = {
281
+ workflow_id: workflowId,
282
+ name: workflowMeta?.name || promptName,
283
+ description: workflowMeta?.description || '',
284
+ prompts: sortedPrompts
285
+ };
286
+ const messages = [
287
+ {
236
288
  role: "user",
237
289
  content: {
238
290
  type: "text",
239
- text: prompt.instructions
291
+ text: JSON.stringify(workflowDocument, null, 2)
240
292
  }
241
- });
242
- }
243
- // If user provided input, append it as the final message
293
+ }
294
+ ];
244
295
  if (userInput) {
245
296
  messages.push({
246
297
  role: "user",
@@ -251,11 +302,58 @@ class SecondBrainOSServer {
251
302
  });
252
303
  }
253
304
  return {
254
- description: `Workflow prompt chain (${sortedPrompts.length} steps)`,
305
+ description: `Workflow: ${workflowDocument.name} (${sortedPrompts.length} prompts)`,
255
306
  messages
256
307
  };
257
308
  });
258
309
  }
310
+ async buildAgentPrompt(agentId, userInput) {
311
+ const agents = await this.fetchAndEnrichAgents();
312
+ const agent = agents.find((a) => a.id === agentId);
313
+ if (!agent) {
314
+ throw new McpError(ErrorCode.InvalidRequest, `Agent not found: ${agentId}`);
315
+ }
316
+ // Build the agent document as a structured JSON object
317
+ const agentDocument = {
318
+ name: agent.name,
319
+ description: agent.description || '',
320
+ behaviour_and_instructions: agent.behaviour_and_instructions || '',
321
+ actions: agent.actions || [],
322
+ workflows: (agent.workflows || []).map((wf) => ({
323
+ id: wf.id,
324
+ name: wf.name,
325
+ prompts: (wf.prompts || []).map((p) => ({
326
+ id: p.id,
327
+ name: p.name,
328
+ order: p.order,
329
+ description: p.description
330
+ }))
331
+ }))
332
+ };
333
+ const messages = [
334
+ {
335
+ role: "user",
336
+ content: {
337
+ type: "text",
338
+ text: JSON.stringify(agentDocument, null, 2)
339
+ }
340
+ }
341
+ ];
342
+ if (userInput) {
343
+ messages.push({
344
+ role: "user",
345
+ content: {
346
+ type: "text",
347
+ text: userInput
348
+ }
349
+ });
350
+ }
351
+ const skillCount = agentDocument.workflows.length;
352
+ return {
353
+ description: `Agent: ${agent.name} (${skillCount} skill${skillCount !== 1 ? 's' : ''})`,
354
+ messages
355
+ };
356
+ }
259
357
  async callRunPromptChain(entity, entityId) {
260
358
  if (!this.runPromptChainPath) {
261
359
  throw new McpError(ErrorCode.InternalError, 'runPromptChain service not available for this user');
@@ -272,6 +370,54 @@ class SecondBrainOSServer {
272
370
  });
273
371
  return response.data;
274
372
  }
373
+ async callGetAIAgentsSchema() {
374
+ if (!this.getAIAgentsSchemaPath) {
375
+ throw new McpError(ErrorCode.InternalError, 'getAIAgentsSchema service not available for this user');
376
+ }
377
+ const url = `${this.baseUrl}${this.getAIAgentsSchemaPath}`;
378
+ const response = await axios.post(url, {
379
+ include_sensitive_config: true
380
+ }, {
381
+ headers: {
382
+ 'Authorization': `Bearer ${this.userId}:${this.userSecret}`,
383
+ 'Content-Type': 'application/json'
384
+ }
385
+ });
386
+ return response.data;
387
+ }
388
+ async fetchAndEnrichAgents() {
389
+ if (this.cachedAgents)
390
+ return this.cachedAgents;
391
+ const data = await this.callGetAIAgentsSchema();
392
+ const agents = data.agents || [];
393
+ // Enrich each agent's workflows with full prompt details
394
+ for (const agent of agents) {
395
+ if (!agent.workflows)
396
+ continue;
397
+ for (const workflow of agent.workflows) {
398
+ if (!workflow.prompts || workflow.prompts.length === 0)
399
+ continue;
400
+ // Fetch prompt metadata (name, order, description) — no instructions
401
+ const enrichedPrompts = await Promise.all(workflow.prompts.map(async (prompt) => {
402
+ try {
403
+ const promptData = await this.callRunPromptChain('prompt', prompt.id);
404
+ return {
405
+ id: prompt.id,
406
+ name: promptData.name || prompt.name,
407
+ order: promptData.order,
408
+ description: promptData.description || ''
409
+ };
410
+ }
411
+ catch {
412
+ return { id: prompt.id, name: prompt.name, order: 0, description: '' };
413
+ }
414
+ }));
415
+ workflow.prompts = enrichedPrompts.sort((a, b) => (a.order || 0) - (b.order || 0));
416
+ }
417
+ }
418
+ this.cachedAgents = agents;
419
+ return agents;
420
+ }
275
421
  setupErrorHandling() {
276
422
  // Error handling is now built into HttpLlm.execute
277
423
  // This method is kept for future error handling implementations
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secondbrainos-mcp-server",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Second Brain OS MCP Server for Claude Desktop",
5
5
  "type": "module",
6
6
  "main": "build/index.js",