@suveren/gateway 0.24.0 → 0.25.0
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/mcp-server/http.mjs
CHANGED
|
@@ -3858,6 +3858,11 @@ function zeroCappedBound(profileId, bounds, actionType) {
|
|
|
3858
3858
|
}
|
|
3859
3859
|
return null;
|
|
3860
3860
|
}
|
|
3861
|
+
function toolAlwaysListed(tool, isBuiltin) {
|
|
3862
|
+
if (tool.internal || !tool.gating?.profile) return false;
|
|
3863
|
+
if (tool.gating.hideUnlessAuthorized || tool.gating.category === "disabled") return false;
|
|
3864
|
+
return !isBuiltin(tool.integrationId);
|
|
3865
|
+
}
|
|
3861
3866
|
function toolIsAuthorizedForDisplay(tool, matchingAuths) {
|
|
3862
3867
|
if (!tool.gating?.hideUnlessAuthorized) return true;
|
|
3863
3868
|
if (matchingAuths.length === 0) return false;
|
|
@@ -4033,7 +4038,7 @@ function createGatedToolHandlerInner(tool, integrationManager2, state2) {
|
|
|
4033
4038
|
return {
|
|
4034
4039
|
content: [{
|
|
4035
4040
|
type: "text",
|
|
4036
|
-
text: refusals.length > 0 ? `Refused: ${reasons.charAt(0).toUpperCase() + reasons.slice(1)} No ticket was requested.` :
|
|
4041
|
+
text: refusals.length > 0 ? `Refused: ${reasons.charAt(0).toUpperCase() + reasons.slice(1)} No ticket was requested.` : noMandateRefusal(tool.namespacedName, profile)
|
|
4037
4042
|
}],
|
|
4038
4043
|
isError: true
|
|
4039
4044
|
};
|
|
@@ -4645,20 +4650,21 @@ Proposal ID: ${proposal.id}. Use check-pending-commitments to track status.`
|
|
|
4645
4650
|
}
|
|
4646
4651
|
});
|
|
4647
4652
|
}
|
|
4648
|
-
function
|
|
4653
|
+
function noMandateRefusal(toolName, profile) {
|
|
4654
|
+
return `Refused: no mandate covers ${toolName} (${shortProfile(profile)}). Nothing was done. Ask the person to grant a ${shortProfile(profile)} mandate in the gateway, then try again. No ticket was requested.`;
|
|
4655
|
+
}
|
|
4656
|
+
function shortProfile(profileId) {
|
|
4657
|
+
const parts = profileId.replace(/@.*$/, "").split("/");
|
|
4658
|
+
return parts[parts.length - 1];
|
|
4659
|
+
}
|
|
4660
|
+
function buildProxiedToolDescription(tool) {
|
|
4649
4661
|
if (!tool.gating || !tool.gating.profile) {
|
|
4650
4662
|
return `[Suveren: no gating config] ${tool.description}`;
|
|
4651
4663
|
}
|
|
4652
4664
|
const profile = tool.gating.profile;
|
|
4653
|
-
const
|
|
4654
|
-
const hasAuth = auths.some(
|
|
4655
|
-
(a) => a.complete && profileMatches(a.profileId, profile)
|
|
4656
|
-
);
|
|
4657
|
-
if (!hasAuth) {
|
|
4658
|
-
return `[Suveren: ${profile} \u2014 no active authorization] ${tool.description}`;
|
|
4659
|
-
}
|
|
4665
|
+
const condition = `works only under a ${shortProfile(profile)} mandate, check list-authorizations`;
|
|
4660
4666
|
if (tool.gating.category === "read") {
|
|
4661
|
-
return `[Suveren: ${profile} \u2014 read] ${tool.description}`;
|
|
4667
|
+
return `[Suveren: ${profile} \u2014 read; ${condition}] ${tool.description}`;
|
|
4662
4668
|
}
|
|
4663
4669
|
const parts = [];
|
|
4664
4670
|
if (tool.gating.staticExecution?.action_type) {
|
|
@@ -4671,7 +4677,7 @@ function buildProxiedToolDescription(tool, state2) {
|
|
|
4671
4677
|
parts.push(`${mappedFields.join(", ")} checked`);
|
|
4672
4678
|
}
|
|
4673
4679
|
const tag = parts.length > 0 ? parts.join(", ") : "gated";
|
|
4674
|
-
return `[Suveren: ${profile} \u2014 ${tag}] ${tool.description}`;
|
|
4680
|
+
return `[Suveren: ${profile} \u2014 ${tag}; ${condition}] ${tool.description}`;
|
|
4675
4681
|
}
|
|
4676
4682
|
|
|
4677
4683
|
// src/lib/agent-visibility.ts
|
|
@@ -4727,7 +4733,8 @@ function buildMandateBrief(opts) {
|
|
|
4727
4733
|
"You are connected to Suveren \u2014 the gateway that gates every privileged tool call you make.",
|
|
4728
4734
|
"Suveren implements the bounded-authority model from the open Human Agency Protocol (HAP).",
|
|
4729
4735
|
"You have bounded authorities granted by human decision owners.",
|
|
4730
|
-
"You MUST stay within these bounds \u2014 the Gatekeeper will reject actions that exceed them."
|
|
4736
|
+
"You MUST stay within these bounds \u2014 the Gatekeeper will reject actions that exceed them.",
|
|
4737
|
+
"Tools are listed even where no mandate covers them yet. If a call is refused because no mandate covers it, tell the person and ask them to grant one \u2014 do not retry it or work around it with another tool."
|
|
4731
4738
|
];
|
|
4732
4739
|
if (opts.asVersionRefusal) {
|
|
4733
4740
|
lines.push("");
|
|
@@ -4823,7 +4830,7 @@ function buildCapabilityMap(profileId, integrationManager2) {
|
|
|
4823
4830
|
const readOnly = [];
|
|
4824
4831
|
const undescribed = [];
|
|
4825
4832
|
for (const tool of allTools) {
|
|
4826
|
-
if (!tool.gating || !tool.gating.profile) {
|
|
4833
|
+
if (tool.internal || !tool.gating || !tool.gating.profile) {
|
|
4827
4834
|
continue;
|
|
4828
4835
|
}
|
|
4829
4836
|
if (!profileMatches(tool.gating.profile, shortName2) && tool.gating.profile !== profileId) {
|
|
@@ -4864,6 +4871,20 @@ function buildCapabilityMap(profileId, integrationManager2) {
|
|
|
4864
4871
|
}
|
|
4865
4872
|
return lines.join("\n");
|
|
4866
4873
|
}
|
|
4874
|
+
function listedWithoutMandate(authorizations, integrationManager2) {
|
|
4875
|
+
if (!integrationManager2) return [];
|
|
4876
|
+
const isBuiltin = (id) => integrationManager2.isBuiltin?.(id) ?? false;
|
|
4877
|
+
const byProfile = /* @__PURE__ */ new Map();
|
|
4878
|
+
for (const tool of integrationManager2.getAllTools()) {
|
|
4879
|
+
if (!toolAlwaysListed(tool, isBuiltin)) continue;
|
|
4880
|
+
const profile = tool.gating.profile;
|
|
4881
|
+
if (authorizations.some((a) => a.complete && profileMatches(a.profileId, profile))) continue;
|
|
4882
|
+
const short = shortProfileName2(profile);
|
|
4883
|
+
byProfile.set(short, [...byProfile.get(short) ?? [], tool.namespacedName]);
|
|
4884
|
+
}
|
|
4885
|
+
return [...byProfile.entries()].map(([profile, tools]) => ` ${profile}: ${tools.join(", ")}`);
|
|
4886
|
+
}
|
|
4887
|
+
var LISTED_WITHOUT_MANDATE_HEADING = "Listed but not usable yet \u2014 no mandate covers these; every call is refused until the person grants one:";
|
|
4867
4888
|
function listAuthorizationsHandler(state2, integrationManager2, contextDir) {
|
|
4868
4889
|
return async (args) => {
|
|
4869
4890
|
if (!state2.spClient.isUnlocked()) {
|
|
@@ -4872,13 +4893,11 @@ function listAuthorizationsHandler(state2, integrationManager2, contextDir) {
|
|
|
4872
4893
|
const authorizations = agentVisibleAuthorizations(state2.getEnrichedAuthorizations(), integrationManager2);
|
|
4873
4894
|
const now = Math.floor(Date.now() / 1e3);
|
|
4874
4895
|
const domain = args?.domain;
|
|
4896
|
+
const notYet = listedWithoutMandate(authorizations, integrationManager2);
|
|
4875
4897
|
if (authorizations.length === 0) {
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
text: "No active authorizations. A decision owner must grant authority via the Authority UI."
|
|
4880
|
-
}]
|
|
4881
|
-
};
|
|
4898
|
+
const text = ["No active authorizations \u2014 no tool is usable yet. Ask the person to grant a mandate in the gateway."];
|
|
4899
|
+
if (notYet.length > 0) text.push("", LISTED_WITHOUT_MANDATE_HEADING, ...notYet);
|
|
4900
|
+
return { content: [{ type: "text", text: text.join("\n") }] };
|
|
4882
4901
|
}
|
|
4883
4902
|
if (domain) {
|
|
4884
4903
|
const matching = authorizations.filter((auth) => {
|
|
@@ -4999,7 +5018,7 @@ function listAuthorizationsHandler(state2, integrationManager2, contextDir) {
|
|
|
4999
5018
|
output.push("");
|
|
5000
5019
|
}
|
|
5001
5020
|
if (active.length > 0) {
|
|
5002
|
-
output.push("Active authorizations:");
|
|
5021
|
+
output.push("Active authorizations (usable now):");
|
|
5003
5022
|
output.push(...active);
|
|
5004
5023
|
}
|
|
5005
5024
|
if (pending.length > 0) {
|
|
@@ -5007,6 +5026,11 @@ function listAuthorizationsHandler(state2, integrationManager2, contextDir) {
|
|
|
5007
5026
|
output.push("Pending (missing owners):");
|
|
5008
5027
|
output.push(...pending);
|
|
5009
5028
|
}
|
|
5029
|
+
if (notYet.length > 0) {
|
|
5030
|
+
if (output.length > 0) output.push("");
|
|
5031
|
+
output.push(LISTED_WITHOUT_MANDATE_HEADING);
|
|
5032
|
+
output.push(...notYet);
|
|
5033
|
+
}
|
|
5010
5034
|
return {
|
|
5011
5035
|
content: [{
|
|
5012
5036
|
type: "text",
|
|
@@ -5623,7 +5647,7 @@ function createMcpServer(state2, integrationManager2) {
|
|
|
5623
5647
|
}
|
|
5624
5648
|
const handler = createGatedToolHandler(tool, integrationManager2, state2);
|
|
5625
5649
|
const zodShape = jsonSchemaToZodShape(tool.inputSchema);
|
|
5626
|
-
const description = buildProxiedToolDescription(tool
|
|
5650
|
+
const description = buildProxiedToolDescription(tool);
|
|
5627
5651
|
try {
|
|
5628
5652
|
const registered = server.registerTool(
|
|
5629
5653
|
tool.namespacedName,
|
|
@@ -5641,10 +5665,11 @@ function createMcpServer(state2, integrationManager2) {
|
|
|
5641
5665
|
}
|
|
5642
5666
|
function refreshTools() {
|
|
5643
5667
|
const auths = state2.getEnrichedAuthorizations();
|
|
5668
|
+
const isBuiltin = (id) => integrationManager2?.isBuiltin?.(id) ?? false;
|
|
5644
5669
|
for (const [, { tool, registered }] of proxiedTools) {
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
if (tool.gating?.profile) {
|
|
5670
|
+
if (toolAlwaysListed(tool, isBuiltin)) {
|
|
5671
|
+
registered.enable();
|
|
5672
|
+
} else if (tool.gating?.profile) {
|
|
5648
5673
|
const matchingAuths = auths.filter(
|
|
5649
5674
|
(a) => a.complete && profileMatches(a.profileId, tool.gating.profile)
|
|
5650
5675
|
);
|