@kya-os/mcp-i-core 1.3.24 → 1.3.25
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/identity/user-did-manager.d.ts +1 -1
- package/dist/identity/user-did-manager.js +32 -24
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -2
- package/dist/runtime/base.js +11 -11
- package/dist/services/provider-resolver.d.ts +18 -0
- package/dist/services/provider-resolver.js +36 -2
- package/dist/services/tool-protection.service.d.ts +25 -3
- package/dist/services/tool-protection.service.js +161 -249
- package/dist/types/tool-protection.d.ts +27 -4
- package/dist/utils/base64.js +48 -21
- package/dist/utils/storage-keys.js +6 -6
- package/package.json +2 -2
|
@@ -56,7 +56,7 @@ class UserDidManager {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
catch (error) {
|
|
59
|
-
console.warn(
|
|
59
|
+
console.warn("[UserDidManager] OAuth key pair lookup failed:", error);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
// Check session storage if available
|
|
@@ -69,7 +69,7 @@ class UserDidManager {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
catch (error) {
|
|
72
|
-
console.warn(
|
|
72
|
+
console.warn("[UserDidManager] Session key pair lookup failed:", error);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
return null;
|
|
@@ -96,13 +96,16 @@ class UserDidManager {
|
|
|
96
96
|
return this.sessionDidCache.get(sessionId);
|
|
97
97
|
}
|
|
98
98
|
// PRIORITY 1: If OAuth identity provided, check for persistent user DID mapping
|
|
99
|
-
if (oauthIdentity &&
|
|
99
|
+
if (oauthIdentity &&
|
|
100
|
+
oauthIdentity.provider &&
|
|
101
|
+
oauthIdentity.subject &&
|
|
102
|
+
this.config.storage?.getByOAuth) {
|
|
100
103
|
try {
|
|
101
104
|
const persistentUserDid = await this.config.storage.getByOAuth(oauthIdentity.provider, oauthIdentity.subject);
|
|
102
105
|
if (persistentUserDid) {
|
|
103
|
-
console.
|
|
106
|
+
console.error("[UserDidManager] Found persistent user DID from OAuth mapping:", {
|
|
104
107
|
provider: oauthIdentity.provider,
|
|
105
|
-
userDid: persistentUserDid.substring(0, 20) +
|
|
108
|
+
userDid: persistentUserDid.substring(0, 20) + "...",
|
|
106
109
|
});
|
|
107
110
|
// Cache it for this session
|
|
108
111
|
this.sessionDidCache.set(sessionId, persistentUserDid);
|
|
@@ -113,7 +116,7 @@ class UserDidManager {
|
|
|
113
116
|
}
|
|
114
117
|
catch (error) {
|
|
115
118
|
// Log but continue - DID is cached and will be returned
|
|
116
|
-
console.warn(
|
|
119
|
+
console.warn("[UserDidManager] Failed to cache persistent DID in session storage:", error);
|
|
117
120
|
}
|
|
118
121
|
}
|
|
119
122
|
return persistentUserDid;
|
|
@@ -121,7 +124,7 @@ class UserDidManager {
|
|
|
121
124
|
}
|
|
122
125
|
catch (error) {
|
|
123
126
|
// Log but continue - will check session storage or generate new DID
|
|
124
|
-
console.warn(
|
|
127
|
+
console.warn("[UserDidManager] OAuth lookup failed, falling back to session storage:", error);
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
// PRIORITY 2: Check session storage if available
|
|
@@ -131,18 +134,21 @@ class UserDidManager {
|
|
|
131
134
|
if (storedDid) {
|
|
132
135
|
this.sessionDidCache.set(sessionId, storedDid);
|
|
133
136
|
// If OAuth identity provided but no persistent mapping found, create one now
|
|
134
|
-
if (oauthIdentity &&
|
|
137
|
+
if (oauthIdentity &&
|
|
138
|
+
oauthIdentity.provider &&
|
|
139
|
+
oauthIdentity.subject &&
|
|
140
|
+
this.config.storage.setByOAuth) {
|
|
135
141
|
try {
|
|
136
142
|
await this.config.storage.setByOAuth(oauthIdentity.provider, oauthIdentity.subject, storedDid, 90 * 24 * 60 * 60 // 90 days TTL for persistent mapping
|
|
137
143
|
);
|
|
138
|
-
console.
|
|
144
|
+
console.error("[UserDidManager] Created persistent OAuth mapping for existing user DID:", {
|
|
139
145
|
provider: oauthIdentity.provider,
|
|
140
|
-
userDid: storedDid.substring(0, 20) +
|
|
146
|
+
userDid: storedDid.substring(0, 20) + "...",
|
|
141
147
|
});
|
|
142
148
|
}
|
|
143
149
|
catch (error) {
|
|
144
150
|
// Log but continue - mapping creation failed, but DID is still valid
|
|
145
|
-
console.warn(
|
|
151
|
+
console.warn("[UserDidManager] Failed to create OAuth mapping:", error);
|
|
146
152
|
}
|
|
147
153
|
}
|
|
148
154
|
return storedDid;
|
|
@@ -150,7 +156,7 @@ class UserDidManager {
|
|
|
150
156
|
}
|
|
151
157
|
catch (error) {
|
|
152
158
|
// Log but continue - session will be anonymous
|
|
153
|
-
console.warn(
|
|
159
|
+
console.warn("[UserDidManager] Storage.get failed:", error);
|
|
154
160
|
}
|
|
155
161
|
}
|
|
156
162
|
// PHASE 5: No ephemeral DID generation - session stays anonymous
|
|
@@ -176,21 +182,23 @@ class UserDidManager {
|
|
|
176
182
|
await this.config.storage.set(sessionId, userDid, 1800); // 30 minutes TTL
|
|
177
183
|
}
|
|
178
184
|
catch (error) {
|
|
179
|
-
console.warn(
|
|
185
|
+
console.warn("[UserDidManager] Failed to store user DID in session storage:", error);
|
|
180
186
|
}
|
|
181
187
|
}
|
|
182
188
|
// Create OAuth mapping if provided
|
|
183
|
-
if (oauthIdentity?.provider &&
|
|
189
|
+
if (oauthIdentity?.provider &&
|
|
190
|
+
oauthIdentity?.subject &&
|
|
191
|
+
this.config.storage?.setByOAuth) {
|
|
184
192
|
try {
|
|
185
193
|
await this.config.storage.setByOAuth(oauthIdentity.provider, oauthIdentity.subject, userDid, 90 * 24 * 60 * 60 // 90 days TTL for persistent mapping
|
|
186
194
|
);
|
|
187
|
-
console.
|
|
195
|
+
console.error("[UserDidManager] Created OAuth → DID mapping:", {
|
|
188
196
|
provider: oauthIdentity.provider,
|
|
189
|
-
userDid: userDid.substring(0, 20) +
|
|
197
|
+
userDid: userDid.substring(0, 20) + "...",
|
|
190
198
|
});
|
|
191
199
|
}
|
|
192
200
|
catch (error) {
|
|
193
|
-
console.warn(
|
|
201
|
+
console.warn("[UserDidManager] Failed to create OAuth mapping:", error);
|
|
194
202
|
}
|
|
195
203
|
}
|
|
196
204
|
}
|
|
@@ -217,7 +225,7 @@ class UserDidManager {
|
|
|
217
225
|
// Generate did:web (requires web server setup)
|
|
218
226
|
// For now, fall back to did:key
|
|
219
227
|
// TODO: Implement did:web generation if needed
|
|
220
|
-
console.warn(
|
|
228
|
+
console.warn("[UserDidManager] did:web not yet implemented, using did:key");
|
|
221
229
|
}
|
|
222
230
|
// Generate Ed25519 keypair for user DID
|
|
223
231
|
const keyPair = await this.config.crypto.generateKeyPair();
|
|
@@ -258,21 +266,21 @@ class UserDidManager {
|
|
|
258
266
|
* Simple implementation for did:key generation
|
|
259
267
|
*/
|
|
260
268
|
base58Encode(bytes) {
|
|
261
|
-
const alphabet =
|
|
269
|
+
const alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
262
270
|
let num = BigInt(0);
|
|
263
271
|
// Convert bytes to big integer
|
|
264
272
|
for (let i = 0; i < bytes.length; i++) {
|
|
265
273
|
num = num * BigInt(256) + BigInt(bytes[i]);
|
|
266
274
|
}
|
|
267
275
|
// Convert to base58
|
|
268
|
-
let result =
|
|
276
|
+
let result = "";
|
|
269
277
|
while (num > 0) {
|
|
270
278
|
result = alphabet[Number(num % BigInt(58))] + result;
|
|
271
279
|
num = num / BigInt(58);
|
|
272
280
|
}
|
|
273
281
|
// Add leading zeros
|
|
274
282
|
for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
|
|
275
|
-
result =
|
|
283
|
+
result = "1" + result;
|
|
276
284
|
}
|
|
277
285
|
return result;
|
|
278
286
|
}
|
|
@@ -280,9 +288,9 @@ class UserDidManager {
|
|
|
280
288
|
* Convert base64 string to Uint8Array
|
|
281
289
|
*/
|
|
282
290
|
base64ToBytes(base64) {
|
|
283
|
-
if (typeof Buffer !==
|
|
291
|
+
if (typeof Buffer !== "undefined") {
|
|
284
292
|
// Node.js environment
|
|
285
|
-
return new Uint8Array(Buffer.from(base64,
|
|
293
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
286
294
|
}
|
|
287
295
|
else {
|
|
288
296
|
// Browser/Workers environment
|
|
@@ -323,7 +331,7 @@ class UserDidManager {
|
|
|
323
331
|
}
|
|
324
332
|
catch (error) {
|
|
325
333
|
// Log but continue - cache is already cleared
|
|
326
|
-
console.warn(
|
|
334
|
+
console.warn("[UserDidManager] Storage.delete failed, continuing:", error);
|
|
327
335
|
}
|
|
328
336
|
}
|
|
329
337
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export type { OAuthServiceConfig } from "./services/oauth-service";
|
|
|
26
26
|
export { ToolContextBuilder } from "./services/tool-context-builder";
|
|
27
27
|
export type { ToolContextBuilderConfig } from "./services/tool-context-builder";
|
|
28
28
|
export { OAuthProviderRegistry } from "./services/oauth-provider-registry";
|
|
29
|
-
export { ProviderResolver } from "./services/provider-resolver";
|
|
30
|
-
export { ProviderValidator, ProviderValidationError } from "./services/provider-validator";
|
|
29
|
+
export { ProviderResolver, ConsentOnlyModeError, } from "./services/provider-resolver";
|
|
30
|
+
export { ProviderValidator, ProviderValidationError, } from "./services/provider-validator";
|
|
31
31
|
export { OAuthTokenRetrievalService } from "./services/oauth-token-retrieval.service";
|
|
32
32
|
export type { OAuthTokenRetrievalServiceConfig } from "./services/oauth-token-retrieval.service";
|
|
33
33
|
export { BatchDelegationService } from "./services/batch-delegation.service";
|
|
@@ -52,7 +52,7 @@ export { CascadingRevocationManager, createCascadingRevocationManager, type Revo
|
|
|
52
52
|
export { MemoryStatusListStorage } from "./delegation/storage/memory-statuslist-storage";
|
|
53
53
|
export { MemoryDelegationGraphStorage } from "./delegation/storage/memory-graph-storage";
|
|
54
54
|
export { createDidKeyResolver, isEd25519DidKey, extractPublicKeyFromDidKey, publicKeyToJwk, resolveDidKeySync, } from "./delegation/did-key-resolver";
|
|
55
|
-
export { base58Encode, base58Decode, isValidBase58
|
|
55
|
+
export { base58Encode, base58Decode, isValidBase58 } from "./utils/base58";
|
|
56
56
|
export { SchemaVerifier, createSchemaVerifier, type SchemaMetadata, type FieldComplianceResult, type SchemaComplianceReport, type FullComplianceReport, } from "./compliance/schema-verifier";
|
|
57
57
|
export { SCHEMA_REGISTRY, getAllSchemas, getSchemasByCategory, getSchemaById, getCriticalSchemas, getSchemaStats, } from "./compliance/schema-registry";
|
|
58
58
|
export { canonicalizeJSON, createUnsignedVCJWT, completeVCJWT, parseVCJWT, type VCJWTHeader, type VCJWTPayload, type EncodeVCAsJWTOptions, } from "./delegation/utils";
|
package/dist/index.js
CHANGED
|
@@ -20,8 +20,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
20
20
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
21
|
};
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.
|
|
24
|
-
exports.IdpTokenResolver = exports.UserDidManager = exports.fetchRemoteConfig = exports.bytesToBase64 = exports.base64urlDecodeToString = exports.base64urlDecodeToBytes = exports.base64urlEncodeFromString = exports.base64urlEncodeFromBytes = exports.parseVCJWT = exports.completeVCJWT = exports.createUnsignedVCJWT = exports.canonicalizeJSON = exports.getSchemaStats = exports.getCriticalSchemas = exports.getSchemaById = exports.getSchemasByCategory = exports.getAllSchemas = exports.SCHEMA_REGISTRY = exports.createSchemaVerifier = exports.SchemaVerifier = exports.isValidBase58 = exports.base58Decode = exports.base58Encode = exports.resolveDidKeySync = exports.publicKeyToJwk = exports.extractPublicKeyFromDidKey = exports.isEd25519DidKey = exports.createDidKeyResolver = exports.MemoryDelegationGraphStorage = exports.MemoryStatusListStorage = void 0;
|
|
23
|
+
exports.CascadingRevocationManager = exports.createDelegationGraph = exports.DelegationGraphManager = exports.isIndexSet = exports.BitstringManager = exports.createStatusListManager = exports.StatusList2021Manager = exports.createDelegationVerifier = exports.DelegationCredentialVerifier = exports.createDelegationIssuer = exports.DelegationCredentialIssuer = exports.OAuthRequiredError = exports.DelegationRequiredError = exports.NoOpToolProtectionCache = exports.InMemoryToolProtectionCache = exports.createProofVerificationError = exports.PROOF_VERIFICATION_ERROR_CODES = exports.ProofVerificationError = exports.migrateLegacyKeys = exports.StorageKeyHelpers = exports.createStorageProviders = exports.NoOpOAuthConfigCache = exports.InMemoryOAuthConfigCache = exports.BatchDelegationService = exports.OAuthTokenRetrievalService = exports.ProviderValidationError = exports.ProviderValidator = exports.ConsentOnlyModeError = exports.ProviderResolver = exports.OAuthProviderRegistry = exports.ToolContextBuilder = exports.OAuthService = exports.OAuthConfigService = exports.createSessionRegistrationService = exports.SessionRegistrationService = exports.authorizationMatches = exports.AccessControlApiService = exports.ProofVerifier = exports.CryptoService = exports.ToolProtectionService = exports.MCPIRuntimeBase = exports.MemoryIdentityProvider = exports.MemoryNonceCacheProvider = exports.MemoryStorageProvider = exports.IdentityProvider = exports.NonceCacheProvider = exports.StorageProvider = exports.FetchProvider = exports.ClockProvider = exports.CryptoProvider = void 0;
|
|
24
|
+
exports.IdpTokenResolver = exports.UserDidManager = exports.fetchRemoteConfig = exports.bytesToBase64 = exports.base64urlDecodeToString = exports.base64urlDecodeToBytes = exports.base64urlEncodeFromString = exports.base64urlEncodeFromBytes = exports.parseVCJWT = exports.completeVCJWT = exports.createUnsignedVCJWT = exports.canonicalizeJSON = exports.getSchemaStats = exports.getCriticalSchemas = exports.getSchemaById = exports.getSchemasByCategory = exports.getAllSchemas = exports.SCHEMA_REGISTRY = exports.createSchemaVerifier = exports.SchemaVerifier = exports.isValidBase58 = exports.base58Decode = exports.base58Encode = exports.resolveDidKeySync = exports.publicKeyToJwk = exports.extractPublicKeyFromDidKey = exports.isEd25519DidKey = exports.createDidKeyResolver = exports.MemoryDelegationGraphStorage = exports.MemoryStatusListStorage = exports.createCascadingRevocationManager = void 0;
|
|
25
25
|
// Base providers
|
|
26
26
|
var base_1 = require("./providers/base");
|
|
27
27
|
Object.defineProperty(exports, "CryptoProvider", { enumerable: true, get: function () { return base_1.CryptoProvider; } });
|
|
@@ -72,6 +72,7 @@ Object.defineProperty(exports, "OAuthProviderRegistry", { enumerable: true, get:
|
|
|
72
72
|
// Provider Resolver (Phase 2)
|
|
73
73
|
var provider_resolver_1 = require("./services/provider-resolver");
|
|
74
74
|
Object.defineProperty(exports, "ProviderResolver", { enumerable: true, get: function () { return provider_resolver_1.ProviderResolver; } });
|
|
75
|
+
Object.defineProperty(exports, "ConsentOnlyModeError", { enumerable: true, get: function () { return provider_resolver_1.ConsentOnlyModeError; } });
|
|
75
76
|
// Provider Validator (Phase 3)
|
|
76
77
|
var provider_validator_1 = require("./services/provider-validator");
|
|
77
78
|
Object.defineProperty(exports, "ProviderValidator", { enumerable: true, get: function () { return provider_validator_1.ProviderValidator; } });
|
package/dist/runtime/base.js
CHANGED
|
@@ -113,14 +113,14 @@ class MCPIRuntimeBase {
|
|
|
113
113
|
userDid = resolvedDid ?? undefined;
|
|
114
114
|
if (this.config.audit?.enabled) {
|
|
115
115
|
if (userDid) {
|
|
116
|
-
console.
|
|
116
|
+
console.error("[MCP-I] Resolved existing user DID for session:", {
|
|
117
117
|
userDid: userDid.substring(0, 20) + "...",
|
|
118
118
|
hasOAuth: !!oauthIdentity,
|
|
119
119
|
provider: oauthIdentity?.provider,
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
122
|
else {
|
|
123
|
-
console.
|
|
123
|
+
console.error("[MCP-I] Session started anonymous (no userDid):", {
|
|
124
124
|
sessionId: sessionId.substring(0, 8) + "...",
|
|
125
125
|
hasOAuth: !!oauthIdentity,
|
|
126
126
|
});
|
|
@@ -219,7 +219,7 @@ class MCPIRuntimeBase {
|
|
|
219
219
|
await this.userDidManager.setUserDidForSession(sessionId, userDid, oauthIdentity);
|
|
220
220
|
}
|
|
221
221
|
if (this.config.audit?.enabled) {
|
|
222
|
-
console.
|
|
222
|
+
console.error("[MCP-I] Session identity updated (Phase 5):", {
|
|
223
223
|
sessionId: sessionId.substring(0, 8) + "...",
|
|
224
224
|
userDid: userDid.substring(0, 20) + "...",
|
|
225
225
|
provider: oauthIdentity?.provider,
|
|
@@ -248,7 +248,7 @@ class MCPIRuntimeBase {
|
|
|
248
248
|
// Get agent identity to check protection
|
|
249
249
|
const identity = await this.getIdentity();
|
|
250
250
|
if (this.config.audit?.enabled) {
|
|
251
|
-
console.
|
|
251
|
+
console.error("[MCP-I] Checking tool protection:", {
|
|
252
252
|
tool: toolName,
|
|
253
253
|
agentDid: identity.did.slice(0, 20) + "...",
|
|
254
254
|
hasDelegation: !!(session?.delegationToken || session?.consentProof),
|
|
@@ -312,7 +312,7 @@ class MCPIRuntimeBase {
|
|
|
312
312
|
// Verify delegation token with AccessControlApiService
|
|
313
313
|
try {
|
|
314
314
|
if (this.config.audit?.enabled) {
|
|
315
|
-
console.
|
|
315
|
+
console.error("[MCP-I] 🔐 Verifying delegation token with AccessControlApiService", {
|
|
316
316
|
tool: toolName,
|
|
317
317
|
agentDid: identity.did.slice(0, 20) + "...",
|
|
318
318
|
hasDelegationToken: !!delegationToken,
|
|
@@ -331,7 +331,7 @@ class MCPIRuntimeBase {
|
|
|
331
331
|
if (session?.userDid) {
|
|
332
332
|
verifyRequest.user_did = session.userDid;
|
|
333
333
|
if (this.config.audit?.enabled) {
|
|
334
|
-
console.
|
|
334
|
+
console.error("[MCP-I] 🔐 Including user_did in verification request", {
|
|
335
335
|
userDid: session.userDid.slice(0, 20) + "...",
|
|
336
336
|
});
|
|
337
337
|
}
|
|
@@ -442,7 +442,7 @@ class MCPIRuntimeBase {
|
|
|
442
442
|
}
|
|
443
443
|
// User identifier validation passed (direct match or trusted AgentShield verification)
|
|
444
444
|
if (this.config.audit?.enabled) {
|
|
445
|
-
console.
|
|
445
|
+
console.error("[MCP-I] ✅ User identifier validation PASSED", {
|
|
446
446
|
tool: toolName,
|
|
447
447
|
agentDid: identity.did.slice(0, 20) + "...",
|
|
448
448
|
userDid: sessionUserDid.substring(0, 20) + "...",
|
|
@@ -530,7 +530,7 @@ class MCPIRuntimeBase {
|
|
|
530
530
|
}
|
|
531
531
|
// Authorization method validation passed
|
|
532
532
|
if (this.config.audit?.enabled) {
|
|
533
|
-
console.
|
|
533
|
+
console.error("[MCP-I] ✅ Authorization method validation PASSED", {
|
|
534
534
|
tool: toolName,
|
|
535
535
|
agentDid: identity.did.slice(0, 20) + "...",
|
|
536
536
|
authType: delegationAuth.type,
|
|
@@ -541,7 +541,7 @@ class MCPIRuntimeBase {
|
|
|
541
541
|
// If credential is missing entirely (KV/Memory verifiers), skip validation for backward compatibility
|
|
542
542
|
// Verification succeeded
|
|
543
543
|
if (this.config.audit?.enabled) {
|
|
544
|
-
console.
|
|
544
|
+
console.error("[MCP-I] ✅ Delegation verification SUCCEEDED", {
|
|
545
545
|
tool: toolName,
|
|
546
546
|
agentDid: identity.did.slice(0, 20) + "...",
|
|
547
547
|
delegationId: verificationResult.data.delegation_id,
|
|
@@ -614,7 +614,7 @@ class MCPIRuntimeBase {
|
|
|
614
614
|
else {
|
|
615
615
|
// No protection required - tool can be executed freely
|
|
616
616
|
if (this.config.audit?.enabled) {
|
|
617
|
-
console.
|
|
617
|
+
console.error("[MCP-I] Tool protection check passed (no delegation required)", {
|
|
618
618
|
tool: toolName,
|
|
619
619
|
agentDid: identity.did.slice(0, 20) + "...",
|
|
620
620
|
reason: "Tool not configured to require delegation",
|
|
@@ -1120,7 +1120,7 @@ class MCPIRuntimeBase {
|
|
|
1120
1120
|
this.config.audit.logFunction(logLine);
|
|
1121
1121
|
}
|
|
1122
1122
|
else {
|
|
1123
|
-
console.
|
|
1123
|
+
console.error("[AUDIT]", logLine);
|
|
1124
1124
|
}
|
|
1125
1125
|
}
|
|
1126
1126
|
createDIDDocument(identity) {
|
|
@@ -9,10 +9,19 @@
|
|
|
9
9
|
import type { ToolProtection } from "@kya-os/contracts/tool-protection";
|
|
10
10
|
import type { OAuthProviderRegistry } from "./oauth-provider-registry.js";
|
|
11
11
|
import type { OAuthConfigService } from "./oauth-config.service.js";
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when a tool is configured for consent-only mode (no OAuth needed)
|
|
14
|
+
* This is NOT an error condition - it's a signal to skip OAuth flow
|
|
15
|
+
*/
|
|
16
|
+
export declare class ConsentOnlyModeError extends Error {
|
|
17
|
+
readonly toolProtection: ToolProtection;
|
|
18
|
+
constructor(toolProtection: ToolProtection);
|
|
19
|
+
}
|
|
12
20
|
/**
|
|
13
21
|
* Resolves OAuth provider for tools with priority-based fallback strategy
|
|
14
22
|
*
|
|
15
23
|
* Priority order:
|
|
24
|
+
* 0. Check for consent-only mode (authorization.type === 'none') - skip OAuth
|
|
16
25
|
* 1. Tool-specific oauthProvider field (Phase 2+ preferred)
|
|
17
26
|
* 2. Scope prefix inference (fallback)
|
|
18
27
|
* 3. Project-configured provider from AgentShield dashboard
|
|
@@ -22,12 +31,21 @@ export declare class ProviderResolver {
|
|
|
22
31
|
private registry;
|
|
23
32
|
private configService;
|
|
24
33
|
constructor(registry: OAuthProviderRegistry, configService: OAuthConfigService);
|
|
34
|
+
/**
|
|
35
|
+
* Check if a tool is configured for consent-only mode
|
|
36
|
+
* Consent-only means delegation is required but no OAuth provider is needed
|
|
37
|
+
*
|
|
38
|
+
* @param toolProtection - Tool protection configuration
|
|
39
|
+
* @returns true if consent-only mode
|
|
40
|
+
*/
|
|
41
|
+
isConsentOnlyMode(toolProtection: ToolProtection): boolean;
|
|
25
42
|
/**
|
|
26
43
|
* Resolve OAuth provider for a tool
|
|
27
44
|
*
|
|
28
45
|
* @param toolProtection - Tool protection configuration
|
|
29
46
|
* @param projectId - Project ID for fetching provider config
|
|
30
47
|
* @returns Provider name (never null - throws if cannot resolve)
|
|
48
|
+
* @throws ConsentOnlyModeError if tool is consent-only (not a real error)
|
|
31
49
|
* @throws Error if provider cannot be resolved
|
|
32
50
|
*/
|
|
33
51
|
resolveProvider(toolProtection: ToolProtection, projectId: string): Promise<string>;
|
|
@@ -8,11 +8,25 @@
|
|
|
8
8
|
* @package @kya-os/mcp-i-core
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.ProviderResolver = void 0;
|
|
11
|
+
exports.ProviderResolver = exports.ConsentOnlyModeError = void 0;
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when a tool is configured for consent-only mode (no OAuth needed)
|
|
14
|
+
* This is NOT an error condition - it's a signal to skip OAuth flow
|
|
15
|
+
*/
|
|
16
|
+
class ConsentOnlyModeError extends Error {
|
|
17
|
+
toolProtection;
|
|
18
|
+
constructor(toolProtection) {
|
|
19
|
+
super("Tool is configured for consent-only mode (no OAuth provider required)");
|
|
20
|
+
this.toolProtection = toolProtection;
|
|
21
|
+
this.name = "ConsentOnlyModeError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.ConsentOnlyModeError = ConsentOnlyModeError;
|
|
12
25
|
/**
|
|
13
26
|
* Resolves OAuth provider for tools with priority-based fallback strategy
|
|
14
27
|
*
|
|
15
28
|
* Priority order:
|
|
29
|
+
* 0. Check for consent-only mode (authorization.type === 'none') - skip OAuth
|
|
16
30
|
* 1. Tool-specific oauthProvider field (Phase 2+ preferred)
|
|
17
31
|
* 2. Scope prefix inference (fallback)
|
|
18
32
|
* 3. Project-configured provider from AgentShield dashboard
|
|
@@ -25,15 +39,35 @@ class ProviderResolver {
|
|
|
25
39
|
this.registry = registry;
|
|
26
40
|
this.configService = configService;
|
|
27
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a tool is configured for consent-only mode
|
|
44
|
+
* Consent-only means delegation is required but no OAuth provider is needed
|
|
45
|
+
*
|
|
46
|
+
* @param toolProtection - Tool protection configuration
|
|
47
|
+
* @returns true if consent-only mode
|
|
48
|
+
*/
|
|
49
|
+
isConsentOnlyMode(toolProtection) {
|
|
50
|
+
// Check explicit authorization.type === 'none'
|
|
51
|
+
if (toolProtection.authorization?.type === "none") {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
28
56
|
/**
|
|
29
57
|
* Resolve OAuth provider for a tool
|
|
30
58
|
*
|
|
31
59
|
* @param toolProtection - Tool protection configuration
|
|
32
60
|
* @param projectId - Project ID for fetching provider config
|
|
33
61
|
* @returns Provider name (never null - throws if cannot resolve)
|
|
62
|
+
* @throws ConsentOnlyModeError if tool is consent-only (not a real error)
|
|
34
63
|
* @throws Error if provider cannot be resolved
|
|
35
64
|
*/
|
|
36
65
|
async resolveProvider(toolProtection, projectId) {
|
|
66
|
+
// Priority 0: Check for consent-only mode (no OAuth required)
|
|
67
|
+
if (this.isConsentOnlyMode(toolProtection)) {
|
|
68
|
+
console.error(`[ProviderResolver] Tool is consent-only mode (authorization.type=none), skipping OAuth resolution`);
|
|
69
|
+
throw new ConsentOnlyModeError(toolProtection);
|
|
70
|
+
}
|
|
37
71
|
// Priority 1: Tool-specific provider (Phase 2+ preferred)
|
|
38
72
|
if (toolProtection.oauthProvider) {
|
|
39
73
|
// Ensure registry is loaded before checking
|
|
@@ -54,7 +88,7 @@ class ProviderResolver {
|
|
|
54
88
|
await this.registry.loadFromAgentShield(projectId);
|
|
55
89
|
}
|
|
56
90
|
if (this.registry.hasProvider(inferredProvider)) {
|
|
57
|
-
console.
|
|
91
|
+
console.error(`[ProviderResolver] Inferred provider "${inferredProvider}" from scopes`);
|
|
58
92
|
return inferredProvider;
|
|
59
93
|
}
|
|
60
94
|
}
|
|
@@ -4,11 +4,23 @@
|
|
|
4
4
|
* This service manages tool protection configuration from AgentShield API with
|
|
5
5
|
* efficient caching and automatic synchronization support.
|
|
6
6
|
*
|
|
7
|
+
* CONFIGURATION PRECEDENCE (highest to lowest):
|
|
8
|
+
* ---------------------------------------------
|
|
9
|
+
* 1. Remote config (AgentShield API) - WINS (source of truth)
|
|
10
|
+
* 2. Local config (localConfig) - Base defaults, overridden by remote
|
|
11
|
+
* 3. Framework defaults
|
|
12
|
+
*
|
|
13
|
+
* OFFLINE FALLBACK (only when API unavailable):
|
|
14
|
+
* ---------------------------------------------
|
|
15
|
+
* 1. Stale cache (if allowStaleCache=true and within maxStaleCacheAge)
|
|
16
|
+
* 2. offlineFallbackConfig (explicit offline-only config)
|
|
17
|
+
* 3. failSafeBehavior (deny-all or allow-all)
|
|
18
|
+
*
|
|
7
19
|
* CORE FUNCTIONALITY:
|
|
8
20
|
* -------------------
|
|
9
|
-
* 1. Fetches tool protection config from AgentShield API
|
|
10
|
-
* 2.
|
|
11
|
-
* 3.
|
|
21
|
+
* 1. Fetches tool protection config from AgentShield API (remote wins)
|
|
22
|
+
* 2. Merges with local config (local serves as base defaults)
|
|
23
|
+
* 3. Caches responses with configurable TTL (default 5 minutes)
|
|
12
24
|
* 4. Provides delegation requirement checking before tool execution
|
|
13
25
|
*
|
|
14
26
|
* SYNCHRONIZATION WITH AGENTSHIELD:
|
|
@@ -133,6 +145,16 @@ export declare class ToolProtectionService {
|
|
|
133
145
|
* @param options.bypassCDNCache When true, adds cache-busting to bypass CDN caches (used by clearAndRefresh)
|
|
134
146
|
*/
|
|
135
147
|
private fetchFromApi;
|
|
148
|
+
/**
|
|
149
|
+
* Parse tool protections from API response
|
|
150
|
+
*
|
|
151
|
+
* Extracts tool protection configs from merged config format:
|
|
152
|
+
* { data: { config: { toolProtection: { tools: {...} } } } }
|
|
153
|
+
*
|
|
154
|
+
* @param response API response from AgentShield
|
|
155
|
+
* @returns Record of tool name to ToolProtection
|
|
156
|
+
*/
|
|
157
|
+
private parseToolProtectionsFromResponse;
|
|
136
158
|
/**
|
|
137
159
|
* Clear the cache for a project or agent (useful for testing or manual refresh)
|
|
138
160
|
*
|