@kya-os/mcp-i-core 1.3.10-canary.clientinfo.20251126124133 → 1.3.10

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 (64) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/__tests__/utils/mock-providers.d.ts +2 -1
  3. package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
  4. package/dist/__tests__/utils/mock-providers.js.map +1 -1
  5. package/dist/config/remote-config.d.ts +51 -0
  6. package/dist/config/remote-config.d.ts.map +1 -1
  7. package/dist/config/remote-config.js +74 -0
  8. package/dist/config/remote-config.js.map +1 -1
  9. package/dist/config.d.ts +1 -1
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +4 -1
  12. package/dist/config.js.map +1 -1
  13. package/dist/delegation/did-key-resolver.d.ts +64 -0
  14. package/dist/delegation/did-key-resolver.d.ts.map +1 -0
  15. package/dist/delegation/did-key-resolver.js +159 -0
  16. package/dist/delegation/did-key-resolver.js.map +1 -0
  17. package/dist/delegation/utils.d.ts +76 -0
  18. package/dist/delegation/utils.d.ts.map +1 -1
  19. package/dist/delegation/utils.js +117 -0
  20. package/dist/delegation/utils.js.map +1 -1
  21. package/dist/identity/user-did-manager.d.ts +95 -12
  22. package/dist/identity/user-did-manager.d.ts.map +1 -1
  23. package/dist/identity/user-did-manager.js +107 -25
  24. package/dist/identity/user-did-manager.js.map +1 -1
  25. package/dist/index.d.ts +5 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +23 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/runtime/base.d.ts +25 -8
  30. package/dist/runtime/base.d.ts.map +1 -1
  31. package/dist/runtime/base.js +74 -21
  32. package/dist/runtime/base.js.map +1 -1
  33. package/dist/services/session-registration.service.d.ts.map +1 -1
  34. package/dist/services/session-registration.service.js +10 -90
  35. package/dist/services/session-registration.service.js.map +1 -1
  36. package/dist/services/tool-protection.service.d.ts +5 -2
  37. package/dist/services/tool-protection.service.d.ts.map +1 -1
  38. package/dist/services/tool-protection.service.js +72 -24
  39. package/dist/services/tool-protection.service.js.map +1 -1
  40. package/dist/utils/base58.d.ts +31 -0
  41. package/dist/utils/base58.d.ts.map +1 -0
  42. package/dist/utils/base58.js +103 -0
  43. package/dist/utils/base58.js.map +1 -0
  44. package/package.json +3 -3
  45. package/src/__tests__/identity/user-did-manager.test.ts +64 -45
  46. package/src/__tests__/integration/full-flow.test.ts +23 -10
  47. package/src/__tests__/runtime/base-extensions.test.ts +23 -21
  48. package/src/__tests__/runtime/proof-client-did.test.ts +19 -18
  49. package/src/__tests__/services/agentshield-integration.test.ts +10 -3
  50. package/src/__tests__/services/tool-protection-merged-config.test.ts +485 -0
  51. package/src/__tests__/services/tool-protection.service.test.ts +18 -11
  52. package/src/config/__tests__/merged-config.spec.ts +445 -0
  53. package/src/config/remote-config.ts +90 -0
  54. package/src/config.ts +3 -0
  55. package/src/delegation/__tests__/did-key-resolver.test.ts +265 -0
  56. package/src/delegation/did-key-resolver.ts +179 -0
  57. package/src/delegation/utils.ts +179 -0
  58. package/src/identity/user-did-manager.ts +185 -29
  59. package/src/index.ts +36 -1
  60. package/src/runtime/base.ts +84 -21
  61. package/src/services/session-registration.service.ts +26 -121
  62. package/src/services/tool-protection.service.ts +125 -56
  63. package/src/utils/base58.ts +109 -0
  64. package/coverage/coverage-final.json +0 -57
@@ -1,11 +1,17 @@
1
1
  /**
2
2
  * User DID Manager
3
3
  *
4
- * Handles ephemeral user DID generation for MCP-I sessions.
5
- * Generates did:key DIDs for users when they join a chat session.
4
+ * Manages user DIDs for MCP-I sessions.
6
5
  *
7
- * This enables tracking which client/user initiated tool calls without
8
- * requiring user registration or persistent identity.
6
+ * Phase 5: Anonymous Sessions Until OAuth
7
+ * - Sessions start anonymous (no userDid) until OAuth completes
8
+ * - User DIDs are resolved via AgentShield identity/resolve after OAuth
9
+ * - Eliminates DID fragmentation (same user = same DID across sessions)
10
+ *
11
+ * DID Resolution Priority:
12
+ * 1. OAuth mapping lookup (persistent)
13
+ * 2. Session storage lookup
14
+ * 3. Return null (session stays anonymous)
9
15
  */
