@solongate/proxy 0.1.21 → 0.1.23

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
@@ -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(
@@ -201,7 +202,18 @@ server.tool(
201
202
 
202
203
  const transport = new StdioServerTransport();
203
204
  await server.connect(transport);
204
- console.log('${name} is running');
205
+ console.log('');
206
+ console.log('${name} is running (stdio mode)');
207
+ console.log('');
208
+ console.log('This server communicates over stdin/stdout (MCP protocol).');
209
+ console.log('It does NOT open a URL or port \u2014 it is used by MCP clients.');
210
+ console.log('');
211
+ console.log('To connect:');
212
+ console.log(' 1. Open this folder in Claude Code, Cursor, or another MCP client');
213
+ console.log(' 2. .mcp.json is auto-detected \u2014 your tools are ready to use');
214
+ console.log(' 3. Try asking: "Use the hello tool to greet Alice"');
215
+ console.log('');
216
+ console.log('Press Ctrl+C to stop.');
205
217
  `
206
218
  );
207
219
  writeFileSync(
@@ -213,7 +225,7 @@ console.log('${name} is running');
213
225
  command: "node",
214
226
  args: ["dist/index.js"],
215
227
  env: {
216
- SOLONGATE_API_KEY: "sg_test_YOUR_KEY_HERE"
228
+ SOLONGATE_API_KEY: "sg_live_YOUR_KEY_HERE"
217
229
  }
218
230
  }
219
231
  }
@@ -293,11 +305,16 @@ async function main() {
293
305
  bEmpty();
294
306
  log(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
295
307
  bEmpty();
296
- bLine(`${c.yellow}Use with Claude Code:${c.reset}`);
308
+ bLine(`${c.yellow}Use with Claude Code / Cursor / MCP client:${c.reset}`);
297
309
  bEmpty();
298
- bLine(` ${c.dim}1.${c.reset} Open the project folder in Claude Code`);
299
- bLine(` ${c.dim}2.${c.reset} .mcp.json is auto-detected on startup`);
300
- bLine(` ${c.dim}3.${c.reset} Restart Claude Code if already open`);
310
+ bLine(` ${c.dim}1.${c.reset} Replace ${c.blue3}sg_live_YOUR_KEY_HERE${c.reset} in .mcp.json`);
311
+ bLine(` ${c.dim}2.${c.reset} Open this folder in your MCP client`);
312
+ bLine(` ${c.dim}3.${c.reset} .mcp.json is auto-detected on startup`);
313
+ bEmpty();
314
+ bLine(`${c.yellow}Direct test (without MCP client):${c.reset}`);
315
+ bEmpty();
316
+ bLine(` ${c.dim}1.${c.reset} Replace ${c.blue3}sg_live_YOUR_KEY_HERE${c.reset} in .env`);
317
+ bLine(` ${c.dim}2.${c.reset} ${c.cyan}$${c.reset} npm run build && npm start`);
301
318
  bEmpty();
302
319
  log(` ${c.dim}\u2570${hr}\u256F${c.reset}`);
303
320
  log("");
package/dist/index.js CHANGED
@@ -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(
@@ -913,7 +914,18 @@ server.tool(
913
914
 
914
915
  const transport = new StdioServerTransport();
915
916
  await server.connect(transport);
916
- console.log('${name} is running');
917
+ console.log('');
918
+ console.log('${name} is running (stdio mode)');
919
+ console.log('');
920
+ console.log('This server communicates over stdin/stdout (MCP protocol).');
921
+ console.log('It does NOT open a URL or port \u2014 it is used by MCP clients.');
922
+ console.log('');
923
+ console.log('To connect:');
924
+ console.log(' 1. Open this folder in Claude Code, Cursor, or another MCP client');
925
+ console.log(' 2. .mcp.json is auto-detected \u2014 your tools are ready to use');
926
+ console.log(' 3. Try asking: "Use the hello tool to greet Alice"');
927
+ console.log('');
928
+ console.log('Press Ctrl+C to stop.');
917
929
  `
918
930
  );
919
931
  writeFileSync3(
@@ -925,7 +937,7 @@ console.log('${name} is running');
925
937
  command: "node",
926
938
  args: ["dist/index.js"],
927
939
  env: {
928
- SOLONGATE_API_KEY: "sg_test_YOUR_KEY_HERE"
940
+ SOLONGATE_API_KEY: "sg_live_YOUR_KEY_HERE"
929
941
  }
930
942
  }
931
943
  }
