@solongate/proxy 0.1.27 → 0.2.1
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/index.js +99 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3382,6 +3382,8 @@ var SolonGateProxy = class {
|
|
|
3382
3382
|
await this.connectUpstream();
|
|
3383
3383
|
await this.discoverTools();
|
|
3384
3384
|
this.registerToolsToCloud();
|
|
3385
|
+
this.registerServerToCloud();
|
|
3386
|
+
this.syncPolicyToCloud();
|
|
3385
3387
|
this.createServer();
|
|
3386
3388
|
await this.serve();
|
|
3387
3389
|
this.startPolicyPolling();
|
|
@@ -3493,11 +3495,25 @@ var SolonGateProxy = class {
|
|
|
3493
3495
|
if (this.config.apiKey && !this.config.apiKey.startsWith("sg_test_")) {
|
|
3494
3496
|
const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
|
|
3495
3497
|
log(`Sending audit log: ${name} \u2192 ${decision} (key: ${this.config.apiKey.slice(0, 16)}...)`);
|
|
3498
|
+
let reason = "allowed";
|
|
3499
|
+
let matchedRule;
|
|
3500
|
+
if (result.isError) {
|
|
3501
|
+
const rawText = result.content[0]?.text ?? "denied";
|
|
3502
|
+
try {
|
|
3503
|
+
const parsed = JSON.parse(rawText);
|
|
3504
|
+
reason = parsed.message ?? rawText;
|
|
3505
|
+
const ruleMatch = reason.match(/^Matched rule "([^"]+)":/);
|
|
3506
|
+
if (ruleMatch) matchedRule = ruleMatch[1];
|
|
3507
|
+
} catch {
|
|
3508
|
+
reason = rawText;
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3496
3511
|
sendAuditLog(this.config.apiKey, apiUrl, {
|
|
3497
3512
|
tool: name,
|
|
3498
3513
|
arguments: args ?? {},
|
|
3499
3514
|
decision,
|
|
3500
|
-
reason
|
|
3515
|
+
reason,
|
|
3516
|
+
matchedRule,
|
|
3501
3517
|
evaluationTimeMs
|
|
3502
3518
|
});
|
|
3503
3519
|
} else {
|
|
@@ -3596,6 +3612,88 @@ var SolonGateProxy = class {
|
|
|
3596
3612
|
}
|
|
3597
3613
|
return ["READ"];
|
|
3598
3614
|
}
|
|
3615
|
+
/**
|
|
3616
|
+
* Register the upstream MCP server to the SolonGate Cloud API.
|
|
3617
|
+
* This makes it visible on the Dashboard MCP Servers page.
|
|
3618
|
+
*/
|
|
3619
|
+
registerServerToCloud() {
|
|
3620
|
+
if (!this.config.apiKey || this.config.apiKey.startsWith("sg_test_")) return;
|
|
3621
|
+
const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
|
|
3622
|
+
const transport = this.config.upstream.transport ?? "stdio";
|
|
3623
|
+
let serverName = this.config.name ?? "solongate-proxy";
|
|
3624
|
+
let serverUrl;
|
|
3625
|
+
let command;
|
|
3626
|
+
let args;
|
|
3627
|
+
if (transport === "stdio") {
|
|
3628
|
+
command = this.config.upstream.command;
|
|
3629
|
+
args = (this.config.upstream.args ?? []).join(" ");
|
|
3630
|
+
serverUrl = `stdio://${command}`;
|
|
3631
|
+
serverName = command || serverName;
|
|
3632
|
+
} else {
|
|
3633
|
+
serverUrl = this.config.upstream.url || "";
|
|
3634
|
+
try {
|
|
3635
|
+
const u = new URL(serverUrl);
|
|
3636
|
+
serverName = u.hostname || serverName;
|
|
3637
|
+
} catch {
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
fetch(`${apiUrl}/api/v1/mcp-servers`, {
|
|
3641
|
+
method: "POST",
|
|
3642
|
+
headers: {
|
|
3643
|
+
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
3644
|
+
"Content-Type": "application/json"
|
|
3645
|
+
},
|
|
3646
|
+
body: JSON.stringify({
|
|
3647
|
+
name: serverName,
|
|
3648
|
+
url: serverUrl,
|
|
3649
|
+
command: command || void 0,
|
|
3650
|
+
args: args || void 0
|
|
3651
|
+
})
|
|
3652
|
+
}).then(async (res) => {
|
|
3653
|
+
if (res.ok) {
|
|
3654
|
+
log(`Registered MCP server "${serverName}" to dashboard.`);
|
|
3655
|
+
} else if (res.status === 409) {
|
|
3656
|
+
log(`MCP server "${serverName}" already registered.`);
|
|
3657
|
+
} else {
|
|
3658
|
+
const body = await res.text().catch(() => "");
|
|
3659
|
+
log(`MCP server registration failed (${res.status}): ${body}`);
|
|
3660
|
+
}
|
|
3661
|
+
}).catch((err) => {
|
|
3662
|
+
log(`MCP server registration error: ${err instanceof Error ? err.message : String(err)}`);
|
|
3663
|
+
});
|
|
3664
|
+
}
|
|
3665
|
+
/**
|
|
3666
|
+
* Sync the active policy to the SolonGate Cloud API.
|
|
3667
|
+
* This makes it visible on the Dashboard Policies page.
|
|
3668
|
+
*/
|
|
3669
|
+
syncPolicyToCloud() {
|
|
3670
|
+
if (!this.config.apiKey || this.config.apiKey.startsWith("sg_test_")) return;
|
|
3671
|
+
const apiUrl = this.config.apiUrl ?? "https://api.solongate.com";
|
|
3672
|
+
const policy = this.config.policy;
|
|
3673
|
+
fetch(`${apiUrl}/api/v1/policies`, {
|
|
3674
|
+
method: "POST",
|
|
3675
|
+
headers: {
|
|
3676
|
+
"Authorization": `Bearer ${this.config.apiKey}`,
|
|
3677
|
+
"Content-Type": "application/json"
|
|
3678
|
+
},
|
|
3679
|
+
body: JSON.stringify({
|
|
3680
|
+
id: policy.id || "default",
|
|
3681
|
+
name: policy.name || "Default Policy",
|
|
3682
|
+
description: policy.description || `Policy synced from proxy`,
|
|
3683
|
+
version: policy.version || 1,
|
|
3684
|
+
rules: policy.rules
|
|
3685
|
+
})
|
|
3686
|
+
}).then(async (res) => {
|
|
3687
|
+
if (res.ok) {
|
|
3688
|
+
log(`Synced policy "${policy.name}" to dashboard.`);
|
|
3689
|
+
} else {
|
|
3690
|
+
const body = await res.text().catch(() => "");
|
|
3691
|
+
log(`Policy sync failed (${res.status}): ${body}`);
|
|
3692
|
+
}
|
|
3693
|
+
}).catch((err) => {
|
|
3694
|
+
log(`Policy sync error: ${err instanceof Error ? err.message : String(err)}`);
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3599
3697
|
/**
|
|
3600
3698
|
* Poll for policy updates from dashboard every 60 seconds.
|
|
3601
3699
|
* When user changes policy in dashboard, proxy picks it up automatically.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
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": {
|