@kya-os/mcp-i 1.9.0 → 1.11.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.
Files changed (62) hide show
  1. package/dist/227.js +1 -0
  2. package/dist/{263.js → 242.js} +1 -1
  3. package/dist/283.js +1 -0
  4. package/dist/317.js +1 -0
  5. package/dist/354.js +1 -0
  6. package/dist/361.js +1 -0
  7. package/dist/452.js +1 -0
  8. package/dist/533.js +1 -0
  9. package/dist/622.js +1 -0
  10. package/dist/65.js +1 -0
  11. package/dist/839.js +1 -0
  12. package/dist/843.js +1 -0
  13. package/dist/{644.js → 861.js} +1 -1
  14. package/dist/914.js +1 -0
  15. package/dist/95.js +1 -0
  16. package/dist/cli-adapter/index.js +1 -1
  17. package/dist/runtime/102.js +1 -0
  18. package/dist/runtime/adapter-express.js +3 -3
  19. package/dist/runtime/adapter-nextjs.js +5 -5
  20. package/dist/runtime/audit.d.ts +1 -1
  21. package/dist/runtime/debug.d.ts +1 -1
  22. package/dist/runtime/debug.js +3 -2
  23. package/dist/runtime/delegation-hooks.d.ts +1 -1
  24. package/dist/runtime/http.js +3 -3
  25. package/dist/runtime/identity.d.ts +4 -4
  26. package/dist/runtime/identity.js +4 -4
  27. package/dist/runtime/index.d.ts +6 -2
  28. package/dist/runtime/index.js +10 -2
  29. package/dist/runtime/mcpi-runtime.d.ts +9 -1
  30. package/dist/runtime/mcpi-runtime.js +20 -3
  31. package/dist/runtime/outbound-delegation.d.ts +5 -3
  32. package/dist/runtime/outbound-delegation.js +14 -8
  33. package/dist/runtime/outbound-identity-bridge.d.ts +40 -0
  34. package/dist/runtime/outbound-identity-bridge.js +114 -0
  35. package/dist/runtime/proof-batch-queue.d.ts +1 -1
  36. package/dist/runtime/request-context.d.ts +10 -0
  37. package/dist/runtime/request-context.js +4 -0
  38. package/dist/runtime/resume-token-store-kv.d.ts +44 -0
  39. package/dist/runtime/resume-token-store-kv.js +93 -0
  40. package/dist/runtime/resume-token-store.d.ts +30 -0
  41. package/dist/runtime/resume-token-store.js +46 -0
  42. package/dist/runtime/session.js +6 -0
  43. package/dist/runtime/stdio.js +3 -3
  44. package/dist/runtime/utils/tools.d.ts +1 -1
  45. package/dist/runtime/utils/tools.js +29 -7
  46. package/dist/runtime/well-known.d.ts +12 -1
  47. package/dist/runtime/well-known.js +13 -2
  48. package/package.json +7 -5
  49. package/dist/114.js +0 -1
  50. package/dist/139.js +0 -1
  51. package/dist/200.js +0 -1
  52. package/dist/202.js +0 -1
  53. package/dist/238.js +0 -1
  54. package/dist/294.js +0 -1
  55. package/dist/374.js +0 -1
  56. package/dist/529.js +0 -1
  57. package/dist/627.js +0 -1
  58. package/dist/669.js +0 -1
  59. package/dist/857.js +0 -1
  60. package/dist/997.js +0 -1
  61. package/dist/runtime/verifier-middleware.d.ts +0 -99
  62. 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-core/utils/did-helpers instead
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-core/utils/did-helpers';
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-core/utils/did-helpers instead
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-core/utils/did-helpers';
125
+ export { extractAgentSlug } from '@kya-os/mcp-i-runtime/utils/did-helpers';
126
126
  /**
127
127
  * Convenience function to ensure identity
128
128
  */
@@ -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-core/utils/did-helpers instead
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-core/utils/did-helpers");
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-core/utils/did-helpers instead
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-core/utils/did-helpers");
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
@@ -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/contracts/proof";
27
- export type { DelegationRecord, DelegationStatus, DelegationChain, DelegationConstraints, } from "@kya-os/contracts/delegation";
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";
@@ -6,8 +6,8 @@
6
6
  * audit logging, and well-known endpoints.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.FileToolProtectionSource = exports.InlineToolProtectionSource = exports.createToolProtectionResolver = exports.ToolProtectionResolver = exports.MemoryDelegationVerifier = exports.AgentShieldAPIDelegationVerifier = exports.CloudflareKVDelegationVerifier = exports.createProofBatchQueue = exports.AgentShieldProofDestination = exports.KTAProofDestination = exports.ProofBatchQueue = 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 = 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; } });
