secondbrainos-mcp-server 1.0.5 → 1.0.6
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/build/index.js +36 -9
- package/build/test-mcp-conversion.js +135 -0
- package/package.json +3 -3
- package/build/test-conversion.js +0 -81
package/build/index.js
CHANGED
|
@@ -22,6 +22,14 @@ class SecondBrainOSServer {
|
|
|
22
22
|
model: "chatgpt",
|
|
23
23
|
document
|
|
24
24
|
});
|
|
25
|
+
// Create a map of operationId to function for easier lookup
|
|
26
|
+
this.functionMap = new Map();
|
|
27
|
+
this.application.functions.forEach(func => {
|
|
28
|
+
const operation = func.operation();
|
|
29
|
+
if (operation.operationId) {
|
|
30
|
+
this.functionMap.set(operation.operationId, func);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
25
33
|
this.server = new Server({
|
|
26
34
|
name: "secondbrainos-server",
|
|
27
35
|
version: "1.0.0"
|
|
@@ -59,19 +67,38 @@ class SecondBrainOSServer {
|
|
|
59
67
|
}]
|
|
60
68
|
};
|
|
61
69
|
});
|
|
62
|
-
// List available tools - now using
|
|
70
|
+
// List available tools - now using operationId as the tool name
|
|
63
71
|
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
const tools = [];
|
|
73
|
+
// Iterate through the function map to get tools with proper names
|
|
74
|
+
for (const [operationId, func] of this.functionMap) {
|
|
75
|
+
tools.push({
|
|
76
|
+
name: operationId,
|
|
77
|
+
description: func.description || operationId,
|
|
68
78
|
inputSchema: func.parameters // Convert to MCP format
|
|
69
|
-
})
|
|
70
|
-
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Also include functions without operationId (fallback)
|
|
82
|
+
this.application.functions.forEach(func => {
|
|
83
|
+
const operation = func.operation();
|
|
84
|
+
if (!operation.operationId) {
|
|
85
|
+
tools.push({
|
|
86
|
+
name: func.name,
|
|
87
|
+
description: func.description || func.name,
|
|
88
|
+
inputSchema: func.parameters
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return { tools };
|
|
71
93
|
});
|
|
72
|
-
// Handle tool calls
|
|
94
|
+
// Handle tool calls - now supporting both operationId and original names
|
|
73
95
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
74
|
-
|
|
96
|
+
// First try to find by operationId
|
|
97
|
+
let func = this.functionMap.get(request.params.name);
|
|
98
|
+
// If not found, try the original function name
|
|
99
|
+
if (!func) {
|
|
100
|
+
func = this.application.functions.find(f => f.name === request.params.name);
|
|
101
|
+
}
|
|
75
102
|
if (!func) {
|
|
76
103
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown function: ${request.params.name}`);
|
|
77
104
|
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { OpenApi, HttpLlm } from "@samchon/openapi";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import dotenv from "dotenv";
|
|
4
|
+
import fs from "fs/promises";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { dirname } from 'path';
|
|
8
|
+
// Get __dirname equivalent for ES modules
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
// Load environment variables
|
|
12
|
+
dotenv.config();
|
|
13
|
+
// Function to fetch the schema from the API
|
|
14
|
+
async function fetchSchema() {
|
|
15
|
+
const userId = process.env.USER_ID;
|
|
16
|
+
if (!userId) {
|
|
17
|
+
throw new Error("USER_ID environment variable is required");
|
|
18
|
+
}
|
|
19
|
+
console.log("Fetching schema for user:", userId);
|
|
20
|
+
try {
|
|
21
|
+
const response = await axios.post('https://us-central1-second-brain-os.cloudfunctions.net/generate-open-api-schema', { user_id: userId }, {
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/json'
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return response.data;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error('Failed to fetch schema:', error);
|
|
30
|
+
throw new Error('Failed to fetch API schema');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function testMCPConversion() {
|
|
34
|
+
try {
|
|
35
|
+
console.log("=== MCP Conversion Test ===\n");
|
|
36
|
+
// Step 1: Fetch the original schema
|
|
37
|
+
console.log("1. Fetching OpenAPI schema...");
|
|
38
|
+
const originalSchema = await fetchSchema();
|
|
39
|
+
console.log("✓ Schema fetched successfully");
|
|
40
|
+
console.log(` - Title: ${originalSchema.info?.title}`);
|
|
41
|
+
console.log(` - Version: ${originalSchema.info?.version}`);
|
|
42
|
+
console.log(` - Number of paths: ${Object.keys(originalSchema.paths || {}).length}\n`);
|
|
43
|
+
// Save original schema for reference
|
|
44
|
+
await fs.writeFile(path.join(__dirname, '../output/original-schema.json'), JSON.stringify(originalSchema, null, 2));
|
|
45
|
+
console.log("✓ Original schema saved to output/original-schema.json\n");
|
|
46
|
+
// Step 2: Convert using OpenApi
|
|
47
|
+
console.log("2. Converting schema using @samchon/openapi...");
|
|
48
|
+
const document = OpenApi.convert(originalSchema);
|
|
49
|
+
console.log("✓ Schema converted to OpenApi format\n");
|
|
50
|
+
// Step 3: Create LLM application
|
|
51
|
+
console.log("3. Creating LLM application...");
|
|
52
|
+
const application = HttpLlm.application({
|
|
53
|
+
model: "chatgpt",
|
|
54
|
+
document
|
|
55
|
+
});
|
|
56
|
+
console.log("✓ LLM application created");
|
|
57
|
+
console.log(` - Number of functions: ${application.functions.length}\n`);
|
|
58
|
+
// Step 4: Create MCP-compatible tools
|
|
59
|
+
console.log("4. Converting to MCP tool format...");
|
|
60
|
+
const mcpTools = [];
|
|
61
|
+
const functionMap = new Map();
|
|
62
|
+
application.functions.forEach(func => {
|
|
63
|
+
const operation = func.operation();
|
|
64
|
+
const operationId = operation.operationId || func.name;
|
|
65
|
+
functionMap.set(operationId, func);
|
|
66
|
+
const mcpTool = {
|
|
67
|
+
name: operationId,
|
|
68
|
+
description: func.description || operationId,
|
|
69
|
+
inputSchema: func.parameters
|
|
70
|
+
};
|
|
71
|
+
mcpTools.push(mcpTool);
|
|
72
|
+
});
|
|
73
|
+
console.log(`✓ Converted ${mcpTools.length} tools to MCP format\n`);
|
|
74
|
+
// Step 5: Save the results
|
|
75
|
+
console.log("5. Saving conversion results...");
|
|
76
|
+
// Create output directory if it doesn't exist
|
|
77
|
+
await fs.mkdir(path.join(__dirname, '../output'), { recursive: true });
|
|
78
|
+
// Save MCP tools
|
|
79
|
+
await fs.writeFile(path.join(__dirname, '../output/mcp-tools.json'), JSON.stringify(mcpTools, null, 2));
|
|
80
|
+
console.log("✓ MCP tools saved to output/mcp-tools.json");
|
|
81
|
+
// Save function details
|
|
82
|
+
const functionDetails = application.functions.map(func => {
|
|
83
|
+
const operation = func.operation();
|
|
84
|
+
// Extract method and path from the route property if available
|
|
85
|
+
let method;
|
|
86
|
+
let path;
|
|
87
|
+
// The operation might have these properties in different ways depending on the OpenAPI version
|
|
88
|
+
// Let's check the actual structure
|
|
89
|
+
const route = operation.route;
|
|
90
|
+
if (route) {
|
|
91
|
+
method = route.method;
|
|
92
|
+
path = route.path;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
name: func.name,
|
|
96
|
+
operationId: operation.operationId,
|
|
97
|
+
method,
|
|
98
|
+
path,
|
|
99
|
+
description: func.description,
|
|
100
|
+
parameters: func.parameters,
|
|
101
|
+
operation: {
|
|
102
|
+
summary: operation.summary,
|
|
103
|
+
description: operation.description,
|
|
104
|
+
tags: operation.tags
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
await fs.writeFile(path.join(__dirname, '../output/function-details.json'), JSON.stringify(functionDetails, null, 2));
|
|
109
|
+
console.log("✓ Function details saved to output/function-details.json\n");
|
|
110
|
+
// Step 6: Display summary
|
|
111
|
+
console.log("=== Conversion Summary ===");
|
|
112
|
+
console.log(`Total tools converted: ${mcpTools.length}`);
|
|
113
|
+
console.log("\nSample tools:");
|
|
114
|
+
mcpTools.slice(0, 5).forEach(tool => {
|
|
115
|
+
console.log(` - ${tool.name}: ${tool.description}`);
|
|
116
|
+
});
|
|
117
|
+
if (mcpTools.length > 5) {
|
|
118
|
+
console.log(` ... and ${mcpTools.length - 5} more`);
|
|
119
|
+
}
|
|
120
|
+
console.log("\n✓ Test completed successfully!");
|
|
121
|
+
console.log("\nCheck the 'output' directory for:");
|
|
122
|
+
console.log(" - original-schema.json: The raw OpenAPI schema from the API");
|
|
123
|
+
console.log(" - mcp-tools.json: Tools in MCP format");
|
|
124
|
+
console.log(" - function-details.json: Detailed function information");
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
console.error("\n❌ Test failed:", error);
|
|
128
|
+
if (error instanceof Error) {
|
|
129
|
+
console.error("Error details:", error.message);
|
|
130
|
+
}
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Run the test
|
|
135
|
+
testMCPConversion().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "secondbrainos-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Second Brain OS MCP Server for Claude Desktop",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"build": "tsc",
|
|
19
19
|
"dev": "tsx src/index.ts",
|
|
20
20
|
"start": "node build/index.js",
|
|
21
|
-
"test-conversion": "tsx src/test-conversion.ts",
|
|
21
|
+
"test-conversion": "tsx src/test-mcp-conversion.ts",
|
|
22
22
|
"prepublishOnly": "npm run build",
|
|
23
23
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
24
24
|
},
|
|
@@ -47,4 +47,4 @@
|
|
|
47
47
|
"engines": {
|
|
48
48
|
"node": ">=16.0.0"
|
|
49
49
|
}
|
|
50
|
-
}
|
|
50
|
+
}
|
package/build/test-conversion.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
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();
|