secondbrainos-mcp-server 1.2.4 → 1.2.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.
Files changed (2) hide show
  1. package/bin/cli.js +137 -29
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -129,13 +129,103 @@ async function readExistingConfig(configPath) {
129
129
  }
130
130
  }
131
131
 
132
+ /**
133
+ * Get the credentials file path
134
+ */
135
+ function getCredentialsPath() {
136
+ return path.join(homedir(), '.secondbrainos', 'credentials.json');
137
+ }
138
+
139
+ /**
140
+ * Store credentials to ~/.secondbrainos/credentials.json
141
+ */
142
+ async function storeCredentials(USER_ID, USER_SECRET) {
143
+ const credDir = path.join(homedir(), '.secondbrainos');
144
+ await fs.mkdir(credDir, { recursive: true });
145
+ await fs.writeFile(
146
+ getCredentialsPath(),
147
+ JSON.stringify({ USER_ID, USER_SECRET, API_BASE_URL: 'https://api.secondbrainos.com' }, null, 2),
148
+ { mode: 0o600 }
149
+ );
150
+ }
151
+
152
+ /**
153
+ * Configure Claude Code via `claude mcp add`
154
+ */
155
+ async function configureClaudeCode(serverPath, nodePath) {
156
+ try {
157
+ const { stdout } = await execAsync('which claude').catch(() => ({ stdout: '' }));
158
+ if (!stdout.trim()) {
159
+ console.log('\nClaude Code CLI not found — skipping Claude Code configuration.');
160
+ console.log('To set up Claude Code later, install it and run this setup again.');
161
+ return false;
162
+ }
163
+
164
+ // Remove existing config first (ignore errors if it doesn't exist)
165
+ await execAsync('claude mcp remove secondbrainos -s user').catch(() => {});
166
+
167
+ // Add the server with serve subcommand
168
+ await execAsync(`claude mcp add secondbrainos -s user -- ${nodePath} ${serverPath} serve`);
169
+ console.log('Claude Code configured successfully!');
170
+ return true;
171
+ } catch (error) {
172
+ console.log(`\nClaude Code auto-configuration failed: ${error.message}`);
173
+ console.log('You can manually configure it by running:');
174
+ console.log(` claude mcp add secondbrainos -s user -- ${nodePath} ${serverPath} serve`);
175
+ return false;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Run the MCP server (serve mode)
181
+ */
182
+ async function serve() {
183
+ // Load credentials from stored file, with env var override
184
+ let USER_ID = process.env.USER_ID;
185
+ let USER_SECRET = process.env.USER_SECRET;
186
+ let API_BASE_URL = process.env.API_BASE_URL;
187
+
188
+ if (!USER_ID || !USER_SECRET) {
189
+ try {
190
+ const creds = JSON.parse(await fs.readFile(getCredentialsPath(), 'utf8'));
191
+ USER_ID = USER_ID || creds.USER_ID;
192
+ USER_SECRET = USER_SECRET || creds.USER_SECRET;
193
+ API_BASE_URL = API_BASE_URL || creds.API_BASE_URL;
194
+ } catch {
195
+ console.error('Error: No credentials found. Run setup first:');
196
+ console.error(' npx secondbrainos-mcp-server USER_ID USER_SECRET');
197
+ process.exit(1);
198
+ }
199
+ }
200
+
201
+ if (!USER_ID || !USER_SECRET) {
202
+ console.error('Error: Missing USER_ID or USER_SECRET.');
203
+ process.exit(1);
204
+ }
205
+
206
+ // Set env vars for the server process
207
+ process.env.USER_ID = USER_ID;
208
+ process.env.USER_SECRET = USER_SECRET;
209
+ process.env.API_BASE_URL = API_BASE_URL || 'https://api.secondbrainos.com';
210
+
211
+ // Import and run the server
212
+ const packageRoot = path.resolve(__dirname, '..');
213
+ const serverModule = path.join(packageRoot, 'build', 'index.js');
214
+ await import(serverModule);
215
+ }
216
+
132
217
  async function main() {
133
218
  try {
134
219
  // Get command line arguments
135
220
  const args = process.argv.slice(2);
136
-
221
+
222
+ // Handle serve subcommand
223
+ if (args.length === 1 && args[0] === 'serve') {
224
+ return await serve();
225
+ }
226
+
137
227
  let USER_ID, USER_SECRET;
138
-
228
+
139
229
  if (args.length === 1 && args[0].includes(':')) {
140
230
  // Handle the combined format USER_ID:USER_SECRET
141
231
  [USER_ID, USER_SECRET] = args[0].split(':');
@@ -145,70 +235,79 @@ async function main() {
145
235
  } else {
146
236
  console.error('Usage: secondbrainos-mcp USER_ID:USER_SECRET');
147
237
  console.error(' or: secondbrainos-mcp USER_ID USER_SECRET');
238
+ console.error(' or: secondbrainos-mcp serve');
148
239
  process.exit(1);
149
240
  }
150
-
241
+
151
242
  // Validate that we have both values
152
243
  if (!USER_ID || !USER_SECRET) {
153
244
  console.error('Error: Both USER_ID and USER_SECRET are required');
154
245
  process.exit(1);
155
246
  }
156
-
247
+
157
248
  console.log('Verifying user credentials...');
158
-
249
+
159
250
  // Verify user with the cloud function
160
251
  try {
161
252
  const verificationUrl = 'https://us-central1-second-brain-os.cloudfunctions.net/gcf-sbos-verifyuserdatapublic';
162
253
  const response = await axios.post(verificationUrl, {
163
254
  "x-user-api-key": `Bearer ${USER_ID}:${USER_SECRET}`
164
255
  });
165
-
256
+
166
257
  const { exists, email, features } = response.data;
167
-
258
+
168
259
  if (!exists || exists !== 1) {
169
260
  console.error('Error: User does not exist.');
170
261
  process.exit(1);
171
262
  }
172
-
263
+
173
264
  if (!email) {
174
265
  console.error('Error: User email not found.');
175
266
  process.exit(1);
176
267
  }
177
-
268
+
178
269
  // Check if claudemcp feature is enabled
179
270
  if (!features || typeof features !== 'string') {
180
271
  console.error('Error: User features not found.');
181
272
  process.exit(1);
182
273
  }
183
-
274
+
184
275
  const featuresList = features.toLowerCase().split(',').map(f => f.trim().replace(/\s+/g, ''));
185
276
  if (!featuresList.includes('claudemcp')) {
186
277
  console.error('Error: Claude MCP feature not enabled for this user.');
187
278
  process.exit(1);
188
279
  }
189
-
280
+
190
281
  console.log('User verified successfully!');
191
-
282
+
192
283
  } catch (error) {
193
284
  console.error('Error verifying user:', error.message);
194
285
  process.exit(1);
195
286
  }
196
-
197
- // Create Claude Desktop configuration directory if it doesn't exist
287
+
288
+ // Store credentials locally
289
+ try {
290
+ await storeCredentials(USER_ID, USER_SECRET);
291
+ console.log(`Credentials stored at: ${getCredentialsPath()}`);
292
+ } catch (error) {
293
+ console.error('Warning: Could not store credentials:', error.message);
294
+ }
295
+
296
+ // Configure Claude Desktop
198
297
  const claudeConfigDir = getClaudeConfigPath();
199
298
  const claudeConfigFile = path.join(claudeConfigDir, 'claude_desktop_config.json');
200
-
299
+
201
300
  try {
202
301
  await fs.mkdir(claudeConfigDir, { recursive: true });
203
302
  } catch (error) {
204
303
  console.error('Error creating config directory:', error);
205
304
  process.exit(1);
206
305
  }
207
-
306
+
208
307
  // Get the absolute path to the installed package's index.js file
209
308
  const packageRoot = path.resolve(__dirname, '..');
210
309
  const serverPath = path.join(packageRoot, 'build', 'index.js');
211
-
310
+
212
311
  // Check if serverPath exists
213
312
  try {
214
313
  await fs.access(serverPath);
@@ -217,21 +316,21 @@ async function main() {
217
316
  console.error('This might be due to an incomplete installation. Try reinstalling the package with: npm install -g secondbrainos-mcp-server');
218
317
  process.exit(1);
219
318
  }
220
-
319
+
221
320
  // Find Node.js executable
222
321
  const nodePath = await findNodeExecutable();
223
-
322
+
224
323
  // Read existing configuration
225
324
  const existingConfig = await readExistingConfig(claudeConfigFile);
226
-
325
+
227
326
  // Ensure mcpServers object exists
228
327
  if (!existingConfig.mcpServers) {
229
328
  existingConfig.mcpServers = {};
230
329
  }
231
-
330
+
232
331
  // Check if secondbrainos already exists
233
332
  const hadExistingSecondBrainOS = !!existingConfig.mcpServers.secondbrainos;
234
-
333
+
235
334
  // Add or update the secondbrainos server configuration
236
335
  existingConfig.mcpServers.secondbrainos = {
237
336
  command: nodePath,
@@ -243,30 +342,39 @@ async function main() {
243
342
  NODE_PATH: getNodeModulesPath()
244
343
  }
245
344
  };
246
-
345
+
247
346
  try {
248
347
  // Write the updated configuration back
249
348
  await fs.writeFile(claudeConfigFile, JSON.stringify(existingConfig, null, 2));
250
- console.log(`Configuration file ${hadExistingSecondBrainOS ? 'updated' : 'created'} at: ${claudeConfigFile}`);
251
-
349
+ console.log(`Claude Desktop configuration ${hadExistingSecondBrainOS ? 'updated' : 'created'} at: ${claudeConfigFile}`);
350
+
252
351
  // Show summary of configured servers
253
352
  const serverCount = Object.keys(existingConfig.mcpServers).length;
254
353
  console.log(`\nTotal MCP servers configured: ${serverCount}`);
255
354
  console.log('Configured servers:', Object.keys(existingConfig.mcpServers).join(', '));
256
-
355
+
257
356
  } catch (error) {
258
357
  console.error('Error writing configuration file:', error);
259
358
  process.exit(1);
260
359
  }
261
-
360
+
361
+ // Configure Claude Code
362
+ const cliPath = path.join(packageRoot, 'bin', 'cli.js');
363
+ const claudeCodeConfigured = await configureClaudeCode(cliPath, nodePath);
364
+
262
365
  console.log('\nInstallation successful!');
263
- console.log('\nPlease follow these steps to complete setup:');
366
+ console.log('\nClaude Desktop:');
264
367
  console.log('1. Completely quit Claude Desktop if it is running');
265
368
  console.log('2. Restart Claude Desktop');
266
369
  console.log('3. In the Chat Input inside Claude (i.e where you type your messages), you will now see a "🔨" icon which contains all the tools you have access to');
370
+ if (claudeCodeConfigured) {
371
+ console.log('\nClaude Code:');
372
+ console.log('1. Restart Claude Code if it is running');
373
+ console.log('2. Your Second Brain OS tools will be available automatically');
374
+ }
267
375
  console.log('\nIf you encounter issues, check the logs:');
268
376
  console.log(`${getLogPath()}`);
269
-
377
+
270
378
  } catch (error) {
271
379
  console.error('Unexpected error:', error);
272
380
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secondbrainos-mcp-server",
3
- "version": "1.2.4",
3
+ "version": "1.2.5",
4
4
  "description": "Second Brain OS MCP Server for Claude Desktop",
5
5
  "type": "module",
6
6
  "main": "build/index.js",