@@ -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 { NeedsAuthorizationError } from "@kya-os/contracts/runtime";
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,7 +17,9 @@ 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");
23
25
  const mcp_i_core_1 = require("@kya-os/mcp-i-core");
@@ -51,9 +53,16 @@ class MCPIRuntime {
51
53
  this.sessionManager = new session_1.SessionManager(config.session);
52
54
  // Initialize audit logger
53
55
  this.auditLogger = new audit_1.AuditLogger(config.audit);
54
- // Initialize resume token store (NEW - Phase 1)
55
- // Use in-memory store by default (sufficient for most use cases)
56
- this.resumeTokenStore = new auth_handshake_1.MemoryResumeTokenStore(config.delegation?.authorization?.resumeTokenTtl || 600_000);
56
+ // Initialize resume token store (NEW - Phase 1).
57
+ // Durable stores (e.g. Cloudflare KV) are selected from config so a token
58
+ // minted at consent time survives cold starts / restarts / multi-instance
59
+ // — otherwise the user is re-prompted. Memory is the EXPLICIT single-process
60
+ // dev default. Mirrors the delegation-verifier factory pattern.
61
+ const resumeTtl = config.delegation?.authorization?.resumeTokenTtl || 600_000;
62
+ const resumeStoreConfig = config.delegation?.authorization?.resumeTokenStore;
63
+ this.resumeTokenStore = resumeStoreConfig
64
+ ? (0, resume_token_store_1.createResumeTokenStore)({ ttlMs: resumeTtl, ...resumeStoreConfig })
65
+ : new auth_handshake_1.MemoryResumeTokenStore(resumeTtl);
57
66
  // Initialize delegation verifier (NEW - Phase 1)
58
67
  if (config.delegation?.enabled && config.delegation?.verifier) {
59
68
  this.delegationVerifier = (0, delegation_verifier_1.createDelegationVerifier)(config.delegation.verifier);
@@ -99,6 +108,10 @@ class MCPIRuntime {
99
108
  identityBadge: this.config.demo?.identityBadge || false,
100
109
  environment: this.config.identity?.environment || "development",
101
110
  });
111
+ // Bridge AsyncLocalStorage delegation/session context into the compute
112
+ // outbound-identity interceptor when it is preloaded in this process.
113
+ // Best-effort + idempotent — a no-op when compute is not present.
114
+ (0, outbound_identity_bridge_1.ensureOutboundIdentityBridge)();
102
115
  console.error(`✅ XMCP-I Runtime initialized`);
103
116
  console.error(` DID: ${this.cachedIdentity.did}`);
104
117
  console.error(` Key ID: ${this.cachedIdentity.kid}`);
@@ -207,6 +220,10 @@ class MCPIRuntime {
207
220
  delegationId: options.delegationRef,
208
221
  delegationChain: options.delegationChain,
209
222
  delegationScopes: options.delegationScopes,
223
+ // JWS-compact DelegationCredential VC from the verified result —
224
+ // emitted on KYA-OS-Delegation-Credential when the verifier
225
+ // returned a presentable credential.
226
+ delegationCredential: verifyResult.credential?.credential_jwt,
210
227
  identity,
211
228
  });
212
229
  }
@@ -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
- * X-Delegation-Id, X-Delegation-Chain, X-Delegation-Proof, X-Scopes
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 §2 — Outbound Delegation Propagation
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,23 @@
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
- * X-Delegation-Id, X-Delegation-Chain, X-Delegation-Proof, X-Scopes
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 §2 — Outbound Delegation Propagation
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;
22
24
  const mcp_i_core_1 = require("@kya-os/mcp-i-core");
25
+ // C2/C3: @kya-os/mcp-i is CJS; @kya-os/mcp is ESM-only (TS1479 blocks static import).
23
26
  const request_context_js_1 = require("./request-context.js");
24
27
  // Flag to avoid double-installing
25
28
  const DELEGATION_INTERCEPTED_FLAG = "__kyaDelegationIntercepted";
