@solongate/proxy 0.1.20 → 0.1.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/create.js CHANGED
@@ -132,8 +132,8 @@ function createProject(dir, name, _policy) {
132
132
  bin: { [name]: "./dist/index.js" },
133
133
  scripts: {
134
134
  build: "tsup src/index.ts --format esm",
135
- dev: "tsx src/index.ts",
136
- start: "node dist/index.js"
135
+ dev: "tsx --env-file=.env src/index.ts",
136
+ start: "node --env-file=.env dist/index.js"
137
137
  },
138
138
  dependencies: {
139
139
  "@modelcontextprotocol/sdk": "^1.26.0",
@@ -181,13 +181,14 @@ console.log = (...args: unknown[]) => {
181
181
  process.stderr.write(args.map(String).join(' ') + '\\n');
182
182
  };
183
183
 
184
- import { SecureMcpServer, createPermissivePolicySet } from '@solongate/sdk';
184
+ import { SecureMcpServer } from '@solongate/sdk';
185
185
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
186
186
  import { z } from 'zod';
187
187
 
188
+ // Policy is managed from the SolonGate Dashboard (https://solongate.com)
189
+ // No local policySet needed \u2014 it's fetched from the cloud via your API key.
188
190
  const server = new SecureMcpServer(
189
191
  { name: '${name}', version: '0.1.0' },
190
- { policySet: createPermissivePolicySet() },
191
192
  );
192
193
 
193
194
  server.tool(
@@ -213,7 +214,7 @@ console.log('${name} is running');
213
214
  command: "node",
214
215
  args: ["dist/index.js"],
215
216
  env: {
216
- SOLONGATE_API_KEY: "sg_test_YOUR_KEY_HERE"
217
+ SOLONGATE_API_KEY: "sg_live_YOUR_KEY_HERE"
217
218
  }
218
219
  }
219
220
  }
@@ -222,6 +223,11 @@ console.log('${name} is running');
222
223
  2
223
224
  ) + "\n"
224
225
  );
