@kya-os/mcp-i-core 1.3.12 → 1.3.14

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 (254) hide show
  1. package/dist/config/remote-config.js +9 -12
  2. package/dist/runtime/base.js +11 -0
  3. package/dist/services/access-control.service.js +5 -0
  4. package/dist/services/tool-protection.service.js +17 -8
  5. package/package.json +2 -2
  6. package/.turbo/turbo-build.log +0 -4
  7. package/.turbo/turbo-test$colon$coverage.log +0 -4586
  8. package/.turbo/turbo-test.log +0 -3169
  9. package/COMPLIANCE_IMPROVEMENT_REPORT.md +0 -483
  10. package/Composer 3.md +0 -615
  11. package/GPT-5.md +0 -1169
  12. package/OPUS-plan.md +0 -352
  13. package/PHASE_3_AND_4.1_SUMMARY.md +0 -585
  14. package/PHASE_3_SUMMARY.md +0 -317
  15. package/PHASE_4.1.3_SUMMARY.md +0 -428
  16. package/PHASE_4.1_COMPLETE.md +0 -525
  17. package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +0 -1240
  18. package/SCHEMA_COMPLIANCE_REPORT.md +0 -275
  19. package/TEST_PLAN.md +0 -571
  20. package/coverage/coverage-final.json +0 -60
  21. package/dist/cache/oauth-config-cache.d.ts.map +0 -1
  22. package/dist/cache/oauth-config-cache.js.map +0 -1
  23. package/dist/cache/tool-protection-cache.d.ts.map +0 -1
  24. package/dist/cache/tool-protection-cache.js.map +0 -1
  25. package/dist/compliance/index.d.ts.map +0 -1
  26. package/dist/compliance/index.js.map +0 -1
  27. package/dist/compliance/schema-registry.d.ts.map +0 -1
  28. package/dist/compliance/schema-registry.js.map +0 -1
  29. package/dist/compliance/schema-verifier.d.ts.map +0 -1
  30. package/dist/compliance/schema-verifier.js.map +0 -1
  31. package/dist/config/remote-config.d.ts.map +0 -1
  32. package/dist/config/remote-config.js.map +0 -1
  33. package/dist/config.d.ts.map +0 -1
  34. package/dist/config.js.map +0 -1
  35. package/dist/delegation/audience-validator.d.ts.map +0 -1
  36. package/dist/delegation/audience-validator.js.map +0 -1
  37. package/dist/delegation/bitstring.d.ts.map +0 -1
  38. package/dist/delegation/bitstring.js.map +0 -1
  39. package/dist/delegation/cascading-revocation.d.ts.map +0 -1
  40. package/dist/delegation/cascading-revocation.js.map +0 -1
  41. package/dist/delegation/delegation-graph.d.ts.map +0 -1
  42. package/dist/delegation/delegation-graph.js.map +0 -1
  43. package/dist/delegation/did-key-resolver.d.ts.map +0 -1
  44. package/dist/delegation/did-key-resolver.js.map +0 -1
  45. package/dist/delegation/index.d.ts.map +0 -1
  46. package/dist/delegation/index.js.map +0 -1
  47. package/dist/delegation/statuslist-manager.d.ts.map +0 -1
  48. package/dist/delegation/statuslist-manager.js.map +0 -1
  49. package/dist/delegation/storage/index.d.ts.map +0 -1
  50. package/dist/delegation/storage/index.js.map +0 -1
  51. package/dist/delegation/storage/memory-graph-storage.d.ts.map +0 -1
  52. package/dist/delegation/storage/memory-graph-storage.js.map +0 -1
  53. package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +0 -1
  54. package/dist/delegation/storage/memory-statuslist-storage.js.map +0 -1
  55. package/dist/delegation/utils.d.ts.map +0 -1
  56. package/dist/delegation/utils.js.map +0 -1
  57. package/dist/delegation/vc-issuer.d.ts.map +0 -1
  58. package/dist/delegation/vc-issuer.js.map +0 -1
  59. package/dist/delegation/vc-verifier.d.ts.map +0 -1
  60. package/dist/delegation/vc-verifier.js.map +0 -1
  61. package/dist/identity/idp-token-resolver.d.ts.map +0 -1
  62. package/dist/identity/idp-token-resolver.js.map +0 -1
  63. package/dist/identity/idp-token-storage.interface.d.ts.map +0 -1
  64. package/dist/identity/idp-token-storage.interface.js.map +0 -1
  65. package/dist/identity/user-did-manager.d.ts.map +0 -1
  66. package/dist/identity/user-did-manager.js.map +0 -1
  67. package/dist/index.d.ts.map +0 -1
  68. package/dist/index.js.map +0 -1
  69. package/dist/providers/base.d.ts.map +0 -1
  70. package/dist/providers/base.js.map +0 -1
  71. package/dist/providers/memory.d.ts.map +0 -1
  72. package/dist/providers/memory.js.map +0 -1
  73. package/dist/runtime/audit-logger.d.ts.map +0 -1
  74. package/dist/runtime/audit-logger.js.map +0 -1
  75. package/dist/runtime/base.d.ts.map +0 -1
  76. package/dist/runtime/base.js.map +0 -1
  77. package/dist/services/access-control.service.d.ts.map +0 -1
  78. package/dist/services/access-control.service.js.map +0 -1
  79. package/dist/services/authorization/authorization-registry.d.ts.map +0 -1
  80. package/dist/services/authorization/authorization-registry.js.map +0 -1
  81. package/dist/services/authorization/types.d.ts.map +0 -1
  82. package/dist/services/authorization/types.js.map +0 -1
  83. package/dist/services/batch-delegation.service.d.ts.map +0 -1
  84. package/dist/services/batch-delegation.service.js.map +0 -1
  85. package/dist/services/crypto.service.d.ts.map +0 -1
  86. package/dist/services/crypto.service.js.map +0 -1
  87. package/dist/services/errors.d.ts.map +0 -1
  88. package/dist/services/errors.js.map +0 -1
  89. package/dist/services/index.d.ts.map +0 -1
  90. package/dist/services/index.js.map +0 -1
  91. package/dist/services/oauth-config.service.d.ts.map +0 -1
  92. package/dist/services/oauth-config.service.js.map +0 -1
  93. package/dist/services/oauth-provider-registry.d.ts.map +0 -1
  94. package/dist/services/oauth-provider-registry.js.map +0 -1
  95. package/dist/services/oauth-service.d.ts.map +0 -1
  96. package/dist/services/oauth-service.js.map +0 -1
  97. package/dist/services/oauth-token-retrieval.service.d.ts.map +0 -1
  98. package/dist/services/oauth-token-retrieval.service.js.map +0 -1
  99. package/dist/services/proof-verifier.d.ts.map +0 -1
  100. package/dist/services/proof-verifier.js.map +0 -1
  101. package/dist/services/provider-resolver.d.ts.map +0 -1
  102. package/dist/services/provider-resolver.js.map +0 -1
  103. package/dist/services/provider-validator.d.ts.map +0 -1
  104. package/dist/services/provider-validator.js.map +0 -1
  105. package/dist/services/session-registration.service.d.ts.map +0 -1
  106. package/dist/services/session-registration.service.js.map +0 -1
  107. package/dist/services/storage.service.d.ts.map +0 -1
  108. package/dist/services/storage.service.js.map +0 -1
  109. package/dist/services/tool-context-builder.d.ts.map +0 -1
  110. package/dist/services/tool-context-builder.js.map +0 -1
  111. package/dist/services/tool-protection.service.d.ts.map +0 -1
  112. package/dist/services/tool-protection.service.js.map +0 -1
  113. package/dist/types/oauth-required-error.d.ts.map +0 -1
  114. package/dist/types/oauth-required-error.js.map +0 -1
  115. package/dist/types/tool-protection.d.ts.map +0 -1
  116. package/dist/types/tool-protection.js.map +0 -1
  117. package/dist/utils/base58.d.ts.map +0 -1
  118. package/dist/utils/base58.js.map +0 -1
  119. package/dist/utils/base64.d.ts.map +0 -1
  120. package/dist/utils/base64.js.map +0 -1
  121. package/dist/utils/cors.d.ts.map +0 -1
  122. package/dist/utils/cors.js.map +0 -1
  123. package/dist/utils/did-helpers.d.ts.map +0 -1
  124. package/dist/utils/did-helpers.js.map +0 -1
  125. package/dist/utils/index.d.ts.map +0 -1
  126. package/dist/utils/index.js.map +0 -1
  127. package/dist/utils/storage-keys.d.ts.map +0 -1
  128. package/dist/utils/storage-keys.js.map +0 -1
  129. package/docs/API_REFERENCE.md +0 -1362
  130. package/docs/COMPLIANCE_MATRIX.md +0 -691
  131. package/docs/STATUSLIST2021_GUIDE.md +0 -696
  132. package/docs/W3C_VC_DELEGATION_GUIDE.md +0 -710
  133. package/src/__tests__/cache/tool-protection-cache.test.ts +0 -640
  134. package/src/__tests__/config/provider-runtime-config.test.ts +0 -309
  135. package/src/__tests__/delegation-e2e.test.ts +0 -690
  136. package/src/__tests__/identity/user-did-manager.test.ts +0 -232
  137. package/src/__tests__/index.test.ts +0 -56
  138. package/src/__tests__/integration/full-flow.test.ts +0 -789
  139. package/src/__tests__/integration.test.ts +0 -281
  140. package/src/__tests__/providers/base.test.ts +0 -173
  141. package/src/__tests__/providers/memory.test.ts +0 -319
  142. package/src/__tests__/regression/phase2-regression.test.ts +0 -429
  143. package/src/__tests__/runtime/audit-logger.test.ts +0 -154
  144. package/src/__tests__/runtime/base-extensions.test.ts +0 -595
  145. package/src/__tests__/runtime/base.test.ts +0 -869
  146. package/src/__tests__/runtime/delegation-flow.test.ts +0 -164
  147. package/src/__tests__/runtime/proof-client-did.test.ts +0 -376
  148. package/src/__tests__/runtime/route-interception.test.ts +0 -686
  149. package/src/__tests__/runtime/tool-protection-enforcement.test.ts +0 -908
  150. package/src/__tests__/services/agentshield-integration.test.ts +0 -791
  151. package/src/__tests__/services/cache-busting.test.ts +0 -125
  152. package/src/__tests__/services/oauth-service-pkce.test.ts +0 -556
  153. package/src/__tests__/services/provider-resolver-edge-cases.test.ts +0 -591
  154. package/src/__tests__/services/tool-protection-merged-config.test.ts +0 -485
  155. package/src/__tests__/services/tool-protection-oauth-provider.test.ts +0 -480
  156. package/src/__tests__/services/tool-protection.service.test.ts +0 -1373
  157. package/src/__tests__/utils/mock-providers.ts +0 -340
  158. package/src/cache/oauth-config-cache.d.ts +0 -69
  159. package/src/cache/oauth-config-cache.d.ts.map +0 -1
  160. package/src/cache/oauth-config-cache.js.map +0 -1
  161. package/src/cache/oauth-config-cache.ts +0 -123
  162. package/src/cache/tool-protection-cache.ts +0 -171
  163. package/src/compliance/EXAMPLE.md +0 -412
  164. package/src/compliance/__tests__/schema-verifier.test.ts +0 -797
  165. package/src/compliance/index.ts +0 -8
  166. package/src/compliance/schema-registry.ts +0 -460
  167. package/src/compliance/schema-verifier.ts +0 -708
  168. package/src/config/__tests__/merged-config.spec.ts +0 -445
  169. package/src/config/__tests__/remote-config.spec.ts +0 -268
  170. package/src/config/remote-config.ts +0 -264
  171. package/src/config.ts +0 -312
  172. package/src/delegation/__tests__/audience-validator.test.ts +0 -112
  173. package/src/delegation/__tests__/bitstring.test.ts +0 -346
  174. package/src/delegation/__tests__/cascading-revocation.test.ts +0 -628
  175. package/src/delegation/__tests__/delegation-graph.test.ts +0 -584
  176. package/src/delegation/__tests__/did-key-resolver.test.ts +0 -265
  177. package/src/delegation/__tests__/utils.test.ts +0 -152
  178. package/src/delegation/__tests__/vc-issuer.test.ts +0 -442
  179. package/src/delegation/__tests__/vc-verifier.test.ts +0 -922
  180. package/src/delegation/audience-validator.ts +0 -52
  181. package/src/delegation/bitstring.ts +0 -278
  182. package/src/delegation/cascading-revocation.ts +0 -370
  183. package/src/delegation/delegation-graph.ts +0 -299
  184. package/src/delegation/did-key-resolver.ts +0 -179
  185. package/src/delegation/index.ts +0 -14
  186. package/src/delegation/statuslist-manager.ts +0 -353
  187. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +0 -366
  188. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +0 -228
  189. package/src/delegation/storage/index.ts +0 -9
  190. package/src/delegation/storage/memory-graph-storage.ts +0 -178
  191. package/src/delegation/storage/memory-statuslist-storage.ts +0 -77
  192. package/src/delegation/utils.ts +0 -221
  193. package/src/delegation/vc-issuer.ts +0 -232
  194. package/src/delegation/vc-verifier.ts +0 -568
  195. package/src/identity/idp-token-resolver.ts +0 -181
  196. package/src/identity/idp-token-storage.interface.ts +0 -94
  197. package/src/identity/user-did-manager.ts +0 -526
  198. package/src/index.ts +0 -310
  199. package/src/providers/base.d.ts +0 -91
  200. package/src/providers/base.d.ts.map +0 -1
  201. package/src/providers/base.js.map +0 -1
  202. package/src/providers/base.ts +0 -96
  203. package/src/providers/memory.ts +0 -142
  204. package/src/runtime/audit-logger.ts +0 -39
  205. package/src/runtime/base.ts +0 -1392
  206. package/src/services/__tests__/access-control.integration.test.ts +0 -443
  207. package/src/services/__tests__/access-control.proof-response-validation.test.ts +0 -578
  208. package/src/services/__tests__/access-control.service.test.ts +0 -970
  209. package/src/services/__tests__/batch-delegation.service.test.ts +0 -351
  210. package/src/services/__tests__/crypto.service.test.ts +0 -531
  211. package/src/services/__tests__/oauth-provider-registry.test.ts +0 -142
  212. package/src/services/__tests__/proof-verifier.integration.test.ts +0 -485
  213. package/src/services/__tests__/proof-verifier.test.ts +0 -489
  214. package/src/services/__tests__/provider-resolution.integration.test.ts +0 -202
  215. package/src/services/__tests__/provider-resolver.test.ts +0 -213
  216. package/src/services/__tests__/storage.service.test.ts +0 -358
  217. package/src/services/access-control.service.ts +0 -990
  218. package/src/services/authorization/authorization-registry.ts +0 -66
  219. package/src/services/authorization/types.ts +0 -71
  220. package/src/services/batch-delegation.service.ts +0 -137
  221. package/src/services/crypto.service.ts +0 -302
  222. package/src/services/errors.ts +0 -76
  223. package/src/services/index.ts +0 -18
  224. package/src/services/oauth-config.service.d.ts +0 -53
  225. package/src/services/oauth-config.service.d.ts.map +0 -1
  226. package/src/services/oauth-config.service.js.map +0 -1
  227. package/src/services/oauth-config.service.ts +0 -192
  228. package/src/services/oauth-provider-registry.d.ts +0 -57
  229. package/src/services/oauth-provider-registry.d.ts.map +0 -1
  230. package/src/services/oauth-provider-registry.js.map +0 -1
  231. package/src/services/oauth-provider-registry.ts +0 -141
  232. package/src/services/oauth-service.ts +0 -544
  233. package/src/services/oauth-token-retrieval.service.ts +0 -245
  234. package/src/services/proof-verifier.ts +0 -478
  235. package/src/services/provider-resolver.d.ts +0 -48
  236. package/src/services/provider-resolver.d.ts.map +0 -1
  237. package/src/services/provider-resolver.js.map +0 -1
  238. package/src/services/provider-resolver.ts +0 -146
  239. package/src/services/provider-validator.ts +0 -170
  240. package/src/services/session-registration.service.ts +0 -251
  241. package/src/services/storage.service.ts +0 -566
  242. package/src/services/tool-context-builder.ts +0 -237
  243. package/src/services/tool-protection.service.ts +0 -1070
  244. package/src/types/oauth-required-error.ts +0 -63
  245. package/src/types/tool-protection.ts +0 -155
  246. package/src/utils/__tests__/did-helpers.test.ts +0 -156
  247. package/src/utils/base58.ts +0 -109
  248. package/src/utils/base64.ts +0 -148
  249. package/src/utils/cors.ts +0 -83
  250. package/src/utils/did-helpers.ts +0 -210
  251. package/src/utils/index.ts +0 -8
  252. package/src/utils/storage-keys.ts +0 -278
  253. package/tsconfig.json +0 -21
  254. package/vitest.config.ts +0 -56