@@ -85,7 +88,7 @@ function installDelegationInterceptor(logger) {
85
88
  const baseHeaders = input instanceof Request ? input.headers : undefined;
86
89
  const headers = new Headers(init?.headers ?? baseHeaders);
87
90
  // Only inject if we have a delegation context and haven't already injected
88
- if (!headers.has("X-Delegation-Proof")) {
91
+ if (!headers.has("KYA-OS-Delegation-Proof")) {
89
92
  const ctx = (0, request_context_js_1.getContext)();
90
93
  if (ctx?.delegationRef &&
91
94
  ctx.delegationPrivateKeyJwk &&
@@ -108,10 +111,13 @@ function installDelegationInterceptor(logger) {
108
111
  kid: ctx.delegationAgentKid,
109
112
  targetHostname,
110
113
  });
111
- headers.set("X-Delegation-Id", ctx.delegationRef);
112
- headers.set("X-Delegation-Chain", ctx.delegationChain ?? ctx.delegationRef);
113
- headers.set("X-Delegation-Proof", proof);
114
- headers.set("X-Scopes", (ctx.delegationScopes ?? []).join(","));
114
+ headers.set("KYA-OS-Delegation-Chain", ctx.delegationChain ?? ctx.delegationRef);
115
+ headers.set("KYA-OS-Delegation-Proof", proof);
116
+ headers.set("KYA-OS-Granted-Scopes", (ctx.delegationScopes ?? []).join(","));
117
+ // Emit the JWS-compact DelegationCredential VC when the context carries one.
118
+ if (ctx.delegationCredential) {
119
+ headers.set("KYA-OS-Delegation-Credential", ctx.delegationCredential);
120
+ }
115
121
  logger?.debug("Delegation headers injected", {
116
122
  delegationRef: ctx.delegationRef,
117
123
  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,114 @@
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
+ const privateKeyJwk = ctx.delegationPrivateKeyJwk;
61
+ const kid = ctx.delegationAgentKid;
62
+ const delegationRef = ctx.delegationRef;
63
+ return {
64
+ delegationRef,
65
+ delegationChain,
66
+ delegationScopes,
67
+ agentDid,
68
+ userDid,
69
+ kid,
70
+ delegationCredential: ctx.delegationCredential,
71
+ buildProof: (targetHostname) => (0, mcp_i_core_1.buildDelegationProofJWT)({
72
+ agentDid,
73
+ userDid,
74
+ delegationId: delegationRef,
75
+ delegationChain,
76
+ scopes: delegationScopes,
77
+ privateKeyJwk,
78
+ kid,
79
+ targetHostname,
80
+ }),
81
+ };
82
+ }
83
+ /** Resolve the stable MCP session id from the active request context. */
84
+ function sessionIdProvider() {
85
+ return (0, request_context_1.getContext)()?.session?.sessionId;
86
+ }
87
+ /**
88
+ * Register the AsyncLocalStorage-backed delegation / session providers with the
89
+ * compute outbound-identity interceptor, if it is installed in this process.
90
+ *
91
+ * Idempotent and best-effort: safe to call from multiple init sites. Returns
92
+ * true when the registrar was found and providers were wired, false otherwise.
93
+ */
94
+ function ensureOutboundIdentityBridge(logger) {
95
+ if (bridged)
96
+ return true;
97
+ const registry = readRegistry();
98
+ if (!registry?.setDelegationProvider) {
99
+ logger?.debug("Outbound identity bridge: compute interceptor not present — skipping");
100
+ return false;
101
+ }
102
+ registry.setDelegationProvider(delegationProvider);
103
+ registry.setSessionIdProvider?.(sessionIdProvider);
104
+ bridged = true;
105
+ logger?.debug("Outbound identity bridge: delegation + session providers registered");
106
+ return true;
107
+ }
108
+ /**
109
+ * Test-only reset of the idempotency guard. Not part of the public runtime API.
110
+ * @internal
111
+ */
112
+ function __resetOutboundIdentityBridgeForTests() {
113
+ bridged = false;
114
+ }
@@ -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/contracts/proof";
19
+ import type { DetachedProof } from "@kya-os/mcp/types" with { "resolution-mode": "import" };
20
20
  /**
21
21
  * Proof submission destination
22
22
  */
@@ -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
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ /**
3
+ * Cloudflare KV Resume Token Store
4
+ *
5
+ * Durable resume-token store backed by a Cloudflare Workers KV namespace, so a
6
+ * resume token minted at consent time survives cold starts, process restarts,
7
+ * and multi-instance deployments (the failure mode the in-memory store causes —
8
+ * the user gets re-prompted because the token vanished). Mirrors the
9
+ * delegation-verifier-kv.ts adapter shape.
10
+ *
11
+ * Key structure:
12
+ * - `resume:{token}` — JSON-encoded {@link StoredResumeToken}
13
+ *
14
+ * Tokens are minted with CSPRNG entropy (see generateResumeToken in
15
+ * @kya-os/mcp-i-core), never time+Math.random.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.CloudflareKVResumeTokenStore = void 0;
19
+ const mcp_i_core_1 = require("@kya-os/mcp-i-core");
20
+ // Cloudflare KV requires expirationTtl >= 60 seconds.
21
+ const MIN_KV_TTL_SECONDS = 60;
22
+ function toTtlSeconds(ms) {
23
+ return Math.max(MIN_KV_TTL_SECONDS, Math.ceil(ms / 1000));
24
+ }
25
+ class CloudflareKVResumeTokenStore {
26
+ kv;
27
+ ttlMs;
28
+ constructor(kv, ttlMs = 600_000) {
29
+ this.kv = kv;
30
+ this.ttlMs = ttlMs;
31
+ }
32
+ key(token) {
33
+ return `resume:${token}`;
34
+ }
35
+ async read(token) {
36
+ const raw = await this.kv.get(this.key(token));
37
+ if (!raw)
38
+ return null;
39
+ try {
40
+ return JSON.parse(raw);
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ async create(agentDid, scopes, metadata) {
47
+ const token = (0, mcp_i_core_1.generateResumeToken)("rt");
48
+ const now = Date.now();
49
+ const record = {
50
+ agentDid,
51
+ scopes,
52
+ createdAt: now,
53
+ expiresAt: now + this.ttlMs,
54
+ metadata,
55
+ fulfilled: false,
56
+ };
57
+ await this.kv.put(this.key(token), JSON.stringify(record), {
58
+ expirationTtl: toTtlSeconds(this.ttlMs),
59
+ });
60
+ return token;
61
+ }
62
+ async get(token) {
63
+ const record = await this.read(token);
64
+ if (!record)
65
+ return null;
66
+ if (Date.now() > record.expiresAt) {
67
+ await this.kv.delete(this.key(token));
68
+ return null;
69
+ }
70
+ if (record.fulfilled)
71
+ return null;
72
+ return {
73
+ agentDid: record.agentDid,
74
+ scopes: record.scopes,
75
+ createdAt: record.createdAt,
76
+ expiresAt: record.expiresAt,
77
+ metadata: record.metadata,
78
+ };
79
+ }
80
+ async fulfill(token) {
81
+ const record = await this.read(token);
82
+ if (!record)
83
+ return;
84
+ record.fulfilled = true;
85
+ // Preserve the original expiry window so a fulfilled token can't outlive
86
+ // its TTL; floor at the KV minimum.
87
+ const remainingMs = Math.max(0, record.expiresAt - Date.now());
88
+ await this.kv.put(this.key(token), JSON.stringify(record), {
89
+ expirationTtl: toTtlSeconds(remainingMs),
90
+ });
91
+ }
92
+ }
93
+ exports.CloudflareKVResumeTokenStore = CloudflareKVResumeTokenStore;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Resume Token Store Factory
3
+ *
4
+ * Selects a {@link ResumeTokenStore} implementation from config, mirroring the
5
+ * delegation-verifier factory (`createDelegationVerifier`). This replaces the
6
+ * hardcoded in-memory store in the runtime so consent→reuse can be made durable
7
+ * (Cloudflare KV) on multi-instance / serverless deployments, while keeping the
8
+ * in-memory store as an EXPLICIT single-process dev default.
9
+ */
10
+ import { type ResumeTokenStore } from "@kya-os/mcp-i-core";
11
+ import { type ResumeTokenKVNamespace } from "./resume-token-store-kv";
12
+ /**
13
+ * Configuration for resume-token stores.
14
+ *
15
+ * - `memory` — in-memory TTL map. Single-process dev only; tokens are lost on
16
+ * restart and not shared across instances.
17
+ * - `cloudflare-kv` — durable, edge-replicated. Survives cold starts/restarts.
18
+ */
19
+ export interface ResumeTokenStoreConfig {
20
+ type: "memory" | "cloudflare-kv";
21
+ /** Token TTL in milliseconds (default: 600_000 = 10 minutes). */
22
+ ttlMs?: number;
23
+ /** Cloudflare KV namespace (required for `cloudflare-kv`). */
24
+ kvNamespace?: ResumeTokenKVNamespace;
25
+ }
26
+ /**
27
+ * Create a resume-token store from config. Memory is an explicit opt-in for
28
+ * single-process development; durable stores must be selected deliberately.
29
+ */
30
+ export declare function createResumeTokenStore(config: ResumeTokenStoreConfig): ResumeTokenStore;