secondbrainos-mcp-server 1.5.4 → 1.7.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/README.md +27 -14
- package/bin/cli.js +3 -40
- package/build/index.js +52 -143
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,8 +25,8 @@ secondbrainos-mcp USER_ID USER_SECRET
|
|
|
25
25
|
This will:
|
|
26
26
|
1. Verify your account credentials
|
|
27
27
|
2. Confirm you have access to the Claude MCP feature
|
|
28
|
-
3.
|
|
29
|
-
4. Configure
|
|
28
|
+
3. Store credentials securely at `~/.secondbrainos/credentials.json`
|
|
29
|
+
4. Configure Claude Desktop and Claude Code to use `serve` mode (credentials read from file, not embedded in config)
|
|
30
30
|
|
|
31
31
|
### Claude Code
|
|
32
32
|
|
|
@@ -52,16 +52,20 @@ The server uses `@samchon/openapi` library for robust OpenAPI handling, providin
|
|
|
52
52
|
- Support for complex parameters and nested objects
|
|
53
53
|
|
|
54
54
|
### Prompts
|
|
55
|
-
The server exposes
|
|
55
|
+
The server exposes four types of MCP prompts, available as slash commands (e.g. `/secondbrainos:agent_my_agent`):
|
|
56
|
+
|
|
57
|
+
#### Start (`start_secondbrainos`)
|
|
58
|
+
- Returns a context document with SBOS terminology, agent architecture, and an index of all available agents and skills with their slash commands
|
|
59
|
+
- Useful for orienting Claude at the start of a session
|
|
56
60
|
|
|
57
61
|
#### Skills (Workflows)
|
|
58
|
-
-
|
|
62
|
+
- Discovered via `runPromptChain` on first `ListPrompts` call, then cached for the session
|
|
59
63
|
- Each skill appears with a `[Skill]` prefix and returns a structured document with `skill_id`, `name`, `description`, and an ordered list of prompts (metadata only, no instructions)
|
|
60
64
|
- Supports an optional `user_input` argument to provide additional context
|
|
61
65
|
|
|
62
66
|
#### Agents
|
|
63
|
-
-
|
|
64
|
-
- Each agent appears with an `[Agent]` prefix and returns a structured document containing `agent_id`, `name`, `description`, `behaviour_and_instructions`, `searchMyKnowledge_collection_id`, `actions` (with id, name, description, body_parameters), and `workflows` (with
|
|
67
|
+
- Discovered via `getAIAgentsSchema` on first `ListPrompts` call, then cached for the session
|
|
68
|
+
- Each agent appears with an `[Agent]` prefix and returns a structured document containing `agent_id`, `name`, `description`, `behaviour_and_instructions`, `searchMyKnowledge_collection_id`, `actions` (with id, name, description, body_parameters), and `workflows` (with prompt order and description)
|
|
65
69
|
- Supports an optional `user_input` argument
|
|
66
70
|
|
|
67
71
|
#### Knowledge Bases
|
|
@@ -132,20 +136,29 @@ secondbrainos-mcp-server/
|
|
|
132
136
|
└── README.md # This file
|
|
133
137
|
```
|
|
134
138
|
|
|
135
|
-
##
|
|
139
|
+
## Credentials
|
|
136
140
|
|
|
137
|
-
The server
|
|
138
|
-
- `USER_ID`: Your Second Brain OS user ID
|
|
139
|
-
- `USER_SECRET`: Your Second Brain OS user secret
|
|
140
|
-
- `API_BASE_URL` (optional): Override the default API base URL
|
|
141
|
+
Credentials are stored securely at `~/.secondbrainos/credentials.json` (created during setup with mode `0o600`). The server reads from this file in `serve` mode. Environment variables `USER_ID`, `USER_SECRET`, and `API_BASE_URL` can override the stored credentials if set.
|
|
141
142
|
|
|
142
143
|
## How It Works
|
|
143
144
|
|
|
144
|
-
1. **Schema Fetching**: On startup, the server fetches your personalized OpenAPI schema from
|
|
145
|
+
1. **Schema Fetching**: On startup, the server fetches your personalized OpenAPI schema from `schema.secondbrainos.com`
|
|
145
146
|
2. **Schema Conversion**: The `@samchon/openapi` library converts the schema to an optimized format for LLM function calling
|
|
146
147
|
3. **MCP Tools**: Each API endpoint becomes an MCP tool that Claude can use
|
|
147
|
-
4. **MCP Prompts**:
|
|
148
|
-
5. **
|
|
148
|
+
4. **MCP Prompts**: On first `ListPrompts` call (automatic on session connect), the server fetches all agents via `getAIAgentsSchema` and all workflows via `runPromptChain`, caches them in memory, and exposes them as slash commands
|
|
149
|
+
5. **Slash Commands**: When a user runs a slash command (e.g. `/secondbrainos:agent_my_agent`), the server returns the full agent/skill definition from cache — no additional API calls, no credit cost
|
|
150
|
+
6. **Function Execution**: When Claude calls a tool, the server executes the corresponding API call via `api.secondbrainos.com` with proper authentication
|
|
151
|
+
7. **File Upload**: Local file paths in tool arguments are automatically uploaded to GCS via signed URL before the API call
|
|
152
|
+
|
|
153
|
+
### Credit Cost
|
|
154
|
+
|
|
155
|
+
| Event | Credits |
|
|
156
|
+
|-------|---------|
|
|
157
|
+
| Session init | n workflows + n agents |
|
|
158
|
+
| Slash commands | 0 (cached) |
|
|
159
|
+
| Tool calls | Billed per call via service router |
|
|
160
|
+
|
|
161
|
+
See [`docs/architecture.md`](docs/architecture.md) for detailed diagrams.
|
|
149
162
|
|
|
150
163
|
## Troubleshooting
|
|
151
164
|
|
package/bin/cli.js
CHANGED
|
@@ -332,13 +332,12 @@ async function main() {
|
|
|
332
332
|
const hadExistingSecondBrainOS = !!existingConfig.mcpServers.secondbrainos;
|
|
333
333
|
|
|
334
334
|
// Add or update the secondbrainos server configuration
|
|
335
|
+
// Uses serve mode which reads credentials from ~/.secondbrainos/credentials.json
|
|
336
|
+
const cliPath = path.join(packageRoot, 'bin', 'cli.js');
|
|
335
337
|
existingConfig.mcpServers.secondbrainos = {
|
|
336
338
|
command: nodePath,
|
|
337
|
-
args: [
|
|
339
|
+
args: [cliPath, 'serve'],
|
|
338
340
|
env: {
|
|
339
|
-
USER_ID,
|
|
340
|
-
USER_SECRET,
|
|
341
|
-
API_BASE_URL: 'https://api.secondbrainos.com',
|
|
342
341
|
NODE_PATH: getNodeModulesPath()
|
|
343
342
|
}
|
|
344
343
|
};
|
|
@@ -362,42 +361,6 @@ async function main() {
|
|
|
362
361
|
const cliPath = path.join(packageRoot, 'bin', 'cli.js');
|
|
363
362
|
const claudeCodeConfigured = await configureClaudeCode(cliPath, nodePath);
|
|
364
363
|
|
|
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
364
|
console.log('\nInstallation successful!');
|
|
402
365
|
console.log('\nClaude Desktop:');
|
|
403
366
|
console.log('1. Completely quit Claude Desktop if it is running');
|
package/build/index.js
CHANGED
|
@@ -5,9 +5,8 @@ import { OpenApi, HttpLlm } from "@samchon/openapi";
|
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
import dotenv from "dotenv";
|
|
7
7
|
import yaml from 'js-yaml';
|
|
8
|
-
import fs from 'fs';
|
|
9
8
|
import path from 'path';
|
|
10
|
-
import
|
|
9
|
+
import fs from 'fs';
|
|
11
10
|
dotenv.config();
|
|
12
11
|
function toSnakeCase(str) {
|
|
13
12
|
return str
|
|
@@ -15,12 +14,6 @@ function toSnakeCase(str) {
|
|
|
15
14
|
.replace(/[^a-z0-9]+/g, '_')
|
|
16
15
|
.replace(/^_+|_+$/g, '');
|
|
17
16
|
}
|
|
18
|
-
function toKebabCase(str) {
|
|
19
|
-
return str
|
|
20
|
-
.toLowerCase()
|
|
21
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
22
|
-
.replace(/^-+|-+$/g, '');
|
|
23
|
-
}
|
|
24
17
|
class SecondBrainOSServer {
|
|
25
18
|
constructor(initialSchema) {
|
|
26
19
|
this.originalSpec = initialSchema;
|
|
@@ -80,7 +73,7 @@ class SecondBrainOSServer {
|
|
|
80
73
|
tools: {},
|
|
81
74
|
prompts: {}
|
|
82
75
|
},
|
|
83
|
-
instructions: "SBOS provides tools for managing knowledge along with definitions for sub-agents and associated skills.
|
|
76
|
+
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
77
|
});
|
|
85
78
|
this.setupHandlers();
|
|
86
79
|
this.setupErrorHandling();
|
|
@@ -253,6 +246,13 @@ class SecondBrainOSServer {
|
|
|
253
246
|
console.error('Failed to fetch agents for prompts/list:', error);
|
|
254
247
|
}
|
|
255
248
|
}
|
|
249
|
+
// Add start_secondbrainos prompt — returns the server-use context document
|
|
250
|
+
prompts.push({
|
|
251
|
+
name: "start_secondbrainos",
|
|
252
|
+
title: "[Start] Second Brain OS",
|
|
253
|
+
description: "Load SBOS context: terminology, architecture, and available agents & skills index",
|
|
254
|
+
arguments: []
|
|
255
|
+
});
|
|
256
256
|
// Add Knowledge Bases prompt (collects searchMyKnowledge_collection_ids from agents)
|
|
257
257
|
if (this.getAIAgentsSchemaPath) {
|
|
258
258
|
try {
|
|
@@ -285,6 +285,22 @@ class SecondBrainOSServer {
|
|
|
285
285
|
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
286
286
|
const promptName = request.params.name;
|
|
287
287
|
const userInput = request.params.arguments?.user_input;
|
|
288
|
+
// Check if this is the start_secondbrainos prompt
|
|
289
|
+
if (promptName === "start_secondbrainos") {
|
|
290
|
+
const content = await this.buildServerUseContent();
|
|
291
|
+
return {
|
|
292
|
+
description: "Second Brain OS — Server Context",
|
|
293
|
+
messages: [
|
|
294
|
+
{
|
|
295
|
+
role: "user",
|
|
296
|
+
content: {
|
|
297
|
+
type: "text",
|
|
298
|
+
text: content
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
};
|
|
303
|
+
}
|
|
288
304
|
// Check if this is the Knowledge Bases prompt
|
|
289
305
|
if (promptName === "knowledge_bases") {
|
|
290
306
|
const agents = await this.fetchAndEnrichAgents();
|
|
@@ -322,23 +338,14 @@ class SecondBrainOSServer {
|
|
|
322
338
|
if (agentId) {
|
|
323
339
|
return this.buildAgentPrompt(agentId, userInput);
|
|
324
340
|
}
|
|
325
|
-
// Otherwise treat as a workflow prompt
|
|
341
|
+
// Otherwise treat as a workflow prompt — use cached data
|
|
326
342
|
const workflowId = this.workflowNameToId.get(promptName) || promptName;
|
|
327
|
-
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
const prompts = workflowMeta?.prompts || [];
|
|
331
|
-
if (prompts.length === 0) {
|
|
343
|
+
const workflows = await this.fetchAndEnrichWorkflows();
|
|
344
|
+
const workflowMeta = workflows.find((wf) => wf.workflow_id === workflowId);
|
|
345
|
+
if (!workflowMeta || !workflowMeta.prompts || workflowMeta.prompts.length === 0) {
|
|
332
346
|
throw new McpError(ErrorCode.InvalidRequest, `No prompts found for workflow: ${workflowId}`);
|
|
333
347
|
}
|
|
334
|
-
const sortedPrompts = prompts
|
|
335
|
-
.map((p) => ({
|
|
336
|
-
id: p.prompt_id,
|
|
337
|
-
name: p.name || '',
|
|
338
|
-
order: p.order || 0,
|
|
339
|
-
description: p.description || ''
|
|
340
|
-
}))
|
|
341
|
-
.sort((a, b) => (a.order || 0) - (b.order || 0));
|
|
348
|
+
const sortedPrompts = workflowMeta.prompts;
|
|
342
349
|
const workflowDocument = {
|
|
343
350
|
skill_id: workflowId,
|
|
344
351
|
name: workflowMeta?.name || promptName,
|
|
@@ -418,15 +425,12 @@ class SecondBrainOSServer {
|
|
|
418
425
|
messages
|
|
419
426
|
};
|
|
420
427
|
}
|
|
421
|
-
async callRunPromptChain(
|
|
428
|
+
async callRunPromptChain() {
|
|
422
429
|
if (!this.runPromptChainPath) {
|
|
423
430
|
throw new McpError(ErrorCode.InternalError, 'runPromptChain service not available for this user');
|
|
424
431
|
}
|
|
425
432
|
const url = `${this.baseUrl}${this.runPromptChainPath}`;
|
|
426
|
-
const response = await axios.post(url, {
|
|
427
|
-
entity,
|
|
428
|
-
entity_id: entityId
|
|
429
|
-
}, {
|
|
433
|
+
const response = await axios.post(url, {}, {
|
|
430
434
|
headers: {
|
|
431
435
|
'Authorization': `Bearer ${this.userId}:${this.userSecret}`,
|
|
432
436
|
'Content-Type': 'application/json'
|
|
@@ -523,20 +527,10 @@ class SecondBrainOSServer {
|
|
|
523
527
|
async fetchAndEnrichAgents() {
|
|
524
528
|
if (this.cachedAgents)
|
|
525
529
|
return this.cachedAgents;
|
|
526
|
-
//
|
|
527
|
-
const
|
|
528
|
-
this.callGetAIAgentsSchema(),
|
|
529
|
-
this.fetchAndEnrichWorkflows()
|
|
530
|
-
]);
|
|
530
|
+
// Single API call — getAIAgentsSchema now returns prompt order/description
|
|
531
|
+
const agentData = await this.callGetAIAgentsSchema();
|
|
531
532
|
const agents = agentData.agents || [];
|
|
532
|
-
//
|
|
533
|
-
const promptLookup = new Map();
|
|
534
|
-
for (const wf of workflows) {
|
|
535
|
-
for (const p of wf.prompts || []) {
|
|
536
|
-
promptLookup.set(p.id, p);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
// Enrich agent workflows using the lookup — no extra API calls
|
|
533
|
+
// Sort prompts within each workflow by order
|
|
540
534
|
for (const agent of agents) {
|
|
541
535
|
if (!agent.workflows)
|
|
542
536
|
continue;
|
|
@@ -544,16 +538,13 @@ class SecondBrainOSServer {
|
|
|
544
538
|
if (!workflow.prompts || workflow.prompts.length === 0)
|
|
545
539
|
continue;
|
|
546
540
|
workflow.prompts = workflow.prompts
|
|
547
|
-
.map((prompt) => {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
};
|
|
555
|
-
})
|
|
556
|
-
.sort((a, b) => (a.order || 0) - (b.order || 0));
|
|
541
|
+
.map((prompt) => ({
|
|
542
|
+
id: prompt.id,
|
|
543
|
+
name: prompt.name || '',
|
|
544
|
+
order: prompt.order || 0,
|
|
545
|
+
description: prompt.description || ''
|
|
546
|
+
}))
|
|
547
|
+
.sort((a, b) => (Number(a.order) || 0) - (Number(b.order) || 0));
|
|
557
548
|
}
|
|
558
549
|
}
|
|
559
550
|
this.cachedAgents = agents;
|
|
@@ -563,7 +554,7 @@ class SecondBrainOSServer {
|
|
|
563
554
|
if (this.cachedWorkflows)
|
|
564
555
|
return this.cachedWorkflows;
|
|
565
556
|
// Single API call — now returns all workflows with prompt metadata
|
|
566
|
-
const data = await this.callRunPromptChain(
|
|
557
|
+
const data = await this.callRunPromptChain();
|
|
567
558
|
const workflows = (data.workflows || []).filter((wf) => wf.name && wf.workflow_id);
|
|
568
559
|
const enriched = workflows.map((wf) => ({
|
|
569
560
|
...wf,
|
|
@@ -580,25 +571,17 @@ class SecondBrainOSServer {
|
|
|
580
571
|
return enriched;
|
|
581
572
|
}
|
|
582
573
|
/**
|
|
583
|
-
*
|
|
584
|
-
*
|
|
574
|
+
* Build the server-use context document content.
|
|
575
|
+
* Used by the start_secondbrainos prompt.
|
|
585
576
|
*/
|
|
586
|
-
async
|
|
587
|
-
const skillsBase = path.join(homedir(), '.claude', 'skills', 'secondbrainos');
|
|
588
|
-
// Helper to write a SKILL.md file
|
|
589
|
-
const writeSkill = (dir, content) => {
|
|
590
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
591
|
-
fs.writeFileSync(path.join(dir, 'SKILL.md'), content, 'utf-8');
|
|
592
|
-
};
|
|
593
|
-
// 1. server-use — context document for Claude Code sessions
|
|
594
|
-
// Gather agent and workflow names for the index
|
|
577
|
+
async buildServerUseContent() {
|
|
595
578
|
let agentIndex = '';
|
|
596
579
|
let skillIndex = '';
|
|
597
580
|
try {
|
|
598
581
|
const agents = await this.fetchAndEnrichAgents();
|
|
599
582
|
agentIndex = agents
|
|
600
583
|
.filter((a) => a.name && a.id)
|
|
601
|
-
.map((a) => `- ${a.name} → \`/secondbrainos:agent_${toSnakeCase(a.name)}
|
|
584
|
+
.map((a) => `- ${a.name} (id: ${a.id}) → \`/secondbrainos:agent_${toSnakeCase(a.name)}\`${a.description ? `\n ${a.description}` : ''}`)
|
|
602
585
|
.join('\n');
|
|
603
586
|
}
|
|
604
587
|
catch { /* skip if unavailable */ }
|
|
@@ -606,11 +589,11 @@ class SecondBrainOSServer {
|
|
|
606
589
|
const workflows = await this.fetchAndEnrichWorkflows();
|
|
607
590
|
skillIndex = workflows
|
|
608
591
|
.filter((wf) => wf.name)
|
|
609
|
-
.map((wf) => `- ${wf.name} → \`/secondbrainos:skill_${toSnakeCase(wf.name)}
|
|
592
|
+
.map((wf) => `- ${wf.name} (id: ${wf.workflow_id}) → \`/secondbrainos:skill_${toSnakeCase(wf.name)}\`${wf.description ? `\n ${wf.description}` : ''}`)
|
|
610
593
|
.join('\n');
|
|
611
594
|
}
|
|
612
595
|
catch { /* skip if unavailable */ }
|
|
613
|
-
|
|
596
|
+
return `---
|
|
614
597
|
name: server-use
|
|
615
598
|
description: Second Brain OS server context — terminology, architecture, and available agents/skills index
|
|
616
599
|
user-invocable: false
|
|
@@ -630,14 +613,13 @@ An agent definition combines:
|
|
|
630
613
|
2. **Services (Tools)** — the MCP tools the agent can use
|
|
631
614
|
3. **Workflows (Skills)** — the prompt chains the agent follows
|
|
632
615
|
|
|
633
|
-
|
|
616
|
+
## Loading Agent & Skill Details
|
|
617
|
+
- To get full agent definitions (behaviour, knowledge, actions, workflows): use the \`getAIAgentsSchema\` tool
|
|
618
|
+
- To get full skill/workflow details and run prompt chains: use the \`runPromptChain\` tool
|
|
634
619
|
|
|
635
620
|
## 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
621
|
- **Users** invoke agents or skills via slash commands (e.g. \`/secondbrainos:agent_...\` or \`/secondbrainos:skill_...\`)
|
|
639
622
|
- **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
623
|
|
|
642
624
|
## Available Agents
|
|
643
625
|
${agentIndex || '_None configured_'}
|
|
@@ -645,85 +627,12 @@ ${agentIndex || '_None configured_'}
|
|
|
645
627
|
## Available Skills
|
|
646
628
|
${skillIndex || '_None configured_'}
|
|
647
629
|
`;
|
|
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
630
|
}
|
|
719
631
|
setupErrorHandling() {
|
|
720
632
|
// Error handling is now built into HttpLlm.execute
|
|
721
633
|
// This method is kept for future error handling implementations
|
|
722
634
|
}
|
|
723
635
|
async run() {
|
|
724
|
-
// Write skill files before connecting so Claude Code sees them at session start.
|
|
725
|
-
// This is fast now (~2-3s) since enrichment uses single API calls.
|
|
726
|
-
await this.writeSkillFiles().catch(err => console.error('Failed to write skill files:', err));
|
|
727
636
|
const transport = new StdioServerTransport();
|
|
728
637
|
await this.server.connect(transport);
|
|
729
638
|
console.error("Second Brain OS MCP server running on stdio");
|