secondbrainos-mcp-server 1.0.3 → 1.0.5

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
@@ -28,25 +28,122 @@ This will:
28
28
  3. Create the necessary configuration files for Claude Desktop
29
29
  4. Configure the server to dynamically fetch your available API endpoints
30
30
 
31
- ### After Installation
31
+ ## Features
32
32
 
33
- 1. Completely quit Claude Desktop if it is running
34
- 2. Restart Claude Desktop
35
- 3. Look for the Second Brain OS server in the 🔌 plugins menu
33
+ ### Enhanced OpenAPI Support
34
+ The server uses `@samchon/openapi` library for robust OpenAPI handling, providing:
35
+ - Support for all OpenAPI/Swagger versions (v2.0, v3.0, v3.1)
36
+ - Automatic schema conversion to a standardized format
37
+ - Better handling of complex schemas including references, nullable properties, and union types
36
38
 
37
- ## Troubleshooting
39
+ ### Improved Function Execution
40
+ - Type-safe function execution with built-in error handling
41
+ - Automatic request formatting based on OpenAPI specifications
42
+ - Support for complex parameters and nested objects
43
+
44
+ ### Better Error Handling
45
+ - Detailed error messages for debugging
46
+ - Proper handling of authentication failures, bad requests, and service errors
47
+ - Graceful fallback for unexpected errors
48
+
49
+ ## Development
50
+
51
+ ### Setup
52
+
53
+ 1. Clone the repository:
54
+ ```bash
55
+ git clone https://github.com/your-username/secondbrainos-mcp-server.git
56
+ cd secondbrainos-mcp-server
57
+ ```
58
+
59
+ 2. Install dependencies:
60
+ ```bash
61
+ npm install
62
+ ```
63
+
64
+ 3. Create a `.env` file from the example:
65
+ ```bash
66
+ cp .env.example .env
67
+ # Edit .env with your actual USER_ID and USER_SECRET
68
+ ```
69
+
70
+ ### Testing the Schema Conversion
38
71
 
39
- If you encounter issues, check the Claude Desktop logs:
72
+ To see how your OpenAPI schema is converted to MCP tools:
40
73
 
41
74
  ```bash
42
- tail -f ~/Library/Logs/Claude/mcp*.log
75
+ npm run test-conversion
76
+ ```
77
+
78
+ This will:
79
+ - Fetch your OpenAPI schema from Second Brain OS
80
+ - Convert it to LLM function calling format
81
+ - Display all available functions and their schemas
82
+ - Show any conversion errors
83
+ - Demonstrate the MCP tool format
84
+
85
+ ### Development Scripts
86
+
87
+ - `npm run build` - Compile TypeScript to JavaScript
88
+ - `npm run dev` - Run the MCP server in development mode
89
+ - `npm run test-conversion` - Test the OpenAPI to MCP conversion
90
+ - `npm start` - Run the compiled server
91
+
92
+ ### Project Structure
93
+
94
+ ```
95
+ secondbrainos-mcp-server/
96
+ ├── src/
97
+ │ ├── index.ts # Main MCP server implementation
98
+ │ └── test-conversion.ts # Schema conversion testing utility
99
+ ├── build/ # Compiled JavaScript (git-ignored)
100
+ ├── bin/
101
+ │ └── cli.js # CLI setup script
102
+ ├── .env.example # Environment variables template
103
+ ├── package.json # Package configuration
104
+ ├── tsconfig.json # TypeScript configuration
105
+ └── README.md # This file
43
106
  ```
44
107
 
45
- Common issues:
46
- - Make sure Node.js is properly installed
108
+ ## Environment Variables
109
+
110
+ The server requires the following environment variables:
111
+ - `USER_ID`: Your Second Brain OS user ID
112
+ - `USER_SECRET`: Your Second Brain OS user secret
113
+ - `API_BASE_URL` (optional): Override the default API base URL
114
+
115
+ ## How It Works
116
+
117
+ 1. **Schema Fetching**: On startup, the server fetches your personalized OpenAPI schema from Second Brain OS
118
+ 2. **Schema Conversion**: The `@samchon/openapi` library converts the schema to an optimized format for LLM function calling
119
+ 3. **MCP Tools**: Each API endpoint becomes an MCP tool that Claude can use
120
+ 4. **Function Execution**: When Claude calls a tool, the server executes the corresponding API call with proper authentication
121
+
122
+ ## Troubleshooting
123
+
124
+ ### Claude Desktop doesn't see the server
125
+ 1. Ensure Claude Desktop is completely quit before running the setup
126
+ 2. Check the configuration file was created at the correct location
127
+ 3. Review the logs at the platform-specific location mentioned during setup
128
+
129
+ ### Authentication errors
47
130
  - Verify your USER_ID and USER_SECRET are correct