@@ -1,869 +0,0 @@
1
- /**
2
- * Tests for MCPIRuntimeBase
3
- */
4
-
5
- import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
6
- import { MCPIRuntimeBase } from "../../runtime/base";
7
- import { ProviderRuntimeConfig } from "../../config";
8
- import {
9
- createMockProviders,
10
- MockClockProvider,
11
- MockFetchProvider,
12
- MockIdentityProvider,
13
- MockNonceCacheProvider,
14
- } from "../utils/mock-providers";
15
-
16
- describe("MCPIRuntimeBase", () => {
17
- let runtime: MCPIRuntimeBase;
18
- let config: ProviderRuntimeConfig;
19
- let mockProviders: ReturnType<typeof createMockProviders>;
20
-
21
- beforeEach(() => {
22
- vi.clearAllMocks();
23
- mockProviders = createMockProviders();
24
- config = {
25
- ...mockProviders,
26
- environment: "development",
27
- session: {
28
- timestampSkewSeconds: 120,
29
- ttlMinutes: 30,
30
- },
31
- audit: {
32
- enabled: true,
33
- logFunction: vi.fn(),
34
- includePayloads: true,
35
- },
36
- wellKnown: {
37
- enabled: true,
38
- serviceName: "Test Service",
39
- serviceEndpoint: "https://test.example.com",
40
- },
41
- showVerifyLink: true,
42
- identityBadge: true,
43
- };
44
- runtime = new MCPIRuntimeBase(config);
45
- });
46
-
47
- describe("constructor", () => {
48
- it("should initialize with providers", () => {
49
- expect(runtime).toBeDefined();
50
- expect((runtime as any).crypto).toBe(mockProviders.cryptoProvider);
51
- expect((runtime as any).clock).toBe(mockProviders.clockProvider);
52
- expect((runtime as any).fetch).toBe(mockProviders.fetchProvider);
53
- expect((runtime as any).storage).toBe(mockProviders.storageProvider);
54
- expect((runtime as any).nonceCache).toBe(
55
- mockProviders.nonceCacheProvider
56
- );
57
- expect((runtime as any).identity).toBe(mockProviders.identityProvider);
58
- });
59
-
60
- it("should store config", () => {
61
- expect((runtime as any).config).toEqual(config);
62
- });
63
- });
64
-
65
- describe("initialize", () => {
66
- it("should load identity on initialization", async () => {
67
- await runtime.initialize();
68
- const identity = await runtime.getIdentity();
69
- expect(identity.did).toBe("did:key:zmock123");
70
- });
71
-
72
- it("should call nonce cache initialize if available", async () => {
73
- const initializeFn = vi.fn();
74
- (mockProviders.nonceCacheProvider as any).initialize = initializeFn;
75
-
76
- await runtime.initialize();
77
- expect(initializeFn).toHaveBeenCalled();
78
- });
79
-
80
- it("should log audit event on initialization", async () => {
81
- await runtime.initialize();
82
-
83
- expect(config.audit!.logFunction).toHaveBeenCalledWith(
84
- expect.stringContaining("runtime_initialized")
85
- );
86
-
87
- const logCall = (config.audit!.logFunction as any).mock.calls[0][0];
88
- const logData = JSON.parse(logCall);
89
- expect(logData.event).toBe("runtime_initialized");
90
- expect(logData.data.did).toBe("did:key:zmock123");
91
- expect(logData.data.environment).toBe("development");
92
- });
93
-
94
- it("should not log audit if disabled", async () => {
95
- config.audit!.enabled = false;
96
- await runtime.initialize();
97
- expect(config.audit!.logFunction).not.toHaveBeenCalled();
98
- });
99
- });
100
-
101
- describe("getIdentity", () => {
102
- it("should return cached identity if available", async () => {
103
- await runtime.initialize();
104
- const identity1 = await runtime.getIdentity();
105
- const identity2 = await runtime.getIdentity();
106
-
107
- expect(identity1).toBe(identity2);
108
- });
109
-
110
- it("should load identity if not cached", async () => {
111
- const identity = await runtime.getIdentity();
112
- expect(identity.did).toBe("did:key:zmock123");
113
- });
114
- });
115
-
116
- describe("handleHandshake", () => {
117
- const handshakeRequest = {
118
- nonce: "test-nonce-123",
119
- audience: "https://client.example.com",
120
- timestamp: Date.now(),
121
- clientDid: "did:key:zclient123",
122
- };
123
-
124
- beforeEach(async () => {
125
- await runtime.initialize();
126
- });
127
-
128
- it("should create session and return handshake response", async () => {
129
- const response = await runtime.handleHandshake(handshakeRequest);
130
-
131
- expect(response.sessionId).toBeDefined();
132
- expect(response.agentDid).toBe("did:key:zmock123");
133
- expect(response.timestamp).toBe(
134
- (mockProviders.clockProvider as MockClockProvider).now()
135
- );
136
- expect(response.capabilities).toEqual(["identity", "proof", "audit"]);
137
- expect(response.signature).toBeDefined();
138
- });
139
-
140
- it("should store session internally", async () => {
141
- const response = await runtime.handleHandshake(handshakeRequest);
142
- const session = await runtime.getCurrentSession();
143
-
144
- expect(session).toBeDefined();
145
- expect(session.id).toBe(response.sessionId);
146
- expect(session.clientDid).toBe(handshakeRequest.clientDid);
147
- expect(session.agentDid).toBeUndefined(); // ✅ FIXED: agentDid should be undefined when not provided (no fallback)
148
- expect(session.serverDid).toBe("did:key:zmock123"); // ✅ NEW: serverDid should be set to identity.did
149
- expect(session.audience).toBe(handshakeRequest.audience);
150
- });
151
-
152
- it("should set session expiry", async () => {
153
- const clock = mockProviders.clockProvider as MockClockProvider;
154
- const currentTime = Date.now();
155
- clock.setTime(currentTime);
156
-
157
- await runtime.handleHandshake(handshakeRequest);
158
- const session = await runtime.getCurrentSession();
159
-
160
- expect(session.expiresAt).toBe(currentTime + 30 * 60 * 1000); // 30 minutes
161
- });
162
-
163
- it("should sign handshake response", async () => {
164
- const response = await runtime.handleHandshake(handshakeRequest);
165
- expect(response.signature).toBe(
166
- Buffer.from(new Uint8Array([1, 2, 3, 4, 5])).toString("base64")
167
- );
168
- });
169
-
170
- it("should use agentDid when provided in handshake request", async () => {
171
- const handshakeWithAgentDid = {
172
- ...handshakeRequest,
173
- agentDid: "did:key:zagent456",
174
- };
175
-
176
- const response = await runtime.handleHandshake(handshakeWithAgentDid);
177
- const session = await runtime.getCurrentSession();
178
-
179
- expect(session.agentDid).toBe("did:key:zagent456"); // ✅ Should use agentDid, not clientDid
180
- expect(session.clientDid).toBe(handshakeRequest.clientDid); // clientDid should remain unchanged
181
- expect(session.serverDid).toBe("did:key:zmock123"); // ✅ serverDid should be set to identity.did
182
- });
183
-
184
- it("should extract and store clientInfo when provided", async () => {
185
- const handshakeWithClientInfo = {
186
- ...handshakeRequest,
187
- clientInfo: {
188
- name: "Claude Desktop",
189
- title: "Claude Desktop Preview",
190
- version: "1.0.0",
191
- platform: "desktop",
192
- vendor: "Anthropic",
193
- persistentId: "persistent-client-id",
194
- },
195
- clientProtocolVersion: "2025-06-18",
196
- clientCapabilities: {
197
- tools: { listChanged: true },
198
- },
199
- };
200
-
201
- await runtime.handleHandshake(handshakeWithClientInfo);
202
- const session = await runtime.getCurrentSession();
203
-
204
- expect(session.clientInfo).toBeDefined();
205
- expect(session.clientInfo?.name).toBe("Claude Desktop");
206
- expect(session.clientInfo?.title).toBe("Claude Desktop Preview");
207
- expect(session.clientInfo?.version).toBe("1.0.0");
208
- expect(session.clientInfo?.platform).toBe("desktop");
209
- expect(session.clientInfo?.clientId).toBeDefined();
210
- expect(typeof session.clientInfo?.clientId).toBe("string");
211
- expect(session.clientInfo?.vendor).toBe("Anthropic");
212
- expect(session.clientInfo?.persistentId).toBe("persistent-client-id");
213
- expect(session.clientInfo?.protocolVersion).toBe("2025-06-18");
214
- expect(session.clientInfo?.capabilities).toEqual({
215
- tools: { listChanged: true },
216
- });
217
- });
218
-
219
- it("should handle handshake without clientInfo gracefully", async () => {
220
- await runtime.handleHandshake(handshakeRequest);
221
- const session = await runtime.getCurrentSession();
222
-
223
- expect(session.clientInfo).toBeUndefined();
224
- });
225
-
226
- it("should preserve clientId when provided by adapter", async () => {
227
- const handshakeWithClientId = {
228
- ...handshakeRequest,
229
- clientInfo: {
230
- name: "Claude Desktop",
231
- clientId: "server-specified-client-id",
232
- },
233
- };
234
-
235
- await runtime.handleHandshake(handshakeWithClientId);
236
- const session = await runtime.getCurrentSession();
237
-
238
- expect(session.clientInfo?.clientId).toBe("server-specified-client-id");
239
- });
240
-
241
- it("should default clientInfo name to 'unknown' when name is missing", async () => {
242
- const handshakeWithPartialClientInfo = {
243
- ...handshakeRequest,
244
- clientInfo: {
245
- version: "1.0.0",
246
- platform: "desktop",
247
- },
248
- };
249
-
250
- await runtime.handleHandshake(handshakeWithPartialClientInfo);
251
- const session = await runtime.getCurrentSession();
252
-
253
- expect(session.clientInfo).toBeDefined();
254
- expect(session.clientInfo?.name).toBe("unknown");
255
- expect(session.clientInfo?.version).toBe("1.0.0");
256
- expect(session.clientInfo?.platform).toBe("desktop");
257
- });
258
- });
259
-
260
- describe("processToolCall", () => {
261
- const mockHandler = vi.fn().mockResolvedValue({ result: "success" });
262
- const session = {
263
- id: "session123",
264
- audience: "https://client.example.com",
265
- nonce: "test-nonce",
266
- };
267
-
268
- beforeEach(async () => {
269
- await runtime.initialize();
270
- });
271
-
272
- it("should execute tool handler and return clean result", async () => {
273
- const result = await runtime.processToolCall(
274
- "testTool",
275
- { arg: "value" },
276
- mockHandler,
277
- session
278
- );
279
-
280
- expect(mockHandler).toHaveBeenCalledWith({ arg: "value" });
281
- expect(result).toEqual({ result: "success" });
282
- });
283
-
284
- it("should create and store proof", async () => {
285
- await runtime.processToolCall(
286
- "testTool",
287
- { arg: "value" },
288
- mockHandler,
289
- session
290
- );
291
-
292
- const proof = runtime.getLastProof();
293
- expect(proof).toBeDefined();
294
- expect(proof.did).toBe("did:key:zmock123");
295
- expect(proof.signature).toBeDefined();
296
- expect(proof.nonce).toBe("test-nonce");
297
- expect(proof.sessionId).toBe("session123");
298
- expect(proof.audience).toBe("https://client.example.com");
299
- });
300
-
301
- it("should log audit event", async () => {
302
- const clock = mockProviders.clockProvider as MockClockProvider;
303
- const currentTime = Date.now();
304
- clock.setTime(currentTime);
305
-
306
- await runtime.processToolCall(
307
- "testTool",
308
- { arg: "value" },
309
- mockHandler,
310
- session
311
- );
312
-
313
- expect(config.audit!.logFunction).toHaveBeenCalled();
314
-
315
- // Find the tool_executed log entry (might not be the first one)
316
- const logCalls = (config.audit!.logFunction as any).mock.calls;
317
- const toolLogCall = logCalls.find((call: any[]) => {
318
- const log = JSON.parse(call[0]);
319
- return log.event === "tool_executed";
320
- });
321
-
322
- expect(toolLogCall).toBeDefined();
323
- const logData = JSON.parse(toolLogCall[0]);
324
- expect(logData.event).toBe("tool_executed");
325
- expect(logData.data.tool).toBe("testTool");
326
- expect(logData.data.sessionId).toBe("session123");
327
- expect(logData.data.timestamp).toBe(currentTime);
328
- });
329
-
330
- it("should handle tool handler errors", async () => {
331
- const errorHandler = vi.fn().mockRejectedValue(new Error("Tool failed"));
332
-
333
- await expect(
334
- runtime.processToolCall("errorTool", {}, errorHandler)
335
- ).rejects.toThrow("Tool failed");
336
- });
337
- });
338
-
339
- describe("issueNonce", () => {
340
- beforeEach(async () => {
341
- await runtime.initialize();
342
- });
343
-
344
- it("should generate and cache nonce", async () => {
345
- const nonce = await runtime.issueNonce("session123");
346
-
347
- expect(nonce).toBeDefined();
348
- expect(nonce).toHaveLength(44); // Base64 encoded 32 bytes
349
-
350
- const nonceCache =
351
- mockProviders.nonceCacheProvider as MockNonceCacheProvider;
352
- const identity = await runtime.getIdentity();
353
- expect(await nonceCache.has(nonce, identity.did)).toBe(true);
354
- });
355
-
356
- it("should set 5 minute expiry", async () => {
357
- const clock = mockProviders.clockProvider as MockClockProvider;
358
- const currentTime = Date.now();
359
- clock.setTime(currentTime);
360
-
361
- const nonce = await runtime.issueNonce("session123");
362
-
363
- // Check that nonce expires after 5 minutes
364
- clock.setTime(currentTime + 5 * 60 * 1000 + 1);
365
- const nonceCache =
366
- mockProviders.nonceCacheProvider as MockNonceCacheProvider;
367
- const identity = await runtime.getIdentity();
368
- expect(await nonceCache.has(nonce, identity.did)).toBe(false);
369
- });
370
- });
371
-
372
- describe("createProof", () => {
373
- const testData = { foo: "bar" };
374
-
375
- beforeEach(async () => {
376
- await runtime.initialize();
377
- });
378
-
379
- it("should create proof with all fields", async () => {
380
- const clock = mockProviders.clockProvider as MockClockProvider;
381
- const currentTime = Date.now();
382
- clock.setTime(currentTime);
383
-
384
- const proof = await runtime.createProof(testData);
385
-
386
- expect(proof.timestamp).toBe(currentTime);
387
- expect(proof.nonce).toBeDefined();
388
- expect(proof.did).toBe("did:key:zmock123");
389
- expect(proof.signature).toBeDefined();
390
- expect(proof.algorithm).toBe("Ed25519");
391
- expect(proof.sessionId).toBeUndefined();
392
- expect(proof.audience).toBeUndefined();
393
- });
394
-
395
- it("should use session nonce if provided", async () => {
396
- const session = {
397
- id: "session123",
398
- nonce: "session-nonce",
399
- audience: "https://client.example.com",
400
- };
401
-
402
- const proof = await runtime.createProof(testData, session);
403
-
404
- expect(proof.nonce).toBe("session-nonce");
405
- expect(proof.sessionId).toBe("session123");
406
- expect(proof.audience).toBe("https://client.example.com");
407
- });
408
-
409
- it("should generate and cache new nonce if not in session", async () => {
410
- const proof = await runtime.createProof(testData);
411
-
412
- const nonceCache =
413
- mockProviders.nonceCacheProvider as MockNonceCacheProvider;
414
- const identity = await runtime.getIdentity();
415
- expect(await nonceCache.has(proof.nonce, identity.did)).toBe(true);
416
- });
417
- });
418
-
419
- describe("verifyProof", () => {
420
- const testData = { foo: "bar" };
421
- let validProof: any;
422
-
423
- beforeEach(async () => {
424
- await runtime.initialize();
425
-
426
- // Set up DID document for verification
427
- const fetchProvider = mockProviders.fetchProvider as MockFetchProvider;
428
- fetchProvider.setDIDDocument("did:key:zmock123", {
429
- verificationMethod: [
430
- {
431
- publicKeyBase64: "mock-public-key",
432
- },
433
- ],
434
- });
435
-
436
- // Create a valid proof
437
- validProof = await runtime.createProof(testData);
438
- });
439
-
440
- it("should verify valid proof", async () => {
441
- // Remove the nonce from cache first (simulating a fresh verification)
442
- const nonceCache =
443
- mockProviders.nonceCacheProvider as MockNonceCacheProvider;
444
- nonceCache.clear();
445
-
446
- const isValid = await runtime.verifyProof(testData, validProof);
447
- expect(isValid).toBe(true);
448
- });
449
-
450
- it("should reject if nonce already used", async () => {
451
- // Pre-add nonce to cache with agent-scoped key
452
- const nonceCache =
453
- mockProviders.nonceCacheProvider as MockNonceCacheProvider;
454
- await nonceCache.add(
455
- validProof.nonce,
456
- Date.now() + 10000,
457
- validProof.did
458
- );
459
-
460
- const isValid = await runtime.verifyProof(testData, validProof);
461
- expect(isValid).toBe(false);
462
- });
463
-
464
- it("should use agent-scoped nonces in legacy verification (prevents cross-agent replay)", async () => {
465
- const agentDid1 = "did:key:agent1";
466
- const agentDid2 = "did:key:agent2";
467
- const sameNonce = "same-nonce-value";
468
-
469
- // Set up DID documents for both agents
470
- const fetchProvider = mockProviders.fetchProvider as MockFetchProvider;
471
- fetchProvider.setDIDDocument(agentDid1, {
472
- verificationMethod: [
473
- {
474
- publicKeyBase64: "mock-public-key-agent1",
475
- },
476
- ],
477
- });
478
- fetchProvider.setDIDDocument(agentDid2, {
479
- verificationMethod: [
480
- {
481
- publicKeyBase64: "mock-public-key-agent2",
482
- },
483
- ],
484
- });
485
-
486
- // Create proof for agent 1
487
- const proof1 = {
488
- ...validProof,
489
- did: agentDid1,
490
- nonce: sameNonce,
491
- };
492
-
493
- // Create proof for agent 2 with same nonce
494
- const proof2 = {
495
- ...validProof,
496
- did: agentDid2,
497
- nonce: sameNonce,
498
- };
499
-
500
- const nonceCache =
501
- mockProviders.nonceCacheProvider as MockNonceCacheProvider;
502
- nonceCache.clear();
503
-
504
- // Verify proof for agent 1 (should succeed)
505
- const isValid1 = await runtime.verifyProof(testData, proof1);
506
- expect(isValid1).toBe(true);
507
-
508
- // Verify that nonce was added with agent-scoped key
509
- // The nonce should be scoped to agentDid1, so agentDid2 should be able to use the same nonce
510
- const hasNonceAgent1 = await nonceCache.has(sameNonce, agentDid1);
511
- expect(hasNonceAgent1).toBe(true);
512
-
513
- // Verify proof for agent 2 with same nonce (should succeed because nonces are agent-scoped)
514
- const isValid2 = await runtime.verifyProof(testData, proof2);
515
- expect(isValid2).toBe(true);
516
-
517
- // Verify that both agents' nonces are cached separately
518
- const hasNonceAgent2 = await nonceCache.has(sameNonce, agentDid2);
519
- expect(hasNonceAgent2).toBe(true);
520
- });
521
-
522
- it("should reject if timestamp outside skew", async () => {
523
- const clock = mockProviders.clockProvider as MockClockProvider;
524
- const currentTime = Date.now();
525
- clock.setTime(currentTime + 121 * 1000); // 121 seconds later (skew is 120)
526
-
527
- const isValid = await runtime.verifyProof(testData, validProof);
528
- expect(isValid).toBe(false);
529
- });
530
-
531
- it("should reject if DID cannot be resolved", async () => {
532
- const fetchProvider = mockProviders.fetchProvider as MockFetchProvider;
533
- fetchProvider.setDIDDocument("did:key:zmock123", null as any);
534
-
535
- const isValid = await runtime.verifyProof(testData, validProof);
536
- expect(isValid).toBe(false);
537
- });
538
-
539
- it("should reject if signature invalid", async () => {
540
- validProof.signature = "invalid-signature";
541
-
542
- const isValid = await runtime.verifyProof(testData, validProof);
543
- expect(isValid).toBe(false);
544
- });
545
-
546
- it("should handle verification errors gracefully", async () => {
547
- const fetchProvider = mockProviders.fetchProvider as MockFetchProvider;
548
- (fetchProvider.resolveDID as any) = vi
549
- .fn()
550
- .mockRejectedValue(new Error("Network error"));
551
-
552
- const isValid = await runtime.verifyProof(testData, validProof);
553
- expect(isValid).toBe(false);
554
- });
555
- });
556
-
557
- describe("getCurrentSession", () => {
558
- beforeEach(async () => {
559
- await runtime.initialize();
560
- });
561
-
562
- it("should return active session", async () => {
563
- await runtime.handleHandshake({
564
- clientDid: "did:key:zclient123",
565
- audience: "https://client.example.com",
566
- });
567
-
568
- const session = await runtime.getCurrentSession();
569
- expect(session).toBeDefined();
570
- expect(session.clientDid).toBe("did:key:zclient123");
571
- });
572
-
573
- it("should return null if no sessions", async () => {
574
- const session = await runtime.getCurrentSession();
575
- expect(session).toBeNull();
576
- });
577
-
578
- it("should return null if session expired", async () => {
579
- const clock = mockProviders.clockProvider as MockClockProvider;
580
- const currentTime = Date.now();
581
- clock.setTime(currentTime);
582
-
583
- await runtime.handleHandshake({
584
- clientDid: "did:key:zclient123",
585
- audience: "https://client.example.com",
586
- });
587
-
588
- // Advance time past session expiry
589
- clock.setTime(currentTime + 31 * 60 * 1000); // 31 minutes
590
-
591
- const session = await runtime.getCurrentSession();
592
- expect(session).toBeNull();
593
- });
594
- });
595
-
596
- describe("getLastProof", () => {
597
- it("should return undefined initially", () => {
598
- const proof = runtime.getLastProof();
599
- expect(proof).toBeUndefined();
600
- });
601
-
602
- it("should return last generated proof", async () => {
603
- await runtime.initialize();
604
- await runtime.processToolCall(
605
- "testTool",
606
- {},
607
- vi.fn().mockResolvedValue({ result: "ok" })
608
- );
609
-
610
- const proof = runtime.getLastProof();
611
- expect(proof).toBeDefined();
612
- expect(proof.did).toBe("did:key:zmock123");
613
- });
614
- });
615
-
616
- describe("createWellKnownHandler", () => {
617
- let handler: any;
618
-
619
- beforeEach(async () => {
620
- await runtime.initialize();
621
- handler = runtime.createWellKnownHandler({
622
- serviceName: "Test Service",
623
- serviceEndpoint: "https://test.example.com",
624
- });
625
- });
626
-
627
- it("should handle /.well-known/did.json", async () => {
628
- const response = await handler("/.well-known/did.json");
629
-
630
- expect(response.status).toBe(200);
631
- expect(response.headers["Content-Type"]).toBe("application/did+json");
632
-
633
- const result = JSON.parse(response.body);
634
- expect(result).toEqual({
635
- "@context": ["https://www.w3.org/ns/did/v1"],
636
- id: "did:key:zmock123",
637
- verificationMethod: [
638
- {
639
- id: "did:key:zmock123#key-1",
640
- type: "Ed25519VerificationKey2020",
641
- controller: "did:key:zmock123",
642
- publicKeyBase64: "mock-public-key",
643
- },
644
- ],
645
- authentication: ["did:key:zmock123#key-1"],
646
- assertionMethod: ["did:key:zmock123#key-1"],
647
- });
648
- });
649
-
650
- it("should handle /.well-known/mcp-identity", async () => {
651
- const clock = mockProviders.clockProvider as MockClockProvider;
652
- const currentTime = Date.now();
653
- clock.setTime(currentTime);
654
-
655
- const result = await handler("/.well-known/mcp-identity");
656
-
657
- expect(result).toEqual({
658
- did: "did:key:zmock123",
659
- publicKey: "mock-public-key",
660
- serviceName: "Test Service",
661
- serviceEndpoint: "https://test.example.com",
662
- timestamp: currentTime,
663
- });
664
- });
665
-
666
- it("should return null for unknown paths", async () => {
667
- const result = await handler("/unknown/path");
668
- expect(result).toBeNull();
669
- });
670
-
671
- it("should use default values if config not provided", async () => {
672
- const defaultHandler = runtime.createWellKnownHandler();
673
- const result = await defaultHandler("/.well-known/mcp-identity");
674
-
675
- expect(result.serviceName).toBe("MCP-I Service");
676
- expect(result.serviceEndpoint).toBe("https://example.com");
677
- });
678
- });
679
-
680
- describe("createDebugEndpoint", () => {
681
- beforeEach(async () => {
682
- await runtime.initialize();
683
- });
684
-
685
- it("should return debug info in development", async () => {
686
- const clock = mockProviders.clockProvider as MockClockProvider;
687
- const currentTime = Date.now();
688
- clock.setTime(currentTime);
689
-
690
- const endpoint = runtime.createDebugEndpoint();
691
- expect(endpoint).toBeDefined();
692
-
693
- const result = await endpoint();
694
- expect(result).toEqual({
695
- identity: {
696
- did: "did:key:zmock123",
697
- publicKey: "mock-public-key",
698
- },
699
- session: null,
700
- config: {
701
- environment: "development",
702
- timestampSkewSeconds: 120,
703
- sessionTtlMinutes: 30,
704
- },
705
- timestamp: currentTime,
706
- });
707
- });
708
-
709
- it("should include session if active", async () => {
710
- await runtime.handleHandshake({
711
- clientDid: "did:key:zclient123",
712
- audience: "https://client.example.com",
713
- });
714
-
715
- const endpoint = runtime.createDebugEndpoint();
716
- const result = await endpoint();
717
-
718
- expect(result.session).toBeDefined();
719
- expect(result.session.clientDid).toBe("did:key:zclient123");
720
- });
721
-
722
- it("should return null in production", () => {
723
- config.environment = "production";
724
- const prodRuntime = new MCPIRuntimeBase(config);
725
-
726
- const endpoint = prodRuntime.createDebugEndpoint();
727
- expect(endpoint).toBeNull();
728
- });
729
- });
730
-
731
- describe("getAuditLogger", () => {
732
- it("should return audit logger", () => {
733
- const logger = runtime.getAuditLogger();
734
- expect(logger).toBeDefined();
735
- expect(logger.log).toBeDefined();
736
- });
737
-
738
- it("should log through runtime audit", async () => {
739
- await runtime.initialize();
740
- const logger = runtime.getAuditLogger();
741
-
742
- logger.log("test_event", { test: "data" });
743
-
744
- expect(config.audit!.logFunction).toHaveBeenCalledWith(
745
- expect.stringContaining("test_event")
746
- );
747
- });
748
- });
749
-
750
- describe("rotateKeys", () => {
751
- beforeEach(async () => {
752
- await runtime.initialize();
753
- });
754
-
755
- it("should rotate keys and update identity", async () => {
756
- const oldIdentity = await runtime.getIdentity();
757
- const newIdentity = await runtime.rotateKeys();
758
-
759
- expect(newIdentity.did).toBe("did:key:zmock456-1");
760
- expect(newIdentity.privateKey).toBe("mock-private-key-rotated-1");
761
- expect(newIdentity.publicKey).toBe("mock-public-key-rotated-1");
762
-
763
- const currentIdentity = await runtime.getIdentity();
764
- expect(currentIdentity).toEqual(newIdentity);
765
- });
766
-
767
- it("should log audit event", async () => {
768
- const clock = mockProviders.clockProvider as MockClockProvider;
769
- const currentTime = Date.now();
770
- clock.setTime(currentTime);
771
-
772
- // Get the old identity first
773
- const oldIdentity = await runtime.getIdentity();
774
-
775
- await runtime.rotateKeys();
776
-
777
- expect(config.audit!.logFunction).toHaveBeenCalled();
778
-
779
- // Find the keys_rotated log entry
780
- const logCalls = (config.audit!.logFunction as any).mock.calls;
781
- const rotateLogCall = logCalls.find((call: any[]) => {
782
- const log = JSON.parse(call[0]);
783
- return log.event === "keys_rotated";
784
- });
785
-
786
- expect(rotateLogCall).toBeDefined();
787
- const logData = JSON.parse(rotateLogCall[0]);
788
- expect(logData.event).toBe("keys_rotated");
789
- expect(logData.data.oldDid).toBe(oldIdentity.did);
790
- expect(logData.data.newDid).toBe("did:key:zmock456-1");
791
- expect(logData.data.timestamp).toBe(currentTime);
792
- });
793
- });
794
-
795
- describe("audit logging", () => {
796
- it("should use custom log function if provided", async () => {
797
- await runtime.initialize();
798
- expect(config.audit!.logFunction).toHaveBeenCalled();
799
- });
800
-
801
- it("should console.log if no custom function", async () => {
802
- const consoleLogSpy = vi
803
- .spyOn(console, "log")
804
- .mockImplementation(() => {});
805
-
806
- config.audit!.logFunction = undefined;
807
- const runtimeNoLogFn = new MCPIRuntimeBase(config);
808
- await runtimeNoLogFn.initialize();
809
-
810
- expect(consoleLogSpy).toHaveBeenCalledWith("[AUDIT]", expect.any(String));
811
- consoleLogSpy.mockRestore();
812
- });
813
-
814
- it("should exclude payloads if configured", async () => {
815
- config.audit!.includePayloads = false;
816
- const runtimeNoPayloads = new MCPIRuntimeBase(config);
817
- await runtimeNoPayloads.initialize();
818
-
819
- const logCall = (config.audit!.logFunction as any).mock.calls[0][0];
820
- const logData = JSON.parse(logCall);
821
- expect(logData.data).toBeUndefined();
822
- });
823
-
824
- it("should include formatted timestamp", async () => {
825
- const clock = mockProviders.clockProvider as MockClockProvider;
826
- const currentTime = Date.now();
827
- clock.setTime(currentTime);
828
-
829
- await runtime.initialize();
830
-
831
- const logCall = (config.audit!.logFunction as any).mock.calls[0][0];
832
- const logData = JSON.parse(logCall);
833
- expect(logData.timestampFormatted).toBe(
834
- new Date(currentTime).toISOString()
835
- );
836
- });
837
- });
838
-
839
- describe("helper methods", () => {
840
- it("should handle DID document with publicKeyMultibase", async () => {
841
- await runtime.initialize();
842
-
843
- const fetchProvider = mockProviders.fetchProvider as MockFetchProvider;
844
- fetchProvider.setDIDDocument("did:key:ztest", {
845
- verificationMethod: [
846
- {
847
- publicKeyMultibase: "zBase58EncodedKey",
848
- },
849
- ],
850
- });
851
-
852
- // This would be called internally during verification
853
- const didDoc = await fetchProvider.resolveDID("did:key:ztest");
854
- const extractPublicKey = (runtime as any).extractPublicKey.bind(runtime);
855
- const publicKey = extractPublicKey(didDoc);
856
-
857
- expect(publicKey).toBe("zBase58EncodedKey");
858
- });
859
-
860
- it("should throw if no public key in DID document", async () => {
861
- await runtime.initialize();
862
-
863
- const didDoc = { verificationMethod: [{}] };
864
- const extractPublicKey = (runtime as any).extractPublicKey.bind(runtime);
865
-
866
- expect(() => extractPublicKey(didDoc)).toThrow("Public key not found");
867
- });
868
- });
869
- });