@solongate/proxy 0.82.21 → 0.82.22

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/inject.js DELETED
@@ -1,375 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/inject.ts
4
- import { readFileSync, writeFileSync, existsSync, copyFileSync } from "fs";
5
- import { resolve } from "path";
6
- import { execSync } from "child_process";
7
-
8
- // src/cli-utils.ts
9
- var c = {
10
- reset: "\x1B[0m",
11
- bold: "\x1B[1m",
12
- dim: "\x1B[2m",
13
- italic: "\x1B[3m",
14
- white: "\x1B[97m",
15
- gray: "\x1B[90m",
16
- blue1: "\x1B[38;2;20;50;160m",
17
- blue2: "\x1B[38;2;40;80;190m",
18
- blue3: "\x1B[38;2;60;110;215m",
19
- blue4: "\x1B[38;2;90;140;230m",
20
- blue5: "\x1B[38;2;130;170;240m",
21
- blue6: "\x1B[38;2;170;200;250m",
22
- green: "\x1B[38;2;80;200;120m",
23
- red: "\x1B[38;2;220;80;80m",
24
- cyan: "\x1B[38;2;100;200;220m",
25
- yellow: "\x1B[38;2;220;200;80m",
26
- bgBlue: "\x1B[48;2;20;50;160m"
27
- };
28
- function log(msg) {
29
- process.stderr.write(msg + "\n");
30
- }
31
- var BANNER_FULL = [
32
- " \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
33
- " \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D",
34
- " \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 ",
35
- " \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u255D ",
36
- " \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
37
- " \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
38
- ];
39
- var BANNER_COLORS = [c.blue1, c.blue2, c.blue3, c.blue4, c.blue5, c.blue6];
40
- function printBanner(subtitle) {
41
- log("");
42
- for (let i = 0; i < BANNER_FULL.length; i++) {
43
- log(`${c.bold}${BANNER_COLORS[i]}${BANNER_FULL[i]}${c.reset}`);
44
- }
45
- log("");
46
- log(` ${c.dim}${c.italic}${subtitle}${c.reset}`);
47
- log("");
48
- }
49
-
50
- // src/inject.ts
51
- function parseInjectArgs(argv) {
52
- const args = argv.slice(2);
53
- const opts = {
54
- dryRun: false,
55
- restore: false,
56
- skipInstall: false
57
- };
58
- for (let i = 0; i < args.length; i++) {
59
- switch (args[i]) {
60
- case "--file":
61
- opts.file = args[++i];
62
- break;
63
- case "--dry-run":
64
- opts.dryRun = true;
65
- break;
66
- case "--restore":
67
- opts.restore = true;
68
- break;
69
- case "--skip-install":
70
- opts.skipInstall = true;
71
- break;
72
- case "--help":
73
- case "-h":
74
- printHelp();
75
- process.exit(0);
76
- }
77
- }
78
- return opts;
79
- }
80
- function printHelp() {
81
- log(`
82
- SolonGate Inject \u2014 Add security to your MCP server in seconds
83
-
84
- USAGE
85
- npx @solongate/proxy inject [options]
86
-
87
- OPTIONS
88
- --file <path> Entry file to modify (default: auto-detect)
89
- --dry-run Preview changes without writing
90
- --restore Restore original file from backup
91
- --skip-install Don't install SDK package
92
- -h, --help Show this help message
93
-
94
- EXAMPLES
95
- npx @solongate/proxy inject # Auto-detect and inject
96
- npx @solongate/proxy inject --file src/main.ts # Specify entry file
97
- npx @solongate/proxy inject --dry-run # Preview changes
98
- npx @solongate/proxy inject --restore # Undo injection
99
-
100
- WHAT IT DOES
101
- Replaces McpServer with SecureMcpServer (2 lines changed)
102
- All tool() calls are automatically protected by SolonGate.
103
- `);
104
- }
105
- function detectProject() {
106
- if (!existsSync(resolve("package.json"))) return false;
107
- try {
108
- const pkg = JSON.parse(readFileSync(resolve("package.json"), "utf-8"));
109
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
110
- return !!(allDeps["@modelcontextprotocol/sdk"] || allDeps["@modelcontextprotocol/server"]);
111
- } catch {
112
- return false;
113
- }
114
- }
115
- function findTsEntryFile() {
116
- try {
117
- const pkg = JSON.parse(readFileSync(resolve("package.json"), "utf-8"));
118
- if (pkg.bin) {
119
- const binPath = typeof pkg.bin === "string" ? pkg.bin : Object.values(pkg.bin)[0];
120
- if (typeof binPath === "string") {
121
- const srcPath = binPath.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
122
- if (existsSync(resolve(srcPath))) return resolve(srcPath);
123
- if (existsSync(resolve(binPath))) return resolve(binPath);
124
- }
125
- }
126
- if (pkg.main) {
127
- const srcPath = pkg.main.replace(/^\.\/dist\//, "./src/").replace(/\.js$/, ".ts");
128
- if (existsSync(resolve(srcPath))) return resolve(srcPath);
129
- }
130
- } catch {
131
- }
132
- const candidates = [
133
- "src/index.ts",
134
- "src/server.ts",
135
- "src/main.ts",
136
- "index.ts",
137
- "server.ts",
138
- "main.ts"
139
- ];
140
- for (const c2 of candidates) {
141
- const full = resolve(c2);
142
- if (existsSync(full)) {
143
- try {
144
- const content = readFileSync(full, "utf-8");
145
- if (content.includes("McpServer") || content.includes("McpServer")) {
146
- return full;
147
- }
148
- } catch {
149
- }
150
- }
151
- }
152
- for (const c2 of candidates) {
153
- if (existsSync(resolve(c2))) return resolve(c2);
154
- }
155
- return null;
156
- }
157
- function detectPackageManager() {
158
- if (existsSync(resolve("pnpm-lock.yaml"))) return "pnpm";
159
- if (existsSync(resolve("yarn.lock"))) return "yarn";
160
- return "npm";
161
- }
162
- function installSdk() {
163
- try {
164
- const pkg = JSON.parse(readFileSync(resolve("package.json"), "utf-8"));
165
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
166
- if (allDeps["@solongate/proxy"]) {
167
- log(" @solongate/proxy already installed");
168
- return true;
169
- }
170
- } catch {
171
- }
172
- const pm = detectPackageManager();
173
- const cmd = pm === "yarn" ? "yarn add @solongate/proxy" : `${pm} install @solongate/proxy`;
174
- log(` Installing @solongate/proxy via ${pm}...`);
175
- try {
176
- execSync(cmd, { stdio: "pipe", cwd: process.cwd() });
177
- return true;
178
- } catch (err) {
179
- log(` Failed to install: ${err instanceof Error ? err.message : String(err)}`);
180
- log(" You can install manually: npm install @solongate/proxy");
181
- return false;
182
- }
183
- }
184
- function injectTypeScript(filePath) {
185
- const original = readFileSync(filePath, "utf-8");
186
- const changes = [];
187
- let modified = original;
188
- if (modified.includes("SecureMcpServer")) {
189
- return { file: filePath, changes: ["Already injected \u2014 skipping"], original, modified };
190
- }
191
- const mcpImportPatterns = [
192
- // Solo import: import { McpServer } from '...'
193
- /import\s*\{\s*McpServer\s*\}\s*from\s*['"][^'"]+['"]/,
194
- // Import with others: import { McpServer, ... } from '...'
195
- /import\s*\{[^}]*McpServer[^}]*\}\s*from\s*['"][^'"]+['"]/
196
- ];
197
- let importReplaced = false;
198
- for (const pattern of mcpImportPatterns) {
199
- const match = modified.match(pattern);
200
- if (match) {
201
- const importLine = match[0];
202
- const namedImports = importLine.match(/\{([^}]+)\}/)?.[1] ?? "";
203
- const importNames = namedImports.split(",").map((s) => s.trim()).filter(Boolean);
204
- if (importNames.length === 1 && importNames[0] === "McpServer") {
205
- modified = modified.replace(
206
- importLine,
207
- `import { SecureMcpServer } from '@solongate/proxy'`
208
- );
209
- changes.push("Replaced McpServer import with SecureMcpServer from @solongate/proxy");
210
- } else {
211
- const otherImports = importNames.filter((n) => n !== "McpServer");
212
- const fromModule = importLine.match(/from\s*['"]([^'"]+)['"]/)?.[1] ?? "";
213
- modified = modified.replace(
214
- importLine,
215
- `import { ${otherImports.join(", ")} } from '${fromModule}';
216
- import { SecureMcpServer } from '@solongate/proxy'`
217
- );
218
- changes.push("Removed McpServer from existing import, added SecureMcpServer import from @solongate/proxy");
219
- }
220
- importReplaced = true;
221
- break;
222
- }
223
- }
224
- if (!importReplaced) {
225
- const insertPos = findImportInsertPosition(modified);
226
- modified = modified.slice(0, insertPos) + `import { SecureMcpServer } from '@solongate/proxy';
227
- ` + modified.slice(insertPos);
228
- changes.push("Added SecureMcpServer import from @solongate/proxy");
229
- }
230
- const constructorPattern = /new\s+McpServer\s*\(/g;
231
- const constructorCount = (modified.match(constructorPattern) || []).length;
232
- if (constructorCount > 0) {
233
- modified = modified.replace(constructorPattern, "new SecureMcpServer(");
234
- changes.push(`Replaced ${constructorCount} McpServer constructor(s) with SecureMcpServer`);
235
- }
236
- return { file: filePath, changes, original, modified };
237
- }
238
- function findImportInsertPosition(content) {
239
- let pos = 0;
240
- if (content.startsWith("#!")) {
241
- pos = content.indexOf("\n") + 1;
242
- }
243
- const lines = content.slice(pos).split("\n");
244
- let offset = pos;
245
- for (const line of lines) {
246
- const trimmed = line.trim();
247
- if (trimmed === "" || trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*") || trimmed.startsWith("*/")) {
248
- offset += line.length + 1;
249
- } else {
250
- break;
251
- }
252
- }
253
- const importRegex = /^import\s+.+$/gm;
254
- let lastImportEnd = offset;
255
- let importMatch;
256
- while ((importMatch = importRegex.exec(content)) !== null) {
257
- lastImportEnd = importMatch.index + importMatch[0].length + 1;
258
- }
259
- return lastImportEnd > offset ? lastImportEnd : offset;
260
- }
261
- function showDiff(result) {
262
- if (result.original === result.modified) {
263
- log(" No changes needed.");
264
- return;
265
- }
266
- const origLines = result.original.split("\n");
267
- const modLines = result.modified.split("\n");
268
- log("");
269
- log(` File: ${result.file}`);
270
- log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
271
- const maxLines = Math.max(origLines.length, modLines.length);
272
- let diffCount = 0;
273
- for (let i = 0; i < maxLines; i++) {
274
- const orig = origLines[i];
275
- const mod = modLines[i];
276
- if (orig !== mod) {
277
- if (diffCount < 30) {
278
- if (orig !== void 0) log(` - ${orig}`);
279
- if (mod !== void 0) log(` + ${mod}`);
280
- }
281
- diffCount++;
282
- }
283
- }
284
- if (diffCount > 30) {
285
- log(` ... and ${diffCount - 30} more line changes`);
286
- }
287
- log("");
288
- }
289
- async function main() {
290
- const opts = parseInjectArgs(process.argv);
291
- printBanner("Inject SDK");
292
- if (!detectProject()) {
293
- log(" Could not detect a TypeScript MCP server project.");
294
- log(" Make sure you are in a project directory with:");
295
- log(" package.json + @modelcontextprotocol/sdk in dependencies");
296
- log("");
297
- log(" To create a new MCP server: npx @solongate/proxy create <name>");
298
- process.exit(1);
299
- }
300
- log(" Language: TypeScript");
301
- const entryFile = opts.file ? resolve(opts.file) : findTsEntryFile();
302
- if (!entryFile || !existsSync(entryFile)) {
303
- log(` Could not find entry file.${opts.file ? ` File not found: ${opts.file}` : ""}`);
304
- log("");
305
- log(" Specify it manually: --file <path>");
306
- log("");
307
- log(" Common entry points:");
308
- log(" src/index.ts, src/server.ts, index.ts");
309
- process.exit(1);
310
- }
311
- log(` Entry: ${entryFile}`);
312
- log("");
313
- const backupPath = entryFile + ".solongate-backup";
314
- if (opts.restore) {
315
- if (!existsSync(backupPath)) {
316
- log(" No backup found. Nothing to restore.");
317
- process.exit(1);
318
- }
319
- copyFileSync(backupPath, entryFile);
320
- log(` Restored original file from backup.`);
321
- log(` Backup: ${backupPath}`);
322
- process.exit(0);
323
- }
324
- if (!opts.skipInstall && !opts.dryRun) {
325
- installSdk();
326
- log("");
327
- }
328
- const result = injectTypeScript(entryFile);
329
- log(` Changes (${result.changes.length}):`);
330
- for (const change of result.changes) {
331
- log(` - ${change}`);
332
- }
333
- if (result.changes.length === 1 && result.changes[0].includes("Already injected")) {
334
- log("");
335
- log(" Your MCP server is already protected by SolonGate!");
336
- process.exit(0);
337
- }
338
- if (result.original === result.modified) {
339
- log("");
340
- log(" No changes were made. The file may not contain recognizable MCP patterns.");
341
- log(" See docs: https://solongate.com/docs/integration");
342
- process.exit(0);
343
- }
344
- if (opts.dryRun) {
345
- log("");
346
- log(" --- DRY RUN (no changes written) ---");
347
- showDiff(result);
348
- log(" To apply: npx @solongate/proxy inject");
349
- process.exit(0);
350
- }
351
- if (!existsSync(backupPath)) {
352
- copyFileSync(entryFile, backupPath);
353
- log("");
354
- log(` Backup: ${backupPath}`);
355
- }
356
- writeFileSync(entryFile, result.modified);
357
- log("");
358
- log(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
359
- log(" \u2502 SolonGate SDK injected successfully! \u2502");
360
- log(" \u2502 \u2502");
361
- log(" \u2502 McpServer \u2192 SecureMcpServer \u2502");
362
- log(" \u2502 All tool() calls are now auto-protected. \u2502");
363
- log(" \u2502 \u2502");
364
- log(" \u2502 Set your API key: \u2502");
365
- log(" \u2502 export SOLONGATE_API_KEY=sg_live_xxx \u2502");
366
- log(" \u2502 \u2502");
367
- log(" \u2502 To undo: \u2502");
368
- log(" \u2502 npx @solongate/proxy inject --restore \u2502");
369
- log(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
370
- log("");
371
- }
372
- main().catch((err) => {
373
- log(`Fatal: ${err instanceof Error ? err.message : String(err)}`);
374
- process.exit(1);
375
- });