secondbrainos-mcp-server 1.1.0 → 1.2.1

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 +197 -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,115 @@ 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
+ const skillName = wf.name || wf.workflow_id;
205
+ prompts.push({
206
+ name: skillName,
207
+ title: `[Skill] ${skillName}`,
208
+ description: wf.description || wf.name,
209
+ arguments: [
210
+ {
211
+ name: "user_input",
212
+ description: "Optional context or input to guide the skill execution",
213
+ required: false
214
+ }
215
+ ]
216
+ });
197
217
  }
198
218
  }
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
- };
219
+ catch (error) {
220
+ console.error('Failed to fetch workflows for prompts/list:', error);
221
+ }
212
222
  }
213
- catch (error) {
214
- console.error('Failed to fetch workflows for prompts/list:', error);
215
- return { prompts: [] };
223
+ // Fetch agents as prompts
224
+ if (this.getAIAgentsSchemaPath) {
225
+ try {
226
+ const agents = await this.fetchAndEnrichAgents();
227
+ this.agentNameToId.clear();
228
+ for (const agent of agents) {
229
+ if (agent.name && agent.id) {
230
+ const agentPromptName = `[Agent] ${agent.name}`;
231
+ this.agentNameToId.set(agentPromptName, agent.id);
232
+ prompts.push({
233
+ name: agentPromptName,
234
+ title: `[Agent] ${agent.name}`,
235
+ description: agent.description || agent.name,
236
+ arguments: [
237
+ {
238
+ name: "user_input",
239
+ description: "Optional context or input to guide the agent",
240
+ required: false
241
+ }
242
+ ]
243
+ });
244
+ }
245
+ }
246
+ }
247
+ catch (error) {
248
+ console.error('Failed to fetch agents for prompts/list:', error);
249
+ }
216
250
  }
251
+ return { prompts };
217
252
  });
218
- // Get a specific prompt (workflow's prompt chain)
253
+ // Get a specific prompt (workflow prompt chain or agent document)
219
254
  this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
220
255
  const promptName = request.params.name;
221
- const workflowId = this.workflowNameToId.get(promptName) || promptName;
222
256
  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 || [];
257
+ // Check if this is an agent prompt
258
+ const agentId = this.agentNameToId.get(promptName);
259
+ if (agentId) {
260
+ return this.buildAgentPrompt(agentId, userInput);
261
+ }
262
+ // Otherwise treat as a workflow prompt
263
+ const workflowId = this.workflowNameToId.get(promptName) || promptName;
264
+ // Fetch workflow metadata from the workflows list
265
+ const workflowsData = await this.callRunPromptChain('', '');
266
+ const workflowMeta = (workflowsData.workflows || []).find((wf) => wf.workflow_id === workflowId);
267
+ const workflowDetail = await this.callRunPromptChain('workflow', workflowId);
268
+ const promptIds = workflowDetail.prompt_id || [];
226
269
  if (promptIds.length === 0) {
227
270
  throw new McpError(ErrorCode.InvalidRequest, `No prompts found for workflow: ${workflowId}`);
228
271
  }
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
272
+ // Fetch prompt metadata (no instructions)
273
+ const promptResults = await Promise.all(promptIds.map(async (promptId) => {
274
+ const promptData = await this.callRunPromptChain('prompt', promptId);
275
+ return {
276
+ id: promptId,
277
+ name: promptData.name,
278
+ order: promptData.order,
279
+ description: promptData.description || ''
280
+ };
281
+ }));
232
282
  const sortedPrompts = promptResults.sort((a, b) => (a.order || 0) - (b.order || 0));
233
- const messages = [];
234
- for (const prompt of sortedPrompts) {
235
- messages.push({
283
+ const workflowDocument = {
284
+ skill_id: workflowId,
285
+ name: workflowMeta?.name || promptName,
286
+ description: workflowMeta?.description || '',
287
+ prompts: sortedPrompts
288
+ };
289
+ const messages = [
290
+ {
236
291
  role: "user",
237
292
  content: {
238
293
  type: "text",
239
- text: prompt.instructions
294
+ text: JSON.stringify(workflowDocument, null, 2)
240
295
  }
241
- });
242
- }
243
- // If user provided input, append it as the final message
296
+ }
297
+ ];
244
298
  if (userInput) {
245
299
  messages.push({
246
300
  role: "user",
@@ -251,11 +305,58 @@ class SecondBrainOSServer {
251
305
  });
252
306
  }
253
307
  return {
254
- description: `Workflow prompt chain (${sortedPrompts.length} steps)`,
308
+ description: `Skill: ${workflowDocument.name} (${sortedPrompts.length} prompts)`,
255
309
  messages
256
310
  };
257
311
  });
