@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 +20 -9
- package/dist/index.js +86 -10
- package/package.json +1 -1
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
|
|
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
|
}
|
|
@@ -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}
|
|
294
|
-
bLine(` ${c.dim}2.${c.reset} .
|
|
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
|
|
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
|
}
|
|
@@ -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(
|
|
1006
|
-
|
|
1007
|
-
bLine(` ${c2.dim}
|
|
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) =>
|
|
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.
|
|
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": {
|