@mcp-i/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +390 -0
  3. package/dist/auth/handshake.d.ts +104 -0
  4. package/dist/auth/handshake.d.ts.map +1 -0
  5. package/dist/auth/handshake.js +230 -0
  6. package/dist/auth/handshake.js.map +1 -0
  7. package/dist/auth/index.d.ts +3 -0
  8. package/dist/auth/index.d.ts.map +1 -0
  9. package/dist/auth/index.js +2 -0
  10. package/dist/auth/index.js.map +1 -0
  11. package/dist/auth/types.d.ts +31 -0
  12. package/dist/auth/types.d.ts.map +1 -0
  13. package/dist/auth/types.js +7 -0
  14. package/dist/auth/types.js.map +1 -0
  15. package/dist/delegation/audience-validator.d.ts +9 -0
  16. package/dist/delegation/audience-validator.d.ts.map +1 -0
  17. package/dist/delegation/audience-validator.js +17 -0
  18. package/dist/delegation/audience-validator.js.map +1 -0
  19. package/dist/delegation/bitstring.d.ts +37 -0
  20. package/dist/delegation/bitstring.d.ts.map +1 -0
  21. package/dist/delegation/bitstring.js +117 -0
  22. package/dist/delegation/bitstring.js.map +1 -0
  23. package/dist/delegation/cascading-revocation.d.ts +45 -0
  24. package/dist/delegation/cascading-revocation.d.ts.map +1 -0
  25. package/dist/delegation/cascading-revocation.js +148 -0
  26. package/dist/delegation/cascading-revocation.js.map +1 -0
  27. package/dist/delegation/delegation-graph.d.ts +49 -0
  28. package/dist/delegation/delegation-graph.d.ts.map +1 -0
  29. package/dist/delegation/delegation-graph.js +99 -0
  30. package/dist/delegation/delegation-graph.js.map +1 -0
  31. package/dist/delegation/did-key-resolver.d.ts +64 -0
  32. package/dist/delegation/did-key-resolver.d.ts.map +1 -0
  33. package/dist/delegation/did-key-resolver.js +154 -0
  34. package/dist/delegation/did-key-resolver.js.map +1 -0
  35. package/dist/delegation/did-web-resolver.d.ts +83 -0
  36. package/dist/delegation/did-web-resolver.d.ts.map +1 -0
  37. package/dist/delegation/did-web-resolver.js +218 -0
  38. package/dist/delegation/did-web-resolver.js.map +1 -0
  39. package/dist/delegation/index.d.ts +21 -0
  40. package/dist/delegation/index.d.ts.map +1 -0
  41. package/dist/delegation/index.js +21 -0
  42. package/dist/delegation/index.js.map +1 -0
  43. package/dist/delegation/outbound-headers.d.ts +81 -0
  44. package/dist/delegation/outbound-headers.d.ts.map +1 -0
  45. package/dist/delegation/outbound-headers.js +139 -0
  46. package/dist/delegation/outbound-headers.js.map +1 -0
  47. package/dist/delegation/outbound-proof.d.ts +43 -0
  48. package/dist/delegation/outbound-proof.d.ts.map +1 -0
  49. package/dist/delegation/outbound-proof.js +52 -0
  50. package/dist/delegation/outbound-proof.js.map +1 -0
  51. package/dist/delegation/statuslist-manager.d.ts +44 -0
  52. package/dist/delegation/statuslist-manager.d.ts.map +1 -0
  53. package/dist/delegation/statuslist-manager.js +126 -0
  54. package/dist/delegation/statuslist-manager.js.map +1 -0
  55. package/dist/delegation/storage/memory-graph-storage.d.ts +70 -0
  56. package/dist/delegation/storage/memory-graph-storage.d.ts.map +1 -0
  57. package/dist/delegation/storage/memory-graph-storage.js +145 -0
  58. package/dist/delegation/storage/memory-graph-storage.js.map +1 -0
  59. package/dist/delegation/storage/memory-statuslist-storage.d.ts +19 -0
  60. package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +1 -0
  61. package/dist/delegation/storage/memory-statuslist-storage.js +33 -0
  62. package/dist/delegation/storage/memory-statuslist-storage.js.map +1 -0
  63. package/dist/delegation/utils.d.ts +49 -0
  64. package/dist/delegation/utils.d.ts.map +1 -0
  65. package/dist/delegation/utils.js +131 -0
  66. package/dist/delegation/utils.js.map +1 -0
  67. package/dist/delegation/vc-issuer.d.ts +56 -0
  68. package/dist/delegation/vc-issuer.d.ts.map +1 -0
  69. package/dist/delegation/vc-issuer.js +80 -0
  70. package/dist/delegation/vc-issuer.js.map +1 -0
  71. package/dist/delegation/vc-verifier.d.ts +112 -0
  72. package/dist/delegation/vc-verifier.d.ts.map +1 -0
  73. package/dist/delegation/vc-verifier.js +280 -0
  74. package/dist/delegation/vc-verifier.js.map +1 -0
  75. package/dist/index.d.ts +45 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +53 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/logging/index.d.ts +2 -0
  80. package/dist/logging/index.d.ts.map +1 -0
  81. package/dist/logging/index.js +2 -0
  82. package/dist/logging/index.js.map +1 -0
  83. package/dist/logging/logger.d.ts +23 -0
  84. package/dist/logging/logger.d.ts.map +1 -0
  85. package/dist/logging/logger.js +82 -0
  86. package/dist/logging/logger.js.map +1 -0
  87. package/dist/middleware/index.d.ts +7 -0
  88. package/dist/middleware/index.d.ts.map +1 -0
  89. package/dist/middleware/index.js +7 -0
  90. package/dist/middleware/index.js.map +1 -0
  91. package/dist/middleware/with-mcpi.d.ts +152 -0
  92. package/dist/middleware/with-mcpi.d.ts.map +1 -0
  93. package/dist/middleware/with-mcpi.js +472 -0
  94. package/dist/middleware/with-mcpi.js.map +1 -0
  95. package/dist/proof/errors.d.ts +49 -0
  96. package/dist/proof/errors.d.ts.map +1 -0
  97. package/dist/proof/errors.js +61 -0
  98. package/dist/proof/errors.js.map +1 -0
  99. package/dist/proof/generator.d.ts +65 -0
  100. package/dist/proof/generator.d.ts.map +1 -0
  101. package/dist/proof/generator.js +163 -0
  102. package/dist/proof/generator.js.map +1 -0
  103. package/dist/proof/index.d.ts +4 -0
  104. package/dist/proof/index.d.ts.map +1 -0
  105. package/dist/proof/index.js +4 -0
  106. package/dist/proof/index.js.map +1 -0
  107. package/dist/proof/verifier.d.ts +108 -0
  108. package/dist/proof/verifier.d.ts.map +1 -0
  109. package/dist/proof/verifier.js +299 -0
  110. package/dist/proof/verifier.js.map +1 -0
  111. package/dist/providers/base.d.ts +64 -0
  112. package/dist/providers/base.d.ts.map +1 -0
  113. package/dist/providers/base.js +19 -0
  114. package/dist/providers/base.js.map +1 -0
  115. package/dist/providers/index.d.ts +3 -0
  116. package/dist/providers/index.d.ts.map +1 -0
  117. package/dist/providers/index.js +3 -0
  118. package/dist/providers/index.js.map +1 -0
  119. package/dist/providers/memory.d.ts +33 -0
  120. package/dist/providers/memory.d.ts.map +1 -0
  121. package/dist/providers/memory.js +102 -0
  122. package/dist/providers/memory.js.map +1 -0
  123. package/dist/session/index.d.ts +2 -0
  124. package/dist/session/index.d.ts.map +1 -0
  125. package/dist/session/index.js +2 -0
  126. package/dist/session/index.js.map +1 -0
  127. package/dist/session/manager.d.ts +77 -0
  128. package/dist/session/manager.d.ts.map +1 -0
  129. package/dist/session/manager.js +251 -0
  130. package/dist/session/manager.js.map +1 -0
  131. package/dist/types/protocol.d.ts +320 -0
  132. package/dist/types/protocol.d.ts.map +1 -0
  133. package/dist/types/protocol.js +229 -0
  134. package/dist/types/protocol.js.map +1 -0
  135. package/dist/utils/base58.d.ts +31 -0
  136. package/dist/utils/base58.d.ts.map +1 -0
  137. package/dist/utils/base58.js +104 -0
  138. package/dist/utils/base58.js.map +1 -0
  139. package/dist/utils/base64.d.ts +13 -0
  140. package/dist/utils/base64.d.ts.map +1 -0
  141. package/dist/utils/base64.js +99 -0
  142. package/dist/utils/base64.js.map +1 -0
  143. package/dist/utils/crypto-service.d.ts +37 -0
  144. package/dist/utils/crypto-service.d.ts.map +1 -0
  145. package/dist/utils/crypto-service.js +153 -0
  146. package/dist/utils/crypto-service.js.map +1 -0
  147. package/dist/utils/did-helpers.d.ts +156 -0
  148. package/dist/utils/did-helpers.d.ts.map +1 -0
  149. package/dist/utils/did-helpers.js +193 -0
  150. package/dist/utils/did-helpers.js.map +1 -0
  151. package/dist/utils/ed25519-constants.d.ts +18 -0
  152. package/dist/utils/ed25519-constants.d.ts.map +1 -0
  153. package/dist/utils/ed25519-constants.js +21 -0
  154. package/dist/utils/ed25519-constants.js.map +1 -0
  155. package/dist/utils/index.d.ts +5 -0
  156. package/dist/utils/index.d.ts.map +1 -0
  157. package/dist/utils/index.js +5 -0
  158. package/dist/utils/index.js.map +1 -0
  159. package/package.json +105 -0
  160. package/src/__tests__/integration/full-flow.test.ts +362 -0
  161. package/src/__tests__/providers/base.test.ts +173 -0
  162. package/src/__tests__/providers/memory.test.ts +332 -0
  163. package/src/__tests__/utils/mock-providers.ts +319 -0
  164. package/src/__tests__/utils/node-crypto-provider.ts +93 -0
  165. package/src/auth/handshake.ts +411 -0
  166. package/src/auth/index.ts +11 -0
  167. package/src/auth/types.ts +40 -0
  168. package/src/delegation/__tests__/audience-validator.test.ts +110 -0
  169. package/src/delegation/__tests__/bitstring.test.ts +346 -0
  170. package/src/delegation/__tests__/cascading-revocation.test.ts +624 -0
  171. package/src/delegation/__tests__/delegation-graph.test.ts +623 -0
  172. package/src/delegation/__tests__/did-key-resolver.test.ts +265 -0
  173. package/src/delegation/__tests__/did-web-resolver.test.ts +467 -0
  174. package/src/delegation/__tests__/outbound-headers.test.ts +230 -0
  175. package/src/delegation/__tests__/outbound-proof.test.ts +179 -0
  176. package/src/delegation/__tests__/statuslist-manager.test.ts +515 -0
  177. package/src/delegation/__tests__/utils.test.ts +185 -0
  178. package/src/delegation/__tests__/vc-issuer.test.ts +487 -0
  179. package/src/delegation/__tests__/vc-verifier.test.ts +1029 -0
  180. package/src/delegation/audience-validator.ts +24 -0
  181. package/src/delegation/bitstring.ts +160 -0
  182. package/src/delegation/cascading-revocation.ts +224 -0
  183. package/src/delegation/delegation-graph.ts +143 -0
  184. package/src/delegation/did-key-resolver.ts +181 -0
  185. package/src/delegation/did-web-resolver.ts +270 -0
  186. package/src/delegation/index.ts +33 -0
  187. package/src/delegation/outbound-headers.ts +193 -0
  188. package/src/delegation/outbound-proof.ts +90 -0
  189. package/src/delegation/statuslist-manager.ts +219 -0
  190. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
  191. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
  192. package/src/delegation/storage/memory-graph-storage.ts +178 -0
  193. package/src/delegation/storage/memory-statuslist-storage.ts +42 -0
  194. package/src/delegation/utils.ts +189 -0
  195. package/src/delegation/vc-issuer.ts +137 -0
  196. package/src/delegation/vc-verifier.ts +440 -0
  197. package/src/index.ts +264 -0
  198. package/src/logging/__tests__/logger.test.ts +366 -0
  199. package/src/logging/index.ts +6 -0
  200. package/src/logging/logger.ts +91 -0
  201. package/src/middleware/__tests__/with-mcpi.test.ts +504 -0
  202. package/src/middleware/index.ts +16 -0
  203. package/src/middleware/with-mcpi.ts +766 -0
  204. package/src/proof/__tests__/proof-generator.test.ts +483 -0
  205. package/src/proof/__tests__/verifier.test.ts +488 -0
  206. package/src/proof/errors.ts +75 -0
  207. package/src/proof/generator.ts +255 -0
  208. package/src/proof/index.ts +22 -0
  209. package/src/proof/verifier.ts +449 -0
  210. package/src/providers/base.ts +68 -0
  211. package/src/providers/index.ts +15 -0
  212. package/src/providers/memory.ts +130 -0
  213. package/src/session/__tests__/session-manager.test.ts +342 -0
  214. package/src/session/index.ts +7 -0
  215. package/src/session/manager.ts +332 -0
  216. package/src/types/protocol.ts +596 -0
  217. package/src/utils/__tests__/base58.test.ts +281 -0
  218. package/src/utils/__tests__/base64.test.ts +239 -0
  219. package/src/utils/__tests__/crypto-service.test.ts +530 -0
  220. package/src/utils/__tests__/did-helpers.test.ts +156 -0
  221. package/src/utils/base58.ts +115 -0
  222. package/src/utils/base64.ts +116 -0
  223. package/src/utils/crypto-service.ts +209 -0
  224. package/src/utils/did-helpers.ts +210 -0
  225. package/src/utils/ed25519-constants.ts +23 -0
  226. package/src/utils/index.ts +9 -0
