@kya-os/mcp-i-core 1.3.7-canary.0 → 1.3.7-canary.clientinfo.20251126041014
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test$colon$coverage.log +4239 -0
- package/.turbo/turbo-test.log +2973 -0
- package/COMPLIANCE_IMPROVEMENT_REPORT.md +483 -0
- package/Composer 3.md +615 -0
- package/GPT-5.md +1169 -0
- package/OPUS-plan.md +352 -0
- package/PHASE_3_AND_4.1_SUMMARY.md +585 -0
- package/PHASE_3_SUMMARY.md +317 -0
- package/PHASE_4.1.3_SUMMARY.md +428 -0
- package/PHASE_4.1_COMPLETE.md +525 -0
- package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +1240 -0
- package/SCHEMA_COMPLIANCE_REPORT.md +275 -0
- package/TEST_PLAN.md +571 -0
- package/coverage/coverage-final.json +57 -0
- package/dist/__tests__/utils/mock-providers.d.ts +1 -2
- package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
- package/dist/__tests__/utils/mock-providers.js.map +1 -1
- package/dist/cache/oauth-config-cache.d.ts +69 -0
- package/dist/cache/oauth-config-cache.d.ts.map +1 -0
- package/dist/cache/oauth-config-cache.js +76 -0
- package/dist/cache/oauth-config-cache.js.map +1 -0
- package/dist/identity/idp-token-resolver.d.ts +53 -0
- package/dist/identity/idp-token-resolver.d.ts.map +1 -0
- package/dist/identity/idp-token-resolver.js +108 -0
- package/dist/identity/idp-token-resolver.js.map +1 -0
- package/dist/identity/idp-token-storage.interface.d.ts +42 -0
- package/dist/identity/idp-token-storage.interface.d.ts.map +1 -0
- package/dist/identity/idp-token-storage.interface.js +12 -0
- package/dist/identity/idp-token-storage.interface.js.map +1 -0
- package/dist/identity/user-did-manager.d.ts +39 -1
- package/dist/identity/user-did-manager.d.ts.map +1 -1
- package/dist/identity/user-did-manager.js +69 -3
- package/dist/identity/user-did-manager.js.map +1 -1
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/audit-logger.d.ts +37 -0
- package/dist/runtime/audit-logger.d.ts.map +1 -0
- package/dist/runtime/audit-logger.js +9 -0
- package/dist/runtime/audit-logger.js.map +1 -0
- package/dist/runtime/base.d.ts +19 -2
- package/dist/runtime/base.d.ts.map +1 -1
- package/dist/runtime/base.js +227 -11
- package/dist/runtime/base.js.map +1 -1
- package/dist/services/access-control.service.d.ts.map +1 -1
- package/dist/services/access-control.service.js +199 -15
- package/dist/services/access-control.service.js.map +1 -1
- package/dist/services/authorization/authorization-registry.d.ts +29 -0
- package/dist/services/authorization/authorization-registry.d.ts.map +1 -0
- package/dist/services/authorization/authorization-registry.js +57 -0
- package/dist/services/authorization/authorization-registry.js.map +1 -0
- package/dist/services/authorization/types.d.ts +53 -0
- package/dist/services/authorization/types.d.ts.map +1 -0
- package/dist/services/authorization/types.js +10 -0
- package/dist/services/authorization/types.js.map +1 -0
- package/dist/services/batch-delegation.service.d.ts +53 -0
- package/dist/services/batch-delegation.service.d.ts.map +1 -0
- package/dist/services/batch-delegation.service.js +95 -0
- package/dist/services/batch-delegation.service.js.map +1 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +4 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/oauth-config.service.d.ts +53 -0
- package/dist/services/oauth-config.service.d.ts.map +1 -0
- package/dist/services/oauth-config.service.js +141 -0
- package/dist/services/oauth-config.service.js.map +1 -0
- package/dist/services/oauth-provider-registry.d.ts +88 -0
- package/dist/services/oauth-provider-registry.d.ts.map +1 -0
- package/dist/services/oauth-provider-registry.js +128 -0
- package/dist/services/oauth-provider-registry.js.map +1 -0
- package/dist/services/oauth-service.d.ts +77 -0
- package/dist/services/oauth-service.d.ts.map +1 -0
- package/dist/services/oauth-service.js +373 -0
- package/dist/services/oauth-service.js.map +1 -0
- package/dist/services/oauth-token-retrieval.service.d.ts +49 -0
- package/dist/services/oauth-token-retrieval.service.d.ts.map +1 -0
- package/dist/services/oauth-token-retrieval.service.js +150 -0
- package/dist/services/oauth-token-retrieval.service.js.map +1 -0
- package/dist/services/provider-resolver.d.ts +48 -0
- package/dist/services/provider-resolver.d.ts.map +1 -0
- package/dist/services/provider-resolver.js +121 -0
- package/dist/services/provider-resolver.js.map +1 -0
- package/dist/services/provider-validator.d.ts +55 -0
- package/dist/services/provider-validator.d.ts.map +1 -0
- package/dist/services/provider-validator.js +135 -0
- package/dist/services/provider-validator.js.map +1 -0
- package/dist/services/session-registration.service.d.ts +80 -0
- package/dist/services/session-registration.service.d.ts.map +1 -0
- package/dist/services/session-registration.service.js +228 -0
- package/dist/services/session-registration.service.js.map +1 -0
- package/dist/services/tool-context-builder.d.ts +57 -0
- package/dist/services/tool-context-builder.d.ts.map +1 -0
- package/dist/services/tool-context-builder.js +125 -0
- package/dist/services/tool-context-builder.js.map +1 -0
- package/dist/services/tool-protection.service.d.ts +27 -0
- package/dist/services/tool-protection.service.d.ts.map +1 -1
- package/dist/services/tool-protection.service.js +194 -4
- package/dist/services/tool-protection.service.js.map +1 -1
- package/dist/types/oauth-required-error.d.ts +40 -0
- package/dist/types/oauth-required-error.d.ts.map +1 -0
- package/dist/types/oauth-required-error.js +40 -0
- package/dist/types/oauth-required-error.js.map +1 -0
- package/dist/utils/did-helpers.d.ts +33 -0
- package/dist/utils/did-helpers.d.ts.map +1 -1
- package/dist/utils/did-helpers.js +40 -0
- package/dist/utils/did-helpers.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/docs/API_REFERENCE.md +1362 -0
- package/docs/COMPLIANCE_MATRIX.md +691 -0
- package/docs/STATUSLIST2021_GUIDE.md +696 -0
- package/docs/W3C_VC_DELEGATION_GUIDE.md +710 -0
- package/package.json +23 -54
- package/scripts/audit-compliance.ts +724 -0
- package/src/__tests__/cache/tool-protection-cache.test.ts +640 -0
- package/src/__tests__/config/provider-runtime-config.test.ts +309 -0
- package/src/__tests__/delegation-e2e.test.ts +690 -0
- package/src/__tests__/identity/user-did-manager.test.ts +213 -0
- package/src/__tests__/index.test.ts +56 -0
- package/src/__tests__/integration/full-flow.test.ts +776 -0
- package/src/__tests__/integration.test.ts +281 -0
- package/src/__tests__/providers/base.test.ts +173 -0
- package/src/__tests__/providers/memory.test.ts +319 -0
- package/src/__tests__/regression/phase2-regression.test.ts +429 -0
- package/src/__tests__/runtime/audit-logger.test.ts +154 -0
- package/src/__tests__/runtime/base-extensions.test.ts +593 -0
- package/src/__tests__/runtime/base.test.ts +869 -0
- package/src/__tests__/runtime/delegation-flow.test.ts +164 -0
- package/src/__tests__/runtime/proof-client-did.test.ts +375 -0
- package/src/__tests__/runtime/route-interception.test.ts +686 -0
- package/src/__tests__/runtime/tool-protection-enforcement.test.ts +908 -0
- package/src/__tests__/services/agentshield-integration.test.ts +784 -0
- package/src/__tests__/services/cache-busting.test.ts +125 -0
- package/src/__tests__/services/oauth-service-pkce.test.ts +556 -0
- package/src/__tests__/services/provider-resolver-edge-cases.test.ts +591 -0
- package/src/__tests__/services/tool-protection-oauth-provider.test.ts +480 -0
- package/src/__tests__/services/tool-protection.service.test.ts +1366 -0
- package/src/__tests__/utils/mock-providers.ts +340 -0
- package/src/cache/oauth-config-cache.d.ts +69 -0
- package/src/cache/oauth-config-cache.d.ts.map +1 -0
- package/src/cache/oauth-config-cache.js.map +1 -0
- package/src/cache/oauth-config-cache.ts +123 -0
- package/src/cache/tool-protection-cache.ts +171 -0
- package/src/compliance/EXAMPLE.md +412 -0
- package/src/compliance/__tests__/schema-verifier.test.ts +797 -0
- package/src/compliance/index.ts +8 -0
- package/src/compliance/schema-registry.ts +460 -0
- package/src/compliance/schema-verifier.ts +708 -0
- package/src/config/__tests__/remote-config.spec.ts +268 -0
- package/src/config/remote-config.ts +174 -0
- package/src/config.ts +309 -0
- package/src/delegation/__tests__/audience-validator.test.ts +112 -0
- package/src/delegation/__tests__/bitstring.test.ts +346 -0
- package/src/delegation/__tests__/cascading-revocation.test.ts +628 -0
- package/src/delegation/__tests__/delegation-graph.test.ts +584 -0
- package/src/delegation/__tests__/utils.test.ts +152 -0
- package/src/delegation/__tests__/vc-issuer.test.ts +442 -0
- package/src/delegation/__tests__/vc-verifier.test.ts +922 -0
- package/src/delegation/audience-validator.ts +52 -0
- package/src/delegation/bitstring.ts +278 -0
- package/src/delegation/cascading-revocation.ts +370 -0
- package/src/delegation/delegation-graph.ts +299 -0
- package/src/delegation/index.ts +14 -0
- package/src/delegation/statuslist-manager.ts +353 -0
- package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
- package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
- package/src/delegation/storage/index.ts +9 -0
- package/src/delegation/storage/memory-graph-storage.ts +178 -0
- package/src/delegation/storage/memory-statuslist-storage.ts +77 -0
- package/src/delegation/utils.ts +42 -0
- package/src/delegation/vc-issuer.ts +232 -0
- package/src/delegation/vc-verifier.ts +568 -0
- package/src/identity/idp-token-resolver.ts +147 -0
- package/src/identity/idp-token-storage.interface.ts +59 -0
- package/src/identity/user-did-manager.ts +370 -0
- package/src/index.ts +271 -0
- package/src/providers/base.d.ts +91 -0
- package/src/providers/base.d.ts.map +1 -0
- package/src/providers/base.js.map +1 -0
- package/src/providers/base.ts +96 -0
- package/src/providers/memory.ts +142 -0
- package/src/runtime/audit-logger.ts +39 -0
- package/src/runtime/base.ts +1329 -0
- package/src/services/__tests__/access-control.integration.test.ts +443 -0
- package/src/services/__tests__/access-control.proof-response-validation.test.ts +578 -0
- package/src/services/__tests__/access-control.service.test.ts +970 -0
- package/src/services/__tests__/batch-delegation.service.test.ts +351 -0
- package/src/services/__tests__/crypto.service.test.ts +531 -0
- package/src/services/__tests__/oauth-provider-registry.test.ts +142 -0
- package/src/services/__tests__/proof-verifier.integration.test.ts +485 -0
- package/src/services/__tests__/proof-verifier.test.ts +489 -0
- package/src/services/__tests__/provider-resolution.integration.test.ts +202 -0
- package/src/services/__tests__/provider-resolver.test.ts +213 -0
- package/src/services/__tests__/storage.service.test.ts +358 -0
- package/src/services/access-control.service.ts +990 -0
- package/src/services/authorization/authorization-registry.ts +66 -0
- package/src/services/authorization/types.ts +71 -0
- package/src/services/batch-delegation.service.ts +137 -0
- package/src/services/crypto.service.ts +302 -0
- package/src/services/errors.ts +76 -0
- package/src/services/index.ts +18 -0
- package/src/services/oauth-config.service.d.ts +53 -0
- package/src/services/oauth-config.service.d.ts.map +1 -0
- package/src/services/oauth-config.service.js.map +1 -0
- package/src/services/oauth-config.service.ts +192 -0
- package/src/services/oauth-provider-registry.d.ts +57 -0
- package/src/services/oauth-provider-registry.d.ts.map +1 -0
- package/src/services/oauth-provider-registry.js.map +1 -0
- package/src/services/oauth-provider-registry.ts +141 -0
- package/src/services/oauth-service.ts +544 -0
- package/src/services/oauth-token-retrieval.service.ts +245 -0
- package/src/services/proof-verifier.ts +478 -0
- package/src/services/provider-resolver.d.ts +48 -0
- package/src/services/provider-resolver.d.ts.map +1 -0
- package/src/services/provider-resolver.js.map +1 -0
- package/src/services/provider-resolver.ts +146 -0
- package/src/services/provider-validator.ts +170 -0
- package/src/services/session-registration.service.ts +317 -0
- package/src/services/storage.service.ts +566 -0
- package/src/services/tool-context-builder.ts +172 -0
- package/src/services/tool-protection.service.ts +982 -0
- package/src/types/oauth-required-error.ts +63 -0
- package/src/types/tool-protection.ts +155 -0
- package/src/utils/__tests__/did-helpers.test.ts +101 -0
- package/src/utils/base64.ts +148 -0
- package/src/utils/cors.ts +83 -0
- package/src/utils/did-helpers.ts +150 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/storage-keys.ts +278 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +56 -0
|
@@ -0,0 +1,1240 @@
|
|
|
1
|
+
Based on my comprehensive investigation, I can now answer all your questions with empirical evidence from the codebase:
|
|
2
|
+
|
|
3
|
+
A. MCP-I Handshake Usage
|
|
4
|
+
|
|
5
|
+
Yes, we use the MCP-I handshake! It occurs in packages/mcp-i-core/src/runtime/base.ts (lines 109-150):
|
|
6
|
+
|
|
7
|
+
async handleHandshake(request: any): Promise<any> {
|
|
8
|
+
// Creates session with:
|
|
9
|
+
// - agentDid: from request (MCP client's DID)
|
|
10
|
+
// - serverDid: our server's DID
|
|
11
|
+
// - userDid: generated for the user
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
When it occurs: During initial MCP connection between client and server.
|
|
15
|
+
|
|
16
|
+
Note: Our implementation is simplified compared to the full spec - we don't implement the cryptographic challenge-response, but we do exchange DIDs and establish sessions.
|
|
17
|
+
|
|
18
|
+
B. OAuth Provider UI in AgentShield Dashboard
|
|
19
|
+
|
|
20
|
+
Yes, I was aware! The OAuth provider UI exists at:
|
|
21
|
+
|
|
22
|
+
- Database: bouncer_configs table with OAuth fields
|
|
23
|
+
- UI: /dashboard/bouncer/config/[projectId]/page.tsx
|
|
24
|
+
- Providers: GitHub, Google, Microsoft, Slack, Stripe, etc.
|
|
25
|
+
|
|
26
|
+
Expected Flow:
|
|
27
|
+
|
|
28
|
+
1. Customer adds OAuth provider (e.g., GitHub) in bouncer dashboard
|
|
29
|
+
2. Tool requires delegation → triggers OAuth flow with that provider
|
|
30
|
+
3. User authenticates via GitHub OAuth
|
|
31
|
+
4. UserDID linked to GitHub identity (this is what Phase 4 adds!)
|
|
32
|
+
5. Future calls: Same UserDID retrieved via GitHub identity, no re-delegation needed
|
|
33
|
+
|
|
34
|
+
Critical Finding: Currently OAuth is project-level, not tool-specific. All tools in a project use the same OAuth provider.
|
|
35
|
+
|
|
36
|
+
C. Tool-to-OAuth Assignment
|
|
37
|
+
|
|
38
|
+
Current State: Tools CANNOT be assigned to specific OAuth providers.
|
|
39
|
+
|
|
40
|
+
How it works now:
|
|
41
|
+
|
|
42
|
+
- Tools specify abstract scopes: ['files:read', 'files:write']
|
|
43
|
+
- Project configures ONE OAuth provider
|
|
44
|
+
- Scopes auto-translate: files:read → GitHub: ['public_repo']
|
|
45
|
+
|
|
46
|
+
North Star Architecture (for future):
|
|
47
|
+
// Add tool-specific OAuth mapping
|
|
48
|
+
toolOAuthMappings: {
|
|
49
|
+
'github_code_reader': { provider: 'github', scopes: ['repo'] },
|
|
50
|
+
'google_drive_reader': { provider: 'google', scopes: ['drive.readonly'] },
|
|
51
|
+
'slack_messenger': { provider: 'slack', scopes: ['chat:write'] }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Iterative Approach:
|
|
55
|
+
|
|
56
|
+
- Phase 4: Single OAuth provider per project (current)
|
|
57
|
+
- Phase 5: Multiple providers, tool-specific assignment
|
|
58
|
+
- Phase 6: Dynamic provider selection based on context
|
|
59
|
+
|
|
60
|
+
D. DID Tracking Confirmation
|
|
61
|
+
|
|
62
|
+
Yes, after Phase 4 we track ALL these DIDs:
|
|
63
|
+
|
|
64
|
+
1. ✅ UserDID: The human user (issuerDid in delegations)
|
|
65
|
+
- Currently ephemeral did:key:z6MkUser...
|
|
66
|
+
- Phase 4 makes it persistent via OAuth linking
|
|
67
|
+
|
|
68
|
+
2. ✅ MCP Client DID: The AI client (e.g., Claude Desktop)
|
|
69
|
+
- Tracked as agentDid in handshake
|
|
70
|
+
- Example: did:key:z6MkClaude...
|
|
71
|
+
|
|
72
|
+
3. ✅ Agent DID: Same as MCP Client DID
|
|
73
|
+
- The entity making tool calls (subjectDid in delegations)
|
|
74
|
+
|
|
75
|
+
4. ✅ Server/Bouncer DID: The MCP-I server
|
|
76
|
+
- Example: did:web:service-x-bouncer
|
|
77
|
+
|
|
78
|
+
E. Cross-Agent Delegation Validation
|
|
79
|
+
|
|
80
|
+
YES! The bouncer can validate delegations from ANY agent:
|
|
81
|
+
|
|
82
|
+
Evidence from agent-shield/apps/web/app/api/v1/bouncer/delegations/verify/route.ts:
|
|
83
|
+
|
|
84
|
+
- Accepts any agent_did
|
|
85
|
+
- Queries centralized AgentShield database
|
|
86
|
+
- Returns valid/invalid for that agent+scopes combination
|
|
87
|
+
|
|
88
|
+
This means service-x-bouncer can validate delegations for:
|
|
89
|
+
|
|
90
|
+
- Local agents (Claude Desktop)
|
|
91
|
+
- External SaaS agents (did:web:agent:saavvy-shopping-mcp)
|
|
92
|
+
- Other bouncers acting as agents
|
|
93
|
+
|
|
94
|
+
F. Scenario Explanations
|
|
95
|
+
|
|
96
|
+
Scenario 1: Claude Desktop + service-x-bouncer
|
|
97
|
+
|
|
98
|
+
Claude Desktop (agentDid) → Handshake → service-x-bouncer (serverDid)
|
|
99
|
+
→ Tool call → Check delegation → OAuth flow → User grants (userDid)
|
|
100
|
+
→ Delegation stored → Tool executes
|
|
101
|
+
|
|
102
|
+
Scenario 2: SaaS Agent → service-x
|
|
103
|
+
|
|
104
|
+
saavvy-shopping-mcp (agentDid) → Handshake → service-x-bouncer (serverDid)
|
|
105
|
+
|
|
106
|
+
- ✅ Can do handshake: Yes, any agent can handshake
|
|
107
|
+
- ✅ Can validate delegations: Yes, via AgentShield API
|
|
108
|
+
- What it enables: Session-based tool calls with delegation verification
|
|
109
|
+
- Note: Still requires human (UserDID) to grant initial delegation
|
|
110
|
+
|
|
111
|
+
Scenario 3: Shopping Assistant → service-x
|
|
112
|
+
|
|
113
|
+
Claude → shopping-assistant (local MCP) → service-x-bouncer (remote)
|
|
114
|
+
Two options:
|
|
115
|
+
|
|
116
|
+
1. Direct delegation: User authorizes shopping-assistant to service-x
|
|
117
|
+
2. Delegation chain: shopping-assistant's existing delegation chains to service-x (future feature)
|
|
118
|
+
|
|
119
|
+
G. Agent DID Classification
|
|
120
|
+
|
|
121
|
+
Yes, Agent DIDs apply to ALL of these:
|
|
122
|
+
|
|
123
|
+
An "Agent" = Any software making tool calls to an MCP-I server
|
|
124
|
+
|
|
125
|
+
- ✅ MCP servers ('shopping-assistant'): Has agentDid when calling others
|
|
126
|
+
- ✅ Bouncers ('service-x-bouncer'): Has serverDid when receiving, agentDid when calling upstream
|
|
127
|
+
- ✅ SaaS businesses ('saavvy-shopping-mcp'): Has agentDid when calling MCP-I APIs
|
|
128
|
+
- ✅ AI Clients (Claude Desktop): Primary use case, has agentDid
|
|
129
|
+
|
|
130
|
+
H. MCP Client Identity & Reputation Guidance
|
|
131
|
+
|
|
132
|
+
- **Persistent MCP Client Identity**: The handshake already surfaces `clientInfo`; Phase 4 formalizes storing a durable client identifier (client-issued DID preferred, otherwise a signed instance token) in the session envelope so telemetry survives chat restarts.
|
|
133
|
+
- **Dashboard Attribution**: Delegation/proof logs must include `{ issuerDid, subjectDid, clientInstanceId }` so operators can separate “service agent” activity from the upstream MCP client that initiated the call.
|
|
134
|
+
- **Multi-Hop Enforcement**: If an intermediate MCP-I runtime (e.g., Honey) calls downstream services, we treat that runtime’s DID as the delegation subject while propagating the origin client metadata for reputation scoring and selective throttling.
|
|
135
|
+
|
|
136
|
+
```markdown
|
|
137
|
+
# Updated Phase 4 Plan with Architecture Clarifications
|
|
138
|
+
|
|
139
|
+
Based on a comprehensive analysis, here's the refined plan addressing all architectural concerns:
|
|
140
|
+
|
|
141
|
+
## Part A: Fix Core Delegation Flow (Priority 1)
|
|
142
|
+
|
|
143
|
+
✅ Already in plan - No changes needed
|
|
144
|
+
|
|
145
|
+
- Update delegation creation to include proper `issuerDid` (UserDID)
|
|
146
|
+
- Fix API schema to send full `DelegationRecord`
|
|
147
|
+
|
|
148
|
+
## Part B: OAuth Integration with AgentShield Dashboard (Priority 2)
|
|
149
|
+
|
|
150
|
+
Updated to reflect existing OAuth UI:
|
|
151
|
+
|
|
152
|
+
1. Leverage existing OAuth provider configuration in `bouncer_configs`
|
|
153
|
+
2. Link OAuth identity to persistent UserDID during consent flow
|
|
154
|
+
3. Store mapping in KV: `oauth:github:user123 → did:key:z6MkUser...`
|
|
155
|
+
4. Future tool calls retrieve UserDID via OAuth identity
|
|
156
|
+
|
|
157
|
+
## Part C: MCP-I Handshake Enhancement (NEW - Priority 3)
|
|
158
|
+
|
|
159
|
+
Add proper DID exchange during handshake:
|
|
160
|
+
|
|
161
|
+
1. Ensure `agentDid` is captured from MCP client
|
|
162
|
+
2. Generate/retrieve persistent UserDID if OAuth session exists
|
|
163
|
+
3. Store all DIDs in session context:
|
|
164
|
+
- `agentDid` (MCP client/agent making request)
|
|
165
|
+
- `serverDid` (bouncer/service receiving request)
|
|
166
|
+
- `userDid` (human who grants delegations)
|
|
167
|
+
|
|
168
|
+
## Part D: Cross-Agent Delegation Support (Priority 4)
|
|
169
|
+
|
|
170
|
+
Ensure delegations work across different agents:
|
|
171
|
+
|
|
172
|
+
1. Verify AgentShield API accepts any `agent_did` format
|
|
173
|
+
2. Test delegation validation for external agents (`did:web`)
|
|
174
|
+
3. Document how SaaS agents can integrate with bouncers
|
|
175
|
+
|
|
176
|
+
## Part E: Future Enhancements (Document but don't implement)
|
|
177
|
+
|
|
178
|
+
### Tool-Specific OAuth Providers (Phase 5):
|
|
179
|
+
|
|
180
|
+
- Design schema for tool → OAuth provider mapping
|
|
181
|
+
- Plan migration from project-level to tool-level OAuth
|
|
182
|
+
|
|
183
|
+
### Delegation Chains (Phase 6):
|
|
184
|
+
|
|
185
|
+
- Enable Agent A → Agent B → Agent C delegations
|
|
186
|
+
- Leverage existing `memory-graph-storage.ts`
|
|
187
|
+
|
|
188
|
+
## Implementation Changes Needed:
|
|
189
|
+
|
|
190
|
+
1. Fix UserDID persistence via OAuth linking (main goal)
|
|
191
|
+
2. Ensure handshake captures all DIDs correctly
|
|
192
|
+
3. Document multi-agent scenarios for customers
|
|
193
|
+
4. Test cross-agent delegation validation
|
|
194
|
+
|
|
195
|
+
## Success Criteria:
|
|
196
|
+
|
|
197
|
+
- UserDID persists across sessions via OAuth
|
|
198
|
+
- All 3 DID types tracked (User, Agent, Server)
|
|
199
|
+
- External agents can validate delegations
|
|
200
|
+
- OAuth provider from dashboard is used for consent
|
|
201
|
+
- Documentation explains all scenarios clearly
|
|
202
|
+
|
|
203
|
+
This plan maintains Phase 4's core goal (persistent User identity) while ensuring it fits properly into the broader MCP-I architecture for multi-agent delegation scenarios.
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
# Execution Order Analysis for V3 and Phase 4 Plans
|
|
207
|
+
|
|
208
|
+
## Critical Dependencies Found
|
|
209
|
+
|
|
210
|
+
### 1. Scaffolder Refactor (V3) Must Be First
|
|
211
|
+
|
|
212
|
+
The V3 Scaffolder Cleanup is foundational, creating the `MCPICloudflareServer` class and organizing all services into packages. This setup is crucial for:
|
|
213
|
+
|
|
214
|
+
- Creating `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
215
|
+
- Supporting Phase 4's modifications to the consent service
|
|
216
|
+
- Ensuring Phase 4 changes are correctly placed
|
|
217
|
+
|
|
218
|
+
### 2. Phase 4 Part A with Consent Implementation
|
|
219
|
+
|
|
220
|
+
- V3's Consent Screen Implementation introduces the consent service.
|
|
221
|
+
- Phase 4 Part A addresses critical bugs in delegation creation, particularly the missing `issuerDid`.
|
|
222
|
+
- These tasks should be combined to prevent integration issues.
|
|
223
|
+
|
|
224
|
+
### 3. Overlap in Identity Work
|
|
225
|
+
|
|
226
|
+
- V3 Phase 1: "Identity & DID Management"
|
|
227
|
+
- Phase 4: "User DID & Identity Linking"
|
|
228
|
+
- Both phases cover similar work; Phase 4 details the implementation for V3 Phase 1.
|
|
229
|
+
|
|
230
|
+
## Recommended Execution Order
|
|
231
|
+
|
|
232
|
+
### Week 1: Foundation (Must be Sequential)
|
|
233
|
+
|
|
234
|
+
1. **V3 Scaffolder Cleanup (2-3 days)** - **FIRST PRIORITY**
|
|
235
|
+
- Create `MCPICloudflareServer` class and organize services into packages.
|
|
236
|
+
2. **V3 Consent + Phase 4 Part A (3-4 days) - COMBINED**
|
|
237
|
+
- Implement consent service with proper `issuerDid`.
|
|
238
|
+
- Introduce `getUserDidForSession` method from the start.
|
|
239
|
+
|
|
240
|
+
### Week 2: Core Identity (Can Parallelize Some)
|
|
241
|
+
|
|
242
|
+
**Parallel Track 1:**
|
|
243
|
+
|
|
244
|
+
- **Phase 4 Parts B & C (3 days)**
|
|
245
|
+
- Focus on OAuth integration and fix multi-tenant storage.
|
|
246
|
+
|
|
247
|
+
**Parallel Track 2:**
|
|
248
|
+
|
|
249
|
+
- **V3 Phase 2: Security Fixes (2-3 days)**
|
|
250
|
+
- Work on `CryptoService` in core package independently.
|
|
251
|
+
|
|
252
|
+
### Week 3: Integration & Enhancement
|
|
253
|
+
|
|
254
|
+
3. **Phase 4 Part D & E (3 days)**
|
|
255
|
+
- Configure identity modes and ensure security and privacy enhancements.
|
|
256
|
+
|
|
257
|
+
4. **V3 Phase 3: Integration & Storage (2-3 days)**
|
|
258
|
+
- Integrate with AgentShield and manage storage providers.
|
|
259
|
+
|
|
260
|
+
5. **Phase 4 Part F (1 day - Optional)**
|
|
261
|
+
- Map MCP Client.
|
|
262
|
+
|
|
263
|
+
## What Can Be Done in Parallel?
|
|
264
|
+
|
|
265
|
+
**Highly Parallelizable:**
|
|
266
|
+
|
|
267
|
+
- **V3 Security Fixes (CryptoService)** are independent.
|
|
268
|
+
- Documentation updates and test writing can proceed at any time.
|
|
269
|
+
|
|
270
|
+
**Somewhat Parallelizable (with coordination):**
|
|
271
|
+
|
|
272
|
+
- Phase 4 Part B's OAuth Handler, once consent service is established.
|
|
273
|
+
- Storage providers (V3 Phase 3) can be independent of identity work.
|
|
274
|
+
- Phase 4 Part E's Privacy Service can be built standalone.
|
|
275
|
+
|
|
276
|
+
**Must Be Sequential:**
|
|
277
|
+
|
|
278
|
+
- **Scaffolder Refactor → Everything else**
|
|
279
|
+
- **Consent Service creation → OAuth integration**
|
|
280
|
+
- **User DID implementation → OAuth linking**
|
|
281
|
+
|
|
282
|
+
## Unified Timeline
|
|
283
|
+
|
|
284
|
+
```gantt
|
|
285
|
+
title Implementation Timeline
|
|
286
|
+
dateFormat YYYY-MM-DD
|
|
287
|
+
section Foundation
|
|
288
|
+
Scaffolder Refactor :crit, done, s1, 2024-11-09, 3d
|
|
289
|
+
Consent + Fix Delegation :crit, active, s2, after s1, 4d
|
|
290
|
+
|
|
291
|
+
section Identity
|
|
292
|
+
OAuth Integration :b1, after s2, 2d
|
|
293
|
+
Fix Storage Conflicts :b2, after b1, 1d
|
|
294
|
+
Security Fixes (Parallel) :b3, after s2, 3d
|
|
295
|
+
|
|
296
|
+
section Enhancement
|
|
297
|
+
Identity Modes :c1, after b2, 1d
|
|
298
|
+
Privacy Controls :c2, after c1, 2d
|
|
299
|
+
Integration & Storage :c3, after b3, 3d
|
|
300
|
+
MCP Client Mapping :c4, after c2, 1d
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
```markdown
|
|
304
|
+
## Key Insight: Phase 4 IS Phase 1
|
|
305
|
+
|
|
306
|
+
Phase 4 essentially represents the detailed implementation of V3's Phase 1 ("Identity & DID Management").
|
|
307
|
+
|
|
308
|
+
- **V3 Phase 1 states:** "Identity & DID Management (2-3 days)"
|
|
309
|
+
- **Phase 4 provides:** A 12-day detailed implementation
|
|
310
|
+
|
|
311
|
+
## Recommendation
|
|
312
|
+
|
|
313
|
+
1. Begin with the V3 Scaffolder Refactor as current proof submission work.
|
|
314
|
+
2. Implement Consent with Phase 4 Part A fixes, ensuring code integrity.
|
|
315
|
+
3. Skip V3 Phase 1; use Phase 4 for implementation.
|
|
316
|
+
4. Parallelize security tasks during identity implementation.
|
|
317
|
+
5. Complete integration work as scheduled.
|
|
318
|
+
|
|
319
|
+
**Total timeline:** Approximately 3 weeks with opportunities for parallel work.
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
# Phase 4: User DID & Identity Linking Implementation Plan
|
|
323
|
+
|
|
324
|
+
**Document Version:** 1.0
|
|
325
|
+
**Created:** November 2024
|
|
326
|
+
**Status:** Planning
|
|
327
|
+
**Priority:** CRITICAL - Addresses fundamental identity architecture gaps
|
|
328
|
+
|
|
329
|
+
## Executive Summary
|
|
330
|
+
|
|
331
|
+
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.
|
|
332
|
+
|
|
333
|
+
## Critical Issues Identified During Review
|
|
334
|
+
|
|
335
|
+
### 1. API Schema Mismatch (CRITICAL)
|
|
336
|
+
|
|
337
|
+
- **Current State**: Consent service sends simplified request (agent_did, scopes, expires_in_days)
|
|
338
|
+
- **Expected**: AgentShield API expects full DelegationRecord with issuerDid and subjectDid
|
|
339
|
+
- **Impact**: Current implementation likely fails or creates invalid delegations
|
|
340
|
+
- **Evidence**: `consent.service.ts:358-366` vs `schemas.ts:153-155`
|
|
341
|
+
|
|
342
|
+
### 2. OAuth Identity Not Captured
|
|
343
|
+
|
|
344
|
+
- **Current State**: Consent flow doesn't extract OAuth identity from approval requests
|
|
345
|
+
- **Problem**: OAuth handler exists (`oauth-handler.ts`) but isn't integrated with consent flow
|
|
346
|
+
- **Impact**: Can't link OAuth identity to User DIDs for persistence
|
|
347
|
+
|
|
348
|
+
### 3. User DID Not Used as IssuerDid
|
|
349
|
+
|
|
350
|
+
- **Current State**: UserDidManager generates DIDs but they're not passed to delegation creation
|
|
351
|
+
- **Evidence**: TODO at `consent.service.ts:486-501` confirms this is known issue
|
|
352
|
+
- **Impact**: All delegations missing proper issuerDid (User DID)
|
|
353
|
+
|
|
354
|
+
### 4. MCP Client Info Not Available
|
|
355
|
+
|
|
356
|
+
- **Current State**: Handshake schema doesn't include clientInfo.name
|
|
357
|
+
- **Evidence**: `handshake.ts:7-12` only has optional agentDid
|
|
358
|
+
- **Impact**: Can't map MCP clients to reputation DIDs as planned
|
|
359
|
+
|
|
360
|
+
### 5. No Migration Strategy
|
|
361
|
+
|
|
362
|
+
- **Problem**: Existing delegations use ephemeral DIDs that become invalid
|
|
363
|
+
- **Impact**: Breaking change without backward compatibility
|
|
364
|
+
|
|
365
|
+
### 6. Multi-Tenant Conflicts
|
|
366
|
+
|
|
367
|
+
- **Current State**: Multiple users delegating to same agent overwrite each other
|
|
368
|
+
- **Evidence**: Known issue documented at `consent.service.ts:486-506`
|
|
369
|
+
|
|
370
|
+
## Revised Implementation Plan
|
|
371
|
+
|
|
372
|
+
### Part A: Fix Core Delegation Flow (Priority 1 - 2 days)
|
|
373
|
+
|
|
374
|
+
#### A.1: Update Delegation Creation to Include User DID
|
|
375
|
+
|
|
376
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
377
|
+
|
|
378
|
+
**Current Code** (lines 358-366):
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
const delegationRequest = {
|
|
382
|
+
agent_did: request.agent_did,
|
|
383
|
+
scopes: request.scopes,
|
|
384
|
+
expires_in_days: expiresInDays,
|
|
385
|
+
...(request.customFields && Object.keys(request.customFields).length > 0
|
|
386
|
+
? { metadata: request.customFields }
|
|
387
|
+
: {}),
|
|
388
|
+
};
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Updated Code**:
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
// Extract or generate User DID
|
|
395
|
+
const userDid = await this.getUserDidForSession(request.session_id);
|
|
396
|
+
|
|
397
|
+
const delegationRequest = {
|
|
398
|
+
// Core delegation fields
|
|
399
|
+
issuer_did: userDid, // NEW: User DID (who grants permission)
|
|
400
|
+
subject_did: request.agent_did, // RENAMED: Agent DID (who receives permission)
|
|
401
|
+
scopes: request.scopes,
|
|
402
|
+
expires_in_days: expiresInDays,
|
|
403
|
+
|
|
404
|
+
// Optional OAuth linking (for future persistence)
|
|
405
|
+
oauth_identity: request.oauth_identity ? {
|
|
406
|
+
provider: request.oauth_identity.provider,
|
|
407
|
+
subject: request.oauth_identity.subject,
|
|
408
|
+
email: request.oauth_identity.email
|
|
409
|
+
} : undefined
|
|
410
|
+
|
|
411
|
+
// Custom metadata
|
|
412
|
+
...(request.customFields && Object.keys(request.customFields).length > 0
|
|
413
|
+
? { metadata: request.customFields }
|
|
414
|
+
: {}),
|
|
415
|
+
};
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
**Expected Outcome**:
|
|
419
|
+
|
|
420
|
+
- Delegations include proper issuerDid (User DID)
|
|
421
|
+
- OAuth identity captured for future linking
|
|
422
|
+
- API properly structured from the start
|
|
423
|
+
|
|
424
|
+
**Test Coverage**:
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
describe("Delegation Creation", () => {
|
|
428
|
+
it("should include issuerDid when creating delegation", async () => {
|
|
429
|
+
const result = await consentService.createDelegation(request);
|
|
430
|
+
expect(result.delegation.issuerDid).toBeDefined();
|
|
431
|
+
expect(result.delegation.issuerDid).toMatch(/^did:key:z6Mk/);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it("should capture OAuth identity when provided", async () => {
|
|
435
|
+
const request = {
|
|
436
|
+
...baseRequest,
|
|
437
|
+
oauth_identity: { provider: "google", subject: "123" },
|
|
438
|
+
};
|
|
439
|
+
const result = await consentService.createDelegation(request);
|
|
440
|
+
expect(result.delegation.oauth_identity).toBeDefined();
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
#### A.2: Add getUserDidForSession Method
|
|
446
|
+
|
|
447
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
448
|
+
|
|
449
|
+
**New Method**:
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
private async getUserDidForSession(sessionId: string): Promise<string> {
|
|
453
|
+
// Try to get existing User DID from session
|
|
454
|
+
const session = await this.sessionStorage.get(sessionId);
|
|
455
|
+
if (session?.userDid) {
|
|
456
|
+
return session.userDid;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Generate new User DID using UserDidManager
|
|
460
|
+
const userDidManager = new UserDidManager({
|
|
461
|
+
crypto: this.cryptoProvider,
|
|
462
|
+
storage: this.userDidStorage // KV-based storage
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
const userDid = await userDidManager.getOrCreateUserDid(sessionId);
|
|
466
|
+
|
|
467
|
+
// Store in session for future use
|
|
468
|
+
await this.sessionStorage.set(sessionId, {
|
|
469
|
+
...session,
|
|
470
|
+
userDid
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
return userDid;
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**Expected Outcome**:
|
|
478
|
+
|
|
479
|
+
- Consistent User DID per session
|
|
480
|
+
- Automatic generation if not exists
|
|
481
|
+
- Session-scoped persistence
|
|
482
|
+
|
|
483
|
+
**Test Coverage**:
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
describe("getUserDidForSession", () => {
|
|
487
|
+
it("should return existing User DID from session", async () => {
|
|
488
|
+
const sessionId = "test-session";
|
|
489
|
+
const expectedDid = "did:key:z6MkExisting";
|
|
490
|
+
await sessionStorage.set(sessionId, { userDid: expectedDid });
|
|
491
|
+
|
|
492
|
+
const result = await consentService.getUserDidForSession(sessionId);
|
|
493
|
+
expect(result).toBe(expectedDid);
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
it("should generate new User DID if not in session", async () => {
|
|
497
|
+
const sessionId = "new-session";
|
|
498
|
+
const result = await consentService.getUserDidForSession(sessionId);
|
|
499
|
+
expect(result).toMatch(/^did:key:z6Mk/);
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### Part B: Integrate OAuth with Consent Flow (Priority 2 - 2 days)
|
|
505
|
+
|
|
506
|
+
#### B.1: Update ConsentApprovalRequest Schema
|
|
507
|
+
|
|
508
|
+
**Location**: `packages/contracts/src/consent/schemas.ts`
|
|
509
|
+
|
|
510
|
+
**Add OAuth Identity Fields**:
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
export const consentApprovalRequestSchema = z.object({
|
|
514
|
+
// Existing fields
|
|
515
|
+
agent_did: z.string(),
|
|
516
|
+
session_id: z.string(),
|
|
517
|
+
scopes: z.array(z.string()),
|
|
518
|
+
project_id: z.string(),
|
|
519
|
+
|
|
520
|
+
// NEW: OAuth identity fields
|
|
521
|
+
oauth_identity: z
|
|
522
|
+
.object({
|
|
523
|
+
provider: z.enum(["google", "github", "microsoft", "custom"]),
|
|
524
|
+
subject: z.string(), // OAuth user ID
|
|
525
|
+
email: z.string().email().optional(),
|
|
526
|
+
name: z.string().optional(),
|
|
527
|
+
})
|
|
528
|
+
.optional(),
|
|
529
|
+
|
|
530
|
+
// NEW: Persistent User DID
|
|
531
|
+
user_did: z.string().optional(),
|
|
532
|
+
|
|
533
|
+
// Existing optional fields
|
|
534
|
+
termsAccepted: z.boolean().optional(),
|
|
535
|
+
customFields: z.record(z.unknown()).optional(),
|
|
536
|
+
});
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**Expected Outcome**:
|
|
540
|
+
|
|
541
|
+
- Consent approval can include OAuth identity
|
|
542
|
+
- Clean API design from the start
|
|
543
|
+
- Supports persistent User DIDs
|
|
544
|
+
|
|
545
|
+
#### B.2: Extract OAuth Identity in Consent Page
|
|
546
|
+
|
|
547
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/consent-page-renderer.ts`
|
|
548
|
+
|
|
549
|
+
**Update Consent Page JavaScript**:
|
|
550
|
+
|
|
551
|
+
```javascript
|
|
552
|
+
// In consent page template
|
|
553
|
+
async function approveConsent() {
|
|
554
|
+
// Extract OAuth identity from session/cookie if available
|
|
555
|
+
const oauthIdentity = await getOAuthIdentityFromSession();
|
|
556
|
+
|
|
557
|
+
const approvalRequest = {
|
|
558
|
+
agent_did: '${config.agentDid}',
|
|
559
|
+
session_id: '${config.sessionId}',
|
|
560
|
+
scopes: ${JSON.stringify(config.scopes)},
|
|
561
|
+
project_id: '${config.projectId}',
|
|
562
|
+
|
|
563
|
+
// Include OAuth identity if available
|
|
564
|
+
...(oauthIdentity && { oauth_identity: oauthIdentity }),
|
|
565
|
+
|
|
566
|
+
// Include User DID if already persistent
|
|
567
|
+
...(window.userDid && { user_did: window.userDid }),
|
|
568
|
+
|
|
569
|
+
termsAccepted: document.getElementById('terms-checkbox')?.checked,
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
const response = await fetch('/consent/approve', {
|
|
573
|
+
method: 'POST',
|
|
574
|
+
headers: { 'Content-Type': 'application/json' },
|
|
575
|
+
body: JSON.stringify(approvalRequest)
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Expected Outcome**:
|
|
581
|
+
|
|
582
|
+
- OAuth identity passed to approval endpoint
|
|
583
|
+
- User DID included when available
|
|
584
|
+
- Progressive enhancement approach
|
|
585
|
+
|
|
586
|
+
#### B.3: Connect OAuth Handler to User DID Creation
|
|
587
|
+
|
|
588
|
+
**Location**: `packages/mcp-i-cloudflare/src/runtime/oauth-handler.ts`
|
|
589
|
+
|
|
590
|
+
**Add Identity Linking**:
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
export class OAuthHandler {
|
|
594
|
+
async handleCallback(request: Request): Promise<Response> {
|
|
595
|
+
// Existing OAuth token validation
|
|
596
|
+
const { provider, userInfo } = await this.validateOAuthCallback(request);
|
|
597
|
+
|
|
598
|
+
// NEW: Create or retrieve User DID for OAuth identity
|
|
599
|
+
const userDid = await this.linkOAuthToUserDid(provider, userInfo.sub);
|
|
600
|
+
|
|
601
|
+
// Store OAuth<->DID mapping
|
|
602
|
+
await this.identityStorage.set(
|
|
603
|
+
`oauth:${provider}:${userInfo.sub}`,
|
|
604
|
+
{
|
|
605
|
+
userDid,
|
|
606
|
+
email: userInfo.email,
|
|
607
|
+
name: userInfo.name,
|
|
608
|
+
linkedAt: new Date().toISOString(),
|
|
609
|
+
lastUsed: new Date().toISOString(),
|
|
610
|
+
},
|
|
611
|
+
{ expirationTtl: 30 * 24 * 60 * 60 } // 30 days
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
// Set session cookie with User DID
|
|
615
|
+
return new Response(null, {
|
|
616
|
+
status: 302,
|
|
617
|
+
headers: {
|
|
618
|
+
Location: "/consent",
|
|
619
|
+
"Set-Cookie": `user_did=${userDid}; HttpOnly; Secure; SameSite=Strict`,
|
|
620
|
+
},
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private async linkOAuthToUserDid(
|
|
625
|
+
provider: string,
|
|
626
|
+
subject: string
|
|
627
|
+
): Promise<string> {
|
|
628
|
+
const linkKey = `oauth:${provider}:${subject}`;
|
|
629
|
+
|
|
630
|
+
// Check for existing link
|
|
631
|
+
const existing = await this.identityStorage.get(linkKey);
|
|
632
|
+
if (existing?.userDid) {
|
|
633
|
+
// Update last used timestamp
|
|
634
|
+
await this.identityStorage.set(linkKey, {
|
|
635
|
+
...existing,
|
|
636
|
+
lastUsed: new Date().toISOString(),
|
|
637
|
+
});
|
|
638
|
+
return existing.userDid;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// Generate new persistent User DID
|
|
642
|
+
const userDidManager = new UserDidManager({
|
|
643
|
+
crypto: this.cryptoProvider,
|
|
644
|
+
storage: this.identityStorage,
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
const userDid = await userDidManager.generateUserDid();
|
|
648
|
+
return userDid;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
**Expected Outcome**:
|
|
654
|
+
|
|
655
|
+
- OAuth identities automatically linked to User DIDs
|
|
656
|
+
- Persistent mapping stored in KV
|
|
657
|
+
- Same User DID returned for same OAuth identity
|
|
658
|
+
|
|
659
|
+
**Test Coverage**:
|
|
660
|
+
|
|
661
|
+
```typescript
|
|
662
|
+
describe("OAuth to User DID Linking", () => {
|
|
663
|
+
it("should create new User DID for new OAuth identity", async () => {
|
|
664
|
+
const result = await oauthHandler.linkOAuthToUserDid("google", "user123");
|
|
665
|
+
expect(result).toMatch(/^did:key:z6Mk/);
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
it("should return existing User DID for known OAuth identity", async () => {
|
|
669
|
+
const firstDid = await oauthHandler.linkOAuthToUserDid("google", "user123");
|
|
670
|
+
const secondDid = await oauthHandler.linkOAuthToUserDid(
|
|
671
|
+
"google",
|
|
672
|
+
"user123"
|
|
673
|
+
);
|
|
674
|
+
expect(secondDid).toBe(firstDid);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
it("should update lastUsed timestamp on retrieval", async () => {
|
|
678
|
+
await oauthHandler.linkOAuthToUserDid("google", "user123");
|
|
679
|
+
const link = await identityStorage.get("oauth:google:user123");
|
|
680
|
+
const firstTime = link.lastUsed;
|
|
681
|
+
|
|
682
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
683
|
+
await oauthHandler.linkOAuthToUserDid("google", "user123");
|
|
684
|
+
const updatedLink = await identityStorage.get("oauth:google:user123");
|
|
685
|
+
expect(updatedLink.lastUsed).not.toBe(firstTime);
|
|
686
|
+
});
|
|
687
|
+
});
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### Part C: Fix Multi-Tenant Storage Conflicts (Priority 3 - 1 day)
|
|
691
|
+
|
|
692
|
+
#### C.1: Update Delegation Token Storage Keys
|
|
693
|
+
|
|
694
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/consent.service.ts`
|
|
695
|
+
|
|
696
|
+
**Current Problem** (lines 486-501):
|
|
697
|
+
|
|
698
|
+
- Tokens stored with agent-scoped keys only
|
|
699
|
+
- Multiple users → same agent = overwrite
|
|
700
|
+
|
|
701
|
+
**Fix Storage Keys**:
|
|
702
|
+
|
|
703
|
+
```typescript
|
|
704
|
+
private async storeDelegationToken(
|
|
705
|
+
token: string,
|
|
706
|
+
userDid: string,
|
|
707
|
+
agentDid: string,
|
|
708
|
+
sessionId: string
|
|
709
|
+
): Promise<void> {
|
|
710
|
+
// Primary key: User + Agent (prevents conflicts)
|
|
711
|
+
const userAgentKey = `delegation:user:${userDid}:agent:${agentDid}`;
|
|
712
|
+
await this.delegationStorage.set(userAgentKey, token, {
|
|
713
|
+
expirationTtl: 24 * 60 * 60 // 24 hours
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// Session key for fast lookup
|
|
717
|
+
const sessionKey = `delegation:session:${sessionId}`;
|
|
718
|
+
await this.delegationStorage.set(sessionKey, {
|
|
719
|
+
token,
|
|
720
|
+
userDid,
|
|
721
|
+
agentDid
|
|
722
|
+
}, {
|
|
723
|
+
expirationTtl: 60 * 60 // 1 hour
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
private async retrieveDelegationToken(
|
|
728
|
+
sessionId: string,
|
|
729
|
+
agentDid: string
|
|
730
|
+
): Promise<string | null> {
|
|
731
|
+
// Try session key first (fastest)
|
|
732
|
+
const sessionData = await this.delegationStorage.get(`delegation:session:${sessionId}`);
|
|
733
|
+
if (sessionData?.token) {
|
|
734
|
+
return sessionData.token;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// Try user+agent key
|
|
738
|
+
const userDid = await this.getUserDidForSession(sessionId);
|
|
739
|
+
if (userDid) {
|
|
740
|
+
const token = await this.delegationStorage.get(`delegation:user:${userDid}:agent:${agentDid}`);
|
|
741
|
+
if (token) {
|
|
742
|
+
return token;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**Expected Outcome**:
|
|
751
|
+
|
|
752
|
+
- No more multi-tenant conflicts
|
|
753
|
+
- Fast session-based lookup
|
|
754
|
+
- Clean storage architecture
|
|
755
|
+
|
|
756
|
+
**Test Coverage**:
|
|
757
|
+
|
|
758
|
+
```typescript
|
|
759
|
+
describe("Multi-tenant Delegation Storage", () => {
|
|
760
|
+
it("should store delegations per user+agent combination", async () => {
|
|
761
|
+
const user1Did = "did:key:z6MkUser1";
|
|
762
|
+
const user2Did = "did:key:z6MkUser2";
|
|
763
|
+
const agentDid = "did:key:z6MkAgent";
|
|
764
|
+
|
|
765
|
+
await consentService.storeDelegationToken(
|
|
766
|
+
"token1",
|
|
767
|
+
user1Did,
|
|
768
|
+
agentDid,
|
|
769
|
+
"session1"
|
|
770
|
+
);
|
|
771
|
+
await consentService.storeDelegationToken(
|
|
772
|
+
"token2",
|
|
773
|
+
user2Did,
|
|
774
|
+
agentDid,
|
|
775
|
+
"session2"
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
const token1 = await delegationStorage.get(
|
|
779
|
+
`delegation:user:${user1Did}:agent:${agentDid}`
|
|
780
|
+
);
|
|
781
|
+
const token2 = await delegationStorage.get(
|
|
782
|
+
`delegation:user:${user2Did}:agent:${agentDid}`
|
|
783
|
+
);
|
|
784
|
+
|
|
785
|
+
expect(token1).toBe("token1");
|
|
786
|
+
expect(token2).toBe("token2");
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
### Part D: Identity Mode Configuration (Priority 4 - 1 day)
|
|
792
|
+
|
|
793
|
+
#### D.1: Support Different Identity Modes
|
|
794
|
+
|
|
795
|
+
**Location**: `packages/mcp-i-core/src/identity/user-did-manager.ts`
|
|
796
|
+
|
|
797
|
+
**Add Configuration for Identity Modes**:
|
|
798
|
+
|
|
799
|
+
```typescript
|
|
800
|
+
export interface UserDidManagerConfig {
|
|
801
|
+
// Existing fields...
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Identity mode
|
|
805
|
+
* - 'ephemeral': Generate new DID per session (for development/testing)
|
|
806
|
+
* - 'persistent': Link to OAuth, reuse across sessions (for production)
|
|
807
|
+
* - 'hybrid': Ephemeral by default, persistent after OAuth login (flexible)
|
|
808
|
+
*/
|
|
809
|
+
mode: "ephemeral" | "persistent" | "hybrid";
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
export class UserDidManager {
|
|
813
|
+
async getOrCreateUserDid(
|
|
814
|
+
sessionId: string,
|
|
815
|
+
oauthIdentity?: OAuthIdentity
|
|
816
|
+
): Promise<string> {
|
|
817
|
+
// Mode-based behavior
|
|
818
|
+
switch (this.config.mode) {
|
|
819
|
+
case "ephemeral":
|
|
820
|
+
// Testing mode - always generate new
|
|
821
|
+
return this.generateEphemeralDid(sessionId);
|
|
822
|
+
|
|
823
|
+
case "persistent":
|
|
824
|
+
// Production mode - require OAuth identity
|
|
825
|
+
if (!oauthIdentity) {
|
|
826
|
+
throw new Error("OAuth identity required in persistent mode");
|
|
827
|
+
}
|
|
828
|
+
return this.getOrCreatePersistentDid(oauthIdentity);
|
|
829
|
+
|
|
830
|
+
case "hybrid":
|
|
831
|
+
// Flexible mode - use OAuth if available
|
|
832
|
+
if (oauthIdentity) {
|
|
833
|
+
return this.getOrCreatePersistentDid(oauthIdentity);
|
|
834
|
+
} else {
|
|
835
|
+
return this.generateEphemeralDid(sessionId);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
**Expected Outcome**:
|
|
843
|
+
|
|
844
|
+
- Support for different deployment scenarios
|
|
845
|
+
- Clear separation between dev/test/production modes
|
|
846
|
+
- Flexible configuration based on needs
|
|
847
|
+
|
|
848
|
+
### Part E: Security & Privacy Enhancements (Priority 5 - 2 days)
|
|
849
|
+
|
|
850
|
+
#### E.1: OAuth Account Verification
|
|
851
|
+
|
|
852
|
+
**Location**: `packages/mcp-i-cloudflare/src/runtime/oauth-handler.ts`
|
|
853
|
+
|
|
854
|
+
**Add Verification Step**:
|
|
855
|
+
|
|
856
|
+
```typescript
|
|
857
|
+
private async verifyOAuthAccountOwnership(
|
|
858
|
+
provider: string,
|
|
859
|
+
subject: string,
|
|
860
|
+
email?: string
|
|
861
|
+
): Promise<boolean> {
|
|
862
|
+
// For account linking, require email verification
|
|
863
|
+
if (email && this.config.requireEmailVerification) {
|
|
864
|
+
const verificationToken = await this.generateVerificationToken();
|
|
865
|
+
await this.sendVerificationEmail(email, verificationToken);
|
|
866
|
+
|
|
867
|
+
// Store pending verification
|
|
868
|
+
await this.pendingVerifications.set(
|
|
869
|
+
`verify:${provider}:${subject}`,
|
|
870
|
+
{ token: verificationToken, email },
|
|
871
|
+
{ expirationTtl: 15 * 60 } // 15 minutes
|
|
872
|
+
);
|
|
873
|
+
|
|
874
|
+
return false; // Requires verification completion
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// Check for suspicious patterns
|
|
878
|
+
const recentLinks = await this.getRecentLinks(subject);
|
|
879
|
+
if (recentLinks.length > this.config.maxLinksPerHour) {
|
|
880
|
+
console.warn('Suspicious linking activity detected:', subject);
|
|
881
|
+
return false;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return true;
|
|
885
|
+
}
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
**Expected Outcome**:
|
|
889
|
+
|
|
890
|
+
- Prevents unauthorized account linking
|
|
891
|
+
- Email verification for sensitive operations
|
|
892
|
+
- Rate limiting on identity linking
|
|
893
|
+
|
|
894
|
+
#### E.2: Privacy Controls
|
|
895
|
+
|
|
896
|
+
**Location**: `packages/mcp-i-cloudflare/src/services/privacy.service.ts`
|
|
897
|
+
|
|
898
|
+
**New Privacy Service**:
|
|
899
|
+
|
|
900
|
+
```typescript
|
|
901
|
+
export class PrivacyService {
|
|
902
|
+
async handlePrivacyRequest(
|
|
903
|
+
request: PrivacyRequest
|
|
904
|
+
): Promise<PrivacyResponse> {
|
|
905
|
+
switch (request.type) {
|
|
906
|
+
case "export":
|
|
907
|
+
// GDPR: Right to data portability
|
|
908
|
+
return this.exportUserData(request.userDid);
|
|
909
|
+
|
|
910
|
+
case "delete":
|
|
911
|
+
// GDPR: Right to be forgotten
|
|
912
|
+
return this.deleteUserData(request.userDid);
|
|
913
|
+
|
|
914
|
+
case "opt-out":
|
|
915
|
+
// Switch to ephemeral mode for user
|
|
916
|
+
return this.setUserMode(request.userDid, "ephemeral");
|
|
917
|
+
|
|
918
|
+
case "review":
|
|
919
|
+
// Show all linked identities and delegations
|
|
920
|
+
return this.getUserDataSummary(request.userDid);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
private async deleteUserData(userDid: string): Promise<PrivacyResponse> {
|
|
925
|
+
// Delete OAuth links
|
|
926
|
+
const links = await this.identityStorage.list({ prefix: `oauth:*:*` });
|
|
927
|
+
for (const link of links) {
|
|
928
|
+
if (link.value.userDid === userDid) {
|
|
929
|
+
await this.identityStorage.delete(link.key);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Delete delegations
|
|
934
|
+
await this.delegationStorage.delete(`delegation:user:${userDid}:*`);
|
|
935
|
+
|
|
936
|
+
// Delete User DID
|
|
937
|
+
await this.userDidStorage.delete(userDid);
|
|
938
|
+
|
|
939
|
+
return { success: true, message: "All user data deleted" };
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
**Expected Outcome**:
|
|
945
|
+
|
|
946
|
+
- GDPR compliance
|
|
947
|
+
- User control over data
|
|
948
|
+
- Privacy-first design
|
|
949
|
+
|
|
950
|
+
**Test Coverage**:
|
|
951
|
+
|
|
952
|
+
```typescript
|
|
953
|
+
describe("Privacy Controls", () => {
|
|
954
|
+
it("should delete all user data on request", async () => {
|
|
955
|
+
const userDid = "did:key:z6MkUser";
|
|
956
|
+
await privacyService.deleteUserData(userDid);
|
|
957
|
+
|
|
958
|
+
const links = await identityStorage.list({ prefix: `oauth:` });
|
|
959
|
+
const userLinks = links.filter((l) => l.value.userDid === userDid);
|
|
960
|
+
expect(userLinks).toHaveLength(0);
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
it("should export user data in portable format", async () => {
|
|
964
|
+
const result = await privacyService.exportUserData(userDid);
|
|
965
|
+
expect(result.data).toHaveProperty("identities");
|
|
966
|
+
expect(result.data).toHaveProperty("delegations");
|
|
967
|
+
expect(result.format).toBe("json");
|
|
968
|
+
});
|
|
969
|
+
});
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
### Part F: MCP Client Mapping (Optional - 1 day)
|
|
973
|
+
|
|
974
|
+
Since MCP handshake doesn't include clientInfo.name, we'll make this optional:
|
|
975
|
+
|
|
976
|
+
#### F.1: Extend Handshake Schema (If Possible)
|
|
977
|
+
|
|
978
|
+
**Location**: `packages/contracts/src/handshake.ts`
|
|
979
|
+
|
|
980
|
+
```typescript
|
|
981
|
+
export const HandshakeRequestSchema = z.object({
|
|
982
|
+
agentDid: z.string().optional(),
|
|
983
|
+
|
|
984
|
+
// NEW: Optional client information
|
|
985
|
+
clientInfo: z
|
|
986
|
+
.object({
|
|
987
|
+
name: z.string(), // "Claude Desktop", "OpenAI GPT", etc.
|
|
988
|
+
version: z.string(), // "1.0.0"
|
|
989
|
+
platform: z.string(), // "desktop", "web", "mobile"
|
|
990
|
+
})
|
|
991
|
+
.optional(),
|
|
992
|
+
});
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
#### F.2: Registry-Based Mapping
|
|
996
|
+
|
|
997
|
+
**Location**: `packages/mcp-i-core/src/client/registry.ts`
|
|
998
|
+
|
|
999
|
+
```typescript
|
|
1000
|
+
export const MCP_CLIENT_REGISTRY = {
|
|
1001
|
+
// Well-known clients with reputation DIDs
|
|
1002
|
+
"Claude Desktop": {
|
|
1003
|
+
did: "did:web:knowthat.ai:clients:claude",
|
|
1004
|
+
reputation: "verified",
|
|
1005
|
+
firstSeen: "2024-01-01",
|
|
1006
|
+
},
|
|
1007
|
+
"OpenAI GPT": {
|
|
1008
|
+
did: "did:web:knowthat.ai:clients:openai",
|
|
1009
|
+
reputation: "verified",
|
|
1010
|
+
firstSeen: "2024-01-01",
|
|
1011
|
+
},
|
|
1012
|
+
// Add more as they're discovered
|
|
1013
|
+
};
|
|
1014
|
+
|
|
1015
|
+
export function getClientDid(clientName?: string): string | undefined {
|
|
1016
|
+
if (!clientName) return undefined;
|
|
1017
|
+
return MCP_CLIENT_REGISTRY[clientName]?.did;
|
|
1018
|
+
}
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
**Expected Outcome**:
|
|
1022
|
+
|
|
1023
|
+
- Optional enhancement
|
|
1024
|
+
- Graceful degradation if not available
|
|
1025
|
+
- Foundation for future reputation system
|
|
1026
|
+
|
|
1027
|
+
## Implementation Schedule
|
|
1028
|
+
|
|
1029
|
+
### Week 1: Core Fixes
|
|
1030
|
+
|
|
1031
|
+
- Day 1-2: Part A - Fix Core Delegation Flow
|
|
1032
|
+
- [ ] Update delegation creation to include issuerDid
|
|
1033
|
+
- [ ] Add getUserDidForSession method
|
|
1034
|
+
- [ ] Write and run tests
|
|
1035
|
+
- **Touchpoints**: update `packages/mcp-i-cloudflare/src/services/consent.service.ts`, centralize keys in `packages/mcp-i-cloudflare/src/constants/storage-keys.ts`, and expand `packages/contracts/src/consent/schemas.ts` validation for `oauth_identity` plus `user_did`.
|
|
1036
|
+
|
|
1037
|
+
- Day 3-4: Part B - OAuth Integration (partial)
|
|
1038
|
+
- [ ] Update schemas
|
|
1039
|
+
- [ ] Extract OAuth identity in consent page
|
|
1040
|
+
- [ ] Begin OAuth handler updates
|
|
1041
|
+
|
|
1042
|
+
### Week 2: Integration & Migration
|
|
1043
|
+
|
|
1044
|
+
- Day 5: Part B - Complete OAuth Integration
|
|
1045
|
+
- [ ] Finish OAuth to User DID linking
|
|
1046
|
+
- [ ] Test OAuth flow end-to-end
|
|
1047
|
+
|
|
1048
|
+
- Day 6: Part C - Fix Storage Conflicts
|
|
1049
|
+
- [ ] Update delegation storage keys
|
|
1050
|
+
- [ ] Test multi-tenant scenarios
|
|
1051
|
+
|
|
1052
|
+
- Day 7-8: Part D - Identity Mode Configuration
|
|
1053
|
+
- [ ] Implement mode selection (ephemeral/persistent/hybrid)
|
|
1054
|
+
- [ ] Add mode-specific logic
|
|
1055
|
+
- [ ] Test different deployment scenarios
|
|
1056
|
+
|
|
1057
|
+
### Week 3: Security & Polish
|
|
1058
|
+
|
|
1059
|
+
- Day 9-10: Part E - Security & Privacy
|
|
1060
|
+
- [ ] OAuth verification
|
|
1061
|
+
- [ ] Privacy controls
|
|
1062
|
+
- [ ] GDPR compliance testing
|
|
1063
|
+
|
|
1064
|
+
- Day 11: Part F - Optional MCP Client Mapping
|
|
1065
|
+
- [ ] Extend handshake if possible
|
|
1066
|
+
- [ ] Set up client registry
|
|
1067
|
+
|
|
1068
|
+
- Day 12: Integration Testing & Documentation
|
|
1069
|
+
- [ ] Full end-to-end testing
|
|
1070
|
+
- [ ] Update documentation
|
|
1071
|
+
- [ ] Performance testing
|
|
1072
|
+
|
|
1073
|
+
## Success Metrics
|
|
1074
|
+
|
|
1075
|
+
### Functional Requirements
|
|
1076
|
+
|
|
1077
|
+
- [ ] User DIDs persist across sessions when using OAuth
|
|
1078
|
+
- [ ] Delegations include correct issuerDid (User) and subjectDid (Agent)
|
|
1079
|
+
- [ ] OAuth identity correctly linked to User DIDs
|
|
1080
|
+
- [ ] Multi-tenant conflicts resolved
|
|
1081
|
+
- [ ] Clean architecture from the start
|
|
1082
|
+
|
|
1083
|
+
### Non-Functional Requirements
|
|
1084
|
+
|
|
1085
|
+
- [ ] <100ms overhead for DID operations
|
|
1086
|
+
- [ ] GDPR compliance for data operations
|
|
1087
|
+
- [ ] 95% test coverage for new code
|
|
1088
|
+
- [ ] Clear separation between dev/test/prod modes
|
|
1089
|
+
|
|
1090
|
+
### Security Requirements
|
|
1091
|
+
|
|
1092
|
+
- [ ] OAuth account verification prevents unauthorized linking
|
|
1093
|
+
- [ ] Rate limiting on identity operations
|
|
1094
|
+
- [ ] Audit trail for all identity changes
|
|
1095
|
+
- [ ] Secure token storage with encryption
|
|
1096
|
+
|
|
1097
|
+
## Risk Mitigation
|
|
1098
|
+
|
|
1099
|
+
### Risk 1: Performance Impact
|
|
1100
|
+
|
|
1101
|
+
- **Mitigation**: Caching, async operations
|
|
1102
|
+
- **Monitoring**: Track DID operation latency
|
|
1103
|
+
|
|
1104
|
+
### Risk 2: Privacy Concerns
|
|
1105
|
+
|
|
1106
|
+
- **Mitigation**: Clear mode selection (ephemeral/persistent/hybrid), data deletion API
|
|
1107
|
+
- **Compliance**: GDPR audit before release
|
|
1108
|
+
|
|
1109
|
+
### Risk 3: OAuth Provider Issues
|
|
1110
|
+
|
|
1111
|
+
- **Mitigation**: Support multiple providers, graceful fallback to ephemeral
|
|
1112
|
+
- **Monitoring**: Track OAuth success rates
|
|
1113
|
+
|
|
1114
|
+
## Testing Strategy
|
|
1115
|
+
|
|
1116
|
+
### Unit Tests
|
|
1117
|
+
|
|
1118
|
+
- UserDidManager with all three modes
|
|
1119
|
+
- OAuth to DID linking logic
|
|
1120
|
+
- Multi-tenant storage operations
|
|
1121
|
+
- Privacy service operations
|
|
1122
|
+
|
|
1123
|
+
### Integration Tests
|
|
1124
|
+
|
|
1125
|
+
- Full OAuth login → consent → delegation flow
|
|
1126
|
+
- Session continuity across multiple requests
|
|
1127
|
+
- Mode switching (ephemeral → persistent → hybrid)
|
|
1128
|
+
- Multi-user, multi-agent scenarios
|
|
1129
|
+
|
|
1130
|
+
### E2E Tests
|
|
1131
|
+
|
|
1132
|
+
- User logs in with Google → approves delegation → uses tool
|
|
1133
|
+
- User returns next day → same DID → previous delegations work
|
|
1134
|
+
- User deletes account → all data removed
|
|
1135
|
+
|
|
1136
|
+
### Performance Tests
|
|
1137
|
+
|
|
1138
|
+
- 1000 concurrent DID operations
|
|
1139
|
+
- OAuth linking under load
|
|
1140
|
+
- Storage operations with 10k+ entries
|
|
1141
|
+
|
|
1142
|
+
## Documentation Updates
|
|
1143
|
+
|
|
1144
|
+
### API Documentation
|
|
1145
|
+
|
|
1146
|
+
- New fields in ConsentApprovalRequest
|
|
1147
|
+
- OAuth identity linking endpoints
|
|
1148
|
+
- Privacy control endpoints
|
|
1149
|
+
|
|
1150
|
+
### Configuration Guide
|
|
1151
|
+
|
|
1152
|
+
- How to choose between identity modes
|
|
1153
|
+
- Setting up OAuth providers
|
|
1154
|
+
- Configuring for different environments
|
|
1155
|
+
|
|
1156
|
+
### User Guide
|
|
1157
|
+
|
|
1158
|
+
- Benefits of persistent identity
|
|
1159
|
+
- Privacy controls and data deletion
|
|
1160
|
+
- OAuth account linking process
|
|
1161
|
+
|
|
1162
|
+
## Conclusion
|
|
1163
|
+
|
|
1164
|
+
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.
|
|
1165
|
+
|
|
1166
|
+
The key improvements include:
|
|
1167
|
+
|
|
1168
|
+
1. Proper User DID integration as issuerDid
|
|
1169
|
+
2. OAuth identity linking for persistence
|
|
1170
|
+
3. Multi-tenant conflict resolution
|
|
1171
|
+
4. Comprehensive security and privacy controls
|
|
1172
|
+
5. Clear mode selection for different deployment scenarios
|
|
1173
|
+
|
|
1174
|
+
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.
|
|
1175
|
+
|
|
1176
|
+
## Comparison to Initial Analysis
|
|
1177
|
+
|
|
1178
|
+
### What Changed from Original Plan
|
|
1179
|
+
|
|
1180
|
+
The initial analysis suggested a simpler OAuth bridging approach. After review feedback, the plan now addresses:
|
|
1181
|
+
|
|
1182
|
+
1. **API Schema Alignment**: Fixed to send full DelegationRecord with issuerDid and subjectDid
|
|
1183
|
+
2. **OAuth Integration**: Properly integrated with consent flow (not separate)
|
|
1184
|
+
3. **User DID Usage**: Actually used as issuerDid (was missing before)
|
|
1185
|
+
4. **No Legacy Support**: Since we haven't launched, no need for backward compatibility
|
|
1186
|
+
|
|
1187
|
+
### What Remains from Original Plan
|
|
1188
|
+
|
|
1189
|
+
1. **Core Concept**: OAuth identity → User DID linking for persistence
|
|
1190
|
+
2. **Three-Layer DIDs**: Server/Bouncer, Agent, and User DIDs
|
|
1191
|
+
3. **MCP Client Mapping**: Optional enhancement for reputation tracking
|
|
1192
|
+
4. **Session Continuity**: Tracking users across chat sessions
|
|
1193
|
+
|
|
1194
|
+
## MCP-I Specification Alignment
|
|
1195
|
+
|
|
1196
|
+
### Full Compliance with MCP-I Spec
|
|
1197
|
+
|
|
1198
|
+
This implementation aligns with the [MCP-I specification](https://modelcontextprotocol-identity.io) and [schemas](https://schema.modelcontextprotocol-identity.io/):
|
|
1199
|
+
|
|
1200
|
+
1. **DID Architecture** ✅
|
|
1201
|
+
- Server DID: `did:web:` or `did:key:` format per spec
|
|
1202
|
+
- Agent DID: Properly used as subjectDid in delegations
|
|
1203
|
+
- User DID: Properly used as issuerDid in delegations
|
|
1204
|
+
|
|
1205
|
+
2. **Delegation Model** ✅
|
|
1206
|
+
- Format: User (issuerDid) → Agent (subjectDid)
|
|
1207
|
+
- Includes scopes, constraints, and expiration
|
|
1208
|
+
- Follows W3C Verifiable Credential wrapper format
|
|
1209
|
+
|
|
1210
|
+
3. **Proof Format** ✅
|
|
1211
|
+
- JWS compact format (header.payload.signature)
|
|
1212
|
+
- All required meta fields present
|
|
1213
|
+
- SHA-256 hashing with proper prefixes
|
|
1214
|
+
|
|
1215
|
+
4. **Consent Flow** ✅
|
|
1216
|
+
- Required parameters: tool, scopes, agent_did, session_id, project_id
|
|
1217
|
+
- Proper approval handling
|
|
1218
|
+
- Delegation creation upon approval
|
|
1219
|
+
|
|
1220
|
+
5. **Security Requirements** ✅
|
|
1221
|
+
- Ed25519 signatures
|
|
1222
|
+
- Proper nonce handling
|
|
1223
|
+
- Session-based security
|
|
1224
|
+
|
|
1225
|
+
### Key Alignment Points
|
|
1226
|
+
|
|
1227
|
+
- **issuerDid**: Always the User DID (who grants permission)
|
|
1228
|
+
- **subjectDid**: Always the Agent DID (who receives permission)
|
|
1229
|
+
- **Delegation Storage**: Properly scoped to prevent multi-tenant conflicts
|
|
1230
|
+
- **OAuth Integration**: Enhances but doesn't replace DID-based identity
|
|
1231
|
+
|
|
1232
|
+
### Level 3 Enterprise Features
|
|
1233
|
+
|
|
1234
|
+
While this plan doesn't implement full Level 3 compliance (OAuth 2.1 bridging, anomaly detection), it provides:
|
|
1235
|
+
|
|
1236
|
+
- Foundation for OAuth identity management
|
|
1237
|
+
- Clear path to Level 3 if needed
|
|
1238
|
+
- Level 1-2 compliance out of the box
|
|
1239
|
+
|
|
1240
|
+
The implementation maintains full spec compliance while addressing real-world needs for persistent user identity across sessions.
|