@kya-os/mcp-i 1.10.0 → 1.11.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/317.js +1 -0
- package/dist/342.js +1 -0
- package/dist/354.js +1 -1
- package/dist/95.js +1 -1
- package/dist/auth/oauth/router.js +2 -2
- package/dist/cli-adapter/index.js +1 -1
- package/dist/providers/node-providers.d.ts +1 -1
- package/dist/providers/node-providers.js +9 -9
- package/dist/runtime/337.js +1 -0
- package/dist/runtime/adapter-express.js +3 -3
- package/dist/runtime/adapter-nextjs.js +5 -5
- package/dist/runtime/audit.d.ts +1 -1
- package/dist/runtime/auth-handshake.d.ts +1 -1
- package/dist/runtime/auth-handshake.js +4 -4
- package/dist/runtime/debug.d.ts +1 -1
- package/dist/runtime/debug.js +3 -2
- package/dist/runtime/delegation-hooks.d.ts +1 -1
- package/dist/runtime/delegation-verifier-agentshield.js +1 -0
- package/dist/runtime/http.js +3 -3
- package/dist/runtime/identity.d.ts +4 -4
- package/dist/runtime/identity.js +4 -4
- package/dist/runtime/index.d.ts +6 -2
- package/dist/runtime/index.js +10 -2
- package/dist/runtime/mcpi-runtime-wrapper.d.ts +1 -1
- package/dist/runtime/mcpi-runtime-wrapper.js +4 -4
- package/dist/runtime/mcpi-runtime.d.ts +9 -1
- package/dist/runtime/mcpi-runtime.js +21 -3
- package/dist/runtime/outbound-delegation.d.ts +5 -3
- package/dist/runtime/outbound-delegation.js +15 -8
- package/dist/runtime/outbound-identity-bridge.d.ts +40 -0
- package/dist/runtime/outbound-identity-bridge.js +119 -0
- package/dist/runtime/proof-batch-queue.d.ts +1 -1
- package/dist/runtime/proof.d.ts +2 -2
- package/dist/runtime/proof.js +3 -3
- package/dist/runtime/request-context.d.ts +10 -0
- package/dist/runtime/request-context.js +4 -0
- package/dist/runtime/resume-token-store-kv.d.ts +44 -0
- package/dist/runtime/resume-token-store-kv.js +93 -0
- package/dist/runtime/resume-token-store.d.ts +30 -0
- package/dist/runtime/resume-token-store.js +46 -0
- package/dist/runtime/session.d.ts +2 -2
- package/dist/runtime/session.js +12 -6
- package/dist/runtime/stdio.js +3 -3
- package/dist/runtime/utils/tools.d.ts +2 -2
- package/dist/runtime/utils/tools.js +33 -10
- package/dist/runtime/well-known.d.ts +12 -1
- package/dist/runtime/well-known.js +13 -2
- package/package.json +6 -4
- package/dist/225.js +0 -1
- package/dist/runtime/verifier-middleware.d.ts +0 -99
- package/dist/runtime/verifier-middleware.js +0 -416
|
@@ -113,16 +113,16 @@ export declare class IdentityManager {
|
|
|
113
113
|
export declare const defaultIdentityManager: IdentityManager;
|
|
114
114
|
/**
|
|
115
115
|
* Extract agent ID from DID
|
|
116
|
-
* @deprecated Use extractAgentId from @kya-os/mcp-i-
|
|
116
|
+
* @deprecated Use extractAgentId from @kya-os/mcp-i-runtime/utils/did-helpers instead
|
|
117
117
|
* This re-export is maintained for backward compatibility
|
|
118
118
|
*/
|
|
119
|
-
export { extractAgentId } from '@kya-os/mcp-i-
|
|
119
|
+
export { extractAgentId } from '@kya-os/mcp-i-runtime/utils/did-helpers';
|
|
120
120
|
/**
|
|
121
121
|
* Extract agent slug from DID
|
|
122
|
-
* @deprecated Use extractAgentSlug from @kya-os/mcp-i-
|
|
122
|
+
* @deprecated Use extractAgentSlug from @kya-os/mcp-i-runtime/utils/did-helpers instead
|
|
123
123
|
* This re-export is maintained for backward compatibility
|
|
124
124
|
*/
|
|
125
|
-
export { extractAgentSlug } from '@kya-os/mcp-i-
|
|
125
|
+
export { extractAgentSlug } from '@kya-os/mcp-i-runtime/utils/did-helpers';
|
|
126
126
|
/**
|
|
127
127
|
* Convenience function to ensure identity
|
|
128
128
|
*/
|
package/dist/runtime/identity.js
CHANGED
|
@@ -293,17 +293,17 @@ exports.IdentityManager = IdentityManager;
|
|
|
293
293
|
exports.defaultIdentityManager = new IdentityManager();
|
|
294
294
|
/**
|
|
295
295
|
* Extract agent ID from DID
|
|
296
|
-
* @deprecated Use extractAgentId from @kya-os/mcp-i-
|
|
296
|
+
* @deprecated Use extractAgentId from @kya-os/mcp-i-runtime/utils/did-helpers instead
|
|
297
297
|
* This re-export is maintained for backward compatibility
|
|
298
298
|
*/
|
|
299
|
-
var did_helpers_1 = require("@kya-os/mcp-i-
|
|
299
|
+
var did_helpers_1 = require("@kya-os/mcp-i-runtime/utils/did-helpers");
|
|
300
300
|
Object.defineProperty(exports, "extractAgentId", { enumerable: true, get: function () { return did_helpers_1.extractAgentId; } });
|
|
301
301
|
/**
|
|
302
302
|
* Extract agent slug from DID
|
|
303
|
-
* @deprecated Use extractAgentSlug from @kya-os/mcp-i-
|
|
303
|
+
* @deprecated Use extractAgentSlug from @kya-os/mcp-i-runtime/utils/did-helpers instead
|
|
304
304
|
* This re-export is maintained for backward compatibility
|
|
305
305
|
*/
|
|
306
|
-
var did_helpers_2 = require("@kya-os/mcp-i-
|
|
306
|
+
var did_helpers_2 = require("@kya-os/mcp-i-runtime/utils/did-helpers");
|
|
307
307
|
Object.defineProperty(exports, "extractAgentSlug", { enumerable: true, get: function () { return did_helpers_2.extractAgentSlug; } });
|
|
308
308
|
/**
|
|
309
309
|
* Convenience function to ensure identity
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -16,6 +16,9 @@ export { DebugManager, createDebugEndpoint, type DebugVerificationResult, type D
|
|
|
16
16
|
export { DemoManager, createDemoManager, DemoConsole, formatVerifyLink, type DemoConfig, } from "./demo";
|
|
17
17
|
export { type DelegationVerifier, type DelegationVerifierConfig, type VerifyDelegationResult, type VerifyDelegationOptions, createDelegationVerifier, checkScopes, validateDelegation, extractScopes, } from "./delegation-verifier";
|
|
18
18
|
export { type AuthHandshakeConfig, type VerifyOrHintsResult, type AgentReputation, type ResumeTokenStore, verifyOrHints, hasSensitiveScopes, MemoryResumeTokenStore, } from "./auth-handshake";
|
|
19
|
+
export { createResumeTokenStore, type ResumeTokenStoreConfig, } from "./resume-token-store";
|
|
20
|
+
export { CloudflareKVResumeTokenStore, type ResumeTokenKVNamespace, } from "./resume-token-store-kv";
|
|
21
|
+
export { ensureOutboundIdentityBridge } from "./outbound-identity-bridge";
|
|
19
22
|
export { type ProofDestination, type ProofBatchQueueConfig, ProofBatchQueue, KTAProofDestination, AgentShieldProofDestination, createProofBatchQueue, } from "./proof-batch-queue";
|
|
20
23
|
export { CloudflareKVDelegationVerifier, } from "./delegation-verifier-kv";
|
|
21
24
|
export { AgentShieldAPIDelegationVerifier, } from "./delegation-verifier-agentshield";
|
|
@@ -23,5 +26,6 @@ export { MemoryDelegationVerifier, } from "./delegation-verifier-memory";
|
|
|
23
26
|
export { type ToolProtectionConfig, type ToolProtectionMap, type ToolProtectionConfigSource, ToolProtectionResolver, createToolProtectionResolver, InlineToolProtectionSource, FileToolProtectionSource, AgentShieldToolProtectionSource, } from "./tool-protection";
|
|
24
27
|
export { toolProtectionRegistry, isToolProtected, getToolProtection, } from "./tool-protection-registry";
|
|
25
28
|
export type { HandshakeRequest, SessionContext, NonceCache, NonceCacheEntry, NonceCacheConfig, } from "@kya-os/contracts/handshake";
|
|
26
|
-
export type { ProofMeta, DetachedProof, CanonicalHashes, AuditRecord, } from "@kya-os/
|
|
27
|
-
export type { DelegationRecord, DelegationStatus,
|
|
29
|
+
export type { ProofMeta, DetachedProof, CanonicalHashes, AuditRecord, } from "@kya-os/mcp/types" with { "resolution-mode": "import" };
|
|
30
|
+
export type { DelegationRecord, DelegationStatus, DelegationConstraints, } from "@kya-os/mcp/types" with { "resolution-mode": "import" };
|
|
31
|
+
export type { DelegationChain } from "@kya-os/contracts/delegation";
|
package/dist/runtime/index.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* audit logging, and well-known endpoints.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.
|
|
10
|
-
exports.getToolProtection = exports.isToolProtected = exports.toolProtectionRegistry = exports.AgentShieldToolProtectionSource = void 0;
|
|
9
|
+
exports.ToolProtectionResolver = exports.MemoryDelegationVerifier = exports.AgentShieldAPIDelegationVerifier = exports.CloudflareKVDelegationVerifier = exports.createProofBatchQueue = exports.AgentShieldProofDestination = exports.KTAProofDestination = exports.ProofBatchQueue = exports.ensureOutboundIdentityBridge = exports.CloudflareKVResumeTokenStore = exports.createResumeTokenStore = exports.MemoryResumeTokenStore = exports.hasSensitiveScopes = exports.verifyOrHints = exports.extractScopes = exports.validateDelegation = exports.checkScopes = exports.createDelegationVerifier = exports.formatVerifyLink = exports.DemoConsole = exports.createDemoManager = exports.DemoManager = exports.createDebugEndpoint = exports.DebugManager = exports.extractDIDFromPath = exports.validateAgentDocument = exports.validateDIDDocument = exports.createWellKnownHandler = exports.WellKnownManager = exports.validateAuditRecord = exports.parseAuditLine = exports.logKeyRotationAudit = exports.defaultAuditLogger = exports.AuditLogger = exports.extractCanonicalData = exports.createProofResponse = exports.ProofGenerator = exports.validateHandshakeFormat = exports.createHandshakeRequest = exports.defaultSessionManager = exports.SessionManager = exports.IDENTITY_ERRORS = exports.ensureIdentity = exports.defaultIdentityManager = exports.IdentityManager = exports.RUNTIME_ERRORS = exports.RuntimeFactory = exports.createMCPIRuntime = exports.MCPIRuntime = exports.MCPINodeRuntimeWrapper = void 0;
|
|
10
|
+
exports.getToolProtection = exports.isToolProtected = exports.toolProtectionRegistry = exports.AgentShieldToolProtectionSource = exports.FileToolProtectionSource = exports.InlineToolProtectionSource = exports.createToolProtectionResolver = void 0;
|
|
11
11
|
// Main runtime - Node.js implementation with providers
|
|
12
12
|
var mcpi_runtime_wrapper_1 = require("./mcpi-runtime-wrapper");
|
|
13
13
|
Object.defineProperty(exports, "MCPINodeRuntimeWrapper", { enumerable: true, get: function () { return mcpi_runtime_wrapper_1.MCPINodeRuntimeWrapper; } });
|
|
@@ -69,6 +69,14 @@ var auth_handshake_1 = require("./auth-handshake");
|
|
|
69
69
|
Object.defineProperty(exports, "verifyOrHints", { enumerable: true, get: function () { return auth_handshake_1.verifyOrHints; } });
|
|
70
70
|
Object.defineProperty(exports, "hasSensitiveScopes", { enumerable: true, get: function () { return auth_handshake_1.hasSensitiveScopes; } });
|
|
71
71
|
Object.defineProperty(exports, "MemoryResumeTokenStore", { enumerable: true, get: function () { return auth_handshake_1.MemoryResumeTokenStore; } });
|
|
72
|
+
// Durable resume-token store factory (pluggable persistence)
|
|
73
|
+
var resume_token_store_1 = require("./resume-token-store");
|
|
74
|
+
Object.defineProperty(exports, "createResumeTokenStore", { enumerable: true, get: function () { return resume_token_store_1.createResumeTokenStore; } });
|
|
75
|
+
var resume_token_store_kv_1 = require("./resume-token-store-kv");
|
|
76
|
+
Object.defineProperty(exports, "CloudflareKVResumeTokenStore", { enumerable: true, get: function () { return resume_token_store_kv_1.CloudflareKVResumeTokenStore; } });
|
|
77
|
+
// Outbound identity bridge (mcp-i → compute interceptor)
|
|
78
|
+
var outbound_identity_bridge_1 = require("./outbound-identity-bridge");
|
|
79
|
+
Object.defineProperty(exports, "ensureOutboundIdentityBridge", { enumerable: true, get: function () { return outbound_identity_bridge_1.ensureOutboundIdentityBridge; } });
|
|
72
80
|
// Proof batching (NEW - Phase 1)
|
|
73
81
|
var proof_batch_queue_1 = require("./proof-batch-queue");
|
|
74
82
|
Object.defineProperty(exports, "ProofBatchQueue", { enumerable: true, get: function () { return proof_batch_queue_1.ProofBatchQueue; } });
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Node.js-specific runtime that extends the core runtime with Node.js providers.
|
|
5
5
|
* Provides backward compatibility by accepting legacy configuration format.
|
|
6
6
|
*/
|
|
7
|
-
import { MCPIRuntimeBase, AccessControlApiService, ProofVerifier } from "@kya-os/mcp-i-
|
|
7
|
+
import { MCPIRuntimeBase, AccessControlApiService, ProofVerifier } from "@kya-os/mcp-i-runtime";
|
|
8
8
|
import type { MCPIRuntimeConfig } from "./mcpi-runtime";
|
|
9
9
|
/**
|
|
10
10
|
* Node.js-specific runtime implementation
|
|
@@ -11,7 +11,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.MCPIRuntimeWrapper = exports.MCPINodeRuntimeWrapper = void 0;
|
|
13
13
|
exports.createMCPIRuntime = createMCPIRuntime;
|
|
14
|
-
const
|
|
14
|
+
const mcp_i_runtime_1 = require("@kya-os/mcp-i-runtime");
|
|
15
15
|
const node_providers_1 = require("../providers/node-providers");
|
|
16
16
|
const path_1 = __importDefault(require("path"));
|
|
17
17
|
/**
|
|
@@ -56,7 +56,7 @@ function createProvidersFromConfig(config) {
|
|
|
56
56
|
/**
|
|
57
57
|
* Node.js-specific runtime implementation
|
|
58
58
|
*/
|
|
59
|
-
class MCPINodeRuntimeWrapper extends
|
|
59
|
+
class MCPINodeRuntimeWrapper extends mcp_i_runtime_1.MCPIRuntimeBase {
|
|
60
60
|
legacyConfig;
|
|
61
61
|
// accessControlService is inherited from MCPIRuntimeBase (protected), no need to redeclare
|
|
62
62
|
// proofVerifier is inherited from MCPIRuntimeBase (protected), no need to redeclare
|
|
@@ -66,7 +66,7 @@ class MCPINodeRuntimeWrapper extends mcp_i_core_1.MCPIRuntimeBase {
|
|
|
66
66
|
this.legacyConfig = config;
|
|
67
67
|
// Instantiate ProofVerifier
|
|
68
68
|
// Access protected property from base class using type assertion
|
|
69
|
-
this.proofVerifier = new
|
|
69
|
+
this.proofVerifier = new mcp_i_runtime_1.ProofVerifier({
|
|
70
70
|
cryptoProvider: coreConfig.cryptoProvider,
|
|
71
71
|
clockProvider: coreConfig.clockProvider,
|
|
72
72
|
nonceCacheProvider: coreConfig.nonceCacheProvider,
|
|
@@ -77,7 +77,7 @@ class MCPINodeRuntimeWrapper extends mcp_i_core_1.MCPIRuntimeBase {
|
|
|
77
77
|
const apiKey = process.env.AGENTSHIELD_API_KEY;
|
|
78
78
|
const apiUrl = process.env.AGENTSHIELD_API_URL || "https://kya.vouched.id";
|
|
79
79
|
if (apiKey) {
|
|
80
|
-
this.accessControlService = new
|
|
80
|
+
this.accessControlService = new mcp_i_runtime_1.AccessControlApiService({
|
|
81
81
|
baseUrl: apiUrl,
|
|
82
82
|
apiKey,
|
|
83
83
|
fetchProvider: coreConfig.fetchProvider,
|
|
@@ -9,7 +9,8 @@ import { ToolRequest, ToolResponse } from "./proof";
|
|
|
9
9
|
import { WellKnownConfig } from "./well-known";
|
|
10
10
|
import { DemoManager } from "./demo";
|
|
11
11
|
import { DelegationVerifierConfig } from "./delegation-verifier";
|
|
12
|
-
import {
|
|
12
|
+
import { ResumeTokenStoreConfig } from "./resume-token-store";
|
|
13
|
+
import type { NeedsAuthorizationError } from "@kya-os/mcp/types" with { "resolution-mode": "import" };
|
|
13
14
|
import { ToolProtectionMap, ToolProtectionResolver } from "./tool-protection";
|
|
14
15
|
/**
|
|
15
16
|
* Runtime environment check
|
|
@@ -89,6 +90,13 @@ export interface MCPIRuntimeConfig {
|
|
|
89
90
|
minReputationScore?: number;
|
|
90
91
|
/** Resume token TTL in milliseconds */
|
|
91
92
|
resumeTokenTtl?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Resume-token store selection. Omit for the in-memory single-process
|
|
95
|
+
* dev default (tokens lost on restart, not shared across instances).
|
|
96
|
+
* Set `{ type: 'cloudflare-kv', kvNamespace }` for durable consent→reuse
|
|
97
|
+
* on multi-instance / serverless deployments.
|
|
98
|
+
*/
|
|
99
|
+
resumeTokenStore?: ResumeTokenStoreConfig;
|
|
92
100
|
/** Require authorization for unknown agents */
|
|
93
101
|
requireAuthForUnknown?: boolean;
|
|
94
102
|
};
|
|
@@ -17,9 +17,12 @@ const debug_1 = require("./debug");
|
|
|
17
17
|
const demo_1 = require("./demo");
|
|
18
18
|
const delegation_verifier_1 = require("./delegation-verifier");
|
|
19
19
|
const auth_handshake_1 = require("./auth-handshake");
|
|
20
|
+
const resume_token_store_1 = require("./resume-token-store");
|
|
20
21
|
const request_context_1 = require("./request-context");
|
|
22
|
+
const outbound_identity_bridge_1 = require("./outbound-identity-bridge");
|
|
21
23
|
const tool_protection_1 = require("./tool-protection");
|
|
22
24
|
const tool_protection_registry_1 = require("./tool-protection-registry");
|
|
25
|
+
// C4 drain: delegation-layer symbol stays on @kya-os/mcp-i-core (src/delegation/** not relocated to mcp-i-runtime - pinned by E3.5 #2904).
|
|
23
26
|
const mcp_i_core_1 = require("@kya-os/mcp-i-core");
|
|
24
27
|
/**
|
|
25
28
|
* XMCP-I Runtime class
|
|
@@ -51,9 +54,16 @@ class MCPIRuntime {
|
|
|
51
54
|
this.sessionManager = new session_1.SessionManager(config.session);
|
|
52
55
|
// Initialize audit logger
|
|
53
56
|
this.auditLogger = new audit_1.AuditLogger(config.audit);
|
|
54
|
-
// Initialize resume token store (NEW - Phase 1)
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
+
// Initialize resume token store (NEW - Phase 1).
|
|
58
|
+
// Durable stores (e.g. Cloudflare KV) are selected from config so a token
|
|
59
|
+
// minted at consent time survives cold starts / restarts / multi-instance
|
|
60
|
+
// — otherwise the user is re-prompted. Memory is the EXPLICIT single-process
|
|
61
|
+
// dev default. Mirrors the delegation-verifier factory pattern.
|
|
62
|
+
const resumeTtl = config.delegation?.authorization?.resumeTokenTtl || 600_000;
|
|
63
|
+
const resumeStoreConfig = config.delegation?.authorization?.resumeTokenStore;
|
|
64
|
+
this.resumeTokenStore = resumeStoreConfig
|
|
65
|
+
? (0, resume_token_store_1.createResumeTokenStore)({ ttlMs: resumeTtl, ...resumeStoreConfig })
|
|
66
|
+
: new auth_handshake_1.MemoryResumeTokenStore(resumeTtl);
|
|
57
67
|
// Initialize delegation verifier (NEW - Phase 1)
|
|
58
68
|
if (config.delegation?.enabled && config.delegation?.verifier) {
|
|
59
69
|
this.delegationVerifier = (0, delegation_verifier_1.createDelegationVerifier)(config.delegation.verifier);
|
|
@@ -99,6 +109,10 @@ class MCPIRuntime {
|
|
|
99
109
|
identityBadge: this.config.demo?.identityBadge || false,
|
|
100
110
|
environment: this.config.identity?.environment || "development",
|
|
101
111
|
});
|
|
112
|
+
// Bridge AsyncLocalStorage delegation/session context into the compute
|
|
113
|
+
// outbound-identity interceptor when it is preloaded in this process.
|
|
114
|
+
// Best-effort + idempotent — a no-op when compute is not present.
|
|
115
|
+
(0, outbound_identity_bridge_1.ensureOutboundIdentityBridge)();
|
|
102
116
|
console.error(`✅ XMCP-I Runtime initialized`);
|
|
103
117
|
console.error(` DID: ${this.cachedIdentity.did}`);
|
|
104
118
|
console.error(` Key ID: ${this.cachedIdentity.kid}`);
|
|
@@ -207,6 +221,10 @@ class MCPIRuntime {
|
|
|
207
221
|
delegationId: options.delegationRef,
|
|
208
222
|
delegationChain: options.delegationChain,
|
|
209
223
|
delegationScopes: options.delegationScopes,
|
|
224
|
+
// JWS-compact DelegationCredential VC from the verified result —
|
|
225
|
+
// emitted on KYA-OS-Delegation-Credential when the verifier
|
|
226
|
+
// returned a presentable credential.
|
|
227
|
+
delegationCredential: verifyResult.credential?.credential_jwt,
|
|
210
228
|
identity,
|
|
211
229
|
});
|
|
212
230
|
}
|
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
* HTTP requests made during delegated tool handler execution.
|
|
6
6
|
*
|
|
7
7
|
* Reads delegation context from AsyncLocalStorage (via getContext()),
|
|
8
|
-
* builds a signed Ed25519 JWT, and injects
|
|
9
|
-
*
|
|
8
|
+
* builds a signed Ed25519 JWT, and injects the canonical KYA-OS-* Layer 2
|
|
9
|
+
* delegation headers:
|
|
10
|
+
* KYA-OS-Delegation-Chain, KYA-OS-Delegation-Proof, KYA-OS-Granted-Scopes,
|
|
11
|
+
* and KYA-OS-Delegation-Credential when a DelegationCredential VC is present.
|
|
10
12
|
*
|
|
11
13
|
* Behavior:
|
|
12
14
|
* - Skips injection for internal hostnames (localhost, *.vouched.id, Fly IPs)
|
|
13
15
|
* - On signing failure: logs warning, continues WITHOUT delegation headers
|
|
14
16
|
* - Anonymous/non-delegated calls: no headers injected
|
|
15
17
|
*
|
|
16
|
-
* Related Spec: MCP-I §
|
|
18
|
+
* Related Spec: DIF MCP-I §8 — Outbound Delegation Propagation
|
|
17
19
|
*/
|
|
18
20
|
interface Logger {
|
|
19
21
|
debug: (msg: string, meta?: Record<string, unknown>) => void;
|
|
@@ -6,20 +6,24 @@
|
|
|
6
6
|
* HTTP requests made during delegated tool handler execution.
|
|
7
7
|
*
|
|
8
8
|
* Reads delegation context from AsyncLocalStorage (via getContext()),
|
|
9
|
-
* builds a signed Ed25519 JWT, and injects
|
|
10
|
-
*
|
|
9
|
+
* builds a signed Ed25519 JWT, and injects the canonical KYA-OS-* Layer 2
|
|
10
|
+
* delegation headers:
|
|
11
|
+
* KYA-OS-Delegation-Chain, KYA-OS-Delegation-Proof, KYA-OS-Granted-Scopes,
|
|
12
|
+
* and KYA-OS-Delegation-Credential when a DelegationCredential VC is present.
|
|
11
13
|
*
|
|
12
14
|
* Behavior:
|
|
13
15
|
* - Skips injection for internal hostnames (localhost, *.vouched.id, Fly IPs)
|
|
14
16
|
* - On signing failure: logs warning, continues WITHOUT delegation headers
|
|
15
17
|
* - Anonymous/non-delegated calls: no headers injected
|
|
16
18
|
*
|
|
17
|
-
* Related Spec: MCP-I §
|
|
19
|
+
* Related Spec: DIF MCP-I §8 — Outbound Delegation Propagation
|
|
18
20
|
*/
|
|
19
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
22
|
exports.isInternalDelegationTarget = isInternalDelegationTarget;
|
|
21
23
|
exports.installDelegationInterceptor = installDelegationInterceptor;
|
|
24
|
+
// C4 drain: delegation-layer symbol stays on @kya-os/mcp-i-core (src/delegation/** not relocated to mcp-i-runtime - pinned by E3.5 #2904).
|
|
22
25
|
const mcp_i_core_1 = require("@kya-os/mcp-i-core");
|
|
26
|
+
// C2/C3: @kya-os/mcp-i is CJS; @kya-os/mcp is ESM-only (TS1479 blocks static import).
|
|
23
27
|
const request_context_js_1 = require("./request-context.js");
|
|
24
28
|
// Flag to avoid double-installing
|
|
25
29
|
const DELEGATION_INTERCEPTED_FLAG = "__kyaDelegationIntercepted";
|
|
@@ -85,7 +89,7 @@ function installDelegationInterceptor(logger) {
|
|
|
85
89
|
const baseHeaders = input instanceof Request ? input.headers : undefined;
|
|
86
90
|
const headers = new Headers(init?.headers ?? baseHeaders);
|
|
87
91
|
// Only inject if we have a delegation context and haven't already injected
|
|
88
|
-
if (!headers.has("KYA-Delegation-Proof")) {
|
|
92
|
+
if (!headers.has("KYA-OS-Delegation-Proof")) {
|
|
89
93
|
const ctx = (0, request_context_js_1.getContext)();
|
|
90
94
|
if (ctx?.delegationRef &&
|
|
91
95
|
ctx.delegationPrivateKeyJwk &&
|
|
@@ -108,10 +112,13 @@ function installDelegationInterceptor(logger) {
|
|
|
108
112
|
kid: ctx.delegationAgentKid,
|
|
109
113
|
targetHostname,
|
|
110
114
|
});
|
|
111
|
-
headers.set("KYA-Delegation-
|
|
112
|
-
headers.set("KYA-Delegation-
|
|
113
|
-
headers.set("KYA-
|
|
114
|
-
|
|
115
|
+
headers.set("KYA-OS-Delegation-Chain", ctx.delegationChain ?? ctx.delegationRef);
|
|
116
|
+
headers.set("KYA-OS-Delegation-Proof", proof);
|
|
117
|
+
headers.set("KYA-OS-Granted-Scopes", (ctx.delegationScopes ?? []).join(","));
|
|
118
|
+
// Emit the JWS-compact DelegationCredential VC when the context carries one.
|
|
119
|
+
if (ctx.delegationCredential) {
|
|
120
|
+
headers.set("KYA-OS-Delegation-Credential", ctx.delegationCredential);
|
|
121
|
+
}
|
|
115
122
|
logger?.debug("Delegation headers injected", {
|
|
116
123
|
delegationRef: ctx.delegationRef,
|
|
117
124
|
targetHostname,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound Identity Bridge (mcp-i → @kya-os/compute interceptor)
|
|
3
|
+
*
|
|
4
|
+
* Bridges this package's AsyncLocalStorage request context into the compute
|
|
5
|
+
* outbound-identity interceptor so the Layer-2 delegation headers and the
|
|
6
|
+
* `KYA-OS-Session-Id` anchor are emitted on the compute (OpenClaw sidecar)
|
|
7
|
+
* path — resolving the long-standing `interceptor.ts:183-188` TODO.
|
|
8
|
+
*
|
|
9
|
+
* Why a global rendezvous (not a direct import): neither package depends on
|
|
10
|
+
* the other (compute must not import the SDK; the SDK must not pull in the
|
|
11
|
+
* Fly.io sidecar). When the compute interceptor installs it publishes a
|
|
12
|
+
* registrar on `Symbol.for("kya-os.outbound-identity.registry")`; this module
|
|
13
|
+
* reads that registrar and registers providers backed by `getContext()`. When
|
|
14
|
+
* compute is absent (pure-Node / Cloudflare deployments) the registrar is
|
|
15
|
+
* missing and this is a clean no-op — those paths inject delegation headers via
|
|
16
|
+
* their own fetch wrap (`outbound-delegation.ts`).
|
|
17
|
+
*
|
|
18
|
+
* Authority model follows ADR-001: the DelegationCredential VC is
|
|
19
|
+
* authoritative; `-Chain` / `-Granted-Scopes` are advisory hints.
|
|
20
|
+
*
|
|
21
|
+
* Related Spec: DIF MCP-I §8 — Outbound Delegation Propagation
|
|
22
|
+
*/
|
|
23
|
+
interface Logger {
|
|
24
|
+
debug: (msg: string, meta?: Record<string, unknown>) => void;
|
|
25
|
+
warn: (msg: string, meta?: Record<string, unknown>) => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Register the AsyncLocalStorage-backed delegation / session providers with the
|
|
29
|
+
* compute outbound-identity interceptor, if it is installed in this process.
|
|
30
|
+
*
|
|
31
|
+
* Idempotent and best-effort: safe to call from multiple init sites. Returns
|
|
32
|
+
* true when the registrar was found and providers were wired, false otherwise.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ensureOutboundIdentityBridge(logger?: Logger): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Test-only reset of the idempotency guard. Not part of the public runtime API.
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare function __resetOutboundIdentityBridgeForTests(): void;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Outbound Identity Bridge (mcp-i → @kya-os/compute interceptor)
|
|
4
|
+
*
|
|
5
|
+
* Bridges this package's AsyncLocalStorage request context into the compute
|
|
6
|
+
* outbound-identity interceptor so the Layer-2 delegation headers and the
|
|
7
|
+
* `KYA-OS-Session-Id` anchor are emitted on the compute (OpenClaw sidecar)
|
|
8
|
+
* path — resolving the long-standing `interceptor.ts:183-188` TODO.
|
|
9
|
+
*
|
|
10
|
+
* Why a global rendezvous (not a direct import): neither package depends on
|
|
11
|
+
* the other (compute must not import the SDK; the SDK must not pull in the
|
|
12
|
+
* Fly.io sidecar). When the compute interceptor installs it publishes a
|
|
13
|
+
* registrar on `Symbol.for("kya-os.outbound-identity.registry")`; this module
|
|
14
|
+
* reads that registrar and registers providers backed by `getContext()`. When
|
|
15
|
+
* compute is absent (pure-Node / Cloudflare deployments) the registrar is
|
|
16
|
+
* missing and this is a clean no-op — those paths inject delegation headers via
|
|
17
|
+
* their own fetch wrap (`outbound-delegation.ts`).
|
|
18
|
+
*
|
|
19
|
+
* Authority model follows ADR-001: the DelegationCredential VC is
|
|
20
|
+
* authoritative; `-Chain` / `-Granted-Scopes` are advisory hints.
|
|
21
|
+
*
|
|
22
|
+
* Related Spec: DIF MCP-I §8 — Outbound Delegation Propagation
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.ensureOutboundIdentityBridge = ensureOutboundIdentityBridge;
|
|
26
|
+
exports.__resetOutboundIdentityBridgeForTests = __resetOutboundIdentityBridgeForTests;
|
|
27
|
+
const mcp_i_core_1 = require("@kya-os/mcp-i-core");
|
|
28
|
+
const request_context_1 = require("./request-context");
|
|
29
|
+
/**
|
|
30
|
+
* Must match `OUTBOUND_IDENTITY_REGISTRY_KEY` in
|
|
31
|
+
* `@kya-os/compute`'s `outbound-identity/interceptor.ts`. `Symbol.for` resolves
|
|
32
|
+
* the same registry symbol in both packages within one process.
|
|
33
|
+
*/
|
|
34
|
+
const OUTBOUND_IDENTITY_REGISTRY_KEY = Symbol.for("kya-os.outbound-identity.registry");
|
|
35
|
+
// Idempotency guard — the registered providers are closures over getContext(),
|
|
36
|
+
// so a single registration covers all subsequent requests in this process.
|
|
37
|
+
let bridged = false;
|
|
38
|
+
function readRegistry() {
|
|
39
|
+
// REASON: globalThis has no index signature for our Symbol key; one localized
|
|
40
|
+
// cast reads the typed cross-package slot compute published at install.
|
|
41
|
+
return globalThis[OUTBOUND_IDENTITY_REGISTRY_KEY];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build a compute-compatible delegation provider from the request context.
|
|
45
|
+
* Returns undefined per-call when the active context carries no delegation (or
|
|
46
|
+
* lacks the signing material), so anonymous / non-delegated calls inject no
|
|
47
|
+
* delegation headers.
|
|
48
|
+
*/
|
|
49
|
+
function delegationProvider() {
|
|
50
|
+
const ctx = (0, request_context_1.getContext)();
|
|
51
|
+
if (!ctx?.delegationRef ||
|
|
52
|
+
!ctx.delegationPrivateKeyJwk ||
|
|
53
|
+
!ctx.delegationAgentKid) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const delegationChain = ctx.delegationChain ?? ctx.delegationRef;
|
|
57
|
+
const delegationScopes = ctx.delegationScopes ?? [];
|
|
58
|
+
const agentDid = ctx.session?.serverDid ?? "";
|
|
59
|
+
const userDid = ctx.session?.userDid ?? "";
|
|
60
|
+
// Surface the calling client's DID (xmcp-i#413) so the compute interceptor
|
|
61
|
+
// can attach it to KTA attestations. Spread conditionally below so the field
|
|
62
|
+
// is absent (not `undefined`) when the session carries no client identity.
|
|
63
|
+
const clientDid = ctx.session?.clientDid;
|
|
64
|
+
const privateKeyJwk = ctx.delegationPrivateKeyJwk;
|
|
65
|
+
const kid = ctx.delegationAgentKid;
|
|
66
|
+
const delegationRef = ctx.delegationRef;
|
|
67
|
+
return {
|
|
68
|
+
delegationRef,
|
|
69
|
+
delegationChain,
|
|
70
|
+
delegationScopes,
|
|
71
|
+
agentDid,
|
|
72
|
+
userDid,
|
|
73
|
+
...(clientDid ? { clientDid } : {}),
|
|
74
|
+
kid,
|
|
75
|
+
delegationCredential: ctx.delegationCredential,
|
|
76
|
+
buildProof: (targetHostname) => (0, mcp_i_core_1.buildDelegationProofJWT)({
|
|
77
|
+
agentDid,
|
|
78
|
+
userDid,
|
|
79
|
+
delegationId: delegationRef,
|
|
80
|
+
delegationChain,
|
|
81
|
+
scopes: delegationScopes,
|
|
82
|
+
privateKeyJwk,
|
|
83
|
+
kid,
|
|
84
|
+
targetHostname,
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Resolve the stable MCP session id from the active request context. */
|
|
89
|
+
function sessionIdProvider() {
|
|
90
|
+
return (0, request_context_1.getContext)()?.session?.sessionId;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Register the AsyncLocalStorage-backed delegation / session providers with the
|
|
94
|
+
* compute outbound-identity interceptor, if it is installed in this process.
|
|
95
|
+
*
|
|
96
|
+
* Idempotent and best-effort: safe to call from multiple init sites. Returns
|
|
97
|
+
* true when the registrar was found and providers were wired, false otherwise.
|
|
98
|
+
*/
|
|
99
|
+
function ensureOutboundIdentityBridge(logger) {
|
|
100
|
+
if (bridged)
|
|
101
|
+
return true;
|
|
102
|
+
const registry = readRegistry();
|
|
103
|
+
if (!registry?.setDelegationProvider) {
|
|
104
|
+
logger?.debug("Outbound identity bridge: compute interceptor not present — skipping");
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
registry.setDelegationProvider(delegationProvider);
|
|
108
|
+
registry.setSessionIdProvider?.(sessionIdProvider);
|
|
109
|
+
bridged = true;
|
|
110
|
+
logger?.debug("Outbound identity bridge: delegation + session providers registered");
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Test-only reset of the idempotency guard. Not part of the public runtime API.
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
function __resetOutboundIdentityBridgeForTests() {
|
|
118
|
+
bridged = false;
|
|
119
|
+
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Related: PHASE_1_XMCP_I_SERVER.md Epic 3 (Proof Batching)
|
|
18
18
|
*/
|
|
19
|
-
import { DetachedProof } from "@kya-os/
|
|
19
|
+
import type { DetachedProof } from "@kya-os/mcp/types" with { "resolution-mode": "import" };
|
|
20
20
|
/**
|
|
21
21
|
* Proof submission destination
|
|
22
22
|
*/
|
package/dist/runtime/proof.d.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Requirements: 5.1, 5.2, 5.3, 5.6
|
|
9
9
|
*/
|
|
10
|
-
import { ProofGenerator as CoreProofGenerator, type ProofAgentIdentity, type ToolRequest, type ToolResponse, type ProofOptions, extractCanonicalData } from "@kya-os/mcp-i-
|
|
11
|
-
import { CryptoProvider } from "@kya-os/mcp-i-
|
|
10
|
+
import { ProofGenerator as CoreProofGenerator, type ProofAgentIdentity, type ToolRequest, type ToolResponse, type ProofOptions, extractCanonicalData } from "@kya-os/mcp-i-runtime";
|
|
11
|
+
import { CryptoProvider } from "@kya-os/mcp-i-runtime";
|
|
12
12
|
import { SessionContext } from "@kya-os/contracts/handshake";
|
|
13
13
|
export declare class ProofGenerator extends CoreProofGenerator {
|
|
14
14
|
constructor(identity: ProofAgentIdentity, cryptoProvider?: CryptoProvider);
|
package/dist/runtime/proof.js
CHANGED
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.extractCanonicalData = exports.ProofGenerator = void 0;
|
|
13
13
|
exports.createProofResponse = createProofResponse;
|
|
14
|
-
const
|
|
15
|
-
Object.defineProperty(exports, "extractCanonicalData", { enumerable: true, get: function () { return
|
|
14
|
+
const mcp_i_runtime_1 = require("@kya-os/mcp-i-runtime");
|
|
15
|
+
Object.defineProperty(exports, "extractCanonicalData", { enumerable: true, get: function () { return mcp_i_runtime_1.extractCanonicalData; } });
|
|
16
16
|
const node_providers_1 = require("../providers/node-providers");
|
|
17
|
-
class ProofGenerator extends
|
|
17
|
+
class ProofGenerator extends mcp_i_runtime_1.ProofGenerator {
|
|
18
18
|
constructor(identity, cryptoProvider = new node_providers_1.NodeCryptoProvider()) {
|
|
19
19
|
super(identity, cryptoProvider);
|
|
20
20
|
}
|
|
@@ -19,6 +19,8 @@ export interface RequestContext {
|
|
|
19
19
|
delegationChain?: string;
|
|
20
20
|
/** Scopes granted by the active delegation */
|
|
21
21
|
delegationScopes?: string[];
|
|
22
|
+
/** JWS-compact DelegationCredential VC for the active delegation (emitted on KYA-OS-Delegation-Credential when present) */
|
|
23
|
+
delegationCredential?: string;
|
|
22
24
|
/** Agent Ed25519 private key JWK for delegation proof signing */
|
|
23
25
|
delegationPrivateKeyJwk?: Ed25519PrivateJWK;
|
|
24
26
|
/** Key ID used in delegation proof JWT header */
|
|
@@ -56,6 +58,7 @@ export declare function setDelegationContext(fields: {
|
|
|
56
58
|
delegationRef: string;
|
|
57
59
|
delegationChain: string;
|
|
58
60
|
delegationScopes: string[];
|
|
61
|
+
delegationCredential?: string;
|
|
59
62
|
delegationPrivateKeyJwk?: Ed25519PrivateJWK;
|
|
60
63
|
delegationAgentKid?: string;
|
|
61
64
|
}): void;
|
|
@@ -70,6 +73,13 @@ export declare function setDelegationContextFromIdentity(params: {
|
|
|
70
73
|
delegationId: string;
|
|
71
74
|
delegationChain: string;
|
|
72
75
|
delegationScopes: string[];
|
|
76
|
+
/**
|
|
77
|
+
* JWS-compact DelegationCredential VC for the active delegation. Threaded
|
|
78
|
+
* through to KYA-OS-Delegation-Credential on outbound requests. Sourced
|
|
79
|
+
* from the verified delegation result (e.g. credential.credential_jwt).
|
|
80
|
+
* Omit when the verifier did not return a presentable VC.
|
|
81
|
+
*/
|
|
82
|
+
delegationCredential?: string;
|
|
73
83
|
identity: {
|
|
74
84
|
privateKey: string;
|
|
75
85
|
publicKey: string;
|
|
@@ -71,6 +71,9 @@ function setDelegationContext(fields) {
|
|
|
71
71
|
context.delegationRef = fields.delegationRef;
|
|
72
72
|
context.delegationChain = fields.delegationChain;
|
|
73
73
|
context.delegationScopes = fields.delegationScopes;
|
|
74
|
+
if (fields.delegationCredential !== undefined) {
|
|
75
|
+
context.delegationCredential = fields.delegationCredential;
|
|
76
|
+
}
|
|
74
77
|
if (fields.delegationPrivateKeyJwk !== undefined) {
|
|
75
78
|
context.delegationPrivateKeyJwk = fields.delegationPrivateKeyJwk;
|
|
76
79
|
}
|
|
@@ -90,6 +93,7 @@ function setDelegationContextFromIdentity(params) {
|
|
|
90
93
|
delegationRef: params.delegationId,
|
|
91
94
|
delegationChain: params.delegationChain,
|
|
92
95
|
delegationScopes: params.delegationScopes,
|
|
96
|
+
delegationCredential: params.delegationCredential,
|
|
93
97
|
delegationPrivateKeyJwk: params.identity?.privateKey
|
|
94
98
|
? {
|
|
95
99
|
kty: "OKP",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare KV Resume Token Store
|
|
3
|
+
*
|
|
4
|
+
* Durable resume-token store backed by a Cloudflare Workers KV namespace, so a
|
|
5
|
+
* resume token minted at consent time survives cold starts, process restarts,
|
|
6
|
+
* and multi-instance deployments (the failure mode the in-memory store causes —
|
|
7
|
+
* the user gets re-prompted because the token vanished). Mirrors the
|
|
8
|
+
* delegation-verifier-kv.ts adapter shape.
|
|
9
|
+
*
|
|
10
|
+
* Key structure:
|
|
11
|
+
* - `resume:{token}` — JSON-encoded {@link StoredResumeToken}
|
|
12
|
+
*
|
|
13
|
+
* Tokens are minted with CSPRNG entropy (see generateResumeToken in
|
|
14
|
+
* @kya-os/mcp-i-core), never time+Math.random.
|
|
15
|
+
*/
|
|
16
|
+
import { type ResumeTokenStore } from "@kya-os/mcp-i-core";
|
|
17
|
+
/**
|
|
18
|
+
* Minimal Cloudflare KV surface needed by the store. `put` accepts the standard
|
|
19
|
+
* KV `{ expirationTtl }` (seconds) so the namespace also evicts expired tokens
|
|
20
|
+
* natively; logical expiry via `expiresAt` is enforced regardless.
|
|
21
|
+
*/
|
|
22
|
+
export interface ResumeTokenKVNamespace {
|
|
23
|
+
get(key: string): Promise<string | null>;
|
|
24
|
+
put(key: string, value: string, options?: {
|
|
25
|
+
expirationTtl?: number;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
delete(key: string): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export declare class CloudflareKVResumeTokenStore implements ResumeTokenStore {
|
|
30
|
+
private kv;
|
|
31
|
+
private ttlMs;
|
|
32
|
+
constructor(kv: ResumeTokenKVNamespace, ttlMs?: number);
|
|
33
|
+
private key;
|
|
34
|
+
private read;
|
|
35
|
+
create(agentDid: string, scopes: string[], metadata?: Record<string, unknown>): Promise<string>;
|
|
36
|
+
get(token: string): Promise<{
|
|
37
|
+
agentDid: string;
|
|
38
|
+
scopes: string[];
|
|
39
|
+
createdAt: number;
|
|
40
|
+
expiresAt: number;
|
|
41
|
+
metadata?: Record<string, unknown>;
|
|
42
|
+
} | null>;
|
|
43
|
+
fulfill(token: string): Promise<void>;
|
|
44
|
+
}
|