@solongate/proxy 0.1.2 → 0.1.4

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/create.js ADDED
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/create.ts
4
+ import { mkdirSync, writeFileSync, existsSync } from "fs";
5
+ import { resolve, join } from "path";
6
+ import { execSync } from "child_process";
7
+ function log(msg) {
8
+ process.stderr.write(msg + "\n");
9
+ }
10
+ function parseCreateArgs(argv) {
11
+ const args = argv.slice(2);
12
+ const opts = {
13
+ name: "",
14
+ policy: "restricted",
15
+ noInstall: false
16
+ };
17
+ for (let i = 0; i < args.length; i++) {
18
+ switch (args[i]) {
19
+ case "--policy":
20
+ opts.policy = args[++i];
21
+ break;
22
+ case "--no-install":
23
+ opts.noInstall = true;
24
+ break;
25
+ case "--help":
26
+ case "-h":
27
+ printHelp();
28
+ process.exit(0);
29
+ break;
30
+ default:
31
+ if (!args[i].startsWith("-") && !opts.name) {
32
+ opts.name = args[i];
33
+ }
34
+ }
35
+ }
36
+ if (!opts.name) {
37
+ log("");
38
+ log(" Error: Project name required.");
39
+ log("");
40
+ log(" Usage: npx @solongate/proxy create <name>");
41
+ log("");
42
+ log(" Examples:");
43
+ log(" npx @solongate/proxy create my-mcp-server");
44
+ log(" npx @solongate/proxy create weather-api");
45
+ process.exit(1);
46
+ }
47
+ return opts;
48
+ }
49
+ function printHelp() {
50
+ log(`
51
+ SolonGate Create \u2014 Scaffold a secure MCP server in seconds
52
+
53
+ USAGE
54
+ npx @solongate/proxy create <name> [options]
55
+
56
+ OPTIONS
57
+ --policy <preset> Policy preset (default: restricted)
58
+ --no-install Skip dependency installation
59
+ -h, --help Show this help message
60
+
61
+ EXAMPLES
62
+ npx @solongate/proxy create my-server
63
+ npx @solongate/proxy create db-tools --policy read-only
64
+ `);
65
+ }
66
+ function createProject(dir, name, _policy) {
67
+ writeFileSync(
68
+ join(dir, "package.json"),
69
+ JSON.stringify(
70
+ {
71
+ name,
72
+ version: "0.1.0",
73
+ type: "module",
74
+ private: true,
75
+ bin: { [name]: "./dist/index.js" },
76
+ scripts: {
77
+ build: "tsup src/index.ts --format esm",
78
+ dev: "tsx src/index.ts",
79
+ start: "node dist/index.js"
80
+ },
81
+ dependencies: {
82
+ "@modelcontextprotocol/sdk": "^1.26.0",
83
+ "@solongate/sdk": "latest",
84
+ zod: "^3.25.0"
85
+ },
86
+ devDependencies: {
87
+ tsup: "^8.3.0",
88
+ tsx: "^4.19.0",
89
+ typescript: "^5.7.0"
90
+ }
91
+ },
92
+ null,
93
+ 2
94
+ ) + "\n"
95
+ );
96
+ writeFileSync(
97
+ join(dir, "tsconfig.json"),
98
+ JSON.stringify(
99
+ {
100
+ compilerOptions: {
101
+ target: "ES2022",
102
+ module: "ESNext",
103
+ moduleResolution: "bundler",
104
+ esModuleInterop: true,
105
+ strict: true,
106
+ outDir: "dist",
107
+ rootDir: "src",
108
+ declaration: true,
109
+ skipLibCheck: true
110
+ },
111
+ include: ["src"]
112
+ },
113
+ null,
114
+ 2
115
+ ) + "\n"
116
+ );
117
+ mkdirSync(join(dir, "src"), { recursive: true });
118
+ writeFileSync(
119
+ join(dir, "src", "index.ts"),
120
+ `#!/usr/bin/env node
121
+
122
+ // MCP uses stdout for JSON-RPC \u2014 redirect console to stderr
123
+ console.log = (...args: unknown[]) => {
124
+ process.stderr.write(args.map(String).join(' ') + '\\n');
125
+ };
126
+
127
+ import { SecureMcpServer } from '@solongate/sdk';
128
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
129
+ import { z } from 'zod';
130
+
131
+ // Create a secure MCP server (API key from SOLONGATE_API_KEY env var)
132
+ const server = new SecureMcpServer({
133
+ name: '${name}',
134
+ version: '0.1.0',
135
+ });
136
+
137
+ // \u2500\u2500 Register your tools below \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
138
+
139
+ server.tool(
140
+ 'hello',
141
+ 'Say hello to someone',
142
+ { name: z.string().describe('Name of the person to greet') },
143
+ async ({ name }) => ({
144
+ content: [{ type: 'text', text: \`Hello, \${name}! Welcome to ${name}.\` }],
145
+ }),
146
+ );
147
+
148
+ // Example: Add more tools here
149
+ // server.tool(
150
+ // 'read_data',
151
+ // 'Read data from a source',
152
+ // { query: z.string().describe('What to read') },
153
+ // async ({ query }) => ({
154
+ // content: [{ type: 'text', text: \`Result for: \${query}\` }],
155
+ // }),
156
+ // );
157
+
158
+ // \u2500\u2500 Start the server \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\u2500\u2500\u2500\u2500\u2500
159
+
160
+ const transport = new StdioServerTransport();
161
+ await server.connect(transport);
162
+ console.log('${name} is running');
163
+ `
164
+ );
165
+ writeFileSync(
166
+ join(dir, ".mcp.json"),
167
+ JSON.stringify(
168
+ {
169
+ mcpServers: {
170
+ [name]: {
171
+ command: "node",
172
+ args: ["dist/index.js"],
173
+ env: {
174
+ SOLONGATE_API_KEY: "sg_test_e4460d32_replace_with_your_key"
175
+ }
176
+ }
177
+ }
178
+ },
179
+ null,
180
+ 2
181
+ ) + "\n"
182
+ );
183
+ writeFileSync(
184
+ join(dir, ".gitignore"),
185
+ `node_modules/
186
+ dist/
187
+ *.solongate-backup
188
+ .env
189
+ .env.local
190
+ `
191
+ );
192
+ }
193
+ function withSpinner(message, fn) {
194
+ const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
195
+ let i = 0;
196
+ const id = setInterval(() => {
197
+ process.stderr.write(`\r ${frames[i++ % frames.length]} ${message}`);
198
+ }, 80);
199
+ try {
200
+ fn();
201
+ clearInterval(id);
202
+ process.stderr.write(`\r \u2713 ${message}
203
+ `);
204
+ } catch {
205
+ clearInterval(id);
206
+ process.stderr.write(`\r \u2717 ${message} \u2014 failed
207
+ `);
208
+ }
209
+ }
210
+ function installDeps(dir) {
211
+ withSpinner("Installing dependencies...", () => {
212
+ execSync("npm install", { cwd: dir, stdio: "pipe" });
213
+ });
214
+ }
215
+ async function main() {
216
+ const opts = parseCreateArgs(process.argv);
217
+ const dir = resolve(opts.name);
218
+ log("");
219
+ log(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
220
+ log(" \u2551 SolonGate \u2014 Create MCP Server \u2551");
221
+ log(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
222
+ log("");
223
+ if (existsSync(dir)) {
224
+ log(` Error: Directory "${opts.name}" already exists.`);
225
+ process.exit(1);
226
+ }
227
+ mkdirSync(dir, { recursive: true });
228
+ log(` Project: ${opts.name}`);
229
+ log(` Language: TypeScript`);
230
+ log(` Policy: ${opts.policy}`);
231
+ log("");
232
+ createProject(dir, opts.name, opts.policy);
233
+ log(" Files created:");
234
+ log(" package.json");
235
+ log(" tsconfig.json");
236
+ log(" src/index.ts");
237
+ log(" .mcp.json");
238
+ log(" .gitignore");
239
+ log("");
240
+ if (!opts.noInstall) {
241
+ installDeps(dir);
242
+ log("");
243
+ }
244
+ const W = 46;
245
+ const line = (s) => log(` \u2502 ${s.padEnd(W)} \u2502`);
246
+ log(` \u250C${"\u2500".repeat(W + 2)}\u2510`);
247
+ line("Project created!");
248
+ line("");
249
+ line(`cd ${opts.name}`);
250
+ line("");
251
+ line("npm run build # Build");
252
+ line("npm run dev # Dev mode (tsx)");
253
+ line("npm start # Run built server");
254
+ line("");
255
+ line("Set your API key:");
256
+ line("export SOLONGATE_API_KEY=sg_live_xxx");
257
+ log(` \u2514${"\u2500".repeat(W + 2)}\u2518`);
258
+ log("");
259
+ }
260
+ main().catch((err) => {
261
+ log(`Fatal: ${err instanceof Error ? err.message : String(err)}`);
262
+ process.exit(1);
263
+ });