48
- - Ensure you have the Claude MCP feature enabled in your account
131
+ - Ensure your account has the Claude MCP feature enabled
132
+ - Check that your credentials haven't expired
133
+
134
+ ### Schema conversion errors
135
+ - Run `npm run test-conversion` to see detailed error messages
136
+ - Some complex OpenAPI features may not be supported by LLM function calling
137
+ - Check the console output for specific endpoints that failed conversion
138
+
139
+ ## Contributing
140
+
141
+ 1. Fork the repository
142
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
143
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
144
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
145
+ 5. Open a Pull Request
49
146
 
50
- ## Support
147
+ ## License
51
148
 
52
- If you continue to experience problems, please contact support at support@secondbrainos.com
149
+ MIT
package/bin/cli.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import axios from 'axios';
4
4
  import { promises as fs } from 'fs';
5
+ import * as fsSync from 'fs'; // Add this line to import the synchronous fs functions
5
6
  import path from 'path';
6
7
  import { fileURLToPath } from 'url';
7
8
  import { homedir } from 'os';
@@ -104,7 +105,7 @@ function getNodeModulesPath() {
104
105
  return path.join(prefix, 'npm', 'node_modules');
105
106
  } else if (platform === 'darwin' || platform === 'linux') {
106
107
  // Check if it's a homebrew installation on Mac
107
- if (platform === 'darwin' && fs.existsSync('/opt/homebrew/lib/node_modules')) {
108
+ if (platform === 'darwin' && fsSync.existsSync('/opt/homebrew/lib/node_modules')) {
108
109
  return '/opt/homebrew/lib/node_modules';
109
110
  }
110
111
  // Default Unix-like path
package/build/index.js CHANGED
@@ -1,20 +1,27 @@
1
1
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
3
  import { ListResourcesRequestSchema, ReadResourceRequestSchema, ListToolsRequestSchema, CallToolRequestSchema, ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
4
+ import { OpenApi, HttpLlm } from "@samchon/openapi";
4
5
  import axios from "axios";
5
6
  import dotenv from "dotenv";
6
7
  import yaml from 'js-yaml';
7
8
  dotenv.config();
8
9
  class SecondBrainOSServer {
9
10
  constructor(initialSchema) {
10
- // Initialize with provided schema instead of URL
11
- this.apiSpec = initialSchema;
11
+ this.originalSpec = initialSchema;
12
12
  this.baseUrl = process.env.API_BASE_URL || 'https://api.secondbrainos.com';
13
13
  this.userId = process.env.USER_ID || '';
14
14
  this.userSecret = process.env.USER_SECRET || '';
15
15
  if (!this.userId || !this.userSecret) {
16
16
  throw new Error("USER_ID and USER_SECRET environment variables are required");
17
17
  }
18
+ // Convert OpenAPI schema using @samchon/openapi
19
+ const document = OpenApi.convert(initialSchema);
20
+ // Create LLM application with proper model configuration
21
+ this.application = HttpLlm.application({
22
+ model: "chatgpt",
23
+ document
24
+ });
18
25
  this.server = new Server({
19
26
  name: "secondbrainos-server",
20
27
  version: "1.0.0"
@@ -27,24 +34,6 @@ class SecondBrainOSServer {
27
34
  this.setupHandlers();
28
35
  this.setupErrorHandling();
29
36
  }
30
- // Helper method to extract functions from the API spec
31
- getFunctions() {
32
- const functions = [];
33
- for (const [path, pathItem] of Object.entries(this.apiSpec.paths)) {
34
- for (const [method, operation] of Object.entries(pathItem)) {
35
- if (operation.operationId) {
36
- functions.push({
37
- operationId: operation.operationId,
38
- path,
39
- method: method.toUpperCase(),
40
- summary: operation.summary || operation.operationId,
41
- schema: operation.requestBody?.content?.['application/json']?.schema || {}
42
- });
43
- }
44
- }
45
- }
46
- return functions;
47
- }
48
37
  setupHandlers() {
49
38
  // List available resources
50
39
  this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
@@ -53,7 +42,7 @@ class SecondBrainOSServer {
53
42
  uri: 'secondbrainos://api/spec',
54
43
  name: 'Second Brain OS API Specification',
55
44
  mimeType: 'application/yaml',
56
- description: this.apiSpec?.info?.title || 'API Specification'
45
+ description: this.originalSpec?.info?.title || 'API Specification'
57
46
  }]
58
47
  };
59
48
  });
@@ -66,47 +55,48 @@ class SecondBrainOSServer {
66
55
  contents: [{
67
56
  uri: request.params.uri,
68
57
  mimeType: 'application/yaml',
69
- text: yaml.dump(this.apiSpec)
58
+ text: yaml.dump(this.originalSpec)
70
59
  }]
71
60
  };
72
61
  });
73
- // List available tools
62
+ // List available tools - now using @samchon/openapi functions
74
63
  this.server.setRequestHandler(ListToolsRequestSchema, async () => {
75
- const functions = this.getFunctions();
76
64
  return {
77
- tools: functions.map(func => ({
78
- name: func.operationId,
79
- description: func.summary,
80
- inputSchema: func.schema
65
+ tools: this.application.functions.map(func => ({
66
+ name: func.name,
67
+ description: func.description || func.name,
68
+ inputSchema: func.parameters // Convert to MCP format
81
69
  }))
82
70
  };
83
71
  });
84
72
  // Handle tool calls
85
73
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
86
- const functions = this.getFunctions();
87
- const func = functions.find(f => f.operationId === request.params.name);
74
+ const func = this.application.functions.find(f => f.name === request.params.name);
88
75
  if (!func) {
89
76
  throw new McpError(ErrorCode.MethodNotFound, `Unknown function: ${request.params.name}`);
90
77
  }
91
78
  try {
92
- const bearerToken = `${this.userId}:${this.userSecret}`;
93
- const response = await axios({
94
- method: func.method,
95
- url: `${this.baseUrl}${func.path}`,
96
- data: request.params.arguments,
97
- headers: {
98
- 'Content-Type': 'application/json',
99
- 'Authorization': `Bearer ${bearerToken}`
100
- }
79
+ // Use HttpLlm.execute for better error handling and type safety
80
+ const result = await HttpLlm.execute({
81
+ connection: {
82
+ host: this.baseUrl,
83
+ headers: {
84
+ 'Authorization': `Bearer ${this.userId}:${this.userSecret}`
85
+ }
86
+ },
87
+ application: this.application, // Type assertion to avoid generic issues
88
+ function: func,
89
+ input: request.params.arguments || {}
101
90
  });
102
91
  return {
103
92
  content: [{
104
93
  type: 'text',
105
- text: JSON.stringify(response.data, null, 2)
94
+ text: JSON.stringify(result, null, 2)
106
95
  }]
107
96
  };
108
97
  }
109
98
  catch (error) {
99
+ // Better error handling with HttpLlm
110
100
  if (axios.isAxiosError(error)) {
111
101
  const status = error.response?.status;
112
102
  const errorMessage = error.response?.data?.error || error.message;
@@ -135,12 +125,21 @@ class SecondBrainOSServer {
135
125
  isError: true
136
126
  };
137
127
  }
128
+ else if (error instanceof Error) {
129
+ return {
130
+ content: [{
131
+ type: 'text',
132
+ text: `Error calling function: ${error.message}`
133
+ }],
134
+ isError: true
135
+ };
136
+ }
138
137
  throw error;
139
138
  }
140
139
  });
141
140
  }
142
141
  setupErrorHandling() {
143
- // Add any error handling setup here
142
+ // Error handling is now built into HttpLlm.execute
144
143
  // This method is kept for future error handling implementations
145
144
  }
146
145
  async run() {
@@ -0,0 +1,81 @@
1
+ import { OpenApi, HttpLlm } from "@samchon/openapi";
2
+ import axios from "axios";
3
+ import dotenv from "dotenv";
4
+ dotenv.config();
5
+ async function testSchemaConversion() {
6
+ const userId = process.env.USER_ID;
7
+ const userSecret = process.env.USER_SECRET;
8
+ if (!userId || !userSecret) {
9
+ console.error("❌ USER_ID and USER_SECRET environment variables are required");
10
+ console.error("Create a .env file with:");
11
+ console.error("USER_ID=your_user_id");
12
+ console.error("USER_SECRET=your_user_secret");
13
+ process.exit(1);
14
+ }
15
+ console.log("🔄 Fetching OpenAPI schema from Second Brain OS...");
16
+ try {
17
+ // Fetch the schema
18
+ const response = await axios.post('https://us-central1-second-brain-os.cloudfunctions.net/generate-open-api-schema', { user_id: userId }, {
19
+ headers: {
20
+ 'Content-Type': 'application/json'
21
+ }
22
+ });
23
+ const openApiSchema = response.data;
24
+ console.log("✅ Schema fetched successfully!");
25
+ console.log(`📋 API Title: ${openApiSchema.info?.title || 'Unknown'}`);
26
+ console.log(`📋 API Version: ${openApiSchema.info?.version || 'Unknown'}`);
27
+ // Convert to emended OpenAPI document
28
+ console.log("\n🔄 Converting to emended OpenAPI format...");
29
+ const document = OpenApi.convert(openApiSchema);
30
+ console.log("✅ Conversion successful!");
31
+ // Create LLM application
32
+ console.log("\n🔄 Creating LLM function calling application...");
33
+ const application = HttpLlm.application({
34
+ model: "chatgpt",
35
+ document
36
+ });
37
+ console.log("✅ LLM application created!");
38
+ // Display the converted functions
39
+ console.log(`\n📊 Total functions available: ${application.functions.length}`);
40
+ console.log(`⚠️ Errors during conversion: ${application.errors.length}`);
41
+ if (application.errors.length > 0) {
42
+ console.log("\n❌ Conversion errors:");
43
+ application.errors.forEach((error, index) => {
44
+ console.log(` ${index + 1}. ${error.method.toUpperCase()} ${error.path}`);
45
+ error.messages.forEach(msg => console.log(` - ${msg}`));
46
+ });
47
+ }
48
+ console.log("\n🔧 Available MCP Tools:");
49
+ console.log("=".repeat(80));
50
+ application.functions.slice(0, 10).forEach((func, index) => {
51
+ console.log(`\n${index + 1}. ${func.name}`);
52
+ console.log(` Method: ${func.method.toUpperCase()}`);
53
+ console.log(` Path: ${func.path}`);
54
+ console.log(` Description: ${func.description?.split('\n')[0] || 'No description'}`);
55
+ console.log(` Parameters Schema: ${JSON.stringify(func.parameters).substring(0, 100)}...`);
56
+ });
57
+ if (application.functions.length > 10) {
58
+ console.log(`\n... and ${application.functions.length - 10} more functions`);
59
+ }
60
+ // Show a sample of how it would look as MCP tools
61
+ console.log("\n\n🎯 Sample MCP Tool Format:");
62
+ console.log("=".repeat(80));
63
+ const sampleFunc = application.functions[0];
64
+ if (sampleFunc) {
65
+ const mcpTool = {
66
+ name: sampleFunc.name,
67
+ description: sampleFunc.description || sampleFunc.name,
68
+ inputSchema: sampleFunc.parameters
69
+ };
70
+ console.log(JSON.stringify(mcpTool, null, 2));
71
+ }
72
+ }
73
+ catch (error) {
74
+ console.error("❌ Error:", error instanceof Error ? error.message : error);
75
+ if (axios.isAxiosError(error) && error.response) {
76
+ console.error("Response data:", error.response.data);
77
+ }
78
+ }
79
+ }
80
+ // Run the test
81
+ testSchemaConversion();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secondbrainos-mcp-server",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Second Brain OS MCP Server for Claude Desktop",
5
5
  "type": "module",
6
6
  "main": "build/index.js",
@@ -8,8 +8,17 @@
8
8
  "bin": {
9
9
  "secondbrainos-mcp": "bin/cli.js"
10
10
  },
11
+ "files": [
12
+ "build/",
13
+ "bin/",
14
+ "LICENSE",
15
+ "README.md"
16
+ ],
11
17
  "scripts": {
12
18
  "build": "tsc",
19
+ "dev": "tsx src/index.ts",
20
+ "start": "node build/index.js",
21
+ "test-conversion": "tsx src/test-conversion.ts",
13
22
  "prepublishOnly": "npm run build",
14
23
  "test": "echo \"Error: no test specified\" && exit 1"
15
24
  },
@@ -23,6 +32,7 @@
23
32
  "license": "MIT",
24
33
  "dependencies": {
25
34
  "@modelcontextprotocol/sdk": "^1.0.0",
35
+ "@samchon/openapi": "^2.0.0",
26
36
  "axios": "^1.8.2",
27
37
  "dotenv": "^16.4.7",
28
38
  "js-yaml": "^4.1.0"
@@ -31,9 +41,10 @@
31
41
  "@types/js-yaml": "^4.0.5",
32
42
  "@types/node": "^20.8.10",
33
43
  "ts-node": "^10.9.1",
44
+ "tsx": "^4.7.0",
34
45
  "typescript": "^5.2.2"
35
46
  },
36
47
  "engines": {
37
48
  "node": ">=16.0.0"
38
49
  }
39
- }
50
+ }
package/.env DELETED
@@ -1,2 +0,0 @@
1
- USER_ID=
2
- USER_SECRET=
package/gitignore.txt DELETED
@@ -1,130 +0,0 @@
1
- # Logs
2
- logs
3
- *.log
4
- npm-debug.log*
5
- yarn-debug.log*
6
- yarn-error.log*
7
- lerna-debug.log*
8
- .pnpm-debug.log*
9
-
10
- # Diagnostic reports (https://nodejs.org/api/report.html)
11
- report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12
-
13
- # Runtime data
14
- pids
15
- *.pid
16
- *.seed
17
- *.pid.lock
18
-
19
- # Directory for instrumented libs generated by jscoverage/JSCover
20
- lib-cov
21
-
22
- # Coverage directory used by tools like istanbul
23
- coverage
24
- *.lcov
25
-
26
- # nyc test coverage
27
- .nyc_output
28
-
29
- # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30
- .grunt
31
-
32
- # Bower dependency directory (https://bower.io/)
33
- bower_components
34
-
35
- # node-waf configuration
36
- .lock-wscript
37
-
38
- # Compiled binary addons (https://nodejs.org/api/addons.html)
39
- build/Release
40
-
41
- # Dependency directories
42
- node_modules/
43
- jspm_packages/
44
-
45
- # Snowpack dependency directory (https://snowpack.dev/)
46
- web_modules/
47
-
48
- # TypeScript cache
49
- *.tsbuildinfo
50
-
51
- # Optional npm cache directory
52
- .npm
53
-
54
- # Optional eslint cache
55
- .eslintcache
56
-
57
- # Optional stylelint cache
58
- .stylelintcache
59
-
60
- # Microbundle cache
61
- .rpt2_cache/
62
- .rts2_cache_cjs/
63
- .rts2_cache_es/
64
- .rts2_cache_umd/
65
-
66
- # Optional REPL history
67
- .node_repl_history
68
-
69
- # Output of 'npm pack'
70
- *.tgz
71
-
72
- # Yarn Integrity file
73
- .yarn-integrity
74
-
75
- # dotenv environment variable files
76
- .env
77
- .env.development.local
78
- .env.test.local
79
- .env.production.local
80
- .env.local
81
-
82
- # parcel-bundler cache (https://parceljs.org/)
83
- .cache
84
- .parcel-cache
85
-
86
- # Next.js build output
87
- .next
88
- out
89
-
90
- # Nuxt.js build / generate output
91
- .nuxt
92
- dist
93
-
94
- # Gatsby files
95
- .cache/
96
- # Comment in the public line in if your project uses Gatsby and not Next.js
97
- # https://nextjs.org/blog/next-9-1#public-directory-support
98
- # public
99
-
100
- # vuepress build output
101
- .vuepress/dist
102
-
103
- # vuepress v2.x temp and cache directory
104
- .temp
105
- .cache
106
-
107
- # Docusaurus cache and generated files
108
- .docusaurus
109
-
110
- # Serverless directories
111
- .serverless/
112
-
113
- # FuseBox cache
114
- .fusebox/
115
-
116
- # DynamoDB Local files
117
- .dynamodb/
118
-
119
- # TernJS port file
120
- .tern-port
121
-
122
- # Stores VSCode versions used for testing VSCode extensions
123
- .vscode-test
124
-
125
- # yarn v2
126
- .yarn/cache
127
- .yarn/unplugged
128
- .yarn/build-state.yml
129
- .yarn/install-state.gz
130
- .pnp.*