secondbrainos-mcp-server 1.5.4 → 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 +46 -98
- 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
|
@@ -15,12 +15,6 @@ function toSnakeCase(str) {
|
|
|
15
15
|
.replace(/[^a-z0-9]+/g, '_')
|
|
16
16
|
.replace(/^_+|_+$/g, '');
|
|
17
17
|
}
|
|
18
|
-
function toKebabCase(str) {
|
|
19
|
-
return str
|
|
20
|
-
.toLowerCase()
|
|
21
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
22
|
-
.replace(/^-+|-+$/g, '');
|
|
23
|
-
}
|
|
24
18
|
class SecondBrainOSServer {
|
|
25
19
|
constructor(initialSchema) {
|
|
26
20
|
this.originalSpec = initialSchema;
|
|
@@ -80,7 +74,7 @@ class SecondBrainOSServer {
|
|
|
80
74
|
tools: {},
|
|
81
75
|
prompts: {}
|
|
82
76
|
},
|
|
83
|
-
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."
|
|
84
78
|
});
|
|
85
79
|
this.setupHandlers();
|
|
86
80
|
this.setupErrorHandling();
|
|
@@ -253,6 +247,13 @@ class SecondBrainOSServer {
|
|
|
253
247
|
console.error('Failed to fetch agents for prompts/list:', error);
|
|
254
248
|
}
|
|
255
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
|
+
});
|
|
256
257
|
// Add Knowledge Bases prompt (collects searchMyKnowledge_collection_ids from agents)
|
|
257
258
|
if (this.getAIAgentsSchemaPath) {
|
|
258
259
|
try {
|
|
@@ -285,6 +286,22 @@ class SecondBrainOSServer {
|
|
|
285
286
|
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
286
287
|
const promptName = request.params.name;
|
|
287
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
|
+
}
|
|
288
305
|
// Check if this is the Knowledge Bases prompt
|
|
289
306
|
if (promptName === "knowledge_bases") {
|
|
290
307
|
const agents = await this.fetchAndEnrichAgents();
|
|
@@ -580,25 +597,28 @@ class SecondBrainOSServer {
|
|
|
580
597
|
return enriched;
|
|
581
598
|
}
|
|
582
599
|
/**
|
|
583
|
-
* Write
|
|
584
|
-
* 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.
|
|
585
602
|
*/
|
|
586
|
-
async
|
|
587
|
-
const
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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() {
|
|
595
615
|
let agentIndex = '';
|
|
596
616
|
let skillIndex = '';
|
|
597
617
|
try {
|
|
598
618
|
const agents = await this.fetchAndEnrichAgents();
|
|
599
619
|
agentIndex = agents
|
|
600
620
|
.filter((a) => a.name && a.id)
|
|
601
|
-
.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}` : ''}`)
|
|
602
622
|
.join('\n');
|
|
603
623
|
}
|
|
604
624
|
catch { /* skip if unavailable */ }
|
|
@@ -606,11 +626,11 @@ class SecondBrainOSServer {
|
|
|
606
626
|
const workflows = await this.fetchAndEnrichWorkflows();
|
|
607
627
|
skillIndex = workflows
|
|
608
628
|
.filter((wf) => wf.name)
|
|
609
|
-
.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}` : ''}`)
|
|
610
630
|
.join('\n');
|
|
611
631
|
}
|
|
612
632
|
catch { /* skip if unavailable */ }
|
|
613
|
-
|
|
633
|
+
return `---
|
|
614
634
|
name: server-use
|
|
615
635
|
description: Second Brain OS server context — terminology, architecture, and available agents/skills index
|
|
616
636
|
user-invocable: false
|
|
@@ -630,14 +650,13 @@ An agent definition combines:
|
|
|
630
650
|
2. **Services (Tools)** — the MCP tools the agent can use
|
|
631
651
|
3. **Workflows (Skills)** — the prompt chains the agent follows
|
|
632
652
|
|
|
633
|
-
|
|
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
|
|
634
656
|
|
|
635
657
|
## Accessing Agents & Skills
|
|
636
|
-
- Skill files live at \`~/.claude/skills/secondbrainos/\` (tabs/, workflows/, knowledge-bases/)
|
|
637
|
-
- All skill files are set to \`user-invocable: false\` to avoid duplicating slash commands already available via MCP prompts
|
|
638
658
|
- **Users** invoke agents or skills via slash commands (e.g. \`/secondbrainos:agent_...\` or \`/secondbrainos:skill_...\`)
|
|
639
659
|
- **Users** cannot invoke MCP tools directly via slash commands — they must ask you to load and call the relevant tool
|
|
640
|
-
- When using an agent with sub-agents, load the necessary skills at the start of the conversation by reading the agent's skill files
|
|
641
660
|
|
|
642
661
|
## Available Agents
|
|
643
662
|
${agentIndex || '_None configured_'}
|
|
@@ -645,85 +664,14 @@ ${agentIndex || '_None configured_'}
|
|
|
645
664
|
## Available Skills
|
|
646
665
|
${skillIndex || '_None configured_'}
|
|
647
666
|
`;
|
|
648
|
-
writeSkill(path.join(skillsBase, 'server-use'), serverUseContent);
|
|
649
|
-
// 2. tabs (agents)
|
|
650
|
-
if (this.getAIAgentsSchemaPath) {
|
|
651
|
-
try {
|
|
652
|
-
const agents = await this.fetchAndEnrichAgents();
|
|
653
|
-
for (const agent of agents) {
|
|
654
|
-
if (!agent.name || !agent.id)
|
|
655
|
-
continue;
|
|
656
|
-
const folderName = toKebabCase(agent.name);
|
|
657
|
-
const agentDocument = {
|
|
658
|
-
agent_id: agent.id,
|
|
659
|
-
name: agent.name,
|
|
660
|
-
description: agent.description || '',
|
|
661
|
-
behaviour_and_instructions: agent.behaviour_and_instructions || '',
|
|
662
|
-
searchMyKnowledge_collection_id: agent.searchMyKnowledge_collection_id || '',
|
|
663
|
-
actions: agent.actions || [],
|
|
664
|
-
workflows: (agent.workflows || []).map((wf) => ({
|
|
665
|
-
id: wf.id,
|
|
666
|
-
name: wf.name,
|
|
667
|
-
prompts: (wf.prompts || []).map((p) => ({
|
|
668
|
-
id: p.id,
|
|
669
|
-
name: p.name,
|
|
670
|
-
order: p.order,
|
|
671
|
-
description: p.description
|
|
672
|
-
}))
|
|
673
|
-
}))
|
|
674
|
-
};
|
|
675
|
-
writeSkill(path.join(skillsBase, 'tabs', folderName), `---\nname: ${folderName}\ndescription: "${agent.description || agent.name}"\nuser-invocable: false\n---\n\n${JSON.stringify(agentDocument, null, 2)}\n`);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
catch (error) {
|
|
679
|
-
console.error('Failed to write agent skill files:', error);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
// 3. workflows (uses cached enriched data)
|
|
683
|
-
if (this.runPromptChainPath) {
|
|
684
|
-
try {
|
|
685
|
-
const workflows = await this.fetchAndEnrichWorkflows();
|
|
686
|
-
for (const wf of workflows) {
|
|
687
|
-
const folderName = toKebabCase(wf.name);
|
|
688
|
-
const workflowDocument = {
|
|
689
|
-
skill_id: wf.workflow_id,
|
|
690
|
-
name: wf.name,
|
|
691
|
-
description: wf.description || '',
|
|
692
|
-
prompts: wf.prompts
|
|
693
|
-
};
|
|
694
|
-
writeSkill(path.join(skillsBase, 'workflows', folderName), `---\nname: ${folderName}\ndescription: "${wf.description || wf.name}"\nuser-invocable: false\n---\n\n${JSON.stringify(workflowDocument, null, 2)}\n`);
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
catch (error) {
|
|
698
|
-
console.error('Failed to write workflow skill files:', error);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
// 4. knowledgebases
|
|
702
|
-
if (this.getAIAgentsSchemaPath) {
|
|
703
|
-
try {
|
|
704
|
-
const agents = await this.fetchAndEnrichAgents();
|
|
705
|
-
const collectionIds = agents
|
|
706
|
-
.map((a) => a.searchMyKnowledge_collection_id)
|
|
707
|
-
.filter((id) => id && id.length > 0);
|
|
708
|
-
if (collectionIds.length > 0) {
|
|
709
|
-
const kbDocument = { searchMyKnowledge_collection_ids: collectionIds };
|
|
710
|
-
writeSkill(path.join(skillsBase, 'knowledge-bases'), `---\nname: knowledge-bases\ndescription: Knowledge base collection IDs available to agents\nuser-invocable: false\n---\n\n${JSON.stringify(kbDocument, null, 2)}\n`);
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
catch (error) {
|
|
714
|
-
console.error('Failed to write knowledge bases skill file:', error);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
console.error('Skill files written to ~/.claude/skills/secondbrainos/');
|
|
718
667
|
}
|
|
719
668
|
setupErrorHandling() {
|
|
720
669
|
// Error handling is now built into HttpLlm.execute
|
|
721
670
|
// This method is kept for future error handling implementations
|
|
722
671
|
}
|
|
723
672
|
async run() {
|
|
724
|
-
// Write skill
|
|
725
|
-
|
|
726
|
-
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));
|
|
727
675
|
const transport = new StdioServerTransport();
|
|
728
676
|
await this.server.connect(transport);
|
|
729
677
|
console.error("Second Brain OS MCP server running on stdio");
|