secondbrainos-mcp-server 1.5.3 → 1.6.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.
- package/bin/cli.js +0 -36
- package/build/index.js +47 -93
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -362,42 +362,6 @@ async function main() {
|
|
|
362
362
|
const cliPath = path.join(packageRoot, 'bin', 'cli.js');
|
|
363
363
|
const claudeCodeConfigured = await configureClaudeCode(cliPath, nodePath);
|
|
364
364
|
|
|
365
|
-
// Add SessionStart hook to global Claude Code settings
|
|
366
|
-
if (claudeCodeConfigured) {
|
|
367
|
-
try {
|
|
368
|
-
const claudeSettingsPath = path.join(homedir(), '.claude', 'settings.json');
|
|
369
|
-
let settings = {};
|
|
370
|
-
try {
|
|
371
|
-
settings = JSON.parse(await fs.readFile(claudeSettingsPath, 'utf8'));
|
|
372
|
-
} catch { /* file may not exist yet */ }
|
|
373
|
-
|
|
374
|
-
if (!settings.hooks) settings.hooks = {};
|
|
375
|
-
if (!settings.hooks.SessionStart) settings.hooks.SessionStart = [];
|
|
376
|
-
|
|
377
|
-
// Check if our hook already exists
|
|
378
|
-
const skillFilePath = path.join(homedir(), '.claude', 'skills', 'secondbrainos', 'server-use', 'SKILL.md');
|
|
379
|
-
const hookCommand = `cat "${skillFilePath}" 2>/dev/null || true`;
|
|
380
|
-
const hasHook = settings.hooks.SessionStart.some(
|
|
381
|
-
entry => entry.hooks && entry.hooks.some(h => h.command && h.command.includes('secondbrainos/server-use/SKILL.md'))
|
|
382
|
-
);
|
|
383
|
-
|
|
384
|
-
if (!hasHook) {
|
|
385
|
-
settings.hooks.SessionStart.push({
|
|
386
|
-
hooks: [
|
|
387
|
-
{
|
|
388
|
-
type: "command",
|
|
389
|
-
command: hookCommand
|
|
390
|
-
}
|
|
391
|
-
]
|
|
392
|
-
});
|
|
393
|
-
await fs.writeFile(claudeSettingsPath, JSON.stringify(settings, null, 2));
|
|
394
|
-
console.log('SessionStart hook configured for SBOS context loading.');
|
|
395
|
-
}
|
|
396
|
-
} catch (error) {
|
|
397
|
-
console.log(`Note: Could not configure SessionStart hook: ${error.message}`);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
365
|
console.log('\nInstallation successful!');
|
|
402
366
|
console.log('\nClaude Desktop:');
|
|
403
367
|
console.log('1. Completely quit Claude Desktop if it is running');
|
package/build/index.js
CHANGED
|
@@ -74,7 +74,7 @@ class SecondBrainOSServer {
|
|
|
74
74
|
tools: {},
|
|
75
75
|
prompts: {}
|
|
76
76
|
},
|
|
77
|
-
instructions: "SBOS provides tools for managing knowledge along with definitions for sub-agents and associated skills.
|
|
77
|
+
instructions: "SBOS provides tools for managing knowledge along with definitions for sub-agents and associated skills. Run /secondbrainos:start_secondbrainos to load full SBOS context."
|
|
78
78
|
});
|
|
79
79
|
this.setupHandlers();
|
|
80
80
|
this.setupErrorHandling();
|
|
@@ -247,6 +247,13 @@ class SecondBrainOSServer {
|
|
|
247
247
|
console.error('Failed to fetch agents for prompts/list:', error);
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
+
// Add start_secondbrainos prompt — returns the server-use context document
|
|
251
|
+
prompts.push({
|
|
252
|
+
name: "start_secondbrainos",
|
|
253
|
+
title: "[Start] Second Brain OS",
|
|
254
|
+
description: "Load SBOS context: terminology, architecture, and available agents & skills index",
|
|
255
|
+
arguments: []
|
|
256
|
+
});
|
|
250
257
|
// Add Knowledge Bases prompt (collects searchMyKnowledge_collection_ids from agents)
|
|
251
258
|
if (this.getAIAgentsSchemaPath) {
|
|
252
259
|
try {
|
|
@@ -279,6 +286,22 @@ class SecondBrainOSServer {
|
|
|
279
286
|
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
280
287
|
const promptName = request.params.name;
|
|
281
288
|
const userInput = request.params.arguments?.user_input;
|
|
289
|
+
// Check if this is the start_secondbrainos prompt
|
|
290
|
+
if (promptName === "start_secondbrainos") {
|
|
291
|
+
const content = await this.buildServerUseContent();
|
|
292
|
+
return {
|
|
293
|
+
description: "Second Brain OS — Server Context",
|
|
294
|
+
messages: [
|
|
295
|
+
{
|
|
296
|
+
role: "user",
|
|
297
|
+
content: {
|
|
298
|
+
type: "text",
|
|
299
|
+
text: content
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
]
|
|
303
|
+
};
|
|
304
|
+
}
|
|
282
305
|
// Check if this is the Knowledge Bases prompt
|
|
283
306
|
if (promptName === "knowledge_bases") {
|
|
284
307
|
const agents = await this.fetchAndEnrichAgents();
|
|
@@ -574,25 +597,28 @@ class SecondBrainOSServer {
|
|
|
574
597
|
return enriched;
|
|
575
598
|
}
|
|
576
599
|
/**
|
|
577
|
-
* Write
|
|
578
|
-
* Called on every server startup so
|
|
600
|
+
* Write the server-use skill file to ~/.claude/skills/secondbrainos/
|
|
601
|
+
* Called on every server startup so the context index stays in sync with SBOS.
|
|
579
602
|
*/
|
|
580
|
-
async
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
603
|
+
async writeServerUseSkillFile() {
|
|
604
|
+
const serverUseContent = await this.buildServerUseContent();
|
|
605
|
+
const dir = path.join(homedir(), '.claude', 'skills', 'secondbrainos', 'server-use');
|
|
606
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
607
|
+
fs.writeFileSync(path.join(dir, 'SKILL.md'), serverUseContent, 'utf-8');
|
|
608
|
+
console.error('Server-use skill file written to ~/.claude/skills/secondbrainos/server-use/');
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Build the server-use context document content.
|
|
612
|
+
* Used by both writeServerUseSkillFile and the start_secondbrainos prompt.
|
|
613
|
+
*/
|
|
614
|
+
async buildServerUseContent() {
|
|
589
615
|
let agentIndex = '';
|
|
590
616
|
let skillIndex = '';
|
|
591
617
|
try {
|
|
592
618
|
const agents = await this.fetchAndEnrichAgents();
|
|
593
619
|
agentIndex = agents
|
|
594
620
|
.filter((a) => a.name && a.id)
|
|
595
|
-
.map((a) => `- ${a.name} → \`/secondbrainos:agent_${toSnakeCase(a.name)}
|
|
621
|
+
.map((a) => `- ${a.name} (id: ${a.id}) → \`/secondbrainos:agent_${toSnakeCase(a.name)}\`${a.description ? `\n ${a.description}` : ''}`)
|
|
596
622
|
.join('\n');
|
|
597
623
|
}
|
|
598
624
|
catch { /* skip if unavailable */ }
|
|
@@ -600,12 +626,12 @@ class SecondBrainOSServer {
|
|
|
600
626
|
const workflows = await this.fetchAndEnrichWorkflows();
|
|
601
627
|
skillIndex = workflows
|
|
602
628
|
.filter((wf) => wf.name)
|
|
603
|
-
.map((wf) => `- ${wf.name} → \`/secondbrainos:skill_${toSnakeCase(wf.name)}
|
|
629
|
+
.map((wf) => `- ${wf.name} (id: ${wf.workflow_id}) → \`/secondbrainos:skill_${toSnakeCase(wf.name)}\`${wf.description ? `\n ${wf.description}` : ''}`)
|
|
604
630
|
.join('\n');
|
|
605
631
|
}
|
|
606
632
|
catch { /* skip if unavailable */ }
|
|
607
|
-
|
|
608
|
-
name:
|
|
633
|
+
return `---
|
|
634
|
+
name: server-use
|
|
609
635
|
description: Second Brain OS server context — terminology, architecture, and available agents/skills index
|
|
610
636
|
user-invocable: false
|
|
611
637
|
---
|
|
@@ -624,14 +650,13 @@ An agent definition combines:
|
|
|
624
650
|
2. **Services (Tools)** — the MCP tools the agent can use
|
|
625
651
|
3. **Workflows (Skills)** — the prompt chains the agent follows
|
|
626
652
|
|
|
627
|
-
|
|
653
|
+
## Loading Agent & Skill Details
|
|
654
|
+
- To get full agent definitions (behaviour, knowledge, actions, workflows): use the \`getAIAgentsSchema\` tool
|
|
655
|
+
- To get full skill/workflow details and run prompt chains: use the \`runPromptChain\` tool
|
|
628
656
|
|
|
629
657
|
## Accessing Agents & Skills
|
|
630
|
-
- Skill files live at \`~/.claude/skills/secondbrainos/\` (tabs/, workflows/, knowledgebases/)
|
|
631
|
-
- All skill files are set to \`user-invocable: false\` to avoid duplicating slash commands already available via MCP prompts
|
|
632
658
|
- **Users** invoke agents or skills via slash commands (e.g. \`/secondbrainos:agent_...\` or \`/secondbrainos:skill_...\`)
|
|
633
659
|
- **Users** cannot invoke MCP tools directly via slash commands — they must ask you to load and call the relevant tool
|
|
634
|
-
- When using an agent with sub-agents, load the necessary skills at the start of the conversation by reading the agent's skill files
|
|
635
660
|
|
|
636
661
|
## Available Agents
|
|
637
662
|
${agentIndex || '_None configured_'}
|
|
@@ -639,85 +664,14 @@ ${agentIndex || '_None configured_'}
|
|
|
639
664
|
## Available Skills
|
|
640
665
|
${skillIndex || '_None configured_'}
|
|
641
666
|
`;
|
|
642
|
-
writeSkill(path.join(skillsBase, 'server-use'), serverUseContent);
|
|
643
|
-
// 2. tabs (agents)
|
|
644
|
-
if (this.getAIAgentsSchemaPath) {
|
|
645
|
-
try {
|
|
646
|
-
const agents = await this.fetchAndEnrichAgents();
|
|
647
|
-
for (const agent of agents) {
|
|
648
|
-
if (!agent.name || !agent.id)
|
|
649
|
-
continue;
|
|
650
|
-
const folderName = toSnakeCase(agent.name);
|
|
651
|
-
const agentDocument = {
|
|
652
|
-
agent_id: agent.id,
|
|
653
|
-
name: agent.name,
|
|
654
|
-
description: agent.description || '',
|
|
655
|
-
behaviour_and_instructions: agent.behaviour_and_instructions || '',
|
|
656
|
-
searchMyKnowledge_collection_id: agent.searchMyKnowledge_collection_id || '',
|
|
657
|
-
actions: agent.actions || [],
|
|
658
|
-
workflows: (agent.workflows || []).map((wf) => ({
|
|
659
|
-
id: wf.id,
|
|
660
|
-
name: wf.name,
|
|
661
|
-
prompts: (wf.prompts || []).map((p) => ({
|
|
662
|
-
id: p.id,
|
|
663
|
-
name: p.name,
|
|
664
|
-
order: p.order,
|
|
665
|
-
description: p.description
|
|
666
|
-
}))
|
|
667
|
-
}))
|
|
668
|
-
};
|
|
669
|
-
writeSkill(path.join(skillsBase, 'tabs', folderName), `---\nname: secondbrainos_agent_${folderName}\ndescription: "${agent.description || agent.name}"\nuser-invocable: false\n---\n\n${JSON.stringify(agentDocument, null, 2)}\n`);
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
catch (error) {
|
|
673
|
-
console.error('Failed to write agent skill files:', error);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
// 3. workflows (uses cached enriched data)
|
|
677
|
-
if (this.runPromptChainPath) {
|
|
678
|
-
try {
|
|
679
|
-
const workflows = await this.fetchAndEnrichWorkflows();
|
|
680
|
-
for (const wf of workflows) {
|
|
681
|
-
const folderName = toSnakeCase(wf.name);
|
|
682
|
-
const workflowDocument = {
|
|
683
|
-
skill_id: wf.workflow_id,
|
|
684
|
-
name: wf.name,
|
|
685
|
-
description: wf.description || '',
|
|
686
|
-
prompts: wf.prompts
|
|
687
|
-
};
|
|
688
|
-
writeSkill(path.join(skillsBase, 'workflows', folderName), `---\nname: secondbrainos_skill_${folderName}\ndescription: "${wf.description || wf.name}"\nuser-invocable: false\n---\n\n${JSON.stringify(workflowDocument, null, 2)}\n`);
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
catch (error) {
|
|
692
|
-
console.error('Failed to write workflow skill files:', error);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
// 4. knowledgebases
|
|
696
|
-
if (this.getAIAgentsSchemaPath) {
|
|
697
|
-
try {
|
|
698
|
-
const agents = await this.fetchAndEnrichAgents();
|
|
699
|
-
const collectionIds = agents
|
|
700
|
-
.map((a) => a.searchMyKnowledge_collection_id)
|
|
701
|
-
.filter((id) => id && id.length > 0);
|
|
702
|
-
if (collectionIds.length > 0) {
|
|
703
|
-
const kbDocument = { searchMyKnowledge_collection_ids: collectionIds };
|
|
704
|
-
writeSkill(path.join(skillsBase, 'knowledgebases'), `---\nname: secondbrainos_knowledge_bases\ndescription: Knowledge base collection IDs available to agents\nuser-invocable: false\n---\n\n${JSON.stringify(kbDocument, null, 2)}\n`);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
catch (error) {
|
|
708
|
-
console.error('Failed to write knowledge bases skill file:', error);
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
console.error('Skill files written to ~/.claude/skills/secondbrainos/');
|
|
712
667
|
}
|
|
713
668
|
setupErrorHandling() {
|
|
714
669
|
// Error handling is now built into HttpLlm.execute
|
|
715
670
|
// This method is kept for future error handling implementations
|
|
716
671
|
}
|
|
717
672
|
async run() {
|
|
718
|
-
// Write skill
|
|
719
|
-
|
|
720
|
-
await this.writeSkillFiles().catch(err => console.error('Failed to write skill files:', err));
|
|
673
|
+
// Write server-use skill file before connecting so Claude Code sees it at session start.
|
|
674
|
+
await this.writeServerUseSkillFile().catch(err => console.error('Failed to write server-use skill file:', err));
|
|
721
675
|
const transport = new StdioServerTransport();
|
|
722
676
|
await this.server.connect(transport);
|
|
723
677
|
console.error("Second Brain OS MCP server running on stdio");
|