@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 +25 -8
- package/dist/index.js +91 -9
- 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(
|
|
@@ -201,7 +202,18 @@ server.tool(
|
|
|
201
202
|
|
|
202
203
|
const transport = new StdioServerTransport();
|
|
203
204
|
await server.connect(transport);
|
|
204
|
-
console.log('
|
|
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: "
|
|
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}
|
|
299
|
-
bLine(` ${c.dim}2.${c.reset}
|
|
300
|
-
bLine(` ${c.dim}3.${c.reset}
|
|
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
|
|
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('
|
|
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: "
|
|
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}
|
|
1011
|
-
bLine(` ${c2.dim}2.${c2.reset}
|
|
1012
|
-
bLine(` ${c2.dim}3.${c2.reset}
|
|
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) =>
|
|
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.
|
|
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": {
|