@kya-os/mcp-i-core 1.2.3-canary.7 → 1.3.0-canary.clientinfo.20251126003544

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 (239) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test$colon$coverage.log +4239 -0
  3. package/.turbo/turbo-test.log +2973 -0
  4. package/COMPLIANCE_IMPROVEMENT_REPORT.md +483 -0
  5. package/Composer 3.md +615 -0
  6. package/GPT-5.md +1169 -0
  7. package/OPUS-plan.md +352 -0
  8. package/PHASE_3_AND_4.1_SUMMARY.md +585 -0
  9. package/PHASE_3_SUMMARY.md +317 -0
  10. package/PHASE_4.1.3_SUMMARY.md +428 -0
  11. package/PHASE_4.1_COMPLETE.md +525 -0
  12. package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +1240 -0
  13. package/SCHEMA_COMPLIANCE_REPORT.md +275 -0
  14. package/TEST_PLAN.md +571 -0
  15. package/coverage/coverage-final.json +57 -0
  16. package/dist/__tests__/utils/mock-providers.d.ts +1 -2
  17. package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
  18. package/dist/__tests__/utils/mock-providers.js.map +1 -1
  19. package/dist/cache/oauth-config-cache.d.ts +69 -0
  20. package/dist/cache/oauth-config-cache.d.ts.map +1 -0
  21. package/dist/cache/oauth-config-cache.js +76 -0
  22. package/dist/cache/oauth-config-cache.js.map +1 -0
  23. package/dist/identity/idp-token-resolver.d.ts +53 -0
  24. package/dist/identity/idp-token-resolver.d.ts.map +1 -0
  25. package/dist/identity/idp-token-resolver.js +108 -0
  26. package/dist/identity/idp-token-resolver.js.map +1 -0
  27. package/dist/identity/idp-token-storage.interface.d.ts +42 -0
  28. package/dist/identity/idp-token-storage.interface.d.ts.map +1 -0
  29. package/dist/identity/idp-token-storage.interface.js +12 -0
  30. package/dist/identity/idp-token-storage.interface.js.map +1 -0
  31. package/dist/identity/user-did-manager.d.ts +39 -1
  32. package/dist/identity/user-did-manager.d.ts.map +1 -1
  33. package/dist/identity/user-did-manager.js +69 -3
  34. package/dist/identity/user-did-manager.js.map +1 -1
  35. package/dist/index.d.ts +24 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +43 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/runtime/audit-logger.d.ts +37 -0
  40. package/dist/runtime/audit-logger.d.ts.map +1 -0
  41. package/dist/runtime/audit-logger.js +9 -0
  42. package/dist/runtime/audit-logger.js.map +1 -0
  43. package/dist/runtime/base.d.ts +58 -2
  44. package/dist/runtime/base.d.ts.map +1 -1
  45. package/dist/runtime/base.js +266 -11
  46. package/dist/runtime/base.js.map +1 -1
  47. package/dist/services/access-control.service.d.ts.map +1 -1
  48. package/dist/services/access-control.service.js +200 -35
  49. package/dist/services/access-control.service.js.map +1 -1
  50. package/dist/services/authorization/authorization-registry.d.ts +29 -0
  51. package/dist/services/authorization/authorization-registry.d.ts.map +1 -0
  52. package/dist/services/authorization/authorization-registry.js +57 -0
  53. package/dist/services/authorization/authorization-registry.js.map +1 -0
  54. package/dist/services/authorization/types.d.ts +53 -0
  55. package/dist/services/authorization/types.d.ts.map +1 -0
  56. package/dist/services/authorization/types.js +10 -0
  57. package/dist/services/authorization/types.js.map +1 -0
  58. package/dist/services/batch-delegation.service.d.ts +53 -0
  59. package/dist/services/batch-delegation.service.d.ts.map +1 -0
  60. package/dist/services/batch-delegation.service.js +95 -0
  61. package/dist/services/batch-delegation.service.js.map +1 -0
  62. package/dist/services/index.d.ts +2 -0
  63. package/dist/services/index.d.ts.map +1 -1
  64. package/dist/services/index.js +4 -1
  65. package/dist/services/index.js.map +1 -1
  66. package/dist/services/oauth-config.service.d.ts +53 -0
  67. package/dist/services/oauth-config.service.d.ts.map +1 -0
  68. package/dist/services/oauth-config.service.js +117 -0
  69. package/dist/services/oauth-config.service.js.map +1 -0
  70. package/dist/services/oauth-provider-registry.d.ts +77 -0
  71. package/dist/services/oauth-provider-registry.d.ts.map +1 -0
  72. package/dist/services/oauth-provider-registry.js +112 -0
  73. package/dist/services/oauth-provider-registry.js.map +1 -0
  74. package/dist/services/oauth-service.d.ts +77 -0
  75. package/dist/services/oauth-service.d.ts.map +1 -0
  76. package/dist/services/oauth-service.js +348 -0
  77. package/dist/services/oauth-service.js.map +1 -0
  78. package/dist/services/oauth-token-retrieval.service.d.ts +49 -0
  79. package/dist/services/oauth-token-retrieval.service.d.ts.map +1 -0
  80. package/dist/services/oauth-token-retrieval.service.js +150 -0
  81. package/dist/services/oauth-token-retrieval.service.js.map +1 -0
  82. package/dist/services/provider-resolver.d.ts +48 -0
  83. package/dist/services/provider-resolver.d.ts.map +1 -0
  84. package/dist/services/provider-resolver.js +120 -0
  85. package/dist/services/provider-resolver.js.map +1 -0
  86. package/dist/services/provider-validator.d.ts +55 -0
  87. package/dist/services/provider-validator.d.ts.map +1 -0
  88. package/dist/services/provider-validator.js +135 -0
  89. package/dist/services/provider-validator.js.map +1 -0
  90. package/dist/services/session-registration.service.d.ts +80 -0
  91. package/dist/services/session-registration.service.d.ts.map +1 -0
  92. package/dist/services/session-registration.service.js +172 -0
  93. package/dist/services/session-registration.service.js.map +1 -0
  94. package/dist/services/tool-context-builder.d.ts +57 -0
  95. package/dist/services/tool-context-builder.d.ts.map +1 -0
  96. package/dist/services/tool-context-builder.js +125 -0
  97. package/dist/services/tool-context-builder.js.map +1 -0
  98. package/dist/services/tool-protection.service.d.ts +87 -10
  99. package/dist/services/tool-protection.service.d.ts.map +1 -1
  100. package/dist/services/tool-protection.service.js +282 -112
  101. package/dist/services/tool-protection.service.js.map +1 -1
  102. package/dist/types/oauth-required-error.d.ts +40 -0
  103. package/dist/types/oauth-required-error.d.ts.map +1 -0
  104. package/dist/types/oauth-required-error.js +40 -0
  105. package/dist/types/oauth-required-error.js.map +1 -0
  106. package/dist/utils/did-helpers.d.ts +33 -0
  107. package/dist/utils/did-helpers.d.ts.map +1 -1
  108. package/dist/utils/did-helpers.js +40 -0
  109. package/dist/utils/did-helpers.js.map +1 -1
  110. package/dist/utils/index.d.ts +1 -0
  111. package/dist/utils/index.d.ts.map +1 -1
  112. package/dist/utils/index.js +1 -0
  113. package/dist/utils/index.js.map +1 -1
  114. package/docs/API_REFERENCE.md +1362 -0
  115. package/docs/COMPLIANCE_MATRIX.md +691 -0
  116. package/docs/STATUSLIST2021_GUIDE.md +696 -0
  117. package/docs/W3C_VC_DELEGATION_GUIDE.md +710 -0
  118. package/package.json +24 -50
  119. package/scripts/audit-compliance.ts +724 -0
  120. package/src/__tests__/cache/tool-protection-cache.test.ts +640 -0
  121. package/src/__tests__/config/provider-runtime-config.test.ts +309 -0
  122. package/src/__tests__/delegation-e2e.test.ts +690 -0
  123. package/src/__tests__/identity/user-did-manager.test.ts +213 -0
  124. package/src/__tests__/index.test.ts +56 -0
  125. package/src/__tests__/integration/full-flow.test.ts +776 -0
  126. package/src/__tests__/integration.test.ts +281 -0
  127. package/src/__tests__/providers/base.test.ts +173 -0
  128. package/src/__tests__/providers/memory.test.ts +319 -0
  129. package/src/__tests__/regression/phase2-regression.test.ts +427 -0
  130. package/src/__tests__/runtime/audit-logger.test.ts +154 -0
  131. package/src/__tests__/runtime/base-extensions.test.ts +593 -0
  132. package/src/__tests__/runtime/base.test.ts +869 -0
  133. package/src/__tests__/runtime/delegation-flow.test.ts +164 -0
  134. package/src/__tests__/runtime/proof-client-did.test.ts +375 -0
  135. package/src/__tests__/runtime/route-interception.test.ts +686 -0
  136. package/src/__tests__/runtime/tool-protection-enforcement.test.ts +908 -0
  137. package/src/__tests__/services/agentshield-integration.test.ts +784 -0
  138. package/src/__tests__/services/provider-resolver-edge-cases.test.ts +487 -0
  139. package/src/__tests__/services/tool-protection-oauth-provider.test.ts +480 -0
  140. package/src/__tests__/services/tool-protection.service.test.ts +1366 -0
  141. package/src/__tests__/utils/mock-providers.ts +340 -0
  142. package/src/cache/oauth-config-cache.d.ts +69 -0
  143. package/src/cache/oauth-config-cache.d.ts.map +1 -0
  144. package/src/cache/oauth-config-cache.js +71 -0
  145. package/src/cache/oauth-config-cache.js.map +1 -0
  146. package/src/cache/oauth-config-cache.ts +123 -0
  147. package/src/cache/tool-protection-cache.ts +171 -0
  148. package/src/compliance/EXAMPLE.md +412 -0
  149. package/src/compliance/__tests__/schema-verifier.test.ts +797 -0
  150. package/src/compliance/index.ts +8 -0
  151. package/src/compliance/schema-registry.ts +460 -0
  152. package/src/compliance/schema-verifier.ts +708 -0
  153. package/src/config/__tests__/remote-config.spec.ts +268 -0
  154. package/src/config/remote-config.ts +174 -0
  155. package/src/config.ts +309 -0
  156. package/src/delegation/__tests__/audience-validator.test.ts +112 -0
  157. package/src/delegation/__tests__/bitstring.test.ts +346 -0
  158. package/src/delegation/__tests__/cascading-revocation.test.ts +628 -0
  159. package/src/delegation/__tests__/delegation-graph.test.ts +584 -0
  160. package/src/delegation/__tests__/utils.test.ts +152 -0
  161. package/src/delegation/__tests__/vc-issuer.test.ts +442 -0
  162. package/src/delegation/__tests__/vc-verifier.test.ts +922 -0
  163. package/src/delegation/audience-validator.ts +52 -0
  164. package/src/delegation/bitstring.ts +278 -0
  165. package/src/delegation/cascading-revocation.ts +370 -0
  166. package/src/delegation/delegation-graph.ts +299 -0
  167. package/src/delegation/index.ts +14 -0
  168. package/src/delegation/statuslist-manager.ts +353 -0
  169. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
  170. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
  171. package/src/delegation/storage/index.ts +9 -0
  172. package/src/delegation/storage/memory-graph-storage.ts +178 -0
  173. package/src/delegation/storage/memory-statuslist-storage.ts +77 -0
  174. package/src/delegation/utils.ts +42 -0
  175. package/src/delegation/vc-issuer.ts +232 -0
  176. package/src/delegation/vc-verifier.ts +568 -0
  177. package/src/identity/idp-token-resolver.ts +147 -0
  178. package/src/identity/idp-token-storage.interface.ts +59 -0
  179. package/src/identity/user-did-manager.ts +370 -0
  180. package/src/index.ts +271 -0
  181. package/src/providers/base.d.ts +91 -0
  182. package/src/providers/base.d.ts.map +1 -0
  183. package/src/providers/base.js +38 -0
  184. package/src/providers/base.js.map +1 -0
  185. package/src/providers/base.ts +96 -0
  186. package/src/providers/memory.ts +142 -0
  187. package/src/runtime/audit-logger.ts +39 -0
  188. package/src/runtime/base.ts +1329 -0
  189. package/src/services/__tests__/access-control.integration.test.ts +443 -0
  190. package/src/services/__tests__/access-control.proof-response-validation.test.ts +578 -0
  191. package/src/services/__tests__/access-control.service.test.ts +970 -0
  192. package/src/services/__tests__/batch-delegation.service.test.ts +351 -0
  193. package/src/services/__tests__/crypto.service.test.ts +531 -0
  194. package/src/services/__tests__/oauth-provider-registry.test.ts +142 -0
  195. package/src/services/__tests__/proof-verifier.integration.test.ts +485 -0
  196. package/src/services/__tests__/proof-verifier.test.ts +489 -0
  197. package/src/services/__tests__/provider-resolution.integration.test.ts +198 -0
  198. package/src/services/__tests__/provider-resolver.test.ts +217 -0
  199. package/src/services/__tests__/storage.service.test.ts +358 -0
  200. package/src/services/access-control.service.ts +990 -0
  201. package/src/services/authorization/authorization-registry.ts +66 -0
  202. package/src/services/authorization/types.ts +71 -0
  203. package/src/services/batch-delegation.service.ts +137 -0
  204. package/src/services/crypto.service.ts +302 -0
  205. package/src/services/errors.ts +76 -0
  206. package/src/services/index.ts +18 -0
  207. package/src/services/oauth-config.service.d.ts +53 -0
  208. package/src/services/oauth-config.service.d.ts.map +1 -0
  209. package/src/services/oauth-config.service.js +113 -0
  210. package/src/services/oauth-config.service.js.map +1 -0
  211. package/src/services/oauth-config.service.ts +166 -0
  212. package/src/services/oauth-provider-registry.d.ts +57 -0
  213. package/src/services/oauth-provider-registry.d.ts.map +1 -0
  214. package/src/services/oauth-provider-registry.js +73 -0
  215. package/src/services/oauth-provider-registry.js.map +1 -0
  216. package/src/services/oauth-provider-registry.ts +123 -0
  217. package/src/services/oauth-service.ts +510 -0
  218. package/src/services/oauth-token-retrieval.service.ts +245 -0
  219. package/src/services/proof-verifier.ts +478 -0
  220. package/src/services/provider-resolver.d.ts +48 -0
  221. package/src/services/provider-resolver.d.ts.map +1 -0
  222. package/src/services/provider-resolver.js +106 -0
  223. package/src/services/provider-resolver.js.map +1 -0
  224. package/src/services/provider-resolver.ts +144 -0
  225. package/src/services/provider-validator.ts +170 -0
  226. package/src/services/session-registration.service.ts +251 -0
  227. package/src/services/storage.service.ts +566 -0
  228. package/src/services/tool-context-builder.ts +172 -0
  229. package/src/services/tool-protection.service.ts +958 -0
  230. package/src/types/oauth-required-error.ts +63 -0
  231. package/src/types/tool-protection.ts +155 -0
  232. package/src/utils/__tests__/did-helpers.test.ts +101 -0
  233. package/src/utils/base64.ts +148 -0
  234. package/src/utils/cors.ts +83 -0
  235. package/src/utils/did-helpers.ts +150 -0
  236. package/src/utils/index.ts +8 -0
  237. package/src/utils/storage-keys.ts +278 -0
  238. package/tsconfig.json +21 -0
  239. package/vitest.config.ts +56 -0