226
+ writeFileSync(
227
+ join(dir, ".env"),
228
+ `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
229
+ `
230
+ );
225
231
  writeFileSync(
226
232
  join(dir, ".gitignore"),
227
233
  `node_modules/
@@ -288,11 +294,16 @@ async function main() {
288
294
  bEmpty();
289
295
  log(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
290
296
  bEmpty();
291
- bLine(`${c.yellow}Use with Claude Code:${c.reset}`);
297
+ bLine(`${c.yellow}Use with Claude Code / Cursor / MCP client:${c.reset}`);
298
+ bEmpty();
299
+ bLine(` ${c.dim}1.${c.reset} Replace ${c.blue3}sg_live_YOUR_KEY_HERE${c.reset} in .mcp.json`);
300
+ bLine(` ${c.dim}2.${c.reset} Open this folder in your MCP client`);
301
+ bLine(` ${c.dim}3.${c.reset} .mcp.json is auto-detected on startup`);
302
+ bEmpty();
303
+ bLine(`${c.yellow}Direct test (without MCP client):${c.reset}`);
292
304
  bEmpty();
293
- bLine(` ${c.dim}1.${c.reset} Open the project folder in Claude Code`);
294
- bLine(` ${c.dim}2.${c.reset} .mcp.json is auto-detected on startup`);
295
- bLine(` ${c.dim}3.${c.reset} Restart Claude Code if already open`);
305
+ bLine(` ${c.dim}1.${c.reset} Replace ${c.blue3}sg_live_YOUR_KEY_HERE${c.reset} in .env`);
306
+ bLine(` ${c.dim}2.${c.reset} ${c.cyan}$${c.reset} npm run build && npm start`);
296
307
  bEmpty();
297
308
  log(` ${c.dim}\u2570${hr}\u256F${c.reset}`);
298
309
  log("");
package/dist/index.js CHANGED
@@ -844,8 +844,8 @@ function createProject(dir, name, _policy) {
844
844
  bin: { [name]: "./dist/index.js" },
845
845
  scripts: {
846
846
  build: "tsup src/index.ts --format esm",
847
- dev: "tsx src/index.ts",
848
- start: "node dist/index.js"
847
+ dev: "tsx --env-file=.env src/index.ts",
848
+ start: "node --env-file=.env dist/index.js"
849
849
  },
850
850
  dependencies: {
851
851
  "@modelcontextprotocol/sdk": "^1.26.0",
@@ -893,13 +893,14 @@ console.log = (...args: unknown[]) => {
893
893
  process.stderr.write(args.map(String).join(' ') + '\\n');
894
894
  };
895
895
 
896
- import { SecureMcpServer, createPermissivePolicySet } from '@solongate/sdk';
896
+ import { SecureMcpServer } from '@solongate/sdk';
897
897
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
898
898
  import { z } from 'zod';
899
899
 
900
+ // Policy is managed from the SolonGate Dashboard (https://solongate.com)
901
+ // No local policySet needed \u2014 it's fetched from the cloud via your API key.
900
902
  const server = new SecureMcpServer(
901
903
  { name: '${name}', version: '0.1.0' },
902
- { policySet: createPermissivePolicySet() },
903
904
  );
904
905
 
905
906
  server.tool(
@@ -925,7 +926,7 @@ console.log('${name} is running');
925
926
  command: "node",
926
927
  args: ["dist/index.js"],
927
928
  env: {
928
- SOLONGATE_API_KEY: "sg_test_YOUR_KEY_HERE"
929
+ SOLONGATE_API_KEY: "sg_live_YOUR_KEY_HERE"
929
930
  }
930
931
  }
931
932
  }
@@ -934,6 +935,11 @@ console.log('${name} is running');
934
935
  2
935
936
  ) + "\n"
936
937
  );
938
+ writeFileSync3(
939
+ join2(dir, ".env"),
940
+ `SOLONGATE_API_KEY=sg_live_YOUR_KEY_HERE
941
+ `
942
+ );
937
943
  writeFileSync3(
938
944
  join2(dir, ".gitignore"),
939
945
  `node_modules/
@@ -1000,11 +1006,16 @@ async function main3() {
1000
1006
  bEmpty();
1001
1007
  log3(` ${c2.dim}\u251C${hr}\u2524${c2.reset}`);
1002
1008
  bEmpty();
1003
- bLine(`${c2.yellow}Use with Claude Code:${c2.reset}`);
1009
+ bLine(`${c2.yellow}Use with Claude Code / Cursor / MCP client:${c2.reset}`);
1010
+ bEmpty();
1011
+ bLine(` ${c2.dim}1.${c2.reset} Replace ${c2.blue3}sg_live_YOUR_KEY_HERE${c2.reset} in .mcp.json`);
1012
+ bLine(` ${c2.dim}2.${c2.reset} Open this folder in your MCP client`);
1013
+ bLine(` ${c2.dim}3.${c2.reset} .mcp.json is auto-detected on startup`);
1004
1014
  bEmpty();
1005
- bLine(` ${c2.dim}1.${c2.reset} Open the project folder in Claude Code`);
1006
- bLine(` ${c2.dim}2.${c2.reset} .mcp.json is auto-detected on startup`);
1007
- bLine(` ${c2.dim}3.${c2.reset} Restart Claude Code if already open`);
1015
+ bLine(`${c2.yellow}Direct test (without MCP client):${c2.reset}`);
1016
+ bEmpty();
1017
+ bLine(` ${c2.dim}1.${c2.reset} Replace ${c2.blue3}sg_live_YOUR_KEY_HERE${c2.reset} in .env`);
1018
+ bLine(` ${c2.dim}2.${c2.reset} ${c2.cyan}$${c2.reset} npm run build && npm start`);
1008
1019
  bEmpty();
1009
1020
  log3(` ${c2.dim}\u2570${hr}\u256F${c2.reset}`);
1010
1021
  log3("");
@@ -3058,6 +3069,9 @@ var SolonGate = class {
3058
3069
  timeoutMs: config.evaluationTimeoutMs,
3059
3070
  store
3060
3071
  });
3072
+ if (!options.policySet && !config.policySet && apiKey.startsWith("sg_live_")) {
3073
+ this.fetchCloudPolicyOnce();
3074
+ }
3061
3075
  this.tokenIssuer = config.tokenSecret ? new TokenIssuer({
3062
3076
  secret: config.tokenSecret,
3063
3077
  ttlSeconds: config.tokenTtlSeconds,
@@ -3101,6 +3115,47 @@ var SolonGate = class {
3101
3115
  );
3102
3116
  }
3103
3117
  }
3118
+ /**
3119
+ * Fetch policy from SolonGate Cloud API (fire once, non-blocking).
3120
+ */
3121
+ fetchCloudPolicyOnce() {
3122
+ const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
3123
+ fetch(`${apiUrl}/api/v1/policies/default`, {
3124
+ headers: { "Authorization": `Bearer ${this.apiKey}` },
3125
+ signal: AbortSignal.timeout(1e4)
3126
+ }).then(async (res) => {
3127
+ if (!res.ok) return;
3128
+ const data = await res.json();
3129
+ const policySet = {
3130
+ id: String(data.id ?? "cloud"),
3131
+ name: String(data.name ?? "Cloud Policy"),
3132
+ description: String(data.description ?? ""),
3133
+ version: Number(data._version ?? 1),
3134
+ rules: data.rules ?? [],
3135
+ createdAt: String(data._created_at ?? ""),
3136
+ updatedAt: ""
3137
+ };
3138
+ this.policyEngine.loadPolicySet(policySet);
3139
+ console.warn(`[SolonGate] Loaded cloud policy: ${policySet.name} (${policySet.rules.length} rules)`);
3140
+ }).catch(() => {
3141
+ });
3142
+ }
3143
+ /**
3144
+ * Send audit log to SolonGate Cloud API (fire-and-forget).
3145
+ */
3146
+ sendAuditLog(entry) {
3147
+ if (!this.apiKey.startsWith("sg_live_")) return;
3148
+ const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
3149
+ fetch(`${apiUrl}/api/v1/audit-logs`, {
3150
+ method: "POST",
3151
+ headers: {
3152
+ "Authorization": `Bearer ${this.apiKey}`,
3153
+ "Content-Type": "application/json"
3154
+ },
3155
+ body: JSON.stringify(entry)
3156
+ }).catch(() => {
3157
+ });
3158
+ }
3104
3159
  /**
3105
3160
  * Intercept and evaluate a tool call against the full security pipeline.
3106
3161
  * If denied at any stage, returns an error result without calling upstream.
@@ -3108,11 +3163,32 @@ var SolonGate = class {
3108
3163
  */
3109
3164
  async executeToolCall(params, upstreamCall) {
3110
3165
  await this.validateLicense();
3166
+ const startTime = performance.now();
3111
3167
  return interceptToolCall(params, upstreamCall, {
3112
3168
  policyEngine: this.policyEngine,
3113
3169
  validateSchemas: this.config.validateSchemas,
3114
3170
  verboseErrors: this.config.verboseErrors,
3115
- onDecision: (result) => this.logger.logDecision(result),
3171
+ onDecision: (result) => {
3172
+ this.logger.logDecision(result);
3173
+ if (result.status === "ALLOWED" || result.status === "DENIED") {
3174
+ this.sendAuditLog({
3175
+ tool: params.name,
3176
+ arguments: params.arguments ?? {},
3177
+ decision: result.decision.effect === "ALLOW" ? "ALLOW" : "DENY",
3178
+ reason: result.decision.reason,
3179
+ matchedRule: result.decision.matchedRule?.id,
3180
+ evaluationTimeMs: performance.now() - startTime
3181
+ });
3182
+ } else if (result.status === "ERROR") {
3183
+ this.sendAuditLog({
3184
+ tool: params.name,
3185
+ arguments: params.arguments ?? {},
3186
+ decision: "DENY",
3187
+ reason: result.error.message,
3188
+ evaluationTimeMs: performance.now() - startTime
3189
+ });
3190
+ }
3191
+ },
3116
3192
  tokenIssuer: this.tokenIssuer ?? void 0,
3117
3193
  serverVerifier: this.serverVerifier ?? void 0,
3118
3194
  rateLimiter: this.rateLimiter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "MCP security proxy \u00e2\u20ac\u201d protect any MCP server with policies, input validation, rate limiting, and audit logging. Zero code changes required.",
5
5
  "type": "module",
6
6
  "bin": {