@solongate/proxy 0.1.21 → 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 +13 -7
- package/dist/index.js +79 -8
- package/package.json +1 -1
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
|
|
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: "
|
|
217
|
+
SOLONGATE_API_KEY: "sg_live_YOUR_KEY_HERE"
|
|
217
218
|
}
|
|
218
219
|
}
|
|
219
220
|
}
|
|
@@ -293,11 +294,16 @@ async function main() {
|
|
|
293
294
|
bEmpty();
|
|
294
295
|
log(` ${c.dim}\u251C${hr}\u2524${c.reset}`);
|
|
295
296
|
bEmpty();
|
|
296
|
-
bLine(`${c.yellow}Use with Claude Code:${c.reset}`);
|
|
297
|
+
bLine(`${c.yellow}Use with Claude Code / Cursor / MCP client:${c.reset}`);
|
|
297
298
|
bEmpty();
|
|
298
|
-
bLine(` ${c.dim}1.${c.reset}
|
|
299
|
-
bLine(` ${c.dim}2.${c.reset}
|
|
300
|
-
bLine(` ${c.dim}3.${c.reset}
|
|
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}`);
|
|
304
|
+
bEmpty();
|
|
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`);
|
|
301
307
|
bEmpty();
|
|
302
308
|
log(` ${c.dim}\u2570${hr}\u256F${c.reset}`);
|
|
303
309
|
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
|
|
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: "
|
|
929
|
+
SOLONGATE_API_KEY: "sg_live_YOUR_KEY_HERE"
|
|
929
930
|
}
|
|
930
931
|
}
|
|
931
932
|
}
|
|
@@ -1005,11 +1006,16 @@ async function main3() {
|
|
|
1005
1006
|
bEmpty();
|
|
1006
1007
|
log3(` ${c2.dim}\u251C${hr}\u2524${c2.reset}`);
|
|
1007
1008
|
bEmpty();
|
|
1008
|
-
bLine(`${c2.yellow}Use with Claude Code:${c2.reset}`);
|
|
1009
|
+
bLine(`${c2.yellow}Use with Claude Code / Cursor / MCP client:${c2.reset}`);
|
|
1009
1010
|
bEmpty();
|
|
1010
|
-
bLine(` ${c2.dim}1.${c2.reset}
|
|
1011
|
-
bLine(` ${c2.dim}2.${c2.reset}
|
|
1012
|
-
bLine(` ${c2.dim}3.${c2.reset}
|
|
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`);
|
|
1014
|
+
bEmpty();
|
|
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`);
|
|
1013
1019
|
bEmpty();
|
|
1014
1020
|
log3(` ${c2.dim}\u2570${hr}\u256F${c2.reset}`);
|
|
1015
1021
|
log3("");
|
|
@@ -3063,6 +3069,9 @@ var SolonGate = class {
|
|
|
3063
3069
|
timeoutMs: config.evaluationTimeoutMs,
|
|
3064
3070
|
store
|
|
3065
3071
|
});
|
|
3072
|
+
if (!options.policySet && !config.policySet && apiKey.startsWith("sg_live_")) {
|
|
3073
|
+
this.fetchCloudPolicyOnce();
|
|
3074
|
+
}
|
|
3066
3075
|
this.tokenIssuer = config.tokenSecret ? new TokenIssuer({
|
|
3067
3076
|
secret: config.tokenSecret,
|
|
3068
3077
|
ttlSeconds: config.tokenTtlSeconds,
|
|
@@ -3106,6 +3115,47 @@ var SolonGate = class {
|
|
|
3106
3115
|
);
|
|
3107
3116
|
}
|
|
3108
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
|
+
}
|
|
3109
3159
|
/**
|
|
3110
3160
|
* Intercept and evaluate a tool call against the full security pipeline.
|
|
3111
3161
|
* If denied at any stage, returns an error result without calling upstream.
|
|
@@ -3113,11 +3163,32 @@ var SolonGate = class {
|
|
|
3113
3163
|
*/
|
|
3114
3164
|
async executeToolCall(params, upstreamCall) {
|
|
3115
3165
|
await this.validateLicense();
|
|
3166
|
+
const startTime = performance.now();
|
|
3116
3167
|
return interceptToolCall(params, upstreamCall, {
|
|
3117
3168
|
policyEngine: this.policyEngine,
|
|
3118
3169
|
validateSchemas: this.config.validateSchemas,
|
|
3119
3170
|
verboseErrors: this.config.verboseErrors,
|
|
3120
|
-
onDecision: (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
|
+
},
|
|
3121
3192
|
tokenIssuer: this.tokenIssuer ?? void 0,
|
|
3122
3193
|
serverVerifier: this.serverVerifier ?? void 0,
|
|
3123
3194
|
rateLimiter: this.rateLimiter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.1.
|
|
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": {
|