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.
- package/build/index.js +197 -48
- 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
|
|
33
|
+
// Initialize maps and cache
|
|
34
34
|
this.workflowNameToId = new Map();
|
|
35
|
-
|
|
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
|
-
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
200
|
-
prompts:
|
|
201
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
|
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
|
-
//
|
|
224
|
-
const
|
|
225
|
-
|
|
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
|
|
230
|
-
const promptResults = await Promise.all(promptIds.map((promptId) =>
|
|
231
|
-
|
|
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
|
|
234
|
-
|
|
235
|
-
|
|
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:
|
|
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: `
|
|
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
|