10
16
 
11
17
  import { CryptoProvider } from '../providers/base';
@@ -35,6 +41,35 @@ export interface OAuthIdentity {
35
41
  name?: string;
36
42
  }
37
43
 
44
+ /**
45
+ * User key pair for signing VCs
46
+ *
47
+ * Contains both public and private keys in base64 format.
48
+ * SECURITY: Private keys should be encrypted at rest.
49
+ */
50
+ export interface UserKeyPair {
51
+ /**
52
+ * User DID (did:key format)
53
+ */
54
+ did: string;
55
+
56
+ /**
57
+ * Public key in base64 format
58
+ */
59
+ publicKey: string;
60
+
61
+ /**
62
+ * Private key in base64 format
63
+ * SECURITY: Should be encrypted at rest in production
64
+ */
65
+ privateKey: string;
66
+
67
+ /**
68
+ * Key ID (for JWS header)
69
+ */
70
+ keyId: string;
71
+ }
72
+
38
73
  /**
39
74
  * User DID storage interface
40
75
  */
@@ -65,6 +100,35 @@ export interface UserDidStorage {
65
100
  * If not implemented, OAuth-based storage will be skipped
66
101
  */
67
102
  setByOAuth?(provider: string, subject: string, did: string, ttl?: number): Promise<void>;
103
+
104
+ /**
105
+ * Get user key pair for a session (optional - for VC signing)
106
+ * If not implemented, VC issuance will not be available for this session
107
+ */
108
+ getKeyPair?(sessionId: string): Promise<UserKeyPair | null>;
109
+
110
+ /**
111
+ * Store user key pair for a session (optional - for VC signing)
112
+ * SECURITY: Implementation should encrypt private keys at rest
113
+ */
114
+ setKeyPair?(sessionId: string, keyPair: UserKeyPair, ttl?: number): Promise<void>;
115
+
116
+ /**
117
+ * Get user key pair by OAuth identity (optional - for persistent key storage)
118
+ * If not implemented, OAuth-based key lookup will be skipped
119
+ */
120
+ getKeyPairByOAuth?(provider: string, subject: string): Promise<UserKeyPair | null>;
121
+
122
+ /**
123
+ * Store user key pair for OAuth identity (optional - for persistent key storage)
124
+ * SECURITY: Implementation should encrypt private keys at rest
125
+ */
126
+ setKeyPairByOAuth?(
127
+ provider: string,
128
+ subject: string,
129
+ keyPair: UserKeyPair,
130
+ ttl?: number
131
+ ): Promise<void>;
68
132
  }
69
133
 
