@astramindapp/mcp-server 0.1.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 +136 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +41 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/mind-client.d.ts +172 -0
- package/dist/mind-client.d.ts.map +1 -0
- package/dist/mind-client.js +138 -0
- package/dist/mind-client.js.map +1 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +401 -0
- package/dist/server.js.map +1 -0
- package/dist/setup.d.ts +12 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +332 -0
- package/dist/setup.js.map +1 -0
- package/package.json +46 -0
- package/src/cli.ts +47 -0
- package/src/index.ts +15 -0
- package/src/mind-client.ts +324 -0
- package/src/server.ts +457 -0
- package/src/setup.ts +372 -0
- package/tsconfig.json +20 -0
package/src/setup.ts
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MIND MCP Server — Interactive Setup Wizard
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx @mindapp/mcp-server setup
|
|
7
|
+
* mind-mcp-setup
|
|
8
|
+
*
|
|
9
|
+
* Auto-detects installed AI tools and configures MIND as their memory layer.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from "fs";
|
|
13
|
+
import * as path from "path";
|
|
14
|
+
import * as os from "os";
|
|
15
|
+
import * as readline from "readline";
|
|
16
|
+
|
|
17
|
+
const HOME = os.homedir();
|
|
18
|
+
|
|
19
|
+
// ─── AI Tool Configs ──────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
interface ToolConfig {
|
|
22
|
+
name: string;
|
|
23
|
+
configPath: string;
|
|
24
|
+
configKey: string; // key in the JSON where MCP servers live
|
|
25
|
+
detected: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getToolConfigs(): ToolConfig[] {
|
|
29
|
+
const platform = process.platform;
|
|
30
|
+
const tools: ToolConfig[] = [];
|
|
31
|
+
|
|
32
|
+
// Claude Desktop
|
|
33
|
+
if (platform === "darwin") {
|
|
34
|
+
tools.push({
|
|
35
|
+
name: "Claude Desktop",
|
|
36
|
+
configPath: path.join(
|
|
37
|
+
HOME,
|
|
38
|
+
"Library",
|
|
39
|
+
"Application Support",
|
|
40
|
+
"Claude",
|
|
41
|
+
"claude_desktop_config.json"
|
|
42
|
+
),
|
|
43
|
+
configKey: "mcpServers",
|
|
44
|
+
detected: false,
|
|
45
|
+
});
|
|
46
|
+
} else if (platform === "win32") {
|
|
47
|
+
tools.push({
|
|
48
|
+
name: "Claude Desktop",
|
|
49
|
+
configPath: path.join(
|
|
50
|
+
process.env.APPDATA ?? path.join(HOME, "AppData", "Roaming"),
|
|
51
|
+
"Claude",
|
|
52
|
+
"claude_desktop_config.json"
|
|
53
|
+
),
|
|
54
|
+
configKey: "mcpServers",
|
|
55
|
+
detected: false,
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
// Linux
|
|
59
|
+
tools.push({
|
|
60
|
+
name: "Claude Desktop",
|
|
61
|
+
configPath: path.join(
|
|
62
|
+
HOME,
|
|
63
|
+
".config",
|
|
64
|
+
"Claude",
|
|
65
|
+
"claude_desktop_config.json"
|
|
66
|
+
),
|
|
67
|
+
configKey: "mcpServers",
|
|
68
|
+
detected: false,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Cursor
|
|
73
|
+
const cursorConfig = path.join(HOME, ".cursor", "mcp.json");
|
|
74
|
+
tools.push({
|
|
75
|
+
name: "Cursor",
|
|
76
|
+
configPath: cursorConfig,
|
|
77
|
+
configKey: "mcpServers",
|
|
78
|
+
detected: false,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Windsurf
|
|
82
|
+
const windsurfConfig = path.join(HOME, ".windsurf", "mcp.json");
|
|
83
|
+
tools.push({
|
|
84
|
+
name: "Windsurf",
|
|
85
|
+
configPath: windsurfConfig,
|
|
86
|
+
configKey: "mcpServers",
|
|
87
|
+
detected: false,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// VS Code (Copilot MCP)
|
|
91
|
+
const vscodeConfig = path.join(HOME, ".vscode", "mcp.json");
|
|
92
|
+
tools.push({
|
|
93
|
+
name: "VS Code (Copilot)",
|
|
94
|
+
configPath: vscodeConfig,
|
|
95
|
+
configKey: "servers",
|
|
96
|
+
detected: false,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Detect which tools exist
|
|
100
|
+
for (const tool of tools) {
|
|
101
|
+
const configDir = path.dirname(tool.configPath);
|
|
102
|
+
tool.detected = fs.existsSync(configDir);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return tools;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ─── CLI Helpers ──────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
function createRL(): readline.Interface {
|
|
111
|
+
return readline.createInterface({
|
|
112
|
+
input: process.stdin,
|
|
113
|
+
output: process.stdout,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function ask(rl: readline.Interface, question: string): Promise<string> {
|
|
118
|
+
return new Promise((resolve) => {
|
|
119
|
+
rl.question(question, (answer) => resolve(answer.trim()));
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function print(msg: string) {
|
|
124
|
+
console.log(msg);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function printHeader() {
|
|
128
|
+
print("");
|
|
129
|
+
print("╔══════════════════════════════════════════╗");
|
|
130
|
+
print("║ 🧠 MIND MCP Server — Setup Wizard ║");
|
|
131
|
+
print("║ Give your AI agents persistent memory ║");
|
|
132
|
+
print("╚══════════════════════════════════════════╝");
|
|
133
|
+
print("");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ─── Config Writing ───────────────────────────────────────
|
|
137
|
+
|
|
138
|
+
function getMindServerConfig(apiKey: string): Record<string, unknown> {
|
|
139
|
+
// Use the globally installed CLI path, or fall back to local
|
|
140
|
+
const cliPath = path.resolve(__dirname, "cli.js");
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
command: "node",
|
|
144
|
+
args: [cliPath],
|
|
145
|
+
env: {
|
|
146
|
+
MIND_API_KEY: apiKey,
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function writeToolConfig(
|
|
152
|
+
tool: ToolConfig,
|
|
153
|
+
apiKey: string
|
|
154
|
+
): { success: boolean; error?: string } {
|
|
155
|
+
try {
|
|
156
|
+
const configDir = path.dirname(tool.configPath);
|
|
157
|
+
if (!fs.existsSync(configDir)) {
|
|
158
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let config: Record<string, unknown> = {};
|
|
162
|
+
if (fs.existsSync(tool.configPath)) {
|
|
163
|
+
try {
|
|
164
|
+
const raw = fs.readFileSync(tool.configPath, "utf-8");
|
|
165
|
+
config = JSON.parse(raw);
|
|
166
|
+
} catch {
|
|
167
|
+
// If the file exists but is invalid JSON, start fresh
|
|
168
|
+
config = {};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Get or create the MCP servers section
|
|
173
|
+
const serversKey = tool.configKey;
|
|
174
|
+
if (!config[serversKey] || typeof config[serversKey] !== "object") {
|
|
175
|
+
config[serversKey] = {};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Add MIND server
|
|
179
|
+
(config[serversKey] as Record<string, unknown>)["mind"] =
|
|
180
|
+
getMindServerConfig(apiKey);
|
|
181
|
+
|
|
182
|
+
// Write back
|
|
183
|
+
fs.writeFileSync(
|
|
184
|
+
tool.configPath,
|
|
185
|
+
JSON.stringify(config, null, 2) + "\n",
|
|
186
|
+
"utf-8"
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
return { success: true };
|
|
190
|
+
} catch (err) {
|
|
191
|
+
return { success: false, error: String(err) };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ─── API Key Validation ──────────────────────────────────
|
|
196
|
+
|
|
197
|
+
async function validateApiKey(
|
|
198
|
+
apiKey: string,
|
|
199
|
+
baseUrl: string
|
|
200
|
+
): Promise<{ valid: boolean; error?: string }> {
|
|
201
|
+
try {
|
|
202
|
+
const res = await fetch(`${baseUrl}/developer/v1/profile`, {
|
|
203
|
+
headers: { "X-API-Key": apiKey },
|
|
204
|
+
});
|
|
205
|
+
if (res.ok) {
|
|
206
|
+
return { valid: true };
|
|
207
|
+
}
|
|
208
|
+
return { valid: false, error: `API returned ${res.status}: ${res.statusText}` };
|
|
209
|
+
} catch (err) {
|
|
210
|
+
return { valid: false, error: String(err) };
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ─── Main ─────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
async function main() {
|
|
217
|
+
printHeader();
|
|
218
|
+
|
|
219
|
+
const rl = createRL();
|
|
220
|
+
|
|
221
|
+
// Step 1: API Key
|
|
222
|
+
print("Step 1: Connect to your MIND");
|
|
223
|
+
print("─────────────────────────────");
|
|
224
|
+
print("You need a MIND API key. Get one at: https://m-i-n-d.ai → Settings → Developer → API Keys");
|
|
225
|
+
print("");
|
|
226
|
+
|
|
227
|
+
let apiKey = process.env.MIND_API_KEY ?? "";
|
|
228
|
+
if (apiKey) {
|
|
229
|
+
print(`Found MIND_API_KEY in environment: ${apiKey.slice(0, 12)}...`);
|
|
230
|
+
const useExisting = await ask(rl, "Use this key? (Y/n): ");
|
|
231
|
+
if (useExisting.toLowerCase() === "n") {
|
|
232
|
+
apiKey = "";
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (!apiKey) {
|
|
237
|
+
apiKey = await ask(rl, "Paste your MIND API key: ");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!apiKey) {
|
|
241
|
+
print("\n❌ No API key provided. Exiting.");
|
|
242
|
+
rl.close();
|
|
243
|
+
process.exit(1);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Validate
|
|
247
|
+
const baseUrl = process.env.MIND_BASE_URL ?? "https://m-i-n-d.ai";
|
|
248
|
+
print("\nValidating API key...");
|
|
249
|
+
const validation = await validateApiKey(apiKey, baseUrl);
|
|
250
|
+
|
|
251
|
+
if (!validation.valid) {
|
|
252
|
+
print(`\n⚠️ Could not validate key: ${validation.error}`);
|
|
253
|
+
const proceed = await ask(rl, "Continue anyway? (y/N): ");
|
|
254
|
+
if (proceed.toLowerCase() !== "y") {
|
|
255
|
+
rl.close();
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
print("✅ API key is valid!\n");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Step 2: Detect AI tools
|
|
263
|
+
print("Step 2: Detect your AI tools");
|
|
264
|
+
print("─────────────────────────────");
|
|
265
|
+
|
|
266
|
+
const tools = getToolConfigs();
|
|
267
|
+
const detected = tools.filter((t) => t.detected);
|
|
268
|
+
const notDetected = tools.filter((t) => !t.detected);
|
|
269
|
+
|
|
270
|
+
if (detected.length > 0) {
|
|
271
|
+
print("Found these AI tools on your machine:");
|
|
272
|
+
for (const tool of detected) {
|
|
273
|
+
print(` ✅ ${tool.name}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (notDetected.length > 0) {
|
|
278
|
+
print("\nNot detected (you can still configure manually):");
|
|
279
|
+
for (const tool of notDetected) {
|
|
280
|
+
print(` ⬜ ${tool.name}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
print("");
|
|
285
|
+
|
|
286
|
+
// Step 3: Configure each detected tool
|
|
287
|
+
print("Step 3: Configure MIND memory");
|
|
288
|
+
print("──────────────────────────────");
|
|
289
|
+
|
|
290
|
+
const configured: string[] = [];
|
|
291
|
+
|
|
292
|
+
for (const tool of detected) {
|
|
293
|
+
const answer = await ask(rl, `Add MIND to ${tool.name}? (Y/n): `);
|
|
294
|
+
if (answer.toLowerCase() === "n") {
|
|
295
|
+
print(` ⏭️ Skipped ${tool.name}`);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const result = writeToolConfig(tool, apiKey);
|
|
300
|
+
if (result.success) {
|
|
301
|
+
print(` ✅ ${tool.name} configured!`);
|
|
302
|
+
configured.push(tool.name);
|
|
303
|
+
} else {
|
|
304
|
+
print(` ❌ Failed: ${result.error}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Also offer non-detected tools
|
|
309
|
+
for (const tool of notDetected) {
|
|
310
|
+
const answer = await ask(
|
|
311
|
+
rl,
|
|
312
|
+
`Configure MIND for ${tool.name} anyway? (y/N): `
|
|
313
|
+
);
|
|
314
|
+
if (answer.toLowerCase() !== "y") continue;
|
|
315
|
+
|
|
316
|
+
const result = writeToolConfig(tool, apiKey);
|
|
317
|
+
if (result.success) {
|
|
318
|
+
print(` ✅ ${tool.name} configured!`);
|
|
319
|
+
configured.push(tool.name);
|
|
320
|
+
} else {
|
|
321
|
+
print(` ❌ Failed: ${result.error}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Done
|
|
326
|
+
print("");
|
|
327
|
+
print("══════════════════════════════════════════");
|
|
328
|
+
print("🧠 MIND MCP Server setup complete!");
|
|
329
|
+
print("══════════════════════════════════════════");
|
|
330
|
+
print("");
|
|
331
|
+
|
|
332
|
+
if (configured.length > 0) {
|
|
333
|
+
print("Configured for:");
|
|
334
|
+
for (const name of configured) {
|
|
335
|
+
print(` ✅ ${name}`);
|
|
336
|
+
}
|
|
337
|
+
print("");
|
|
338
|
+
print("⚠️ Restart your AI tools for changes to take effect.");
|
|
339
|
+
print(" (Fully quit and reopen — not just close the window)");
|
|
340
|
+
} else {
|
|
341
|
+
print("No tools configured. You can run this again anytime:");
|
|
342
|
+
print(" npx @mindapp/mcp-server setup");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
print("");
|
|
346
|
+
print("Your AI agents now have persistent memory. 🧠");
|
|
347
|
+
print("Everything they learn gets stored in your MIND knowledge graph.");
|
|
348
|
+
print("");
|
|
349
|
+
|
|
350
|
+
rl.close();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Entry point
|
|
354
|
+
const args = process.argv.slice(2);
|
|
355
|
+
if (args.includes("setup") || args.includes("--setup")) {
|
|
356
|
+
main().catch((err) => {
|
|
357
|
+
console.error("Setup failed:", err);
|
|
358
|
+
process.exit(1);
|
|
359
|
+
});
|
|
360
|
+
} else {
|
|
361
|
+
// If called directly without "setup", show help
|
|
362
|
+
print("MIND MCP Server Setup");
|
|
363
|
+
print("");
|
|
364
|
+
print("Usage:");
|
|
365
|
+
print(" mind-mcp-setup Run interactive setup wizard");
|
|
366
|
+
print(" mind-mcp-setup setup Same as above");
|
|
367
|
+
print("");
|
|
368
|
+
main().catch((err) => {
|
|
369
|
+
console.error("Setup failed:", err);
|
|
370
|
+
process.exit(1);
|
|
371
|
+
});
|
|
372
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "Node16",
|
|
5
|
+
"moduleResolution": "Node16",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"rootDir": "src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"sourceMap": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
20
|
+
}
|