@@ -1005,11 +1017,16 @@ async function main3() {
1005
1017
  bEmpty();
1006
1018
  log3(` ${c2.dim}\u251C${hr}\u2524${c2.reset}`);
1007
1019
  bEmpty();
1008
- bLine(`${c2.yellow}Use with Claude Code:${c2.reset}`);
1020
+ bLine(`${c2.yellow}Use with Claude Code / Cursor / MCP client:${c2.reset}`);
1009
1021
  bEmpty();
1010
- bLine(` ${c2.dim}1.${c2.reset} Open the project folder in Claude Code`);
1011
- bLine(` ${c2.dim}2.${c2.reset} .mcp.json is auto-detected on startup`);
1012
- bLine(` ${c2.dim}3.${c2.reset} Restart Claude Code if already open`);
1022
+ bLine(` ${c2.dim}1.${c2.reset} Replace ${c2.blue3}sg_live_YOUR_KEY_HERE${c2.reset} in .mcp.json`);
1023
+ bLine(` ${c2.dim}2.${c2.reset} Open this folder in your MCP client`);
1024
+ bLine(` ${c2.dim}3.${c2.reset} .mcp.json is auto-detected on startup`);
1025
+ bEmpty();
1026
+ bLine(`${c2.yellow}Direct test (without MCP client):${c2.reset}`);
1027
+ bEmpty();
1028
+ bLine(` ${c2.dim}1.${c2.reset} Replace ${c2.blue3}sg_live_YOUR_KEY_HERE${c2.reset} in .env`);
1029
+ bLine(` ${c2.dim}2.${c2.reset} ${c2.cyan}$${c2.reset} npm run build && npm start`);
1013
1030
  bEmpty();
1014
1031
  log3(` ${c2.dim}\u2570${hr}\u256F${c2.reset}`);
1015
1032
  log3("");
@@ -3063,6 +3080,9 @@ var SolonGate = class {
3063
3080
  timeoutMs: config.evaluationTimeoutMs,
3064
3081
  store
3065
3082
  });
3083
+ if (!options.policySet && !config.policySet && apiKey.startsWith("sg_live_")) {
3084
+ this.fetchCloudPolicyOnce();
3085
+ }
3066
3086
  this.tokenIssuer = config.tokenSecret ? new TokenIssuer({
3067
3087
  secret: config.tokenSecret,
3068
3088
  ttlSeconds: config.tokenTtlSeconds,
@@ -3106,6 +3126,47 @@ var SolonGate = class {
3106
3126
  );
3107
3127
  }
3108
3128
  }
3129
+ /**
3130
+ * Fetch policy from SolonGate Cloud API (fire once, non-blocking).
3131
+ */
3132
+ fetchCloudPolicyOnce() {
3133
+ const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
3134
+ fetch(`${apiUrl}/api/v1/policies/default`, {
3135
+ headers: { "Authorization": `Bearer ${this.apiKey}` },
3136
+ signal: AbortSignal.timeout(1e4)
3137
+ }).then(async (res) => {
3138
+ if (!res.ok) return;
3139
+ const data = await res.json();
3140
+ const policySet = {
3141
+ id: String(data.id ?? "cloud"),
3142
+ name: String(data.name ?? "Cloud Policy"),
3143
+ description: String(data.description ?? ""),
3144
+ version: Number(data._version ?? 1),
3145
+ rules: data.rules ?? [],
3146
+ createdAt: String(data._created_at ?? ""),
3147
+ updatedAt: ""
3148
+ };
3149
+ this.policyEngine.loadPolicySet(policySet);
3150
+ console.warn(`[SolonGate] Loaded cloud policy: ${policySet.name} (${policySet.rules.length} rules)`);
3151
+ }).catch(() => {
3152
+ });
3153
+ }
3154
+ /**
3155
+ * Send audit log to SolonGate Cloud API (fire-and-forget).
3156
+ */
3157
+ sendAuditLog(entry) {
3158
+ if (!this.apiKey.startsWith("sg_live_")) return;
3159
+ const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
3160
+ fetch(`${apiUrl}/api/v1/audit-logs`, {
3161
+ method: "POST",
3162
+ headers: {
3163
+ "Authorization": `Bearer ${this.apiKey}`,
3164
+ "Content-Type": "application/json"
3165
+ },
3166
+ body: JSON.stringify(entry)
3167
+ }).catch(() => {
3168
+ });
3169
+ }
3109
3170
  /**
3110
3171
  * Intercept and evaluate a tool call against the full security pipeline.
3111
3172
  * If denied at any stage, returns an error result without calling upstream.
@@ -3113,11 +3174,32 @@ var SolonGate = class {
3113
3174
  */
3114
3175
  async executeToolCall(params, upstreamCall) {
3115
3176
  await this.validateLicense();
3177
+ const startTime = performance.now();
3116
3178
  return interceptToolCall(params, upstreamCall, {
3117
3179
  policyEngine: this.policyEngine,
3118
3180
  validateSchemas: this.config.validateSchemas,
3119
3181
  verboseErrors: this.config.verboseErrors,
3120
- onDecision: (result) => this.logger.logDecision(result),
3182
+ onDecision: (result) => {
3183
+ this.logger.logDecision(result);
3184
+ if (result.status === "ALLOWED" || result.status === "DENIED") {
3185
+ this.sendAuditLog({
3186
+ tool: params.name,
3187
+ arguments: params.arguments ?? {},
3188
+ decision: result.decision.effect === "ALLOW" ? "ALLOW" : "DENY",
3189
+ reason: result.decision.reason,
3190
+ matchedRule: result.decision.matchedRule?.id,
3191
+ evaluationTimeMs: performance.now() - startTime
3192
+ });
3193
+ } else if (result.status === "ERROR") {
3194
+ this.sendAuditLog({
3195
+ tool: params.name,
3196
+ arguments: params.arguments ?? {},
3197
+ decision: "DENY",
3198
+ reason: result.error.message,
3199
+ evaluationTimeMs: performance.now() - startTime
3200
+ });
3201
+ }
3202
+ },
3121
3203
  tokenIssuer: this.tokenIssuer ?? void 0,
3122
3204
  serverVerifier: this.serverVerifier ?? void 0,
3123
3205
  rateLimiter: this.rateLimiter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
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": {