70
134
  /**
@@ -102,28 +166,84 @@ export interface UserDidManagerConfig {
102
166
  export class UserDidManager {
103
167
  private config: UserDidManagerConfig;
104
168
  private sessionDidCache = new Map<string, string>();
169
+ private sessionKeyPairCache = new Map<string, UserKeyPair>();
105
170
 
106
171
  constructor(config: UserDidManagerConfig) {
107
172
  this.config = config;
108
173
  }
109
174
 
110
175
  /**
111
- * Generate or retrieve user DID for a session
176
+ * Get key pair for a session (for VC signing)
177
+ *
178
+ * Returns the key pair if available, null otherwise.
179
+ * Key pairs are stored when DIDs are generated.
180
+ *
181
+ * @param sessionId - MCP session ID
182
+ * @param oauthIdentity - Optional OAuth identity for persistent lookup
183
+ * @returns UserKeyPair or null if not available
184
+ */
185
+ async getKeyPairForSession(
186
+ sessionId: string,
187
+ oauthIdentity?: OAuthIdentity | null
188
+ ): Promise<UserKeyPair | null> {
189
+ // Check in-memory cache first
190
+ if (this.sessionKeyPairCache.has(sessionId)) {
191
+ return this.sessionKeyPairCache.get(sessionId)!;
192
+ }
193
+
194
+ // Check OAuth-based persistent storage if available
195
+ if (
196
+ oauthIdentity?.provider &&
197
+ oauthIdentity?.subject &&
198
+ this.config.storage?.getKeyPairByOAuth
199
+ ) {
200
+ try {
201
+ const keyPair = await this.config.storage.getKeyPairByOAuth(
202
+ oauthIdentity.provider,
203
+ oauthIdentity.subject
204
+ );
205
+ if (keyPair) {
206
+ this.sessionKeyPairCache.set(sessionId, keyPair);
207
+ return keyPair;
208
+ }
209
+ } catch (error) {
210
+ console.warn('[UserDidManager] OAuth key pair lookup failed:', error);
211
+ }
212
+ }
213
+
214
+ // Check session storage if available
215
+ if (this.config.storage?.getKeyPair) {
216
+ try {
217
+ const keyPair = await this.config.storage.getKeyPair(sessionId);
218
+ if (keyPair) {
219
+ this.sessionKeyPairCache.set(sessionId, keyPair);
220
+ return keyPair;
221
+ }
222
+ } catch (error) {
223
+ console.warn('[UserDidManager] Session key pair lookup failed:', error);
224
+ }
225
+ }
226
+
227
+ return null;
228
+ }
229
+
230
+ /**
231
+ * Get user DID for a session (Phase 5: No ephemeral generation)
112
232
  *
113
233
  * If a user DID already exists for the session, it is returned.
114
- * If OAuth identity is provided, checks for persistent user DID mapping first.
115
- * Otherwise, a new ephemeral did:key is generated.
234
+ * If OAuth identity is provided, checks for persistent user DID mapping.
235
+ * Returns null if no DID found - session stays anonymous until OAuth completes.
116
236
  *
117
237
  * @param sessionId - MCP session ID
118
238
  * @param oauthIdentity - Optional OAuth identity for persistent user DID lookup
119
- * @returns User DID (did:key format)
239
+ * @returns User DID (did:key format) or null if session is anonymous
120
240
  *
121
241
  * @remarks
122
- * - If OAuth identity provided, checks for existing mapping first
123
- * - Falls back to ephemeral DID generation if OAuth unavailable
124
- * - Caches result in session storage for performance
242
+ * - Phase 5: Sessions start anonymous, no ephemeral DID generation
243
+ * - User DIDs are resolved via AgentShield after OAuth completes
244
+ * - Returns null if no existing DID found (instead of generating ephemeral)
125
245
  */
126
- async getOrCreateUserDid(sessionId: string, oauthIdentity?: OAuthIdentity | null): Promise<string> {
246
+ async getOrCreateUserDid(sessionId: string, oauthIdentity?: OAuthIdentity | null): Promise<string | null> {
127
247
  // Check cache first
128
248
  if (this.sessionDidCache.has(sessionId)) {
129
249
  return this.sessionDidCache.get(sessionId)!;
@@ -187,29 +307,45 @@ export class UserDidManager {
187
307
  return storedDid;
188
308
  }
189
309
  } catch (error) {
190
- // Log but continue - will generate new DID
191
- console.warn('[UserDidManager] Storage.get failed, generating new DID:', error);
310
+ // Log but continue - session will be anonymous
311
+ console.warn('[UserDidManager] Storage.get failed:', error);
192
312
  }
193
313
  }
194
314
 
195
- // PRIORITY 3: Generate new user DID
196
- const userDid = await this.generateUserDid();
315
+ // PHASE 5: No ephemeral DID generation - session stays anonymous
316
+ // User DID will be resolved via AgentShield after OAuth completes
317
+ return null;
318
+ }
197
319
 
