secondbrainos-mcp-server 1.6.0 → 1.7.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/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. Create the necessary configuration files for Claude Desktop
29
- 4. Configure the server to dynamically fetch your available API endpoints
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 three types of MCP prompts, available in the client's attach menu:
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
- - Automatically discovers your workflows via the `runPromptChain` service
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
- - Discovers your AI agents via the `getAIAgentsSchema` service
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 enriched prompt metadata)
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
- ## Environment Variables
139
+ ## Credentials
136
140
 
137
- The server requires the following environment variables:
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 Second Brain OS
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**: Your skills (workflows), AI agents, and knowledge bases are exposed as selectable prompts in the client UI
148
- 5. **Function Execution**: When Claude calls a tool, the server executes the corresponding API call with proper authentication
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: [serverPath],
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
  };
@@ -359,7 +358,6 @@ async function main() {
359
358
  }
360
359
 
361
360
  // Configure Claude Code
362
- const cliPath = path.join(packageRoot, 'bin', 'cli.js');
363
361
  const claudeCodeConfigured = await configureClaudeCode(cliPath, nodePath);
364
362
 
365
363
  console.log('\nInstallation successful!');
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 { homedir } from 'os';
9
+ import fs from 'fs';
11
10
  dotenv.config();
12
11
  function toSnakeCase(str) {
13
12
  return str
@@ -339,23 +338,14 @@ class SecondBrainOSServer {
339
338
  if (agentId) {
340
339
  return this.buildAgentPrompt(agentId, userInput);
341
340
  }
342
- // Otherwise treat as a workflow prompt
341
+ // Otherwise treat as a workflow prompt — use cached data
343
342
  const workflowId = this.workflowNameToId.get(promptName) || promptName;
344
- // Single call list response now includes prompt metadata per workflow
345
- const workflowsData = await this.callRunPromptChain('', '');
346
- const workflowMeta = (workflowsData.workflows || []).find((wf) => wf.workflow_id === workflowId);
347
- const prompts = workflowMeta?.prompts || [];
348
- 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) {
349
346
  throw new McpError(ErrorCode.InvalidRequest, `No prompts found for workflow: ${workflowId}`);
350
347
  }
351
- const sortedPrompts = prompts
352
- .map((p) => ({
353
- id: p.prompt_id,
354
- name: p.name || '',
355
- order: p.order || 0,
356
- description: p.description || ''
357
- }))
358
- .sort((a, b) => (a.order || 0) - (b.order || 0));
348
+ const sortedPrompts = workflowMeta.prompts;
359
349
  const workflowDocument = {
360
350
  skill_id: workflowId,
361
351
  name: workflowMeta?.name || promptName,
@@ -435,15 +425,12 @@ class SecondBrainOSServer {
435
425
  messages
436
426
  };
437
427
  }
438
- async callRunPromptChain(entity, entityId) {
428
+ async callRunPromptChain() {
439
429
  if (!this.runPromptChainPath) {
440
430
  throw new McpError(ErrorCode.InternalError, 'runPromptChain service not available for this user');
441
431
  }
442
432
  const url = `${this.baseUrl}${this.runPromptChainPath}`;
443
- const response = await axios.post(url, {
444
- entity,
445
- entity_id: entityId
446
- }, {
433
+ const response = await axios.post(url, {}, {
447
434
  headers: {
448
435
  'Authorization': `Bearer ${this.userId}:${this.userSecret}`,
449
436
  'Content-Type': 'application/json'
@@ -540,20 +527,10 @@ class SecondBrainOSServer {
540
527
  async fetchAndEnrichAgents() {
541
528
  if (this.cachedAgents)
542
529
  return this.cachedAgents;
543
- // Fetch agents and all workflows in parallel
544
- const [agentData, workflows] = await Promise.all([
545
- this.callGetAIAgentsSchema(),
546
- this.fetchAndEnrichWorkflows()
547
- ]);
530
+ // Single API call getAIAgentsSchema now returns prompt order/description
531
+ const agentData = await this.callGetAIAgentsSchema();
548
532
  const agents = agentData.agents || [];
549
- // Build a prompt lookup from the already-fetched workflows
550
- const promptLookup = new Map();
551
- for (const wf of workflows) {
552
- for (const p of wf.prompts || []) {
553
- promptLookup.set(p.id, p);
554
- }
555
- }
556
- // Enrich agent workflows using the lookup — no extra API calls
533
+ // Sort prompts within each workflow by order
557
534
  for (const agent of agents) {
558
535
  if (!agent.workflows)
559
536
  continue;
@@ -561,16 +538,13 @@ class SecondBrainOSServer {
561
538
  if (!workflow.prompts || workflow.prompts.length === 0)
562
539
  continue;
563
540
  workflow.prompts = workflow.prompts
564
- .map((prompt) => {
565
- const enriched = promptLookup.get(prompt.id);
566
- return {
567
- id: prompt.id,
568
- name: enriched?.name || prompt.name,
569
- order: enriched?.order || 0,
570
- description: enriched?.description || ''
571
- };
572
- })
573
- .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));
574
548
  }
575
549
  }
576
550
  this.cachedAgents = agents;
@@ -580,7 +554,7 @@ class SecondBrainOSServer {
580
554
  if (this.cachedWorkflows)
581
555
  return this.cachedWorkflows;
582
556
  // Single API call — now returns all workflows with prompt metadata
583
- const data = await this.callRunPromptChain('', '');
557
+ const data = await this.callRunPromptChain();
584
558
  const workflows = (data.workflows || []).filter((wf) => wf.name && wf.workflow_id);
585
559
  const enriched = workflows.map((wf) => ({
586
560
  ...wf,
@@ -596,20 +570,9 @@ class SecondBrainOSServer {
596
570
  this.cachedWorkflows = enriched;
597
571
  return enriched;
598
572
  }
599
- /**
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.
602
- */
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
573
  /**
611
574
  * Build the server-use context document content.
612
- * Used by both writeServerUseSkillFile and the start_secondbrainos prompt.
575
+ * Used by the start_secondbrainos prompt.
613
576
  */
614
577
  async buildServerUseContent() {
615
578
  let agentIndex = '';
@@ -670,8 +633,6 @@ ${skillIndex || '_None configured_'}
670
633
  // This method is kept for future error handling implementations
671
634
  }
672
635
  async run() {
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));
675
636
  const transport = new StdioServerTransport();
676
637
  await this.server.connect(transport);
677
638
  console.error("Second Brain OS MCP server running on stdio");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secondbrainos-mcp-server",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "Second Brain OS MCP Server for Claude Desktop",
5
5
  "type": "module",
6
6
  "main": "build/index.js",