@@ -0,0 +1,596 @@
1
+ /**
2
+ * MCP-I Protocol Types
3
+ *
4
+ * Inlined type definitions for the MCP-I protocol reference implementation.
5
+ * All types are pure TypeScript — no external dependencies.
6
+ *
7
+ * Related Spec: MCP-I §3, §4, §5, §6
8
+ */
9
+
10
+ // ============================================================================
11
+ // CRISP Delegation Constraints (MCP-I §4.2)
12
+ // ============================================================================
13
+
14
+ export interface CrispBudget {
15
+ unit: 'USD' | 'ops' | 'points';
16
+ cap: number;
17
+ window?: {
18
+ kind: 'rolling' | 'fixed';
19
+ durationSec: number;
20
+ };
21
+ }
22
+
23
+ export interface CrispScope {
24
+ resource: string;
25
+ matcher: 'exact' | 'prefix' | 'regex';
26
+ constraints?: Record<string, unknown>;
27
+ }
28
+
29
+ export interface DelegationConstraints {
30
+ notBefore?: number;
31
+ notAfter?: number;
32
+ scopes?: string[];
33
+ audience?: string | string[];
34
+ crisp?: {
35
+ budget?: CrispBudget;
36
+ scopes: CrispScope[];
37
+ [key: string]: unknown;
38
+ };
39
+ [key: string]: unknown;
40
+ }
41
+
42
+ // ============================================================================
43
+ // Delegation Record (MCP-I §4.1)
44
+ // ============================================================================
45
+
46
+ export type DelegationStatus = 'active' | 'revoked' | 'expired';
47
+
48
+ export interface DelegationRecord {
49
+ id: string;
50
+ issuerDid: string;
51
+ subjectDid: string;
52
+ controller?: string;
53
+ vcId: string;
54
+ parentId?: string;
55
+ constraints: DelegationConstraints;
56
+ signature: string;
57
+ status: DelegationStatus;
58
+ createdAt?: number;
59
+ revokedAt?: number;
60
+ revokedReason?: string;
61
+ metadata?: Record<string, unknown>;
62
+ [key: string]: unknown;
63
+ }
64
+
65
+ // ============================================================================
66
+ // W3C Verifiable Credential types
67
+ // ============================================================================
68
+
69
+ export interface Proof {
70
+ type: string;
71
+ created?: string;
72
+ verificationMethod?: string;
73
+ proofPurpose?: string;
74
+ proofValue?: string;
75
+ jws?: string;
76
+ [key: string]: unknown;
77
+ }
78
+
79
+ export interface CredentialStatus {
80
+ id: string;
81
+ type: 'StatusList2021Entry';
82
+ statusPurpose: 'revocation' | 'suspension';
83
+ statusListIndex: string;
84
+ statusListCredential: string;
85
+ [key: string]: unknown;
86
+ }
87
+
88
+ export interface DelegationCredentialSubject {
89
+ id: string;
90
+ delegation: {
91
+ id: string;
92
+ issuerDid: string;
93
+ subjectDid: string;
94
+ userDid?: string;
95
+ userIdentifier?: string;
96
+ sessionId?: string;
97
+ scopes?: string[];
98
+ controller?: string;
99
+ parentId?: string;
100
+ constraints: DelegationConstraints;
101
+ status: DelegationStatus;
102
+ createdAt?: number;
103
+ metadata?: Record<string, unknown>;
104
+ };
105
+ }
106
+
107
+ export interface DelegationCredential {
108
+ '@context': (string | Record<string, unknown>)[];
109
+ id?: string;
110
+ type: string[];
111
+ issuer: string | { id: string; [key: string]: unknown };
112
+ issuanceDate: string;
113
+ expirationDate?: string;
114
+ credentialSubject: DelegationCredentialSubject;
115
+ credentialStatus?: CredentialStatus;
116
+ proof?: Proof;
117
+ [key: string]: unknown;
118
+ }
119
+
120
+ export const DELEGATION_CREDENTIAL_CONTEXT =
121
+ 'https://schema.modelcontextprotocol-identity.io/xmcp-i/credentials/delegation.v1.0.0.json' as const;
122
+
123
+ // ============================================================================
124
+ // StatusList2021 (W3C)
125
+ // ============================================================================
126
+
127
+ export interface StatusList2021Credential {
128
+ '@context': (string | Record<string, unknown>)[];
129
+ id: string;
130
+ type: string[];
131
+ issuer: string | { id: string };
132
+ issuanceDate: string;
133
+ credentialSubject: {
134
+ id?: string;
135
+ type: 'StatusList2021';
136
+ statusPurpose: 'revocation' | 'suspension';
137
+ encodedList: string;
138
+ };
139
+ proof?: Record<string, unknown>;
140
+ [key: string]: unknown;
141
+ }
142
+
143
+ // ============================================================================
144
+ // Delegation VC utility functions
145
+ // ============================================================================
146
+
147
+ /**
148
+ * Wrap a DelegationRecord in an unsigned W3C VC structure.
149
+ */
150
+ export function wrapDelegationAsVC(
151
+ delegation: DelegationRecord,
152
+ options?: {
153
+ id?: string;
154
+ issuanceDate?: string;
155
+ expirationDate?: string;
156
+ credentialStatus?: CredentialStatus;
157
+ userDid?: string;
158
+ userIdentifier?: string;
159
+ sessionId?: string;
160
+ scopes?: string[];
161
+ }
162
+ ): Omit<DelegationCredential, 'proof'> {
163
+ const now = new Date().toISOString();
164
+ const expirationDate = delegation.constraints.notAfter
165
+ ? new Date(delegation.constraints.notAfter * 1000).toISOString()
166
+ : options?.expirationDate;
167
+
168
+ let issuanceDate = options?.issuanceDate || now;
169
+ if (!options?.issuanceDate && delegation.createdAt) {
170
+ issuanceDate = new Date(delegation.createdAt).toISOString();
171
+ }
172
+
173
+ const scopes = options?.scopes || delegation.constraints.scopes;
174
+
175
+ return {
176
+ '@context': [
177
+ 'https://www.w3.org/2018/credentials/v1',
178
+ DELEGATION_CREDENTIAL_CONTEXT,
179
+ ],
180
+ id: options?.id || delegation.vcId || `urn:uuid:${delegation.id}`,
181
+ type: ['VerifiableCredential', 'DelegationCredential'],
182
+ issuer: delegation.issuerDid,
183
+ issuanceDate,
184
+ ...(expirationDate !== undefined && { expirationDate }),
185
+ credentialSubject: {
186
+ id: delegation.subjectDid,
187
+ delegation: {
188
+ id: delegation.id,
189
+ issuerDid: delegation.issuerDid,
190
+ subjectDid: delegation.subjectDid,
191
+ ...(options?.userDid && { userDid: options.userDid }),
192
+ ...(options?.userIdentifier && { userIdentifier: options.userIdentifier }),
193
+ ...(options?.sessionId && { sessionId: options.sessionId }),
194
+ ...(scopes && scopes.length > 0 && { scopes }),
195
+ ...(delegation.controller !== undefined && { controller: delegation.controller }),
196
+ ...(delegation.parentId !== undefined && { parentId: delegation.parentId }),
197
+ constraints: delegation.constraints,
198
+ status: delegation.status,
199
+ ...(delegation.createdAt !== undefined && { createdAt: delegation.createdAt }),
200
+ ...(delegation.metadata !== undefined && { metadata: delegation.metadata }),
201
+ },
202
+ },
203
+ ...(options?.credentialStatus !== undefined && { credentialStatus: options.credentialStatus }),
204
+ };
205
+ }
206
+
207
+ /**
208
+ * Extract a DelegationRecord from a DelegationCredential.
209
+ */
210
+ export function extractDelegationFromVC(vc: DelegationCredential): DelegationRecord {
211
+ const delegation = vc.credentialSubject.delegation;
212
+
213
+ let signature = '';
214
+ if (vc.proof) {
215
+ const proof = vc.proof as Record<string, unknown>;
216
+ signature = (proof['proofValue'] || proof['jws'] || proof['signatureValue'] || '') as string;
217
+ }
218
+
219
+ return {
220
+ id: delegation.id,
221
+ issuerDid: delegation.issuerDid,
222
+ subjectDid: delegation.subjectDid,
223
+ controller: delegation.controller,
224
+ vcId: vc.id || `vc:${delegation.id}`,
225
+ parentId: delegation.parentId,
226
+ constraints: delegation.constraints,
227
+ signature,
228
+ status: delegation.status,
229
+ createdAt: delegation.createdAt,
230
+ revokedAt: undefined,
231
+ revokedReason: undefined,
232
+ metadata: delegation.metadata,
233
+ };
234
+ }
235
+
236
+ /**
237
+ * Check if a DelegationCredential is expired.
238
+ */
239
+ export function isDelegationCredentialExpired(vc: DelegationCredential): boolean {
240
+ if (vc.expirationDate) {
241
+ if (new Date(vc.expirationDate) < new Date()) {
242
+ return true;
243
+ }
244
+ }
245
+
246
+ const delegation = vc.credentialSubject.delegation;
247
+ if (delegation.constraints.notAfter) {
248
+ const nowSec = Math.floor(Date.now() / 1000);
249
+ if (nowSec > delegation.constraints.notAfter) {
250
+ return true;
251
+ }
252
+ }
253
+
254
+ return false;
255
+ }
256
+
257
+ /**
258
+ * Check if a DelegationCredential is not yet valid.
259
+ */
260
+ export function isDelegationCredentialNotYetValid(vc: DelegationCredential): boolean {
261
+ const delegation = vc.credentialSubject.delegation;
262
+
263
+ if (delegation.constraints.notBefore) {
264
+ const nowSec = Math.floor(Date.now() / 1000);
265
+ if (nowSec < delegation.constraints.notBefore) {
266
+ return true;
267
+ }
268
+ }
269
+
270
+ return false;
271
+ }
272
+
273
+ /**
274
+ * Validate a DelegationCredential.
275
+ * Returns a Zod-compatible result shape.
276
+ */
277
+ export function validateDelegationCredential(vc: unknown): {
278
+ success: boolean;
279
+ error?: { message: string };
280
+ data?: DelegationCredential;
281
+ } {
282
+ if (!vc || typeof vc !== 'object') {
283
+ return { success: false, error: { message: 'Not an object' } };
284
+ }
285
+
286
+ const v = vc as Record<string, unknown>;
287
+
288
+ // Check @context
289
+ if (!Array.isArray(v['@context']) || v['@context'].length === 0) {
290
+ return { success: false, error: { message: 'Missing or invalid @context' } };
291
+ }
292
+ if (v['@context'][0] !== 'https://www.w3.org/2018/credentials/v1') {
293
+ return { success: false, error: { message: 'First @context must be W3C VC context' } };
294
+ }
295
+
296
+ // Check type
297
+ if (!Array.isArray(v['type'])) {
298
+ return { success: false, error: { message: 'Missing type array' } };
299
+ }
300
+ if (!v['type'].includes('VerifiableCredential') || !v['type'].includes('DelegationCredential')) {
301
+ return { success: false, error: { message: 'type must include VerifiableCredential and DelegationCredential' } };
302
+ }
303
+
304
+ // Check issuer
305
+ if (!v['issuer'] || (typeof v['issuer'] !== 'string' && typeof v['issuer'] !== 'object')) {
306
+ return { success: false, error: { message: 'Missing or invalid issuer' } };
307
+ }
308
+
309
+ // Check issuanceDate
310
+ if (!v['issuanceDate'] || typeof v['issuanceDate'] !== 'string') {
311
+ return { success: false, error: { message: 'Missing issuanceDate' } };
312
+ }
313
+
314
+ // Check credentialSubject
315
+ const cs = v['credentialSubject'] as Record<string, unknown> | undefined;
316
+ if (!cs || typeof cs !== 'object') {
317
+ return { success: false, error: { message: 'Missing credentialSubject' } };
318
+ }
319
+
320
+ if (!cs['id'] || typeof cs['id'] !== 'string') {
321
+ return { success: false, error: { message: 'credentialSubject.id missing' } };
322
+ }
323
+
324
+ const del = cs['delegation'] as Record<string, unknown> | undefined;
325
+ if (!del || typeof del !== 'object') {
326
+ return { success: false, error: { message: 'credentialSubject.delegation missing' } };
327
+ }
328
+
329
+ if (!del['id'] || !del['issuerDid'] || !del['subjectDid'] || !del['constraints']) {
330
+ return { success: false, error: { message: 'delegation fields missing' } };
331
+ }
332
+
333
+ return { success: true, data: vc as DelegationCredential };
334
+ }
335
+
336
+ // ============================================================================
337
+ // Handshake and Session (MCP-I §4.5–4.9)
338
+ // ============================================================================
339
+
340
+ export interface MCPClientInfo {
341
+ name: string;
342
+ title?: string;
343
+ version?: string;
344
+ platform?: string;
345
+ vendor?: string;
346
+ persistentId?: string;
347
+ }
348
+
349
+ export interface MCPClientSessionInfo extends MCPClientInfo {
350
+ clientId: string;
351
+ protocolVersion?: string;
352
+ capabilities?: Record<string, unknown>;
353
+ }
354
+
355
+ export interface HandshakeRequest {
356
+ nonce: string;
357
+ audience: string;
358
+ timestamp: number;
359
+ agentDid?: string;
360
+ clientInfo?: MCPClientInfo & { clientId?: string };
361
+ clientProtocolVersion?: string;
362
+ clientCapabilities?: Record<string, unknown>;
363
+ }
364
+
365
+ export type SessionIdentityState = 'anonymous' | 'authenticated';
366
+
367
+ export interface SessionContext {
368
+ sessionId: string;
369
+ audience: string;
370
+ nonce: string;
371
+ timestamp: number;
372
+ createdAt: number;
373
+ lastActivity: number;
374
+ ttlMinutes: number;
375
+ agentDid?: string;
376
+ serverDid?: string;
377
+ clientDid?: string;
378
+ userDid?: string;
379
+ clientInfo?: MCPClientSessionInfo;
380
+ identityState: SessionIdentityState;
381
+ oauthIdentity?: {
382
+ provider: string;
383
+ subject: string;
384
+ email?: string;
385
+ name?: string;
386
+ };
387
+ delegationRef?: string;
388
+ delegationChain?: string;
389
+ delegationScopes?: string[];
390
+ [key: string]: unknown;
391
+ }
392
+
393
+ /**
394
+ * Nonce cache interface for replay prevention.
395
+ */
396
+ export interface NonceCache {
397
+ has(nonce: string, agentDid?: string): Promise<boolean>;
398
+ add(nonce: string, ttl: number, agentDid?: string): Promise<void>;
399
+ cleanup(): Promise<void>;
400
+ }
401
+
402
+ export const DEFAULT_SESSION_TTL_MINUTES = 30;
403
+ export const DEFAULT_TIMESTAMP_SKEW_SECONDS = 120;
404
+ export const NONCE_LENGTH_BYTES = 16;
405
+
406
+ // ============================================================================
407
+ // Proof types (MCP-I §5)
408
+ // ============================================================================
409
+
410
+ export interface ProofMeta {
411
+ did: string;
412
+ kid: string;
413
+ ts: number;
414
+ nonce: string;
415
+ audience: string;
416
+ sessionId: string;
417
+ requestHash: string;
418
+ responseHash: string;
419
+ scopeId?: string;
420
+ delegationRef?: string;
421
+ clientDid?: string;
422
+ }
423
+
424
+ export interface DetachedProof {
425
+ jws: string;
426
+ meta: ProofMeta;
427
+ }
428
+
429
+ export interface CanonicalHashes {
430
+ requestHash: string;
431
+ responseHash: string;
432
+ }
433
+
434
+ export interface AuditRecord {
435
+ version: 'audit.v1';
436
+ ts: number;
437
+ session: string;
438
+ audience: string;
439
+ did: string;
440
+ kid: string;
441
+ reqHash: string;
442
+ resHash: string;
443
+ verified: 'yes' | 'no';
444
+ scope: string;
445
+ }
446
+
447
+ // ============================================================================
448
+ // Audit types
449
+ // ============================================================================
450
+
451
+ export interface AuditContext {
452
+ identity: {
453
+ did: string;
454
+ kid: string;
455
+ [key: string]: unknown;
456
+ };
457
+ session: {
458
+ sessionId: string;
459
+ audience: string;
460
+ [key: string]: unknown;
461
+ };
462
+ requestHash: string;
463
+ responseHash: string;
464
+ verified: 'yes' | 'no';
465
+ scopeId?: string;
466
+ }
467
+
468
+ export interface AuditEventContext {
469
+ eventType: string;
470
+ identity: {
471
+ did: string;
472
+ kid: string;
473
+ [key: string]: unknown;
474
+ };
475
+ session: {
476
+ sessionId: string;
477
+ audience: string;
478
+ [key: string]: unknown;
479
+ };
480
+ eventData?: Record<string, unknown>;
481
+ }
482
+
483
+ // ============================================================================
484
+ // Authorization error types (MCP-I §6)
485
+ // ============================================================================
486
+
487
+ export interface AuthorizationDisplay {
488
+ title?: string;
489
+ hint?: Array<'link' | 'qr' | 'code'>;
490
+ authorizationCode?: string;
491
+ qrUrl?: string;
492
+ [key: string]: unknown;
493
+ }
494
+
495
+ export interface NeedsAuthorizationError {
496
+ error: 'needs_authorization';
497
+ message: string;
498
+ authorizationUrl: string;
499
+ resumeToken: string;
500
+ expiresAt: number;
501
+ scopes: string[];
502
+ display?: AuthorizationDisplay;
503
+ context?: Record<string, unknown>;
504
+ [key: string]: unknown;
505
+ }
506
+
507
+ export function createNeedsAuthorizationError(config: {
508
+ message: string;
509
+ authorizationUrl: string;
510
+ resumeToken: string;
511
+ expiresAt: number;
512
+ scopes: string[];
513
+ display?: AuthorizationDisplay;
514
+ }): NeedsAuthorizationError {
515
+ return {
516
+ error: 'needs_authorization',
517
+ ...config,
518
+ };
519
+ }
520
+
521
+ export function isNeedsAuthorizationError(error: unknown): error is NeedsAuthorizationError {
522
+ return (
523
+ typeof error === 'object' &&
524
+ error !== null &&
525
+ (error as Record<string, unknown>)['error'] === 'needs_authorization'
526
+ );
527
+ }
528
+
529
+ // ============================================================================
530
+ // DetachedProof validation
531
+ // ============================================================================
532
+
533
+ const HASH_REGEX = /^sha256:[a-f0-9]{64}$/;
534
+
535
+ /**
536
+ * Validate a DetachedProof structure.
537
+ * Returns a Zod-compatible result shape.
538
+ */
539
+ export function validateDetachedProof(proof: unknown): {
540
+ success: boolean;
541
+ error?: { message: string; errors?: Array<{ message: string }> };
542
+ data?: DetachedProof;
543
+ } {
544
+ if (!proof || typeof proof !== 'object') {
545
+ return { success: false, error: { message: 'Not an object' } };
546
+ }
547
+
548
+ const p = proof as Record<string, unknown>;
549
+
550
+ // Validate jws
551
+ if (typeof p['jws'] !== 'string' || p['jws'].length < 1) {
552
+ return { success: false, error: { message: 'jws must be a non-empty string' } };
553
+ }
554
+
555
+ // Validate meta
556
+ const meta = p['meta'];
557
+ if (!meta || typeof meta !== 'object') {
558
+ return { success: false, error: { message: 'meta must be an object' } };
559
+ }
560
+
561
+ const m = meta as Record<string, unknown>;
562
+
563
+ // Required string fields
564
+ const requiredStrings = ['did', 'kid', 'nonce', 'audience', 'sessionId'] as const;
565
+ for (const field of requiredStrings) {
566
+ if (typeof m[field] !== 'string' || (m[field] as string).length < 1) {
567
+ return { success: false, error: { message: `meta.${field} must be a non-empty string` } };
568
+ }
569
+ }
570
+
571
+ // Validate ts (positive integer)
572
+ if (typeof m['ts'] !== 'number' || !Number.isInteger(m['ts']) || m['ts'] <= 0) {
573
+ return { success: false, error: { message: 'meta.ts must be a positive integer' } };
574
+ }
575
+
576
+ // Validate hash fields
577
+ const hashFields = ['requestHash', 'responseHash'] as const;
578
+ for (const field of hashFields) {
579
+ if (typeof m[field] !== 'string' || !HASH_REGEX.test(m[field] as string)) {
580
+ return { success: false, error: { message: `meta.${field} must match sha256:<64 hex chars>` } };
581
+ }
582
+ }
583
+
584
+ // Optional string fields
585
+ const optionalStrings = ['scopeId', 'delegationRef', 'clientDid'] as const;
586
+ for (const field of optionalStrings) {
587
+ if (m[field] !== undefined && typeof m[field] !== 'string') {
588
+ return { success: false, error: { message: `meta.${field} must be a string if present` } };
589
+ }
590
+ }
591
+
592
+ return {
593
+ success: true,
594
+ data: proof as DetachedProof,
595
+ };
596
+ }