package/GPT-5.md ADDED
@@ -0,0 +1,1169 @@
1
+ ## Phase 4 — User DID & Identity Linking (Polished Plan, MCP‑I §3.1 Compliant)
2
+
3
+ Status: Ready for implementation
4
+ Scope: MCP‑I Identity, Consent, Delegation, OAuth Linking, Cross‑Agent Validation
5
+ Primary repos: `xmcp-i` (this), AgentShield/bouncer dashboard (API), Know‑That‑AI (reputation – advisory)
6
+
7
+ ### Executive Summary
8
+ Phase 4 delivers persistent User identity by linking OAuth identities to User DIDs and using the User DID as `issuerDid` for delegations. It fixes consent→delegation gaps, resolves multi‑tenant conflicts, and aligns on strict API contracts and error formats. The outcome is spec‑compliant delegation across sessions and agents, with robust observability and privacy controls.
9
+
10
+ — Core moves
11
+ - Use OAuth identity → User DID linking for persistence.
12
+ - Delegation issuance: `issuerDid` = User DID, `subjectDid` = Agent DID.
13
+ - Store delegation tokens per user+agent; session cache is a fast path.
14
+ - Validate with decentralized VCs first; fall back to OAuth verification if needed.
15
+ - Strict API parity with AgentShield wrapper `{ success, data, metadata }` and error `{ code, message, details }`.
16
+
17
+ — Why this is game‑changing
18
+ - True cross‑agent portability via DID/VCs, not just OAuth sessions.
19
+ - Seamless UX: first consent creates delegation; later sessions just work.
20
+ - Enterprise‑ready controls: audit, privacy APIs, and chain validation.
21
+
22
+
23
+ ### Architecture Overview
24
+
25
+ 1) Identity model (three DIDs)
26
+ - Server DID: Receiver of MCP calls (bouncer or app server)
27
+ - Agent DID: Requesting software (Claude Desktop, SaaS agents, other MCP servers)
28
+ - User DID: Human user granting permission; becomes `issuerDid` in delegations
29
+
30
+ 2) Persistence & linking
31
+ - OAuth callback links `oauth:{provider}:{subject}` → `userDid` (KV)
32
+ - `UserDidManager` retrieves/creates User DID based on session or OAuth identity
33
+
34
+ 3) Delegation issuance (Consent → AgentShield)
35
+ - Consent approval constructs a spec‑aligned request embedding `issuerDid` and `subjectDid`
36
+ - Transitional compatibility: if AgentShield endpoint hasn’t adopted `issuer_did`/`subject_did`, include `issuerDid` in `metadata` and continue using `agent_did` until API parity lands; add deprecation header to surface the gap
37
+
38
+ 4) Token storage (multi‑tenant safe)
39
+ - Primary key: `delegation:user:{userDid}:agent:{agentDid}` (KV)
40
+ - Session key: `delegation:session:{sessionId}` (short TTL for speed)
41
+
42
+ 5) Verification order (Edge verification policy)
43
+ - First try decentralized VC verification (DID + VC chain, CRISP constraints, revocation)
44
+ - If absent or invalid, fall back to AgentShield OAuth verification
45
+ - Always produce audit logs and parity‑safe error wrappers
46
+
47
+
48
+ ### End‑to‑End Flows
49
+
50
+ 1) First‑time consent
51
+ 2. Handshake initializes session; `agentDid` captured; ephemeral `userDid` is generated
52
+ 3. Tool call requires scopes → raise `DelegationRequiredError` with consent URL
53
+ 4. User approves on consent page; page posts approval to `/consent/approve`
54
+ 5. Service constructs delegation creation payload with `issuerDid` and `subjectDid`
55
+ 6. AgentShield returns a delegation token (and/or VC); store per user+agent and session
56
+ 7. Success page auto‑closes and returns control to client
57
+
58
+ 8) Return session
59
+ 9. Handshake finds OAuth cookie or identity → retrieve `userDid` via link
60
+ 10. Tool call: delegation token found via session key or user+agent cache
61
+ 11. No consent required; call proceeds
62
+
63
+ 12) Cross‑agent validation
64
+ 13. External agent calls bouncer; provides agent DID
65
+ 14. Verify VC chain; if unavailable, call AgentShield `delegations/verify` for that `agent_did` + scopes
66
+ 15. Decision response uses standard success/error wrapper
67
+
68
+
69
+ ### API Contracts and Parity
70
+
71
+ All endpoints must follow the wrapper:
72
+ ```json
73
+ { "success": true, "data": { ... }, "metadata": { ... } }
74
+ ```
75
+ Errors:
76
+ ```json
77
+ { "code": "string", "message": "string", "details": { ... } }
78
+ ```
79
+
80
+ AgentShield endpoints (must remain parity‑consistent)
81
+ - POST `/api/v1/bouncer/delegations/verify`
82
+ - Request: `{ agent_did: string, scopes: string[], credential_jwt?: string, timestamp?: number, client_info?: any }`
83
+ - Response: `{ success, data: { valid: boolean, reason?: string, expiresAt?: number } }`
84
+ - GET `/api/v1/bouncer/config/{projectId}`
85
+ - Response: `{ success, data: { tools: Record<string, { scopes: string[], requiresDelegation: boolean }> } }`
86
+ - POST `/api/v1/bouncer/proofs`
87
+ - Request: `{ proof: string, session: { id: string, audience: string, agentDid: string } }`
88
+ - Response: `{ success, data: { verified: boolean, ... } }`
89
+
90
+ Delegation creation (transitional until AgentShield upgrades)
91
+ - If AgentShield supports spec names now:
92
+ - Request: `{ issuer_did: string, subject_did: string, scopes: string[], expires_in_days?: number, constraints?: {...}, metadata?: {...} }`
93
+ - If not yet:
94
+ - Request: `{ agent_did: string, scopes: string[], expires_in_days?: number, metadata?: { issuer_did: string, subject_did: string, ... } }`
95
+ - Include a `Deprecation: use-issuer_did/subject_did` header where possible
96
+
97
+
98
+ ### Contracts and Validation (in `@kya-os/contracts`)
99
+
100
+ Consent Approval (back‑compat + new fields optional)
101
+ ```ts
102
+ export const consentApprovalRequestSchema = z.object({
103
+ tool: z.string().min(1),
104
+ scopes: z.array(z.string()),
105
+ agent_did: z.string(),
106
+ session_id: z.string(),
107
+ project_id: z.string(),
108
+ termsAccepted: z.boolean(),
109
+ termsVersion: z.string().max(50).optional(),
110
+ customFields: z.record(z.union([z.string(), z.boolean()])).optional(),
111
+
112
+ // NEW (optional; back‑compatible)
113
+ oauth_identity: z.object({
114
+ provider: z.enum(['google','github','microsoft','custom']),
115
+ subject: z.string(),
116
+ email: z.string().email().optional(),
117
+ name: z.string().optional(),
118
+ }).optional(),
119
+ user_did: z.string().optional(),
120
+ });
121
+ ```
122
+
123
+ Handshake (optional client info)
124
+ ```ts
125
+ export const HandshakeRequestSchema = z.object({
126
+ nonce: z.string().min(1),
127
+ audience: z.string().min(1),
128
+ timestamp: z.number().int().positive(),
129
+ agentDid: z.string().startsWith('did:').optional(),
130
+ clientInfo: z.object({
131
+ name: z.string(),
132
+ version: z.string(),
133
+ platform: z.string(),
134
+ }).optional(),
135
+ });
136
+ ```
137
+
138
+ Error Types (shared)
139
+ ```ts
140
+ export const AgentErrorSchema = z.object({
141
+ code: z.string(),
142
+ message: z.string(),
143
+ details: z.unknown().optional(),
144
+ });
145
+ ```
146
+
147
+
148
+ ### Implementation Changes (xmcp‑i)
149
+
150
+ 1) Consent → Delegation creation (fix critical gap)
151
+ - File: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
152
+ - Build delegation request with `issuerDid` and `subjectDid`:
153
+ ```ts
154
+ const userDid = await this.getUserDidForSession(request.session_id);
155
+ const delegationRequest = {
156
+ issuer_did: userDid,
157
+ subject_did: request.agent_did,
158
+ scopes: request.scopes,
159
+ expires_in_days: expiresInDays,
160
+ ...(request.customFields && Object.keys(request.customFields).length > 0
161
+ ? { metadata: request.customFields }
162
+ : {}),
163
+ };
164
+ ```
165
+
166
+ 2) User DID retrieval
167
+ - Add private method in `ConsentService`:
168
+ ```ts
169
+ private async getUserDidForSession(sessionId: string): Promise<string> {
170
+ const session = await this.sessionStorage.get(sessionId);
171
+ if (session?.userDid) return session.userDid;
172
+ const userDidManager = new UserDidManager({ crypto: this.cryptoProvider, storage: this.userDidStorage });
173
+ const userDid = await userDidManager.getOrCreateUserDid(sessionId);
174
+ await this.sessionStorage.set(sessionId, { ...session, userDid });
175
+ return userDid;
176
+ }
177
+ ```
178
+
179
+ 3) OAuth callback → link identity to DID
180
+ - File: `packages/mcp-i-cloudflare/src/runtime/oauth-handler.ts`
181
+ - Link key: `oauth:{provider}:{subject}` → `{ userDid, email?, name?, linkedAt, lastUsed }`
182
+ - Set `user_did` cookie post‑callback
183
+
184
+ 4) Multi‑tenant storage keys
185
+ - File: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
186
+ ```ts
187
+ const userAgentKey = `delegation:user:${userDid}:agent:${agentDid}`;
188
+ await this.delegationStorage.set(userAgentKey, token, { expirationTtl: 24 * 60 * 60 });
189
+ await this.delegationStorage.set(`delegation:session:${sessionId}`, { token, userDid, agentDid }, { expirationTtl: 60 * 60 });
190
+ ```
191
+
192
+ 5) Identity modes (optional, clear behavior)
193
+ - File: `packages/mcp-i-core/src/identity/user-did-manager.ts`
194
+ - Add `mode: 'ephemeral' | 'persistent' | 'hybrid'` and gate behavior accordingly.
195
+
196
+ 6) Consent page: include `oauth_identity` / `user_did` when available
197
+ - File: `packages/mcp-i-cloudflare/src/services/consent-page-renderer.ts`
198
+ - In the submission JS, conditionally attach both fields if present in session.
199
+
200
+ 7) Audit logs
201
+ - Log: consent shown, approval submitted, delegation created, verification success/failure, OAuth link events.
202
+
203
+
204
+ ### Verification and Chains
205
+
206
+ — Requirements
207
+ - Validate VC structure against MCP‑I §3.1 VC shape; verify signatures and trust roots.
208
+ - Verify delegation chains with parent VCs recursively; detect cycles; respect revocation.
209
+ - Use `resolve_delegation_chain(...)` first; only fallback to OAuth‑based verification if no valid VC chain exists.
210
+
211
+ — Behavior
212
+ - On any failure, return `{ code, message, details }` with appropriate HTTP code and parity wrapper.
213
+
214
+
215
+ ### Privacy & Security
216
+
217
+ — Privacy service (optional but recommended)
218
+ - Handlers: export, delete (forget), opt‑out (switch user to ephemeral), review (list identities+delegations).
219
+
220
+ — Security hardening
221
+ - Rate limit identity linking and delegation issuance per subject and per session.
222
+ - Require email verification toggle for risky link operations.
223
+ - CSP, XSS hardening (already present in consent renderer), secure cookies, SameSite=strict.
224
+
225
+
226
+ ### Migration & Compatibility
227
+
228
+ — Transitional plan for AgentShield parity
229
+ - Phase 4 immediately adds `issuerDid` into `metadata` when `issuer_did`/`subject_did` are not accepted yet.
230
+ - Coordinate dashboard/API update to accept spec names; once deployed, switch client to send first‑class fields and stop duplicating in `metadata`.
231
+ - Add `@validate-api-parity` to CI for any API file changes and ensure contracts in `@kya-os/contracts` are the single source of truth.
232
+
233
+ — Back‑compat
234
+ - New consent fields `oauth_identity`, `user_did` are optional.
235
+ - Handshake `clientInfo` optional.
236
+
237
+
238
+ ### Observability & Tests
239
+
240
+ — Unit
241
+ - `UserDidManager` (all modes), OAuth→DID linking, storage keys, consent validation
242
+
243
+ — Integration
244
+ - OAuth login → consent → delegation; session continuity; multi‑tenant issuance
245
+
246
+ — E2E
247
+ - First‑time consent + later reuse; data deletion; chain validation happy/negative paths
248
+
249
+ — Metrics & logs
250
+ - Latency of DID ops (<100ms p95), issuance/verification rate, error codes distribution
251
+
252
+
253
+ ### Implementation Checklist
254
+
255
+ Week 1
256
+ - Fix delegation creation with `issuerDid` + `subjectDid`
257
+ - Add `getUserDidForSession` and tests
258
+ - Extend consent schema with optional `oauth_identity`/`user_did`
259
+
260
+ Week 2
261
+ - OAuth callback linking to DID + tests
262
+ - Multi‑tenant storage keys + tests
263
+ - Optional: identity modes in `UserDidManager`
264
+
265
+ Week 3
266
+ - Privacy endpoints (export/delete/opt‑out/review) and tests
267
+ - Optional: handshake `clientInfo` + registry
268
+ - Parity validation command passes; docs updated
269
+
270
+ Success criteria
271
+ - User DID persists across sessions via OAuth
272
+ - Delegations include correct `issuerDid` (User) and `subjectDid` (Agent)
273
+ - No storage collisions across users for the same agent
274
+ - VC chain validated when present; OAuth fallback otherwise
275
+ - API parity checks clean; error formats consistent
276
+
277
+
278
+ ### Risks & Mitigations
279
+
280
+ — Performance: cache user DID and session delegations; async persistence
281
+ — Parity drift: block merges on `@validate-api-parity`; contracts as single source of truth
282
+ — Security: link throttling, optional email verification, strict audit logs
283
+ — Privacy: delete/export/opt‑out endpoints; secure storage scopes
284
+
285
+
286
+ ### Notes on Current Code Reality (validated)
287
+ - `consent.service.ts` currently posts `{ agent_did, scopes, expires_in_days }` and lacks `issuerDid` → must be fixed (Priority 1).
288
+ - `oauth-handler.ts` performs token exchange but does not yet link to User DID → add linking.
289
+ - `user-did-manager.ts` supports ephemeral DIDs; extend with modes if needed.
290
+ - `consentApprovalRequestSchema` lacks `oauth_identity`/`user_did` → add optional fields to support persistence (back‑compatible).
291
+ - `HandshakeRequestSchema` does not include `clientInfo` → optional addition for future reputation mapping.
292
+
293
+
294
+ ### Deliverables
295
+ - Updated contracts: consent schema (optional fields), optional handshake `clientInfo`
296
+ - Updated services: consent service, OAuth handler, consent renderer JS
297
+ - Updated storage keys: user+agent, session fast path
298
+ - Optional identity modes + privacy service
299
+ - Docs and parity validation green
300
+
301
+ # Phase 4: User DID & Identity Linking Implementation Plan
302
+
303
+ **Document Version:** 1.1
304
+ **Created:** November 2024
305
+ **Updated:** January 2025
306
+ **Status:** Ready for Implementation
307
+ **Priority:** CRITICAL - Addresses fundamental identity architecture gaps
308
+ **Branch:** feat/delegation-handling
309
+
310
+ ## Executive Summary
311
+
312
+ This document outlines the implementation plan for adding User DID persistence and OAuth identity linking to the MCP-I framework. The plan addresses critical issues identified during review including API schema mismatches, disconnected OAuth/consent flows, and missing User DID integration. Since we haven't launched yet, this plan assumes no existing users and implements the correct architecture from the start.
313
+
314
+ ## Prerequisites Complete ✅
315
+
316
+ The following foundational work has been completed in the current branch (feat/delegation-handling):
317
+
318
+ ### 1. Scaffolder Refactor (V3 Architecture) - COMPLETE
319
+ - **MCPICloudflareServer class created**: All services now hidden in the package
320
+ - **Clean scaffolded output**: Users only see ~100 lines of configuration
321
+ - **Services moved to package**: DelegationService, ProofService, AdminService, ConsentService
322
+ - **Constants extracted**: No more hardcoded URLs in templates
323
+
324
+ ### 2. Consent Service Implementation - COMPLETE
325
+ - **ConsentService class created**: Full consent flow implementation
326
+ - **Transport detection**: Automatic HTTP/SSE/STDIO detection
327
+ - **Consent rendering**: Complete with XSS protection
328
+ - **Integration ready**: Hooks in place for OAuth and User DID
329
+
330
+ ### 3. Proof Submission Fix - COMPLETE
331
+ - **Automatic submission**: Proofs now submitted after tool execution
332
+ - **ProofService integrated**: Proper initialization in runtime
333
+ - **AgentShield integration**: Proofs visible in dashboard
334
+
335
+ ### What This Means for Phase 4
336
+ With the scaffolder refactor and consent service complete, we have:
337
+ - ✅ Clean architecture to build upon
338
+ - ✅ ConsentService ready for OAuth integration (Part B)
339
+ - ✅ MCPICloudflareServer ready for User DID fixes (Part A)
340
+ - ✅ Infrastructure in place for storage improvements (Part C)
341
+
342
+ **Time Saved:** ~5 days of implementation already complete
343
+ **Adjusted Timeline:** 3-4 days remaining for Phase 4 implementation
344
+
345
+ ## Critical Issues Identified During Review
346
+
347
+ ### 1. API Schema Mismatch (CRITICAL)
348
+ - **Current State**: Consent service sends simplified request (agent_did, scopes, expires_in_days)
349
+ - **Expected**: AgentShield API expects full DelegationRecord with issuerDid and subjectDid
350
+ - **Impact**: Current implementation likely fails or creates invalid delegations
351
+ - **Evidence**: `consent.service.ts:358-366` vs `schemas.ts:153-155`
352
+
353
+ ### 2. OAuth Identity Not Captured
354
+ - **Current State**: Consent flow doesn't extract OAuth identity from approval requests
355
+ - **Problem**: OAuth handler exists (`oauth-handler.ts`) but isn't integrated with consent flow
356
+ - **Impact**: Can't link OAuth identity to User DIDs for persistence
357
+
358
+ ### 3. User DID Not Used as IssuerDid
359
+ - **Current State**: UserDidManager generates DIDs but they're not passed to delegation creation
360
+ - **Evidence**: TODO at `consent.service.ts:486-501` confirms this is known issue
361
+ - **Impact**: All delegations missing proper issuerDid (User DID)
362
+
363
+ ### 4. MCP Client Info Not Available
364
+ - **Current State**: Handshake schema doesn't include clientInfo.name
365
+ - **Evidence**: `handshake.ts:7-12` only has optional agentDid
366
+ - **Impact**: Can't map MCP clients to reputation DIDs as planned
367
+
368
+ ### 5. No Migration Strategy
369
+ - **Problem**: Existing delegations use ephemeral DIDs that become invalid
370
+ - **Impact**: Breaking change without backward compatibility
371
+
372
+ ### 6. Multi-Tenant Conflicts
373
+ - **Current State**: Multiple users delegating to same agent overwrite each other
374
+ - **Evidence**: Known issue documented at `consent.service.ts:486-506`
375
+
376
+ ## Revised Implementation Plan
377
+
378
+ ### Part A: Fix Core Delegation Flow (Priority 1 - 2 days)
379
+
380
+ #### A.1: Update Delegation Creation to Include User DID
381
+
382
+ **Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
383
+
384
+ **Current Code** (lines 358-366):
385
+ ```typescript
386
+ const delegationRequest = {
387
+ agent_did: request.agent_did,
388
+ scopes: request.scopes,
389
+ expires_in_days: expiresInDays,
390
+ ...(request.customFields && Object.keys(request.customFields).length > 0
391
+ ? { metadata: request.customFields }
392
+ : {}),
393
+ };
394
+ ```
395
+
396
+ **Updated Code**:
397
+ ```typescript
398
+ // Extract or generate User DID
399
+ const userDid = await this.getUserDidForSession(request.session_id);
400
+
401
+ const delegationRequest = {
402
+ // Core delegation fields
403
+ issuer_did: userDid, // NEW: User DID (who grants permission)
404
+ subject_did: request.agent_did, // RENAMED: Agent DID (who receives permission)
405
+ scopes: request.scopes,
406
+ expires_in_days: expiresInDays,
407
+
408
+ // Optional OAuth linking (for future persistence)
409
+ oauth_identity: request.oauth_identity ? {
410
+ provider: request.oauth_identity.provider,
411
+ subject: request.oauth_identity.subject,
412
+ email: request.oauth_identity.email
413
+ } : undefined
414
+
415
+ // Custom metadata
416
+ ...(request.customFields && Object.keys(request.customFields).length > 0
417
+ ? { metadata: request.customFields }
418
+ : {}),
419
+ };
420
+ ```
421
+
422
+ **Expected Outcome**:
423
+ - Delegations include proper issuerDid (User DID)
424
+ - OAuth identity captured for future linking
425
+ - API properly structured from the start
426
+
427
+ **Test Coverage**:
428
+ ```typescript
429
+ describe('Delegation Creation', () => {
430
+ it('should include issuerDid when creating delegation', async () => {
431
+ const result = await consentService.createDelegation(request);
432
+ expect(result.delegation.issuerDid).toBeDefined();
433
+ expect(result.delegation.issuerDid).toMatch(/^did:key:z6Mk/);
434
+ });
435
+
436
+ it('should capture OAuth identity when provided', async () => {
437
+ const request = { ...baseRequest, oauth_identity: { provider: 'google', subject: '123' }};
438
+ const result = await consentService.createDelegation(request);
439
+ expect(result.delegation.oauth_identity).toBeDefined();
440
+ });
441
+ });
442
+ ```
443
+
444
+ #### A.2: Add getUserDidForSession Method
445
+
446
+ **Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
447
+
448
+ **New Method**:
449
+ ```typescript
450
+ private async getUserDidForSession(sessionId: string): Promise<string> {
451
+ // Try to get existing User DID from session
452
+ const session = await this.sessionStorage.get(sessionId);
453
+ if (session?.userDid) {
454
+ return session.userDid;
455
+ }
456
+
457
+ // Generate new User DID using UserDidManager
458
+ const userDidManager = new UserDidManager({
459
+ crypto: this.cryptoProvider,
460
+ storage: this.userDidStorage // KV-based storage
461
+ });
462
+
463
+ const userDid = await userDidManager.getOrCreateUserDid(sessionId);
464
+
465
+ // Store in session for future use
466
+ await this.sessionStorage.set(sessionId, {
467
+ ...session,
468
+ userDid
469
+ });
470
+
471
+ return userDid;
472
+ }
473
+ ```
474
+
475
+ **Expected Outcome**:
476
+ - Consistent User DID per session
477
+ - Automatic generation if not exists
478
+ - Session-scoped persistence
479
+
480
+ **Test Coverage**:
481
+ ```typescript
482
+ describe('getUserDidForSession', () => {
483
+ it('should return existing User DID from session', async () => {
484
+ const sessionId = 'test-session';
485
+ const expectedDid = 'did:key:z6MkExisting';
486
+ await sessionStorage.set(sessionId, { userDid: expectedDid });
487
+
488
+ const result = await consentService.getUserDidForSession(sessionId);
489
+ expect(result).toBe(expectedDid);
490
+ });
491
+
492
+ it('should generate new User DID if not in session', async () => {
493
+ const sessionId = 'new-session';
494
+ const result = await consentService.getUserDidForSession(sessionId);
495
+ expect(result).toMatch(/^did:key:z6Mk/);
496
+ });
497
+ });
498
+ ```
499
+
500
+ ### Part B: Integrate OAuth with Consent Flow (Priority 2 - 2 days)
501
+
502
+ #### B.1: Update ConsentApprovalRequest Schema
503
+
504
+ **Location**: `packages/contracts/src/consent/schemas.ts`
505
+
506
+ **Add OAuth Identity Fields**:
507
+ ```typescript
508
+ export const consentApprovalRequestSchema = z.object({
509
+ // Existing fields
510
+ agent_did: z.string(),
511
+ session_id: z.string(),
512
+ scopes: z.array(z.string()),
513
+ project_id: z.string(),
514
+
515
+ // NEW: OAuth identity fields
516
+ oauth_identity: z.object({
517
+ provider: z.enum(['google', 'github', 'microsoft', 'custom']),
518
+ subject: z.string(), // OAuth user ID
519
+ email: z.string().email().optional(),
520
+ name: z.string().optional(),
521
+ }).optional(),
522
+
523
+ // NEW: Persistent User DID
524
+ user_did: z.string().optional(),
525
+
526
+ // Existing optional fields
527
+ termsAccepted: z.boolean().optional(),
528
+ customFields: z.record(z.unknown()).optional(),
529
+ });
530
+ ```
531
+
532
+ **Expected Outcome**:
533
+ - Consent approval can include OAuth identity
534
+ - Clean API design from the start
535
+ - Supports persistent User DIDs
536
+
537
+ #### B.2: Extract OAuth Identity in Consent Page
538
+
539
+ **Location**: `packages/mcp-i-cloudflare/src/services/consent-page-renderer.ts`
540
+
541
+ **Update Consent Page JavaScript**:
542
+ ```javascript
543
+ // In consent page template
544
+ async function approveConsent() {
545
+ // Extract OAuth identity from session/cookie if available
546
+ const oauthIdentity = await getOAuthIdentityFromSession();
547
+
548
+ const approvalRequest = {
549
+ agent_did: '${config.agentDid}',
550
+ session_id: '${config.sessionId}',
551
+ scopes: ${JSON.stringify(config.scopes)},
552
+ project_id: '${config.projectId}',
553
+
554
+ // Include OAuth identity if available
555
+ ...(oauthIdentity && { oauth_identity: oauthIdentity }),
556
+
557
+ // Include User DID if already persistent
558
+ ...(window.userDid && { user_did: window.userDid }),
559
+
560
+ termsAccepted: document.getElementById('terms-checkbox')?.checked,
561
+ };
562
+
563
+ const response = await fetch('/consent/approve', {
564
+ method: 'POST',
565
+ headers: { 'Content-Type': 'application/json' },
566
+ body: JSON.stringify(approvalRequest)
567
+ });
568
+ }
569
+ ```
570
+
571
+ **Expected Outcome**:
572
+ - OAuth identity passed to approval endpoint
573
+ - User DID included when available
574
+ - Progressive enhancement approach
575
+
576
+ #### B.3: Connect OAuth Handler to User DID Creation
577
+
578
+ **Location**: `packages/mcp-i-cloudflare/src/runtime/oauth-handler.ts`
579
+
580
+ **Add Identity Linking**:
581
+ ```typescript
582
+ export class OAuthHandler {
583
+ async handleCallback(request: Request): Promise<Response> {
584
+ // Existing OAuth token validation
585
+ const { provider, userInfo } = await this.validateOAuthCallback(request);
586
+
587
+ // NEW: Create or retrieve User DID for OAuth identity
588
+ const userDid = await this.linkOAuthToUserDid(provider, userInfo.sub);
589
+
590
+ // Store OAuth<->DID mapping
591
+ await this.identityStorage.set(
592
+ `oauth:${provider}:${userInfo.sub}`,
593
+ {
594
+ userDid,
595
+ email: userInfo.email,
596
+ name: userInfo.name,
597
+ linkedAt: new Date().toISOString(),
598
+ lastUsed: new Date().toISOString()
599
+ },
600
+ { expirationTtl: 30 * 24 * 60 * 60 } // 30 days
601
+ );
602
+
603
+ // Set session cookie with User DID
604
+ return new Response(null, {
605
+ status: 302,
606
+ headers: {
607
+ 'Location': '/consent',
608
+ 'Set-Cookie': `user_did=${userDid}; HttpOnly; Secure; SameSite=Strict`
609
+ }
610
+ });
611
+ }
612
+
613
+ private async linkOAuthToUserDid(provider: string, subject: string): Promise<string> {
614
+ const linkKey = `oauth:${provider}:${subject}`;
615
+
616
+ // Check for existing link
617
+ const existing = await this.identityStorage.get(linkKey);
618
+ if (existing?.userDid) {
619
+ // Update last used timestamp
620
+ await this.identityStorage.set(linkKey, {
621
+ ...existing,
622
+ lastUsed: new Date().toISOString()
623
+ });
624
+ return existing.userDid;
625
+ }
626
+
627
+ // Generate new persistent User DID
628
+ const userDidManager = new UserDidManager({
629
+ crypto: this.cryptoProvider,
630
+ storage: this.identityStorage
631
+ });
632
+
633
+ const userDid = await userDidManager.generateUserDid();
634
+ return userDid;
635
+ }
636
+ }
637
+ ```
638
+
639
+ **Expected Outcome**:
640
+ - OAuth identities automatically linked to User DIDs
641
+ - Persistent mapping stored in KV
642
+ - Same User DID returned for same OAuth identity
643
+
644
+ **Test Coverage**:
645
+ ```typescript
646
+ describe('OAuth to User DID Linking', () => {
647
+ it('should create new User DID for new OAuth identity', async () => {
648
+ const result = await oauthHandler.linkOAuthToUserDid('google', 'user123');
649
+ expect(result).toMatch(/^did:key:z6Mk/);
650
+ });
651
+
652
+ it('should return existing User DID for known OAuth identity', async () => {
653
+ const firstDid = await oauthHandler.linkOAuthToUserDid('google', 'user123');
654
+ const secondDid = await oauthHandler.linkOAuthToUserDid('google', 'user123');
655
+ expect(secondDid).toBe(firstDid);
656
+ });
657
+
658
+ it('should update lastUsed timestamp on retrieval', async () => {
659
+ await oauthHandler.linkOAuthToUserDid('google', 'user123');
660
+ const link = await identityStorage.get('oauth:google:user123');
661
+ const firstTime = link.lastUsed;
662
+
663
+ await new Promise(resolve => setTimeout(resolve, 100));
664
+ await oauthHandler.linkOAuthToUserDid('google', 'user123');
665
+ const updatedLink = await identityStorage.get('oauth:google:user123');
666
+ expect(updatedLink.lastUsed).not.toBe(firstTime);
667
+ });
668
+ });
669
+ ```
670
+
671
+ ### Part C: Fix Multi-Tenant Storage Conflicts (Priority 3 - 1 day)
672
+
673
+ #### C.1: Update Delegation Token Storage Keys
674
+
675
+ **Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
676
+
677
+ **Current Problem** (lines 486-501):
678
+ - Tokens stored with agent-scoped keys only
679
+ - Multiple users → same agent = overwrite
680
+
681
+ **Fix Storage Keys**:
682
+ ```typescript
683
+ private async storeDelegationToken(
684
+ token: string,
685
+ userDid: string,
686
+ agentDid: string,
687
+ sessionId: string
688
+ ): Promise<void> {
689
+ // Primary key: User + Agent (prevents conflicts)
690
+ const userAgentKey = `delegation:user:${userDid}:agent:${agentDid}`;
691
+ await this.delegationStorage.set(userAgentKey, token, {
692
+ expirationTtl: 24 * 60 * 60 // 24 hours
693
+ });
694
+
695
+ // Session key for fast lookup
696
+ const sessionKey = `delegation:session:${sessionId}`;
697
+ await this.delegationStorage.set(sessionKey, {
698
+ token,
699
+ userDid,
700
+ agentDid
701
+ }, {
702
+ expirationTtl: 60 * 60 // 1 hour
703
+ });
704
+ }
705
+
706
+ private async retrieveDelegationToken(
707
+ sessionId: string,
708
+ agentDid: string
709
+ ): Promise<string | null> {
710
+ // Try session key first (fastest)
711
+ const sessionData = await this.delegationStorage.get(`delegation:session:${sessionId}`);
712
+ if (sessionData?.token) {
713
+ return sessionData.token;
714
+ }
715
+
716
+ // Try user+agent key
717
+ const userDid = await this.getUserDidForSession(sessionId);
718
+ if (userDid) {
719
+ const token = await this.delegationStorage.get(`delegation:user:${userDid}:agent:${agentDid}`);
720
+ if (token) {
721
+ return token;
722
+ }
723
+ }
724
+
725
+ return null;
726
+ }
727
+ ```
728
+
729
+ **Expected Outcome**:
730
+ - No more multi-tenant conflicts
731
+ - Fast session-based lookup
732
+ - Clean storage architecture
733
+
734
+ **Test Coverage**:
735
+ ```typescript
736
+ describe('Multi-tenant Delegation Storage', () => {
737
+ it('should store delegations per user+agent combination', async () => {
738
+ const user1Did = 'did:key:z6MkUser1';
739
+ const user2Did = 'did:key:z6MkUser2';
740
+ const agentDid = 'did:key:z6MkAgent';
741
+
742
+ await consentService.storeDelegationToken('token1', user1Did, agentDid, 'session1');
743
+ await consentService.storeDelegationToken('token2', user2Did, agentDid, 'session2');
744
+
745
+ const token1 = await delegationStorage.get(`delegation:user:${user1Did}:agent:${agentDid}`);
746
+ const token2 = await delegationStorage.get(`delegation:user:${user2Did}:agent:${agentDid}`);
747
+
748
+ expect(token1).toBe('token1');
749
+ expect(token2).toBe('token2');
750
+ });
751
+ });
752
+ ```
753
+
754
+ ### Part D: Identity Mode Configuration (Priority 4 - 1 day)
755
+
756
+ #### D.1: Support Different Identity Modes
757
+
758
+ **Location**: `packages/mcp-i-core/src/identity/user-did-manager.ts`
759
+
760
+ **Add Configuration for Identity Modes**:
761
+ ```typescript
762
+ export interface UserDidManagerConfig {
763
+ // Existing fields...
764
+
765
+ /**
766
+ * Identity mode
767
+ * - 'ephemeral': Generate new DID per session (for development/testing)
768
+ * - 'persistent': Link to OAuth, reuse across sessions (for production)
769
+ * - 'hybrid': Ephemeral by default, persistent after OAuth login (flexible)
770
+ */
771
+ mode: 'ephemeral' | 'persistent' | 'hybrid';
772
+ }
773
+
774
+ export class UserDidManager {
775
+ async getOrCreateUserDid(sessionId: string, oauthIdentity?: OAuthIdentity): Promise<string> {
776
+ // Mode-based behavior
777
+ switch (this.config.mode) {
778
+ case 'ephemeral':
779
+ // Testing mode - always generate new
780
+ return this.generateEphemeralDid(sessionId);
781
+
782
+ case 'persistent':
783
+ // Production mode - require OAuth identity
784
+ if (!oauthIdentity) {
785
+ throw new Error('OAuth identity required in persistent mode');
786
+ }
787
+ return this.getOrCreatePersistentDid(oauthIdentity);
788
+
789
+ case 'hybrid':
790
+ // Flexible mode - use OAuth if available
791
+ if (oauthIdentity) {
792
+ return this.getOrCreatePersistentDid(oauthIdentity);
793
+ } else {
794
+ return this.generateEphemeralDid(sessionId);
795
+ }
796
+ }
797
+ }
798
+ }
799
+ ```
800
+
801
+ **Expected Outcome**:
802
+ - Support for different deployment scenarios
803
+ - Clear separation between dev/test/production modes
804
+ - Flexible configuration based on needs
805
+
806
+ ### Part E: Security & Privacy Enhancements (Priority 5 - 2 days)
807
+
808
+ #### E.1: OAuth Account Verification
809
+
810
+ **Location**: `packages/mcp-i-cloudflare/src/runtime/oauth-handler.ts`
811
+
812
+ **Add Verification Step**:
813
+ ```typescript
814
+ private async verifyOAuthAccountOwnership(
815
+ provider: string,
816
+ subject: string,
817
+ email?: string
818
+ ): Promise<boolean> {
819
+ // For account linking, require email verification
820
+ if (email && this.config.requireEmailVerification) {
821
+ const verificationToken = await this.generateVerificationToken();
822
+ await this.sendVerificationEmail(email, verificationToken);
823
+
824
+ // Store pending verification
825
+ await this.pendingVerifications.set(
826
+ `verify:${provider}:${subject}`,
827
+ { token: verificationToken, email },
828
+ { expirationTtl: 15 * 60 } // 15 minutes
829
+ );
830
+
831
+ return false; // Requires verification completion
832
+ }
833
+
834
+ // Check for suspicious patterns
835
+ const recentLinks = await this.getRecentLinks(subject);
836
+ if (recentLinks.length > this.config.maxLinksPerHour) {
837
+ console.warn('Suspicious linking activity detected:', subject);
838
+ return false;
839
+ }
840
+
841
+ return true;
842
+ }
843
+ ```
844
+
845
+ **Expected Outcome**:
846
+ - Prevents unauthorized account linking
847
+ - Email verification for sensitive operations
848
+ - Rate limiting on identity linking
849
+
850
+ #### E.2: Privacy Controls
851
+
852
+ **Location**: `packages/mcp-i-cloudflare/src/services/privacy.service.ts`
853
+
854
+ **New Privacy Service**:
855
+ ```typescript
856
+ export class PrivacyService {
857
+ async handlePrivacyRequest(request: PrivacyRequest): Promise<PrivacyResponse> {
858
+ switch (request.type) {
859
+ case 'export':
860
+ // GDPR: Right to data portability
861
+ return this.exportUserData(request.userDid);
862
+
863
+ case 'delete':
864
+ // GDPR: Right to be forgotten
865
+ return this.deleteUserData(request.userDid);
866
+
867
+ case 'opt-out':
868
+ // Switch to ephemeral mode for user
869
+ return this.setUserMode(request.userDid, 'ephemeral');
870
+
871
+ case 'review':
872
+ // Show all linked identities and delegations
873
+ return this.getUserDataSummary(request.userDid);
874
+ }
875
+ }
876
+
877
+ private async deleteUserData(userDid: string): Promise<PrivacyResponse> {
878
+ // Delete OAuth links
879
+ const links = await this.identityStorage.list({ prefix: `oauth:*:*` });
880
+ for (const link of links) {
881
+ if (link.value.userDid === userDid) {
882
+ await this.identityStorage.delete(link.key);
883
+ }
884
+ }
885
+
886
+ // Delete delegations
887
+ await this.delegationStorage.delete(`delegation:user:${userDid}:*`);
888
+
889
+ // Delete User DID
890
+ await this.userDidStorage.delete(userDid);
891
+
892
+ return { success: true, message: 'All user data deleted' };
893
+ }
894
+ }
895
+ ```
896
+
897
+ **Expected Outcome**:
898
+ - GDPR compliance
899
+ - User control over data
900
+ - Privacy-first design
901
+
902
+ **Test Coverage**:
903
+ ```typescript
904
+ describe('Privacy Controls', () => {
905
+ it('should delete all user data on request', async () => {
906
+ const userDid = 'did:key:z6MkUser';
907
+ await privacyService.deleteUserData(userDid);
908
+
909
+ const links = await identityStorage.list({ prefix: `oauth:` });
910
+ const userLinks = links.filter(l => l.value.userDid === userDid);
911
+ expect(userLinks).toHaveLength(0);
912
+ });
913
+
914
+ it('should export user data in portable format', async () => {
915
+ const result = await privacyService.exportUserData(userDid);
916
+ expect(result.data).toHaveProperty('identities');
917
+ expect(result.data).toHaveProperty('delegations');
918
+ expect(result.format).toBe('json');
919
+ });
920
+ });
921
+ ```
922
+
923
+ ### Part F: MCP Client Mapping (Optional - 1 day)
924
+
925
+ Since MCP handshake doesn't include clientInfo.name, we'll make this optional:
926
+
927
+ #### F.1: Extend Handshake Schema (If Possible)
928
+
929
+ **Location**: `packages/contracts/src/handshake.ts`
930
+
931
+ ```typescript
932
+ export const HandshakeRequestSchema = z.object({
933
+ agentDid: z.string().optional(),
934
+
935
+ // NEW: Optional client information
936
+ clientInfo: z.object({
937
+ name: z.string(), // "Claude Desktop", "OpenAI GPT", etc.
938
+ version: z.string(), // "1.0.0"
939
+ platform: z.string(), // "desktop", "web", "mobile"
940
+ }).optional(),
941
+ });
942
+ ```
943
+
944
+ #### F.2: Registry-Based Mapping
945
+
946
+ **Location**: `packages/mcp-i-core/src/client/registry.ts`
947
+
948
+ ```typescript
949
+ export const MCP_CLIENT_REGISTRY = {
950
+ // Well-known clients with reputation DIDs
951
+ 'Claude Desktop': {
952
+ did: 'did:web:knowthat.ai:clients:claude',
953
+ reputation: 'verified',
954
+ firstSeen: '2024-01-01',
955
+ },
956
+ 'OpenAI GPT': {
957
+ did: 'did:web:knowthat.ai:clients:openai',
958
+ reputation: 'verified',
959
+ firstSeen: '2024-01-01',
960
+ },
961
+ // Add more as they're discovered
962
+ };
963
+
964
+ export function getClientDid(clientName?: string): string | undefined {
965
+ if (!clientName) return undefined;
966
+ return MCP_CLIENT_REGISTRY[clientName]?.did;
967
+ }
968
+ ```
969
+
970
+ **Expected Outcome**:
971
+ - Optional enhancement
972
+ - Graceful degradation if not available
973
+ - Foundation for future reputation system
974
+
975
+ ## Implementation Schedule
976
+
977
+ ### Week 1: Core Fixes
978
+ - Day 1-2: Part A - Fix Core Delegation Flow
979
+ - [ ] Update delegation creation to include issuerDid
980
+ - [ ] Add getUserDidForSession method
981
+ - [ ] Write and run tests
982
+
983
+ - Day 3-4: Part B - OAuth Integration (partial)
984
+ - [ ] Update schemas
985
+ - [ ] Extract OAuth identity in consent page
986
+ - [ ] Begin OAuth handler updates
987
+
988
+ ### Week 2: Integration & Migration
989
+ - Day 5: Part B - Complete OAuth Integration
990
+ - [ ] Finish OAuth to User DID linking
991
+ - [ ] Test OAuth flow end-to-end
992
+
993
+ - Day 6: Part C - Fix Storage Conflicts
994
+ - [ ] Update delegation storage keys
995
+ - [ ] Test multi-tenant scenarios
996
+
997
+ - Day 7-8: Part D - Identity Mode Configuration
998
+ - [ ] Implement mode selection (ephemeral/persistent/hybrid)
999
+ - [ ] Add mode-specific logic
1000
+ - [ ] Test different deployment scenarios
1001
+
1002
+ ### Week 3: Security & Polish
1003
+ - Day 9-10: Part E - Security & Privacy
1004
+ - [ ] OAuth verification
1005
+ - [ ] Privacy controls
1006
+ - [ ] GDPR compliance testing
1007
+
1008
+ - Day 11: Part F - Optional MCP Client Mapping
1009
+ - [ ] Extend handshake if possible
1010
+ - [ ] Set up client registry
1011
+
1012
+ - Day 12: Integration Testing & Documentation
1013
+ - [ ] Full end-to-end testing
1014
+ - [ ] Update documentation
1015
+ - [ ] Performance testing
1016
+
1017
+ ## Success Metrics
1018
+
1019
+ ### Functional Requirements
1020
+ - [ ] User DIDs persist across sessions when using OAuth
1021
+ - [ ] Delegations include correct issuerDid (User) and subjectDid (Agent)
1022
+ - [ ] OAuth identity correctly linked to User DIDs
1023
+ - [ ] Multi-tenant conflicts resolved
1024
+ - [ ] Clean architecture from the start
1025
+
1026
+ ### Non-Functional Requirements
1027
+ - [ ] <100ms overhead for DID operations
1028
+ - [ ] GDPR compliance for data operations
1029
+ - [ ] 95% test coverage for new code
1030
+ - [ ] Clear separation between dev/test/prod modes
1031
+
1032
+ ### Security Requirements
1033
+ - [ ] OAuth account verification prevents unauthorized linking
1034
+ - [ ] Rate limiting on identity operations
1035
+ - [ ] Audit trail for all identity changes
1036
+ - [ ] Secure token storage with encryption
1037
+
1038
+ ## Risk Mitigation
1039
+
1040
+ ### Risk 1: Performance Impact
1041
+ - **Mitigation**: Caching, async operations
1042
+ - **Monitoring**: Track DID operation latency
1043
+
1044
+ ### Risk 2: Privacy Concerns
1045
+ - **Mitigation**: Clear mode selection (ephemeral/persistent/hybrid), data deletion API
1046
+ - **Compliance**: GDPR audit before release
1047
+
1048
+ ### Risk 3: OAuth Provider Issues
1049
+ - **Mitigation**: Support multiple providers, graceful fallback to ephemeral
1050
+ - **Monitoring**: Track OAuth success rates
1051
+
1052
+ ## Testing Strategy
1053
+
1054
+ ### Unit Tests
1055
+ - UserDidManager with all three modes
1056
+ - OAuth to DID linking logic
1057
+ - Multi-tenant storage operations
1058
+ - Privacy service operations
1059
+
1060
+ ### Integration Tests
1061
+ - Full OAuth login → consent → delegation flow
1062
+ - Session continuity across multiple requests
1063
+ - Mode switching (ephemeral → persistent → hybrid)
1064
+ - Multi-user, multi-agent scenarios
1065
+
1066
+ ### E2E Tests
1067
+ - User logs in with Google → approves delegation → uses tool
1068
+ - User returns next day → same DID → previous delegations work
1069
+ - User deletes account → all data removed
1070
+
1071
+ ### Performance Tests
1072
+ - 1000 concurrent DID operations
1073
+ - OAuth linking under load
1074
+ - Storage operations with 10k+ entries
1075
+
1076
+ ## Documentation Updates
1077
+
1078
+ ### API Documentation
1079
+ - New fields in ConsentApprovalRequest
1080
+ - OAuth identity linking endpoints
1081
+ - Privacy control endpoints
1082
+
1083
+ ### Configuration Guide
1084
+ - How to choose between identity modes
1085
+ - Setting up OAuth providers
1086
+ - Configuring for different environments
1087
+
1088
+ ### User Guide
1089
+ - Benefits of persistent identity
1090
+ - Privacy controls and data deletion
1091
+ - OAuth account linking process
1092
+
1093
+ ## Conclusion
1094
+
1095
+ This plan addresses all critical issues identified in the review and implements the correct architecture from the start. The implementation is broken into manageable phases with clear dependencies and success metrics.
1096
+
1097
+ The key improvements include:
1098
+ 1. Proper User DID integration as issuerDid
1099
+ 2. OAuth identity linking for persistence
1100
+ 3. Multi-tenant conflict resolution
1101
+ 4. Comprehensive security and privacy controls
1102
+ 5. Clear mode selection for different deployment scenarios
1103
+
1104
+ By following this plan, we'll establish a robust identity foundation that enables true user persistence while maintaining the flexibility to support both ephemeral and persistent modes based on use case requirements.
1105
+
1106
+ ## Comparison to Initial Analysis
1107
+
1108
+ ### What Changed from Original Plan
1109
+
1110
+ The initial analysis suggested a simpler OAuth bridging approach. After review feedback, the plan now addresses:
1111
+
1112
+ 1. **API Schema Alignment**: Fixed to send full DelegationRecord with issuerDid and subjectDid
1113
+ 2. **OAuth Integration**: Properly integrated with consent flow (not separate)
1114
+ 3. **User DID Usage**: Actually used as issuerDid (was missing before)
1115
+ 4. **No Legacy Support**: Since we haven't launched, no need for backward compatibility
1116
+
1117
+ ### What Remains from Original Plan
1118
+
1119
+ 1. **Core Concept**: OAuth identity → User DID linking for persistence
1120
+ 2. **Three-Layer DIDs**: Server/Bouncer, Agent, and User DIDs
1121
+ 3. **MCP Client Mapping**: Optional enhancement for reputation tracking
1122
+ 4. **Session Continuity**: Tracking users across chat sessions
1123
+
1124
+ ## MCP-I Specification Alignment
1125
+
1126
+ ### Full Compliance with MCP-I Spec
1127
+
1128
+ This implementation aligns with the [MCP-I specification](https://modelcontextprotocol-identity.io) and [schemas](https://schema.modelcontextprotocol-identity.io/):
1129
+
1130
+ 1. **DID Architecture** ✅
1131
+ - Server DID: `did:web:` or `did:key:` format per spec
1132
+ - Agent DID: Properly used as subjectDid in delegations
1133
+ - User DID: Properly used as issuerDid in delegations
1134
+
1135
+ 2. **Delegation Model** ✅
1136
+ - Format: User (issuerDid) → Agent (subjectDid)
1137
+ - Includes scopes, constraints, and expiration
1138
+ - Follows W3C Verifiable Credential wrapper format
1139
+
1140
+ 3. **Proof Format** ✅
1141
+ - JWS compact format (header.payload.signature)
1142
+ - All required meta fields present
1143
+ - SHA-256 hashing with proper prefixes
1144
+
1145
+ 4. **Consent Flow** ✅
1146
+ - Required parameters: tool, scopes, agent_did, session_id, project_id
1147
+ - Proper approval handling
1148
+ - Delegation creation upon approval
1149
+
1150
+ 5. **Security Requirements** ✅
1151
+ - Ed25519 signatures
1152
+ - Proper nonce handling
1153
+ - Session-based security
1154
+
1155
+ ### Key Alignment Points
1156
+
1157
+ - **issuerDid**: Always the User DID (who grants permission)
1158
+ - **subjectDid**: Always the Agent DID (who receives permission)
1159
+ - **Delegation Storage**: Properly scoped to prevent multi-tenant conflicts
1160
+ - **OAuth Integration**: Enhances but doesn't replace DID-based identity
1161
+
1162
+ ### Level 3 Enterprise Features
1163
+
1164
+ While this plan doesn't implement full Level 3 compliance (OAuth 2.1 bridging, anomaly detection), it provides:
1165
+ - Foundation for OAuth identity management
1166
+ - Clear path to Level 3 if needed
1167
+ - Level 1-2 compliance out of the box
1168
+
1169
+ The implementation maintains full spec compliance while addressing real-world needs for persistent user identity across sessions.