258
312
  }
313
+ async buildAgentPrompt(agentId, userInput) {
314
+ const agents = await this.fetchAndEnrichAgents();
315
+ const agent = agents.find((a) => a.id === agentId);
316
+ if (!agent) {
317
+ throw new McpError(ErrorCode.InvalidRequest, `Agent not found: ${agentId}`);
318
+ }
319
+ // Build the agent document as a structured JSON object
320
+ const agentDocument = {
321
+ name: agent.name,
322
+ description: agent.description || '',
323
+ behaviour_and_instructions: agent.behaviour_and_instructions || '',
324
+ actions: agent.actions || [],
325
+ workflows: (agent.workflows || []).map((wf) => ({
326
+ id: wf.id,
327
+ name: wf.name,
328
+ prompts: (wf.prompts || []).map((p) => ({
329
+ id: p.id,
330
+ name: p.name,
331
+ order: p.order,
332
+ description: p.description
333
+ }))
334
+ }))
335
+ };
336
+ const messages = [
337
+ {
338
+ role: "user",
339
+ content: {
340
+ type: "text",
341
+ text: JSON.stringify(agentDocument, null, 2)
342
+ }
343
+ }
344
+ ];
345
+ if (userInput) {
346
+ messages.push({
347
+ role: "user",
348
+ content: {
349
+ type: "text",
350
+ text: userInput
351
+ }
352
+ });
353
+ }
354
+ const skillCount = agentDocument.workflows.length;
355
+ return {
356
+ description: `Agent: ${agent.name} (${skillCount} skill${skillCount !== 1 ? 's' : ''})`,
357
+ messages
358
+ };
359
+ }
259
360
  async callRunPromptChain(entity, entityId) {
260
361
  if (!this.runPromptChainPath) {
261
362
  throw new McpError(ErrorCode.InternalError, 'runPromptChain service not available for this user');
@@ -272,6 +373,54 @@ class SecondBrainOSServer {
272
373
  });
273
374
  return response.data;
274
375
  }
376
+ async callGetAIAgentsSchema() {
377
+ if (!this.getAIAgentsSchemaPath) {
378
+ throw new McpError(ErrorCode.InternalError, 'getAIAgentsSchema service not available for this user');
379
+ }
380
+ const url = `${this.baseUrl}${this.getAIAgentsSchemaPath}`;
381
+ const response = await axios.post(url, {
382
+ include_sensitive_config: true
383
+ }, {
384
+ headers: {
385
+ 'Authorization': `Bearer ${this.userId}:${this.userSecret}`,
386
+ 'Content-Type': 'application/json'
387
+ }
388
+ });
389
+ return response.data;
390
+ }
391
+ async fetchAndEnrichAgents() {
392
+ if (this.cachedAgents)
393
+ return this.cachedAgents;
394
+ const data = await this.callGetAIAgentsSchema();
395
+ const agents = data.agents || [];
396
+ // Enrich each agent's workflows with full prompt details
397
+ for (const agent of agents) {
398
+ if (!agent.workflows)
399
+ continue;
400
+ for (const workflow of agent.workflows) {
401
+ if (!workflow.prompts || workflow.prompts.length === 0)
402
+ continue;
403
+ // Fetch prompt metadata (name, order, description) — no instructions
404
+ const enrichedPrompts = await Promise.all(workflow.prompts.map(async (prompt) => {
405
+ try {
406
+ const promptData = await this.callRunPromptChain('prompt', prompt.id);
407
+ return {
408
+ id: prompt.id,
409
+ name: promptData.name || prompt.name,
410
+ order: promptData.order,
411
+ description: promptData.description || ''
412
+ };
413
+ }
414
+ catch {
415
+ return { id: prompt.id, name: prompt.name, order: 0, description: '' };
416
+ }
417
+ }));
418
+ workflow.prompts = enrichedPrompts.sort((a, b) => (a.order || 0) - (b.order || 0));
419
+ }
420
+ }
421
+ this.cachedAgents = agents;
422
+ return agents;
423
+ }
275
424
  setupErrorHandling() {
276
425
  // Error handling is now built into HttpLlm.execute
277
426
  // 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.1",
4
4
  "description": "Second Brain OS MCP Server for Claude Desktop",
5
5
  "type": "module",
6
6
  "main": "build/index.js",