secondbrainos-mcp-server 1.5.2 → 1.5.4
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 +36 -0
- package/build/index.js +67 -7
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -362,6 +362,42 @@ 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
|
+
|
|
365
401
|
console.log('\nInstallation successful!');
|
|
366
402
|
console.log('\nClaude Desktop:');
|
|
367
403
|
console.log('1. Completely quit Claude Desktop if it is running');
|
package/build/index.js
CHANGED
|
@@ -15,6 +15,12 @@ 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
|
+
}
|
|
18
24
|
class SecondBrainOSServer {
|
|
19
25
|
constructor(initialSchema) {
|
|
20
26
|
this.originalSpec = initialSchema;
|
|
@@ -584,8 +590,62 @@ class SecondBrainOSServer {
|
|
|
584
590
|
fs.mkdirSync(dir, { recursive: true });
|
|
585
591
|
fs.writeFileSync(path.join(dir, 'SKILL.md'), content, 'utf-8');
|
|
586
592
|
};
|
|
587
|
-
// 1. server-use —
|
|
588
|
-
|
|
593
|
+
// 1. server-use — context document for Claude Code sessions
|
|
594
|
+
// Gather agent and workflow names for the index
|
|
595
|
+
let agentIndex = '';
|
|
596
|
+
let skillIndex = '';
|
|
597
|
+
try {
|
|
598
|
+
const agents = await this.fetchAndEnrichAgents();
|
|
599
|
+
agentIndex = agents
|
|
600
|
+
.filter((a) => a.name && a.id)
|
|
601
|
+
.map((a) => `- ${a.name} → \`/secondbrainos:agent_${toSnakeCase(a.name)}\``)
|
|
602
|
+
.join('\n');
|
|
603
|
+
}
|
|
604
|
+
catch { /* skip if unavailable */ }
|
|
605
|
+
try {
|
|
606
|
+
const workflows = await this.fetchAndEnrichWorkflows();
|
|
607
|
+
skillIndex = workflows
|
|
608
|
+
.filter((wf) => wf.name)
|
|
609
|
+
.map((wf) => `- ${wf.name} → \`/secondbrainos:skill_${toSnakeCase(wf.name)}\``)
|
|
610
|
+
.join('\n');
|
|
611
|
+
}
|
|
612
|
+
catch { /* skip if unavailable */ }
|
|
613
|
+
const serverUseContent = `---
|
|
614
|
+
name: server-use
|
|
615
|
+
description: Second Brain OS server context — terminology, architecture, and available agents/skills index
|
|
616
|
+
user-invocable: false
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
# Second Brain OS — Server Context
|
|
620
|
+
|
|
621
|
+
## Terminology
|
|
622
|
+
These terms are synonyms and used interchangeably in SBOS:
|
|
623
|
+
- **Tabs / Agents** — AI agents with behaviour, knowledge, tools, and skills
|
|
624
|
+
- **Services / Tools** — always MCP tools
|
|
625
|
+
- **Workflows / Skills** — a skill is a structured set of prompts, enabling optimised context per step so the agent can progress through a skill without overload
|
|
626
|
+
|
|
627
|
+
## Agent Architecture
|
|
628
|
+
An agent definition combines:
|
|
629
|
+
1. **Knowledge** — an obfuscated vector store collection ID for \`searchMyKnowledge\`
|
|
630
|
+
2. **Services (Tools)** — the MCP tools the agent can use
|
|
631
|
+
3. **Workflows (Skills)** — the prompt chains the agent follows
|
|
632
|
+
|
|
633
|
+
This means you can spin up sub-agents from an agent's skill definitions (see \`~/.claude/skills/secondbrainos/tabs/\`).
|
|
634
|
+
|
|
635
|
+
## 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
|
+
- **Users** invoke agents or skills via slash commands (e.g. \`/secondbrainos:agent_...\` or \`/secondbrainos:skill_...\`)
|
|
639
|
+
- **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
|
+
|
|
642
|
+
## Available Agents
|
|
643
|
+
${agentIndex || '_None configured_'}
|
|
644
|
+
|
|
645
|
+
## Available Skills
|
|
646
|
+
${skillIndex || '_None configured_'}
|
|
647
|
+
`;
|
|
648
|
+
writeSkill(path.join(skillsBase, 'server-use'), serverUseContent);
|
|
589
649
|
// 2. tabs (agents)
|
|
590
650
|
if (this.getAIAgentsSchemaPath) {
|
|
591
651
|
try {
|
|
@@ -593,7 +653,7 @@ class SecondBrainOSServer {
|
|
|
593
653
|
for (const agent of agents) {
|
|
594
654
|
if (!agent.name || !agent.id)
|
|
595
655
|
continue;
|
|
596
|
-
const folderName =
|
|
656
|
+
const folderName = toKebabCase(agent.name);
|
|
597
657
|
const agentDocument = {
|
|
598
658
|
agent_id: agent.id,
|
|
599
659
|
name: agent.name,
|
|
@@ -612,7 +672,7 @@ class SecondBrainOSServer {
|
|
|
612
672
|
}))
|
|
613
673
|
}))
|
|
614
674
|
};
|
|
615
|
-
writeSkill(path.join(skillsBase, 'tabs', folderName), `---\nname:
|
|
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`);
|
|
616
676
|
}
|
|
617
677
|
}
|
|
618
678
|
catch (error) {
|
|
@@ -624,14 +684,14 @@ class SecondBrainOSServer {
|
|
|
624
684
|
try {
|
|
625
685
|
const workflows = await this.fetchAndEnrichWorkflows();
|
|
626
686
|
for (const wf of workflows) {
|
|
627
|
-
const folderName =
|
|
687
|
+
const folderName = toKebabCase(wf.name);
|
|
628
688
|
const workflowDocument = {
|
|
629
689
|
skill_id: wf.workflow_id,
|
|
630
690
|
name: wf.name,
|
|
631
691
|
description: wf.description || '',
|
|
632
692
|
prompts: wf.prompts
|
|
633
693
|
};
|
|
634
|
-
writeSkill(path.join(skillsBase, 'workflows', folderName), `---\nname:
|
|
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`);
|
|
635
695
|
}
|
|
636
696
|
}
|
|
637
697
|
catch (error) {
|
|
@@ -647,7 +707,7 @@ class SecondBrainOSServer {
|
|
|
647
707
|
.filter((id) => id && id.length > 0);
|
|
648
708
|
if (collectionIds.length > 0) {
|
|
649
709
|
const kbDocument = { searchMyKnowledge_collection_ids: collectionIds };
|
|
650
|
-
writeSkill(path.join(skillsBase, '
|
|
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`);
|
|
651
711
|
}
|
|
652
712
|
}
|
|
653
713
|
catch (error) {
|