198
- // Cache it
320
+ /**
321
+ * Set user DID for a session (Phase 5: After OAuth resolution)
322
+ *
323
+ * Called after AgentShield identity/resolve returns a persistent user DID.
324
+ * Caches the DID and optionally stores in session storage.
325
+ *
326
+ * @param sessionId - MCP session ID
327
+ * @param userDid - Persistent user DID from AgentShield
328
+ * @param oauthIdentity - OAuth identity for creating persistent mappings
329
+ */
330
+ async setUserDidForSession(
331
+ sessionId: string,
332
+ userDid: string,
333
+ oauthIdentity?: OAuthIdentity | null
334
+ ): Promise<void> {
335
+ // Cache in memory
199
336
  this.sessionDidCache.set(sessionId, userDid);
200
337
 
201
- // Store it if storage is available
338
+ // Store in session storage if available
202
339
  if (this.config.storage) {
203
340
  try {
204
341
  await this.config.storage.set(sessionId, userDid, 1800); // 30 minutes TTL
205
342
  } catch (error) {
206
- // Log but continue - DID is cached and will be returned
207
- console.warn('[UserDidManager] Storage.set failed, continuing with cached DID:', error);
343
+ console.warn('[UserDidManager] Failed to store user DID in session storage:', error);
208
344
  }
209
345
  }
210
346
 
211
- // If OAuth identity provided, create persistent mapping
212
- if (oauthIdentity && oauthIdentity.provider && oauthIdentity.subject && this.config.storage?.setByOAuth) {
347
+ // Create OAuth mapping if provided
348
+ if (oauthIdentity?.provider && oauthIdentity?.subject && this.config.storage?.setByOAuth) {
213
349
  try {
214
350
  await this.config.storage.setByOAuth(
215
351
  oauthIdentity.provider,
@@ -217,17 +353,14 @@ export class UserDidManager {
217
353
  userDid,
218
354
  90 * 24 * 60 * 60 // 90 days TTL for persistent mapping
219
355
  );
220
- console.log('[UserDidManager] Created persistent OAuth mapping for new user DID:', {
356
+ console.log('[UserDidManager] Created OAuth DID mapping:', {
221
357
  provider: oauthIdentity.provider,
222
358
  userDid: userDid.substring(0, 20) + '...',
223
359
  });
224
360
  } catch (error) {
225
- // Log but continue - mapping creation failed, but DID is still valid
226
361
  console.warn('[UserDidManager] Failed to create OAuth mapping:', error);
227
362
  }
228
363
  }
229
-
230
- return userDid;
231
364
  }
232
365
 
233
366
  /**
@@ -237,6 +370,19 @@ export class UserDidManager {
237
370
  * did:web can be used if configured, but requires additional setup.
238
371
  */
239
372
  private async generateUserDid(): Promise<string> {
373
+ const keyPairData = await this.generateUserDidWithKeyPair();
374
+ return keyPairData.did;
375
+ }
376
+
377
+ /**
378
+ * Generate a new ephemeral user DID with full key pair
379
+ *
380
+ * Returns the DID along with the key pair for VC signing.
381
+ * Uses did:key format by default.
382
+ *
383
+ * @returns UserKeyPair containing DID, public key, private key, and key ID
384
+ */
385
+ private async generateUserDidWithKeyPair(): Promise<UserKeyPair> {
240
386
  if (this.config.useDidWeb && this.config.didWebBaseUrl) {
241
387
  // Generate did:web (requires web server setup)
242
388
  // For now, fall back to did:key
@@ -246,12 +392,22 @@ export class UserDidManager {
246
392
 
247
393
  // Generate Ed25519 keypair for user DID
248
394
  const keyPair = await this.config.crypto.generateKeyPair();
249
-
395
+
250
396
  // Extract public key bytes (32 bytes for Ed25519)
251
397
  const publicKeyBytes = this.base64ToBytes(keyPair.publicKey);
252
-
398
+
253
399
  // Generate did:key from public key
254
- return this.generateDidKeyFromPublicKey(publicKeyBytes);
400
+ const did = this.generateDidKeyFromPublicKey(publicKeyBytes);
401
+
402
+ // Key ID is the DID with #keys-1 fragment (standard for did:key)
403
+ const keyId = `${did}#keys-1`;
404
+
405
+ return {
406
+ did,
407
+ publicKey: keyPair.publicKey,
408
+ privateKey: keyPair.privateKey,
409
+ keyId,
410
+ };
255
411
  }
256
412
 
257
413
  /**
package/src/index.ts CHANGED
@@ -201,6 +201,22 @@ export { MemoryStatusListStorage } from "./delegation/storage/memory-statuslist-
201
201
 
202
202
  export { MemoryDelegationGraphStorage } from "./delegation/storage/memory-graph-storage";
203
203
 
204
+ // DID:key Resolver (Phase 3 VC Verification)
205
+ export {
206
+ createDidKeyResolver,
207
+ isEd25519DidKey,
208
+ extractPublicKeyFromDidKey,
209
+ publicKeyToJwk,
210
+ resolveDidKeySync,
211
+ } from "./delegation/did-key-resolver";
212
+
213
+ // Base58 Utilities (for did:key encoding/decoding)
214
+ export {
215
+ base58Encode,
216
+ base58Decode,
217
+ isValidBase58,
218
+ } from "./utils/base58";
219
+
204
220
  // Compliance Verification (with JSON Schema draft-07 support)
205
221
  export {
206
222
  SchemaVerifier,
@@ -220,7 +236,24 @@ export {
220
236
  getSchemaStats,
221
237
  } from "./compliance/schema-registry";
222
238
 
223
- export { canonicalizeJSON } from "./delegation/utils";
239
+ export {
240
+ canonicalizeJSON,
241
+ createUnsignedVCJWT,
242
+ completeVCJWT,
243
+ parseVCJWT,
244
+ type VCJWTHeader,
245
+ type VCJWTPayload,
246
+ type EncodeVCAsJWTOptions,
247
+ } from "./delegation/utils";
248
+
249
+ // Base64 utilities for VC JWT encoding
250
+ export {
251
+ base64urlEncodeFromBytes,
252
+ base64urlEncodeFromString,
253
+ base64urlDecodeToBytes,
254
+ base64urlDecodeToString,
255
+ bytesToBase64,
256
+ } from "./utils/base64";
224
257
 
225
258
  // Re-export commonly used types from contracts
226
259
  // Note: @kya-os/contracts exports are at the root level
@@ -263,6 +296,8 @@ export { UserDidManager } from "./identity/user-did-manager";
263
296
  export type {
264
297
  UserDidStorage,
265
298
  UserDidManagerConfig,
299
+ UserKeyPair,
300
+ OAuthIdentity,
266
301
  } from "./identity/user-did-manager";
267
302
 
268
303
  // IDP Token Resolver (Phase 1 - MH-7)
@@ -130,19 +130,16 @@ export class MCPIRuntimeBase {
130
130
  return this.cachedIdentity;
131
131
  }
132
132
 
133
- /**
134
- * Handle handshake request
135
- */
136
133
  /**
137
134
  * Handle MCP handshake request
138
135
  *
136
+ * Phase 5: Anonymous Sessions Until OAuth
137
+ * - Sessions start anonymous (no userDid) unless OAuth identity provided
138
+ * - User DID is resolved via AgentShield after OAuth completes
139
+ * - Eliminates DID fragmentation (same user = same DID across sessions)
140
+ *
139
141
  * @param request - Handshake request object (may include oauthIdentity for persistent user DID lookup)
140
142
  * @returns Handshake response with session ID and agent DID
141
- *
142
- * @remarks
143
- * - Accepts optional oauthIdentity via request.oauthIdentity (backward compatible)
144
- * - If OAuth identity provided, uses it to retrieve/create persistent user DID
145
- * - Falls back to ephemeral user DID generation if OAuth unavailable
146
143
  */
147
144
  async handleHandshake(
148
145
  request: any & {
@@ -155,26 +152,36 @@ export class MCPIRuntimeBase {
155
152
  const timestamp = this.clock.now();
156
153
  const sessionId = await this.generateSessionId();
157
154
 
158
- // Generate user DID if user DID generation is enabled
159
- // Use OAuth identity if provided for persistent user DID lookup
155
+ // Phase 5: Try to resolve user DID from existing OAuth mapping
156
+ // Sessions start anonymous - no ephemeral generation
160
157
  let userDid: string | undefined;
161
158
  if (this.userDidManager) {
162
159
  try {
163
160
  const oauthIdentity = request.oauthIdentity;
164
- userDid = await this.userDidManager.getOrCreateUserDid(
161
+ const resolvedDid = await this.userDidManager.getOrCreateUserDid(
165
162
  sessionId,
166
163
  oauthIdentity
167
164
  );
165
+ // Convert null to undefined for session storage
166
+ userDid = resolvedDid ?? undefined;
167
+
168
168
  if (this.config.audit?.enabled) {
169
- console.log("[MCP-I] Generated user DID for session:", {
170
- userDid: userDid.substring(0, 20) + "...",
171
- hasOAuth: !!oauthIdentity,
172
- provider: oauthIdentity?.provider,
173
- });
169
+ if (userDid) {
170
+ console.log("[MCP-I] Resolved existing user DID for session:", {
171
+ userDid: userDid.substring(0, 20) + "...",
172
+ hasOAuth: !!oauthIdentity,
173
+ provider: oauthIdentity?.provider,
174
+ });
175
+ } else {
176
+ console.log("[MCP-I] Session started anonymous (no userDid):", {
177
+ sessionId: sessionId.substring(0, 8) + "...",
178
+ hasOAuth: !!oauthIdentity,
179
+ });
180
+ }
174
181
  }
175
182
  } catch (error) {
176
- console.warn("[MCP-I] Failed to generate user DID:", error);
177
- // Continue without user DID - not critical
183
+ console.warn("[MCP-I] Failed to resolve user DID:", error);
184
+ // Continue without user DID - session is anonymous
178
185
  }
179
186
  }
180
187
 
@@ -211,11 +218,11 @@ export class MCPIRuntimeBase {
211
218
  }
212
219
  : undefined;
213
220
 
214
- // Create session
221
+ // Create session with Phase 5 identity state
215
222
  const session = {
216
223
  id: sessionId,
217
224
  clientDid: request.clientDid || userDid, // Use provided clientDid or generated userDid
218
- userDid: userDid, // Store generated user DID separately
225
+ userDid: userDid, // Store user DID (may be undefined for anonymous sessions)
219
226
  agentDid: request.agentDid, // ✅ FIXED: Only agent DID, no fallback
220
227
  serverDid: identity.did, // ✅ NEW: Server's DID (for clarity)
221
228
  audience: request.audience,
@@ -223,7 +230,10 @@ export class MCPIRuntimeBase {
223
230
  expiresAt: this.clock.calculateExpiry(
224
231
  (this.config.session?.ttlMinutes || 30) * 60
225
232
  ),
226
- clientInfo, // NEW: Store client information
233
+ clientInfo, // Store client information
234
+ // Phase 5: Identity state tracking
235
+ identityState: userDid ? "authenticated" : "anonymous",
236
+ oauthIdentity: request.oauthIdentity ?? undefined,
227
237
  };
228
238
 
229
239
  this.sessions.set(sessionId, session);
@@ -246,6 +256,59 @@ export class MCPIRuntimeBase {
246
256
  };
247
257
  }
248
258
 
259
+ /**
260
+ * Update session identity after OAuth resolution (Phase 5)
261
+ *
262
+ * Called after AgentShield identity/resolve returns a persistent user DID.
263
+ * Updates the session to authenticated state with the resolved DID.
264
+ *
265
+ * @param sessionId - MCP session ID
266
+ * @param userDid - Persistent user DID from AgentShield
267
+ * @param oauthIdentity - OAuth identity information
268
+ * @throws Error if session not found
269
+ */
270
+ async updateSessionIdentity(
271
+ sessionId: string,
272
+ userDid: string,
273
+ oauthIdentity?: { provider: string; subject: string; email?: string }
274
+ ): Promise<void> {
275
+ const session = this.sessions.get(sessionId);
276
+ if (!session) {
277
+ throw new Error(`Session not found: ${sessionId}`);
278
+ }
279
+
280
+ // Update session with resolved identity
281
+ session.userDid = userDid;
282
+ session.identityState = "authenticated";
283
+ if (oauthIdentity) {
284
+ session.oauthIdentity = oauthIdentity;
285
+ }
286
+
287
+ // Update the sessions map
288
+ this.sessions.set(sessionId, session);
289
+
290
+ // Also update UserDidManager cache if available
291
+ if (this.userDidManager) {
292
+ await this.userDidManager.setUserDidForSession(sessionId, userDid, oauthIdentity);
293
+ }
294
+
295
+ if (this.config.audit?.enabled) {
296
+ console.log("[MCP-I] Session identity updated (Phase 5):", {
297
+ sessionId: sessionId.substring(0, 8) + "...",
298
+ userDid: userDid.substring(0, 20) + "...",
299
+ provider: oauthIdentity?.provider,
300
+ identityState: "authenticated",
301
+ });
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Get session by ID
307
+ */
308
+ getSession(sessionId: string): any | undefined {
309
+ return this.sessions.get(sessionId);
310
+ }
311
+
249
312
  /**
250
313
  * Process tool call with automatic proof generation
251
314
  * Returns clean result only - proof is stored for out-of-band retrieval