@insforge/install 0.0.51 → 0.0.52
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/dist/index.d.ts +2 -0
- package/dist/index.js +275 -294
- package/dist/utils.d.ts +9 -0
- package/dist/utils.js +132 -143
- package/package.json +11 -1
- package/.claude/settings.local.json +0 -5
- package/.mcp.json +0 -15
- package/AGENTS.md +0 -99
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -1,33 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import { hideBin } from "yargs/helpers";
|
|
14
|
-
|
|
15
|
-
import pc from "picocolors";
|
|
16
|
-
import select from "@inquirer/select";
|
|
17
|
-
var { green, red, yellow, cyan } = pc;
|
|
18
|
-
|
|
19
|
-
// Section header helper
|
|
20
|
-
const LINE = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━';
|
|
21
|
-
function printHeader(text) {
|
|
2
|
+
import { clientNames, logger, readConfig, writeConfig } from "./utils.js";
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import yargs from "yargs";
|
|
7
|
+
import { hideBin } from "yargs/helpers";
|
|
8
|
+
import pc from "picocolors";
|
|
9
|
+
import select from "@inquirer/select";
|
|
10
|
+
const { green, red, yellow, cyan } = pc;
|
|
11
|
+
const LINE = '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━';
|
|
12
|
+
function printHeader(text) {
|
|
22
13
|
console.log();
|
|
23
14
|
console.log(LINE);
|
|
24
15
|
console.log(` ${text}`);
|
|
25
16
|
console.log(LINE);
|
|
26
17
|
console.log();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// ASCII art logo for InsForge
|
|
30
|
-
const INSFORGE_LOGO = `
|
|
18
|
+
}
|
|
19
|
+
const INSFORGE_LOGO = `
|
|
31
20
|
██╗███╗ ██╗███████╗███████╗ ██████╗ ██████╗ ██████╗ ███████╗
|
|
32
21
|
██║████╗ ██║██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
|
|
33
22
|
██║██╔██╗ ██║███████╗█████╗ ██║ ██║██████╔╝██║ ███╗█████╗
|
|
@@ -35,9 +24,7 @@ import {
|
|
|
35
24
|
██║██║ ╚████║███████║██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
|
|
36
25
|
╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
|
|
37
26
|
`;
|
|
38
|
-
|
|
39
|
-
// Map client names to display names for better UX
|
|
40
|
-
const clientDisplayNames = {
|
|
27
|
+
const clientDisplayNames = {
|
|
41
28
|
"claude-code": "Claude Code",
|
|
42
29
|
"cursor": "Cursor",
|
|
43
30
|
"windsurf": "Windsurf",
|
|
@@ -48,10 +35,10 @@ import {
|
|
|
48
35
|
"copilot": "GitHub Copilot",
|
|
49
36
|
"qoder": "Qoder",
|
|
50
37
|
"antigravity": "Antigravity",
|
|
51
|
-
"kiro": "Kiro"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
38
|
+
"kiro": "Kiro",
|
|
39
|
+
"opencode": "OpenCode"
|
|
40
|
+
};
|
|
41
|
+
function printPostInstallMessage(clientName) {
|
|
55
42
|
const displayName = clientDisplayNames[clientName] || clientName;
|
|
56
43
|
console.log(INSFORGE_LOGO);
|
|
57
44
|
console.log(green(`✓ InsForge MCP is now configured for ${cyan(displayName)}!`));
|
|
@@ -71,307 +58,301 @@ import {
|
|
|
71
58
|
console.log(' 💬 Discord: https://discord.com/invite/MPxwj5xVvW');
|
|
72
59
|
console.log(' ⭐ GitHub: https://github.com/insforge/insforge');
|
|
73
60
|
console.log();
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
61
|
+
}
|
|
62
|
+
function builder(y) {
|
|
63
|
+
return y.option("client", {
|
|
64
|
+
type: "string",
|
|
65
|
+
description: "Client to use for installation",
|
|
66
|
+
demandOption: false,
|
|
67
|
+
choices: clientNames
|
|
81
68
|
}).option("env", {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
69
|
+
type: "string",
|
|
70
|
+
description: "Environment variables as key=value pairs (can be used multiple times). API_KEY is required.",
|
|
71
|
+
array: true
|
|
85
72
|
}).option("dev", {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
73
|
+
type: "boolean",
|
|
74
|
+
description: "Install dev version (@insforge/mcp@dev) instead of latest",
|
|
75
|
+
default: false
|
|
89
76
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
async function handler(argv) {
|
|
77
|
+
}
|
|
78
|
+
async function handler(argv) {
|
|
93
79
|
let selectedClient = argv.client;
|
|
94
|
-
|
|
95
|
-
// If no client specified, show interactive selection
|
|
96
80
|
if (!selectedClient) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
})
|
|
111
|
-
});
|
|
81
|
+
console.log();
|
|
82
|
+
console.log(LINE);
|
|
83
|
+
console.log(` ${cyan('InsForge MCP Installer')}`);
|
|
84
|
+
console.log(LINE);
|
|
85
|
+
console.log();
|
|
86
|
+
selectedClient = await select({
|
|
87
|
+
message: 'Select your coding agent:',
|
|
88
|
+
pageSize: 15,
|
|
89
|
+
loop: false,
|
|
90
|
+
choices: clientNames.map(name => ({
|
|
91
|
+
name: clientDisplayNames[name] || name,
|
|
92
|
+
value: name
|
|
93
|
+
}))
|
|
94
|
+
});
|
|
112
95
|
}
|
|
113
|
-
|
|
114
|
-
// Validate client
|
|
115
96
|
if (!clientNames.includes(selectedClient)) {
|
|
116
|
-
|
|
117
|
-
|
|
97
|
+
logger.error(`Invalid client: ${selectedClient}. Available clients: ${clientNames.join(", ")}`);
|
|
98
|
+
return;
|
|
118
99
|
}
|
|
119
|
-
|
|
120
|
-
// Update argv.client with selected value for downstream use
|
|
121
100
|
argv.client = selectedClient;
|
|
122
101
|
const envVars = {};
|
|
123
102
|
if (argv.env && argv.env.length > 0) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
103
|
+
for (const envVar of argv.env) {
|
|
104
|
+
const [key, ...valueParts] = envVar.split("=");
|
|
105
|
+
if (key && valueParts.length > 0) {
|
|
106
|
+
envVars[key] = valueParts.join("=");
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
logger.warn(`Invalid environment variable format: ${envVar}. Expected KEY=VALUE format.`);
|
|
110
|
+
}
|
|
130
111
|
}
|
|
131
|
-
}
|
|
132
112
|
}
|
|
133
113
|
if (!envVars.API_KEY) {
|
|
134
|
-
|
|
135
|
-
|
|
114
|
+
logger.error("API_KEY environment variable is required. Use --env API_KEY=your_key");
|
|
115
|
+
return;
|
|
136
116
|
}
|
|
137
|
-
// Add default base URL if not provided
|
|
138
117
|
if (!envVars.API_BASE_URL) {
|
|
139
|
-
|
|
118
|
+
envVars.API_BASE_URL = "http://localhost:7130";
|
|
140
119
|
}
|
|
141
120
|
const name = "insforge";
|
|
142
121
|
const mcpVersion = argv.dev ? "@insforge/mcp@dev" : "@insforge/mcp@latest";
|
|
143
122
|
try {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const config = readConfig(argv.client);
|
|
149
|
-
|
|
150
|
-
// Handle different config structures for different clients
|
|
123
|
+
printHeader('InsForge MCP Installer');
|
|
124
|
+
logger.info(`Setting up MCP for ${cyan(argv.client)}...`);
|
|
125
|
+
printHeader(`Configuring ${argv.client}`);
|
|
126
|
+
const config = readConfig(argv.client);
|
|
151
127
|
if (argv.client === "claude-code") {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
128
|
+
if (!config.mcpServers)
|
|
129
|
+
config.mcpServers = {};
|
|
130
|
+
const isWindows = process.platform === 'win32';
|
|
131
|
+
config.mcpServers[name] = isWindows ? {
|
|
132
|
+
command: "cmd",
|
|
133
|
+
args: ["/c", "npx", "-y", mcpVersion],
|
|
134
|
+
env: {
|
|
135
|
+
API_KEY: envVars.API_KEY,
|
|
136
|
+
API_BASE_URL: envVars.API_BASE_URL
|
|
137
|
+
}
|
|
138
|
+
} : {
|
|
139
|
+
command: "npx",
|
|
140
|
+
args: ["-y", mcpVersion],
|
|
141
|
+
env: {
|
|
142
|
+
API_KEY: envVars.API_KEY,
|
|
143
|
+
API_BASE_URL: envVars.API_BASE_URL
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
writeConfig(config, argv.client);
|
|
147
|
+
const fs = await import('fs');
|
|
148
|
+
const claudeDir = path.join(process.cwd(), '.claude');
|
|
149
|
+
const settingsPath = path.join(claudeDir, 'settings.local.json');
|
|
150
|
+
if (!fs.existsSync(claudeDir)) {
|
|
151
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
161
152
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
153
|
+
let settings = {};
|
|
154
|
+
if (fs.existsSync(settingsPath)) {
|
|
155
|
+
try {
|
|
156
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
logger.warn(`Could not parse existing settings.local.json: ${error.message}`);
|
|
160
|
+
}
|
|
168
161
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
// Create or update .claude/settings.local.json with enableAllProjectMcpServers
|
|
173
|
-
const fs = await import('fs');
|
|
174
|
-
const claudeDir = path.join(process.cwd(), '.claude');
|
|
175
|
-
const settingsPath = path.join(claudeDir, 'settings.local.json');
|
|
176
|
-
|
|
177
|
-
if (!fs.existsSync(claudeDir)) {
|
|
178
|
-
fs.mkdirSync(claudeDir, { recursive: true });
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
let settings = {};
|
|
182
|
-
if (fs.existsSync(settingsPath)) {
|
|
183
|
-
try {
|
|
184
|
-
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
185
|
-
} catch (error) {
|
|
186
|
-
logger.warn(`Could not parse existing settings.local.json: ${error.message}`);
|
|
162
|
+
if (!settings.enabledMcpjsonServers) {
|
|
163
|
+
settings.enabledMcpjsonServers = [];
|
|
187
164
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
} else if (argv.client === "codex") {
|
|
208
|
-
// Use Codex CLI for Codex
|
|
209
|
-
const homeDir = os.homedir();
|
|
210
|
-
const isWindows = process.platform === 'win32';
|
|
211
|
-
const codexPath = isWindows
|
|
212
|
-
? path.join(homeDir, 'AppData', 'Roaming', 'npm', 'codex.cmd')
|
|
213
|
-
: 'codex';
|
|
214
|
-
|
|
215
|
-
const envArgs = Object.entries(envVars)
|
|
216
|
-
.filter(([key]) => key !== 'CLIENT_NAME')
|
|
217
|
-
.map(([key, value]) => `--env ${key}=${value}`)
|
|
218
|
-
.join(' ');
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
// First try to remove existing insforge MCP if it exists
|
|
165
|
+
if (!settings.enabledMcpjsonServers.includes("insforge")) {
|
|
166
|
+
settings.enabledMcpjsonServers.push("insforge");
|
|
167
|
+
}
|
|
168
|
+
if (settings.disabledMcpjsonServers && Array.isArray(settings.disabledMcpjsonServers)) {
|
|
169
|
+
settings.disabledMcpjsonServers = settings.disabledMcpjsonServers.filter((server) => server !== "insforge");
|
|
170
|
+
}
|
|
171
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
172
|
+
logger.info("Added \"insforge\" to enabledMcpjsonServers in .claude/settings.local.json");
|
|
173
|
+
}
|
|
174
|
+
else if (argv.client === "codex") {
|
|
175
|
+
const homeDir = os.homedir();
|
|
176
|
+
const isWindows = process.platform === 'win32';
|
|
177
|
+
const codexPath = isWindows
|
|
178
|
+
? path.join(homeDir, 'AppData', 'Roaming', 'npm', 'codex.cmd')
|
|
179
|
+
: 'codex';
|
|
180
|
+
const envArgs = Object.entries(envVars)
|
|
181
|
+
.filter(([key]) => key !== 'CLIENT_NAME')
|
|
182
|
+
.map(([key, value]) => `--env ${key}=${value}`)
|
|
183
|
+
.join(' ');
|
|
222
184
|
try {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
185
|
+
try {
|
|
186
|
+
const removeCmd = isWindows ? `"${codexPath}" mcp remove ${name}` : `codex mcp remove ${name}`;
|
|
187
|
+
execSync(removeCmd, { stdio: 'pipe' });
|
|
188
|
+
logger.info("Removed existing insforge MCP installation.");
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
logger.info("No existing insforge MCP found");
|
|
192
|
+
}
|
|
193
|
+
const command = isWindows
|
|
194
|
+
? `"${codexPath}" mcp add ${name} ${envArgs} -- npx -y ${mcpVersion}`
|
|
195
|
+
: `codex mcp add ${name} ${envArgs} -- npx -y ${mcpVersion}`;
|
|
196
|
+
logger.info(`Adding insforge MCP server (${mcpVersion})...`);
|
|
197
|
+
execSync(command, { stdio: 'inherit' });
|
|
232
198
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const command = isWindows
|
|
236
|
-
? `"${codexPath}" mcp add ${name} ${envArgs} -- npx -y ${mcpVersion}`
|
|
237
|
-
: `codex mcp add ${name} ${envArgs} -- npx -y ${mcpVersion}`;
|
|
238
|
-
logger.info(`Adding insforge MCP server (${mcpVersion})...`);
|
|
239
|
-
execSync(command, {
|
|
240
|
-
stdio: 'inherit',
|
|
241
|
-
shell: true
|
|
242
|
-
});
|
|
243
|
-
} catch (error) {
|
|
244
|
-
throw new Error(`Failed to add MCP server via Codex CLI: ${error.message}`);
|
|
245
|
-
}
|
|
246
|
-
} else if (argv.client === "cursor") {
|
|
247
|
-
// Cursor uses mcpServers at root level
|
|
248
|
-
if (!config.mcpServers) config.mcpServers = {};
|
|
249
|
-
config.mcpServers[name] = {
|
|
250
|
-
command: "npx",
|
|
251
|
-
args: ["-y", mcpVersion],
|
|
252
|
-
env: {
|
|
253
|
-
API_KEY: envVars.API_KEY,
|
|
254
|
-
API_BASE_URL: envVars.API_BASE_URL
|
|
199
|
+
catch (error) {
|
|
200
|
+
throw new Error(`Failed to add MCP server via Codex CLI: ${error.message}`);
|
|
255
201
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
202
|
+
}
|
|
203
|
+
else if (argv.client === "cursor") {
|
|
204
|
+
if (!config.mcpServers)
|
|
205
|
+
config.mcpServers = {};
|
|
206
|
+
config.mcpServers[name] = {
|
|
207
|
+
command: "npx",
|
|
208
|
+
args: ["-y", mcpVersion],
|
|
209
|
+
env: {
|
|
210
|
+
API_KEY: envVars.API_KEY,
|
|
211
|
+
API_BASE_URL: envVars.API_BASE_URL
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
writeConfig(config, argv.client);
|
|
215
|
+
}
|
|
216
|
+
else if (argv.client === "windsurf") {
|
|
217
|
+
if (!config.mcpServers)
|
|
218
|
+
config.mcpServers = {};
|
|
219
|
+
config.mcpServers[name] = {
|
|
220
|
+
command: "npx",
|
|
221
|
+
args: ["-y", mcpVersion],
|
|
222
|
+
env: {
|
|
223
|
+
API_KEY: envVars.API_KEY,
|
|
224
|
+
API_BASE_URL: envVars.API_BASE_URL
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
writeConfig(config, argv.client);
|
|
228
|
+
}
|
|
229
|
+
else if (argv.client === "cline" || argv.client === "roocode" || argv.client === "trae" || argv.client === "qoder" || argv.client === "kiro") {
|
|
230
|
+
if (!config.mcpServers)
|
|
231
|
+
config.mcpServers = {};
|
|
232
|
+
config.mcpServers[name] = {
|
|
233
|
+
command: "npx",
|
|
234
|
+
args: ["-y", mcpVersion],
|
|
235
|
+
env: {
|
|
236
|
+
API_KEY: envVars.API_KEY,
|
|
237
|
+
API_BASE_URL: envVars.API_BASE_URL
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
writeConfig(config, argv.client);
|
|
241
|
+
}
|
|
242
|
+
else if (argv.client === "copilot") {
|
|
243
|
+
const fs = await import('fs');
|
|
244
|
+
const vscodeDir = path.join(process.cwd(), '.vscode');
|
|
245
|
+
const mcpConfigPath = path.join(vscodeDir, 'mcp.json');
|
|
246
|
+
if (!fs.existsSync(vscodeDir)) {
|
|
247
|
+
fs.mkdirSync(vscodeDir, { recursive: true });
|
|
266
248
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
249
|
+
let copilotConfig = { servers: {} };
|
|
250
|
+
if (fs.existsSync(mcpConfigPath)) {
|
|
251
|
+
try {
|
|
252
|
+
copilotConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
|
|
253
|
+
if (!copilotConfig.servers)
|
|
254
|
+
copilotConfig.servers = {};
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
logger.warn(`Could not parse existing mcp.json: ${error.message}`);
|
|
258
|
+
copilotConfig = { servers: {} };
|
|
259
|
+
}
|
|
277
260
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
261
|
+
copilotConfig.servers[name] = {
|
|
262
|
+
command: "npx",
|
|
263
|
+
args: ["-y", mcpVersion],
|
|
264
|
+
env: {
|
|
265
|
+
API_KEY: envVars.API_KEY,
|
|
266
|
+
API_BASE_URL: envVars.API_BASE_URL
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
fs.writeFileSync(mcpConfigPath, JSON.stringify(copilotConfig, null, 2));
|
|
270
|
+
logger.info(`Configured Copilot MCP at: ${mcpConfigPath}`);
|
|
271
|
+
}
|
|
272
|
+
else if (argv.client === "antigravity") {
|
|
273
|
+
if (!config.mcpServers)
|
|
274
|
+
config.mcpServers = {};
|
|
275
|
+
config.mcpServers[name] = {
|
|
276
|
+
command: "npx",
|
|
277
|
+
args: [
|
|
278
|
+
"-y",
|
|
279
|
+
mcpVersion,
|
|
280
|
+
"--api_key",
|
|
281
|
+
envVars.API_KEY,
|
|
282
|
+
"--api_base_url",
|
|
283
|
+
envVars.API_BASE_URL
|
|
284
|
+
],
|
|
285
|
+
env: {}
|
|
286
|
+
};
|
|
287
|
+
writeConfig(config, argv.client);
|
|
288
|
+
}
|
|
289
|
+
else if (argv.client === "opencode") {
|
|
290
|
+
const fs = await import('fs');
|
|
291
|
+
const opencodeConfigPath = path.join(process.cwd(), 'opencode.json');
|
|
292
|
+
let opencodeConfig = {};
|
|
293
|
+
if (fs.existsSync(opencodeConfigPath)) {
|
|
294
|
+
try {
|
|
295
|
+
opencodeConfig = JSON.parse(fs.readFileSync(opencodeConfigPath, 'utf8'));
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
logger.warn(`Could not parse existing opencode.json: ${error.message}`);
|
|
299
|
+
opencodeConfig = {};
|
|
300
|
+
}
|
|
298
301
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
302
|
+
if (!opencodeConfig.mcp)
|
|
303
|
+
opencodeConfig.mcp = {};
|
|
304
|
+
opencodeConfig.mcp[name] = {
|
|
305
|
+
type: "local",
|
|
306
|
+
command: ["npx", "-y", mcpVersion],
|
|
307
|
+
environment: {
|
|
308
|
+
API_KEY: envVars.API_KEY,
|
|
309
|
+
API_BASE_URL: envVars.API_BASE_URL
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
fs.writeFileSync(opencodeConfigPath, JSON.stringify(opencodeConfig, null, 2));
|
|
313
|
+
logger.info(`Configured OpenCode MCP at: ${opencodeConfigPath}`);
|
|
314
|
+
}
|
|
315
|
+
// Fetch instructions documentation and save to appropriate files
|
|
316
|
+
let instructionsContent = null;
|
|
317
|
+
try {
|
|
318
|
+
const fetch = (await import('node-fetch')).default;
|
|
319
|
+
const apiBaseUrl = envVars.API_BASE_URL || "http://localhost:7130";
|
|
320
|
+
const response = await fetch(`${apiBaseUrl}/api/docs/instructions`);
|
|
321
|
+
if (response.ok) {
|
|
322
|
+
const result = await response.json();
|
|
323
|
+
if (result && result.content) {
|
|
324
|
+
instructionsContent = result.content;
|
|
325
|
+
}
|
|
307
326
|
}
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
fs.writeFileSync(mcpConfigPath, JSON.stringify(copilotConfig, null, 2));
|
|
311
|
-
logger.info(`Configured Copilot MCP at: ${mcpConfigPath}`);
|
|
312
|
-
} else if (argv.client === "antigravity") {
|
|
313
|
-
// Antigravity uses args instead of env vars
|
|
314
|
-
if (!config.mcpServers) config.mcpServers = {};
|
|
315
|
-
config.mcpServers[name] = {
|
|
316
|
-
command: "npx",
|
|
317
|
-
args: [
|
|
318
|
-
"-y",
|
|
319
|
-
mcpVersion,
|
|
320
|
-
"--api_key",
|
|
321
|
-
envVars.API_KEY,
|
|
322
|
-
"--api_base_url",
|
|
323
|
-
envVars.API_BASE_URL
|
|
324
|
-
],
|
|
325
|
-
env: {}
|
|
326
|
-
};
|
|
327
|
-
writeConfig(config, argv.client);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// Fetch instructions documentation and save to appropriate files
|
|
331
|
-
let instructionsContent = null;
|
|
332
|
-
try {
|
|
333
|
-
const fetch = (await import('node-fetch')).default;
|
|
334
|
-
const fs = await import('fs');
|
|
335
|
-
const apiBaseUrl = envVars.API_BASE_URL || "http://localhost:7130";
|
|
336
|
-
const response = await fetch(`${apiBaseUrl}/api/docs/instructions`);
|
|
337
|
-
|
|
338
|
-
if (response.ok) {
|
|
339
|
-
const result = await response.json();
|
|
340
|
-
if (result && result.content) {
|
|
341
|
-
instructionsContent = result.content;
|
|
342
|
-
}
|
|
343
327
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const fs = await import('fs');
|
|
351
|
-
const frontmatter = `---
|
|
328
|
+
catch (fetchError) {
|
|
329
|
+
logger.warn(`Could not download instructions: ${fetchError.message}`);
|
|
330
|
+
}
|
|
331
|
+
if (instructionsContent) {
|
|
332
|
+
const fs = await import('fs');
|
|
333
|
+
const frontmatter = `---
|
|
352
334
|
description: Instructions building apps with MCP
|
|
353
335
|
globs: *
|
|
354
336
|
alwaysApply: true
|
|
355
337
|
---
|
|
356
338
|
|
|
357
339
|
`;
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
340
|
+
const contentWithFrontmatter = frontmatter + instructionsContent;
|
|
341
|
+
const agentsMdPath = path.join(process.cwd(), 'AGENTS.md');
|
|
342
|
+
fs.writeFileSync(agentsMdPath, contentWithFrontmatter, 'utf-8');
|
|
343
|
+
logger.info(`Saved instructions to: ${agentsMdPath}`);
|
|
344
|
+
}
|
|
345
|
+
printHeader('Setup Complete!');
|
|
346
|
+
printPostInstallMessage(argv.client);
|
|
347
|
+
}
|
|
348
|
+
catch (e) {
|
|
349
|
+
logger.error(red(e.message));
|
|
368
350
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (!process.argv.slice(2).length || process.argv[2].startsWith("--")) {
|
|
351
|
+
}
|
|
352
|
+
const parser = yargs(hideBin(process.argv)).scriptName("@insforge/install").command("install", "Install Insforge MCP server", builder, handler).help().alias("h", "help").version().alias("v", "version");
|
|
353
|
+
if (!process.argv.slice(2).length || process.argv[2].startsWith("--")) {
|
|
373
354
|
parser.parse(["install", ...process.argv.slice(2)]);
|
|
374
|
-
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
375
357
|
parser.parse();
|
|
376
|
-
|
|
377
|
-
|
|
358
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface McpConfig {
|
|
2
|
+
mcpServers?: Record<string, unknown>;
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
}
|
|
5
|
+
export declare const logger: import("consola").ConsolaInstance;
|
|
6
|
+
export declare const clientNames: string[];
|
|
7
|
+
export declare function readConfig(client: string, local?: boolean): McpConfig;
|
|
8
|
+
export declare function writeConfig(config: McpConfig, client: string, local?: boolean): void;
|
|
9
|
+
export {};
|
package/dist/utils.js
CHANGED
|
@@ -1,158 +1,147 @@
|
|
|
1
|
-
// src/client-config.ts
|
|
2
1
|
import fs from "fs";
|
|
3
2
|
import os from "os";
|
|
4
3
|
import path from "path";
|
|
5
4
|
import process from "process";
|
|
6
|
-
|
|
7
|
-
// src/logger.ts
|
|
8
5
|
import { createConsola } from "consola";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
vscodePath: path.join("Code/User/globalStorage")
|
|
26
|
-
}
|
|
6
|
+
export const logger = createConsola({});
|
|
7
|
+
const verbose = (msg) => logger.verbose(msg);
|
|
8
|
+
const homeDir = os.homedir();
|
|
9
|
+
const platformPaths = {
|
|
10
|
+
win32: {
|
|
11
|
+
baseDir: process.env.APPDATA || path.join(homeDir, "AppData", "Roaming"),
|
|
12
|
+
vscodePath: path.join("Code", "User", "globalStorage")
|
|
13
|
+
},
|
|
14
|
+
darwin: {
|
|
15
|
+
baseDir: path.join(homeDir, "Library", "Application Support"),
|
|
16
|
+
vscodePath: path.join("Code", "User", "globalStorage")
|
|
17
|
+
},
|
|
18
|
+
linux: {
|
|
19
|
+
baseDir: process.env.XDG_CONFIG_HOME || path.join(homeDir, ".config"),
|
|
20
|
+
vscodePath: path.join("Code/User/globalStorage")
|
|
21
|
+
}
|
|
27
22
|
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
23
|
+
const platform = process.platform;
|
|
24
|
+
const { baseDir, vscodePath } = platformPaths[platform] ?? platformPaths.linux;
|
|
25
|
+
const clientPaths = {
|
|
26
|
+
cursor: {
|
|
27
|
+
type: "file",
|
|
28
|
+
path: path.join(homeDir, ".cursor", "mcp.json"),
|
|
29
|
+
localPath: path.join(process.cwd(), ".cursor", "mcp.json")
|
|
30
|
+
},
|
|
31
|
+
"claude-code": {
|
|
32
|
+
type: "file",
|
|
33
|
+
path: path.join(process.cwd(), ".mcp.json")
|
|
34
|
+
},
|
|
35
|
+
windsurf: {
|
|
36
|
+
type: "file",
|
|
37
|
+
path: path.join(homeDir, ".codeium", "windsurf", "mcp_config.json")
|
|
38
|
+
},
|
|
39
|
+
cline: {
|
|
40
|
+
type: "file",
|
|
41
|
+
path: path.join(baseDir, vscodePath, "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json")
|
|
42
|
+
},
|
|
43
|
+
roocode: {
|
|
44
|
+
type: "file",
|
|
45
|
+
path: path.join(baseDir, vscodePath, "rooveterinaryinc.roo-cline", "settings", "mcp_settings.json")
|
|
46
|
+
},
|
|
47
|
+
trae: {
|
|
48
|
+
type: "file",
|
|
49
|
+
path: path.join(baseDir, "Trae", "User", "mcp.json")
|
|
50
|
+
},
|
|
51
|
+
codex: {
|
|
52
|
+
type: "file",
|
|
53
|
+
path: path.join(homeDir, ".codex", "mcp_config.json")
|
|
54
|
+
},
|
|
55
|
+
copilot: {
|
|
56
|
+
type: "file",
|
|
57
|
+
path: path.join(process.cwd(), ".vscode", "mcp.json")
|
|
58
|
+
},
|
|
59
|
+
qoder: {
|
|
60
|
+
type: "file",
|
|
61
|
+
path: path.join(baseDir, "Qoder", "SharedClientCache", "mcp.json")
|
|
62
|
+
},
|
|
63
|
+
antigravity: {
|
|
64
|
+
type: "file",
|
|
65
|
+
path: path.join(homeDir, ".gemini", "antigravity", "mcp_config.json")
|
|
66
|
+
},
|
|
67
|
+
kiro: {
|
|
68
|
+
type: "file",
|
|
69
|
+
path: path.join(homeDir, ".kiro", "settings", "mcp.json")
|
|
70
|
+
},
|
|
71
|
+
opencode: {
|
|
72
|
+
type: "file",
|
|
73
|
+
path: path.join(process.cwd(), "opencode.json")
|
|
74
|
+
}
|
|
76
75
|
};
|
|
77
|
-
|
|
76
|
+
export const clientNames = Object.keys(clientPaths);
|
|
78
77
|
function getConfigPath(client, local) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
78
|
+
const normalizedClient = client?.toLowerCase() || "claude-code";
|
|
79
|
+
verbose(`Getting config path for client: ${normalizedClient}${local ? " (local)" : ""}`);
|
|
80
|
+
const configTarget = clientPaths[normalizedClient];
|
|
81
|
+
if (!configTarget) {
|
|
82
|
+
throw new Error(`Unsupported client: ${client}. Supported clients: ${clientNames.join(", ")}`);
|
|
83
|
+
}
|
|
84
|
+
if (local && configTarget.localPath) {
|
|
85
|
+
verbose(`Using local config path for ${normalizedClient}: ${configTarget.localPath}`);
|
|
86
|
+
return { ...configTarget, path: configTarget.localPath };
|
|
87
|
+
}
|
|
88
|
+
verbose(`Using default config path for ${normalizedClient}: ${configTarget.path}`);
|
|
89
|
+
return configTarget;
|
|
91
90
|
}
|
|
92
|
-
function readConfig(client, local) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
91
|
+
export function readConfig(client, local) {
|
|
92
|
+
verbose(`Reading config for client: ${client}${local ? " (local)" : ""}`);
|
|
93
|
+
try {
|
|
94
|
+
const configPath = getConfigPath(client, local);
|
|
95
|
+
verbose(`Checking if config file exists at: ${configPath.path}`);
|
|
96
|
+
if (!fs.existsSync(configPath.path)) {
|
|
97
|
+
verbose("Config file not found, returning default empty config");
|
|
98
|
+
return { mcpServers: {} };
|
|
99
|
+
}
|
|
100
|
+
verbose("Reading config file content");
|
|
101
|
+
const rawConfig = JSON.parse(fs.readFileSync(configPath.path, "utf8"));
|
|
102
|
+
verbose(`Config loaded successfully: ${JSON.stringify(rawConfig, null, 2)}`);
|
|
103
|
+
return rawConfig;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
verbose(`Error reading config: ${error instanceof Error ? error.stack : JSON.stringify(error)}`);
|
|
107
|
+
return { mcpServers: {} };
|
|
101
108
|
}
|
|
102
|
-
verbose("Reading config file content");
|
|
103
|
-
const rawConfig = JSON.parse(fs.readFileSync(configPath.path, "utf8"));
|
|
104
|
-
verbose(`Config loaded successfully: ${JSON.stringify(rawConfig, null, 2)}`);
|
|
105
|
-
// Return the raw config to preserve existing structure
|
|
106
|
-
return rawConfig;
|
|
107
|
-
} catch (error) {
|
|
108
|
-
verbose(`Error reading config: ${error instanceof Error ? error.stack : JSON.stringify(error)}`);
|
|
109
|
-
return { mcpServers: {} };
|
|
110
|
-
}
|
|
111
109
|
}
|
|
112
|
-
function writeConfig(config, client, local) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const configPath = getConfigPath(client, local);
|
|
123
|
-
writeConfigFile(config, configPath);
|
|
110
|
+
export function writeConfig(config, client, local) {
|
|
111
|
+
verbose(`Writing config for client: ${client || "default"}${local ? " (local)" : ""}`);
|
|
112
|
+
verbose(`Config data: ${JSON.stringify(config, null, 2)}`);
|
|
113
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
114
|
+
verbose("Invalid mcpServers structure in config");
|
|
115
|
+
throw new Error("Invalid mcpServers structure");
|
|
116
|
+
}
|
|
117
|
+
const configPath = getConfigPath(client, local);
|
|
118
|
+
writeConfigFile(config, configPath);
|
|
124
119
|
}
|
|
125
120
|
function writeConfigFile(config, target) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
121
|
+
const configDir = path.dirname(target.path);
|
|
122
|
+
verbose(`Ensuring config directory exists: ${configDir}`);
|
|
123
|
+
if (!fs.existsSync(configDir)) {
|
|
124
|
+
verbose(`Creating directory: ${configDir}`);
|
|
125
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
126
|
+
}
|
|
127
|
+
let existingConfig = { mcpServers: {} };
|
|
128
|
+
try {
|
|
129
|
+
if (fs.existsSync(target.path)) {
|
|
130
|
+
verbose("Reading existing config file for merging");
|
|
131
|
+
existingConfig = JSON.parse(fs.readFileSync(target.path, "utf8"));
|
|
132
|
+
verbose(`Existing config loaded: ${JSON.stringify(existingConfig, null, 2)}`);
|
|
133
|
+
}
|
|
138
134
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
135
|
+
catch (error) {
|
|
136
|
+
verbose(`Error reading existing config for merge: ${error instanceof Error ? error.message : String(error)}`);
|
|
137
|
+
}
|
|
138
|
+
verbose("Merging configs");
|
|
139
|
+
const mergedConfig = {
|
|
140
|
+
...existingConfig,
|
|
141
|
+
...config
|
|
142
|
+
};
|
|
143
|
+
verbose(`Merged config: ${JSON.stringify(mergedConfig, null, 2)}`);
|
|
144
|
+
verbose(`Writing config to file: ${target.path}`);
|
|
145
|
+
fs.writeFileSync(target.path, JSON.stringify(mergedConfig, null, 2));
|
|
146
|
+
verbose("Config successfully written");
|
|
151
147
|
}
|
|
152
|
-
export {
|
|
153
|
-
logger,
|
|
154
|
-
clientNames,
|
|
155
|
-
getConfigPath,
|
|
156
|
-
readConfig,
|
|
157
|
-
writeConfig
|
|
158
|
-
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@insforge/install",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.52",
|
|
4
4
|
"description": "CLI tool for installing Insforge MCP servers across different AI clients",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
6
9
|
"main": "dist/index.js",
|
|
7
10
|
"bin": {
|
|
8
11
|
"insforge-install": "dist/index.js"
|
|
9
12
|
},
|
|
10
13
|
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"prepublishOnly": "npm run build",
|
|
11
16
|
"start": "node dist/index.js"
|
|
12
17
|
},
|
|
13
18
|
"dependencies": {
|
|
@@ -26,5 +31,10 @@
|
|
|
26
31
|
"license": "MIT",
|
|
27
32
|
"publishConfig": {
|
|
28
33
|
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^20.19.30",
|
|
37
|
+
"@types/yargs": "^17.0.35",
|
|
38
|
+
"typescript": "^5.9.3"
|
|
29
39
|
}
|
|
30
40
|
}
|
package/.mcp.json
DELETED
package/AGENTS.md
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Instructions building apps with MCP
|
|
3
|
-
globs: *
|
|
4
|
-
alwaysApply: true
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# InsForge SDK Documentation - Overview
|
|
8
|
-
|
|
9
|
-
## What is InsForge?
|
|
10
|
-
|
|
11
|
-
Backend-as-a-service (BaaS) platform providing:
|
|
12
|
-
|
|
13
|
-
- **Database**: PostgreSQL with PostgREST API
|
|
14
|
-
- **Authentication**: Email/password + OAuth (Google, GitHub)
|
|
15
|
-
- **Storage**: File upload/download
|
|
16
|
-
- **AI**: Chat completions and image generation (OpenAI-compatible)
|
|
17
|
-
- **Functions**: Serverless function deployment
|
|
18
|
-
|
|
19
|
-
## Installation
|
|
20
|
-
|
|
21
|
-
### 🚨 CRITICAL: Follow these steps in order
|
|
22
|
-
|
|
23
|
-
### Step 1: Download Template
|
|
24
|
-
|
|
25
|
-
Use the `download-template` MCP tool to create a new project with your backend URL and anon key pre-configured.
|
|
26
|
-
|
|
27
|
-
### Step 2: Install SDK
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
npm install @insforge/sdk@latest
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Step 3: Create SDK Client
|
|
34
|
-
|
|
35
|
-
You must create a client instance using `createClient()` with your base URL and anon key:
|
|
36
|
-
|
|
37
|
-
```javascript
|
|
38
|
-
import { createClient } from '@insforge/sdk';
|
|
39
|
-
|
|
40
|
-
const client = createClient({
|
|
41
|
-
baseUrl: 'https://your-app.region.insforge.app', // Your InsForge backend URL
|
|
42
|
-
anonKey: 'your-anon-key-here' // Get this from backend metadata
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
**API BASE URL**: Your API base URL is `https://your-app.region.insforge.app`.
|
|
48
|
-
|
|
49
|
-
## Getting Detailed Documentation
|
|
50
|
-
|
|
51
|
-
### 🚨 CRITICAL: Always Fetch Documentation Before Writing Code
|
|
52
|
-
|
|
53
|
-
Before writing or editing any InsForge integration code, you **MUST** call the `fetch-docs` MCP tool to get the latest SDK documentation. This ensures you have accurate, up-to-date implementation patterns.
|
|
54
|
-
|
|
55
|
-
### Use the InsForge `fetch-docs` MCP tool to get specific SDK documentation:
|
|
56
|
-
|
|
57
|
-
Available documentation types:
|
|
58
|
-
|
|
59
|
-
- `"instructions"` - Essential backend setup (START HERE)
|
|
60
|
-
- `"db-sdk"` - Database operations with SDK
|
|
61
|
-
- **Authentication** - Choose based on implementation:
|
|
62
|
-
- `"auth-sdk"` - Direct SDK methods for custom auth flows
|
|
63
|
-
- `"auth-components-react"` - Pre-built auth UI for React+Vite (singlepage App)
|
|
64
|
-
- `"auth-components-react-router"` - Pre-built auth UI for React(Vite+React Router) (Multipage App)
|
|
65
|
-
- `"auth-components-nextjs"` - Pre-built auth UI for Nextjs (SSR App)
|
|
66
|
-
- `"storage-sdk"` - File storage operations
|
|
67
|
-
- `"functions-sdk"` - Serverless functions invocation
|
|
68
|
-
- `"ai-integration-sdk"` - AI chat and image generation
|
|
69
|
-
- `"real-time"` - Real-time pub/sub (database + client events) via WebSockets
|
|
70
|
-
- `"deployment"` - Deploy frontend applications via MCP tool
|
|
71
|
-
|
|
72
|
-
## When to Use SDK vs MCP Tools
|
|
73
|
-
|
|
74
|
-
### Always SDK for Application Logic:
|
|
75
|
-
|
|
76
|
-
- Authentication (register, login, logout, profiles)
|
|
77
|
-
- Database CRUD (select, insert, update, delete)
|
|
78
|
-
- Storage operations (upload, download files)
|
|
79
|
-
- AI operations (chat, image generation)
|
|
80
|
-
- Serverless function invocation
|
|
81
|
-
|
|
82
|
-
### Use MCP Tools for Infrastructure:
|
|
83
|
-
|
|
84
|
-
- Project scaffolding (`download-template`) - Download starter templates with InsForge integration
|
|
85
|
-
- Backend setup and metadata (`get-backend-metadata`)
|
|
86
|
-
- Database schema management (`run-raw-sql`, `get-table-schema`)
|
|
87
|
-
- Storage bucket creation (`create-bucket`, `list-buckets`, `delete-bucket`)
|
|
88
|
-
- Serverless function deployment (`create-function`, `update-function`, `delete-function`)
|
|
89
|
-
- Frontend deployment (`create-deployment`) - Deploy frontend apps to InsForge hosting
|
|
90
|
-
|
|
91
|
-
## Important Notes
|
|
92
|
-
|
|
93
|
-
- For auth: use `auth-sdk` for custom UI, or framework-specific components for pre-built UI
|
|
94
|
-
- SDK returns `{data, error}` structure for all operations
|
|
95
|
-
- Database inserts require array format: `[{...}]`
|
|
96
|
-
- Serverless functions have single endpoint (no subpaths)
|
|
97
|
-
- Storage: Upload files to buckets, store URLs in database
|
|
98
|
-
- AI operations are OpenAI-compatible
|
|
99
|
-
- **EXTRA IMPORTANT**: Use Tailwind CSS 3.4 (do not upgrade to v4). Lock these dependencies in `package.json`
|