@kya-os/mcp-i 0.1.0 → 1.2.1

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 (229) hide show
  1. package/README.md +406 -71
  2. package/dist/149.js +1 -0
  3. package/dist/189.js +1 -0
  4. package/dist/261.js +1 -0
  5. package/dist/28.js +1 -0
  6. package/dist/295.js +1 -0
  7. package/dist/460.js +1 -0
  8. package/dist/570.js +1 -0
  9. package/dist/634.js +1 -0
  10. package/dist/647.js +1 -0
  11. package/dist/67.js +1 -0
  12. package/dist/739.js +1 -0
  13. package/dist/742.js +1 -0
  14. package/dist/904.js +1 -0
  15. package/dist/938.js +1 -0
  16. package/dist/auth/api-key.d.ts +16 -0
  17. package/dist/auth/api-key.js +82 -0
  18. package/dist/auth/jwt.d.ts +43 -0
  19. package/dist/auth/jwt.js +51 -0
  20. package/dist/auth/oauth/factory.d.ts +12 -0
  21. package/dist/auth/oauth/factory.js +36 -0
  22. package/dist/auth/oauth/index.d.ts +5 -0
  23. package/dist/auth/oauth/index.js +27 -0
  24. package/dist/auth/oauth/providers/proxy-provider.d.ts +13 -0
  25. package/dist/auth/oauth/providers/proxy-provider.js +159 -0
  26. package/dist/auth/oauth/router.d.ts +4 -0
  27. package/dist/auth/oauth/router.js +294 -0
  28. package/dist/auth/oauth/storage/memory-storage.d.ts +12 -0
  29. package/dist/auth/oauth/storage/memory-storage.js +40 -0
  30. package/dist/auth/oauth/types.d.ts +112 -0
  31. package/dist/auth/oauth/types.js +2 -0
  32. package/dist/cache/__tests__/cloudflare-kv-nonce-cache.test.d.ts +4 -0
  33. package/dist/cache/__tests__/cloudflare-kv-nonce-cache.test.js +176 -0
  34. package/dist/cache/__tests__/concurrency.test.d.ts +5 -0
  35. package/dist/cache/__tests__/concurrency.test.js +300 -0
  36. package/dist/cache/__tests__/dynamodb-nonce-cache.test.d.ts +4 -0
  37. package/dist/cache/__tests__/dynamodb-nonce-cache.test.js +176 -0
  38. package/dist/cache/__tests__/memory-nonce-cache.test.d.ts +4 -0
  39. package/dist/cache/__tests__/memory-nonce-cache.test.js +132 -0
  40. package/dist/cache/__tests__/nonce-cache-factory-simple.test.d.ts +4 -0
  41. package/dist/cache/__tests__/nonce-cache-factory-simple.test.js +133 -0
  42. package/dist/cache/__tests__/nonce-cache-factory.test.d.ts +4 -0
  43. package/dist/cache/__tests__/nonce-cache-factory.test.js +252 -0
  44. package/dist/cache/__tests__/redis-nonce-cache.test.d.ts +4 -0
  45. package/dist/cache/__tests__/redis-nonce-cache.test.js +95 -0
  46. package/dist/cache/cloudflare-kv-nonce-cache.d.ts +14 -0
  47. package/dist/cache/cloudflare-kv-nonce-cache.js +93 -0
  48. package/dist/cache/dynamodb-nonce-cache.d.ts +15 -0
  49. package/dist/cache/dynamodb-nonce-cache.js +92 -0
  50. package/dist/cache/index.d.ts +16 -0
  51. package/dist/cache/index.js +32 -0
  52. package/dist/cache/memory-nonce-cache.d.ts +44 -0
  53. package/dist/cache/memory-nonce-cache.js +105 -0
  54. package/dist/cache/nonce-cache-factory.d.ts +20 -0
  55. package/dist/cache/nonce-cache-factory.js +208 -0
  56. package/dist/cache/redis-nonce-cache.d.ts +14 -0
  57. package/dist/cache/redis-nonce-cache.js +53 -0
  58. package/dist/compiler/compiler-context.d.ts +23 -0
  59. package/dist/compiler/compiler-context.js +24 -0
  60. package/dist/compiler/config/constants.d.ts +41 -0
  61. package/dist/compiler/config/constants.js +45 -0
  62. package/dist/compiler/config/index.d.ts +252 -0
  63. package/dist/compiler/config/index.js +15 -0
  64. package/dist/compiler/config/injection.d.ts +26 -0
  65. package/dist/compiler/config/injection.js +58 -0
  66. package/dist/compiler/config/schemas/experimental/index.d.ts +91 -0
  67. package/dist/compiler/config/schemas/experimental/index.js +16 -0
  68. package/dist/compiler/config/schemas/experimental/oauth.d.ts +74 -0
  69. package/dist/compiler/config/schemas/experimental/oauth.js +25 -0
  70. package/dist/compiler/config/schemas/index.d.ts +6 -0
  71. package/dist/compiler/config/schemas/index.js +17 -0
  72. package/dist/compiler/config/schemas/paths.d.ts +9 -0
  73. package/dist/compiler/config/schemas/paths.js +12 -0
  74. package/dist/compiler/config/schemas/transport/http.d.ts +82 -0
  75. package/dist/compiler/config/schemas/transport/http.js +33 -0
  76. package/dist/compiler/config/schemas/transport/stdio.d.ts +9 -0
  77. package/dist/compiler/config/schemas/transport/stdio.js +15 -0
  78. package/dist/compiler/config/schemas/webpack.d.ts +3 -0
  79. package/dist/compiler/config/schemas/webpack.js +15 -0
  80. package/dist/compiler/config/types.d.ts +1 -0
  81. package/dist/compiler/config/types.js +2 -0
  82. package/dist/compiler/config/utils.d.ts +20 -0
  83. package/dist/compiler/config/utils.js +36 -0
  84. package/dist/compiler/generate-env-code.d.ts +1 -0
  85. package/dist/compiler/generate-env-code.js +8 -0
  86. package/dist/compiler/generate-import-code.d.ts +1 -0
  87. package/dist/compiler/generate-import-code.js +24 -0
  88. package/dist/compiler/get-webpack-config/get-entries.d.ts +3 -0
  89. package/dist/compiler/get-webpack-config/get-entries.js +29 -0
  90. package/dist/compiler/get-webpack-config/get-externals.d.ts +7 -0
  91. package/dist/compiler/get-webpack-config/get-externals.js +88 -0
  92. package/dist/compiler/get-webpack-config/get-injected-variables.d.ts +8 -0
  93. package/dist/compiler/get-webpack-config/get-injected-variables.js +25 -0
  94. package/dist/compiler/get-webpack-config/index.d.ts +4 -0
  95. package/dist/compiler/get-webpack-config/index.js +101 -0
  96. package/dist/compiler/get-webpack-config/plugins.d.ts +8 -0
  97. package/dist/compiler/get-webpack-config/plugins.js +132 -0
  98. package/dist/compiler/get-webpack-config/resolve-tsconfig-paths.d.ts +9 -0
  99. package/dist/compiler/get-webpack-config/resolve-tsconfig-paths.js +40 -0
  100. package/dist/compiler/index.d.ts +6 -0
  101. package/dist/compiler/index.js +194 -0
  102. package/dist/compiler/on-first-build.d.ts +3 -0
  103. package/dist/compiler/on-first-build.js +58 -0
  104. package/dist/compiler/parse-xmcp-config.d.ts +9 -0
  105. package/dist/compiler/parse-xmcp-config.js +155 -0
  106. package/dist/compiler/start-http-server.d.ts +1 -0
  107. package/dist/compiler/start-http-server.js +34 -0
  108. package/dist/index.d.ts +12 -54
  109. package/dist/index.js +22 -190
  110. package/dist/index.js.LICENSE.txt +49 -0
  111. package/dist/runtime/__tests__/audit.test.d.ts +4 -0
  112. package/dist/runtime/__tests__/audit.test.js +328 -0
  113. package/dist/runtime/__tests__/identity.test.d.ts +4 -0
  114. package/dist/runtime/__tests__/identity.test.js +164 -0
  115. package/dist/runtime/__tests__/mcpi-runtime.test.d.ts +4 -0
  116. package/dist/runtime/__tests__/mcpi-runtime.test.js +372 -0
  117. package/dist/runtime/__tests__/proof.test.d.ts +4 -0
  118. package/dist/runtime/__tests__/proof.test.js +302 -0
  119. package/dist/runtime/__tests__/session.test.d.ts +4 -0
  120. package/dist/runtime/__tests__/session.test.js +254 -0
  121. package/dist/runtime/__tests__/well-known.test.d.ts +4 -0
  122. package/dist/runtime/__tests__/well-known.test.js +312 -0
  123. package/dist/runtime/adapter-express.js +2 -0
  124. package/dist/runtime/adapter-express.js.LICENSE.txt +252 -0
  125. package/dist/runtime/adapter-nextjs.js +2 -0
  126. package/dist/runtime/adapter-nextjs.js.LICENSE.txt +53 -0
  127. package/dist/runtime/adapters/express/index.d.ts +2 -0
  128. package/dist/runtime/adapters/express/index.js +48 -0
  129. package/dist/runtime/adapters/nextjs/index.d.ts +8 -0
  130. package/dist/runtime/adapters/nextjs/index.js +18 -0
  131. package/dist/runtime/audit.d.ts +93 -0
  132. package/dist/runtime/audit.js +212 -0
  133. package/dist/runtime/debug.d.ts +118 -0
  134. package/dist/runtime/debug.js +612 -0
  135. package/dist/runtime/delegation-hooks.d.ts +85 -0
  136. package/dist/runtime/delegation-hooks.js +116 -0
  137. package/dist/runtime/demo.d.ts +71 -0
  138. package/dist/runtime/demo.js +135 -0
  139. package/dist/runtime/headers.d.ts +1 -0
  140. package/dist/runtime/headers.js +9 -0
  141. package/dist/runtime/http.js +2 -0
  142. package/dist/runtime/http.js.LICENSE.txt +252 -0
  143. package/dist/runtime/identity.d.ts +105 -0
  144. package/dist/runtime/identity.js +232 -0
  145. package/dist/runtime/index.d.ts +16 -0
  146. package/dist/runtime/index.js +56 -0
  147. package/dist/runtime/mcpi-runtime.d.ts +164 -0
  148. package/dist/runtime/mcpi-runtime.js +352 -0
  149. package/dist/runtime/proof.d.ts +87 -0
  150. package/dist/runtime/proof.js +223 -0
  151. package/dist/runtime/session.d.ts +88 -0
  152. package/dist/runtime/session.js +216 -0
  153. package/dist/runtime/stdio.js +2 -0
  154. package/dist/runtime/stdio.js.LICENSE.txt +1 -0
  155. package/dist/runtime/templates/home.d.ts +2 -0
  156. package/dist/runtime/templates/home.js +50 -0
  157. package/dist/runtime/transports/http/base-streamable-http.d.ts +25 -0
  158. package/dist/runtime/transports/http/base-streamable-http.js +16 -0
  159. package/dist/runtime/transports/http/http-context.d.ts +9 -0
  160. package/dist/runtime/transports/http/http-context.js +8 -0
  161. package/dist/runtime/transports/http/index.d.ts +1 -0
  162. package/dist/runtime/transports/http/index.js +55 -0
  163. package/dist/runtime/transports/http/setup-cors.d.ts +4 -0
  164. package/dist/runtime/transports/http/setup-cors.js +24 -0
  165. package/dist/runtime/transports/http/stateless-streamable-http.d.ts +39 -0
  166. package/dist/runtime/transports/http/stateless-streamable-http.js +331 -0
  167. package/dist/runtime/transports/stdio/index.d.ts +1 -0
  168. package/dist/runtime/transports/stdio/index.js +51 -0
  169. package/dist/runtime/utils/server.d.ts +42 -0
  170. package/dist/runtime/utils/server.js +39 -0
  171. package/dist/runtime/utils/tools.d.ts +8 -0
  172. package/dist/runtime/utils/tools.js +115 -0
  173. package/dist/runtime/verifier-middleware.d.ts +76 -0
  174. package/dist/runtime/verifier-middleware.js +322 -0
  175. package/dist/runtime/well-known.d.ts +151 -0
  176. package/dist/runtime/well-known.js +258 -0
  177. package/dist/storage/config.d.ts +28 -0
  178. package/dist/storage/config.js +79 -0
  179. package/dist/storage/delegation.d.ts +59 -0
  180. package/dist/storage/delegation.js +130 -0
  181. package/dist/storage/merkle-verifier.d.ts +84 -0
  182. package/dist/storage/merkle-verifier.js +261 -0
  183. package/dist/test/__tests__/nonce-cache-integration.test.d.ts +1 -0
  184. package/dist/test/__tests__/nonce-cache-integration.test.js +116 -0
  185. package/dist/test/__tests__/nonce-cache.test.d.ts +1 -0
  186. package/dist/test/__tests__/nonce-cache.test.js +122 -0
  187. package/dist/test/__tests__/runtime-integration.test.d.ts +4 -0
  188. package/dist/test/__tests__/runtime-integration.test.js +192 -0
  189. package/dist/test/__tests__/test-infrastructure.test.d.ts +4 -0
  190. package/dist/test/__tests__/test-infrastructure.test.js +178 -0
  191. package/dist/test/deterministic-keys.d.ts +31 -0
  192. package/dist/test/deterministic-keys.js +108 -0
  193. package/dist/test/examples/test-usage-example.d.ts +140 -0
  194. package/dist/test/examples/test-usage-example.js +175 -0
  195. package/dist/test/index.d.ts +11 -0
  196. package/dist/test/index.js +27 -0
  197. package/dist/test/local-verification.d.ts +28 -0
  198. package/dist/test/local-verification.js +342 -0
  199. package/dist/test/mock-identity-provider.d.ts +96 -0
  200. package/dist/test/mock-identity-provider.js +243 -0
  201. package/dist/test/runtime-integration.d.ts +63 -0
  202. package/dist/test/runtime-integration.js +140 -0
  203. package/dist/test/test-environment.d.ts +26 -0
  204. package/dist/test/test-environment.js +50 -0
  205. package/dist/types/declarations.d.ts +1 -0
  206. package/dist/types/declarations.js +6 -0
  207. package/dist/types/middleware.d.ts +2 -0
  208. package/dist/types/middleware.js +2 -0
  209. package/dist/types/tool.d.ts +80 -0
  210. package/dist/types/tool.js +2 -0
  211. package/dist/utils/cli-icons.d.ts +3 -0
  212. package/dist/utils/cli-icons.js +7 -0
  213. package/dist/utils/constants.d.ts +6 -0
  214. package/dist/utils/constants.js +13 -0
  215. package/dist/utils/context.d.ts +33 -0
  216. package/dist/utils/context.js +58 -0
  217. package/dist/utils/file-watcher.d.ts +19 -0
  218. package/dist/utils/file-watcher.js +49 -0
  219. package/dist/utils/fs-utils.d.ts +2 -0
  220. package/dist/utils/fs-utils.js +22 -0
  221. package/dist/utils/path-validation.d.ts +3 -0
  222. package/dist/utils/path-validation.js +56 -0
  223. package/dist/utils/spawn-process.d.ts +9 -0
  224. package/dist/utils/spawn-process.js +50 -0
  225. package/dist/utils/subscribable.d.ts +12 -0
  226. package/dist/utils/subscribable.js +44 -0
  227. package/package.json +99 -21
  228. package/dist/index.d.ts.map +0 -1
  229. package/dist/index.js.map +0 -1
@@ -0,0 +1,372 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for XMCP-I Runtime Integration
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const vitest_1 = require("vitest");
7
+ const mcpi_runtime_js_1 = require("../mcpi-runtime.js");
8
+ const fs_1 = require("fs");
9
+ const promises_1 = require("fs/promises");
10
+ (0, vitest_1.describe)("MCPIRuntime", () => {
11
+ let runtime;
12
+ let mockLogFunction;
13
+ (0, vitest_1.beforeEach)(async () => {
14
+ mockLogFunction = vitest_1.vi.fn();
15
+ // Mock console.log to avoid noise in tests
16
+ vitest_1.vi.spyOn(console, "log").mockImplementation(() => { });
17
+ vitest_1.vi.spyOn(console, "error").mockImplementation(() => { });
18
+ });
19
+ (0, vitest_1.afterEach)(async () => {
20
+ if (runtime) {
21
+ await runtime.cleanup();
22
+ }
23
+ // Cleanup test directory
24
+ try {
25
+ if ((0, fs_1.existsSync)(".test-mcpi")) {
26
+ await (0, promises_1.rmdir)(".test-mcpi", { recursive: true });
27
+ }
28
+ }
29
+ catch {
30
+ // Ignore cleanup errors
31
+ }
32
+ vitest_1.vi.restoreAllMocks();
33
+ });
34
+ (0, vitest_1.describe)("Runtime Initialization", () => {
35
+ (0, vitest_1.it)("should initialize successfully with default config", async () => {
36
+ runtime = new mcpi_runtime_js_1.MCPIRuntime({
37
+ identity: {
38
+ environment: "development",
39
+ devIdentityPath: ".test-mcpi/identity.json",
40
+ },
41
+ audit: {
42
+ logFunction: mockLogFunction,
43
+ },
44
+ });
45
+ await runtime.initialize();
46
+ const stats = runtime.getStats();
47
+ (0, vitest_1.expect)(stats.identity.did).toBeTruthy();
48
+ (0, vitest_1.expect)(stats.identity.keyId).toBeTruthy();
49
+ (0, vitest_1.expect)(stats.runtime.initialized).toBe(true);
50
+ });
51
+ (0, vitest_1.it)("should initialize with well-known endpoints", async () => {
52
+ runtime = new mcpi_runtime_js_1.MCPIRuntime({
53
+ identity: {
54
+ environment: "development",
55
+ devIdentityPath: ".test-mcpi/identity.json",
56
+ },
57
+ wellKnown: {
58
+ environment: "development",
59
+ baseUrl: "http://localhost:3000",
60
+ },
61
+ });
62
+ await runtime.initialize();
63
+ const stats = runtime.getStats();
64
+ (0, vitest_1.expect)(stats.runtime.wellKnownEnabled).toBe(true);
65
+ const handler = runtime.getWellKnownHandler();
66
+ (0, vitest_1.expect)(handler).toBeDefined();
67
+ (0, vitest_1.expect)(handler.handleDIDDocument).toBeTypeOf("function");
68
+ (0, vitest_1.expect)(handler.handleAgentDocument).toBeTypeOf("function");
69
+ });
70
+ (0, vitest_1.it)("should fail initialization without well-known config when accessing handler", async () => {
71
+ runtime = new mcpi_runtime_js_1.MCPIRuntime({
72
+ identity: {
73
+ environment: "development",
74
+ devIdentityPath: ".test-mcpi/identity.json",
75
+ },
76
+ });
77
+ await runtime.initialize();
78
+ (0, vitest_1.expect)(() => runtime.getWellKnownHandler()).toThrow("Well-known endpoints not configured");
79
+ });
80
+ });
81
+ (0, vitest_1.describe)("Handshake Validation", () => {
82
+ (0, vitest_1.beforeEach)(async () => {
83
+ runtime = new mcpi_runtime_js_1.MCPIRuntime({
84
+ identity: {
85
+ environment: "development",
86
+ devIdentityPath: ".test-mcpi/identity.json",
87
+ },
88
+ audit: {
89
+ logFunction: mockLogFunction,
90
+ },
91
+ });
92
+ await runtime.initialize();
93
+ });
94
+ (0, vitest_1.it)("should validate correct handshake", async () => {
95
+ const request = {
96
+ nonce: "test-nonce-123",
97
+ audience: "example.com",
98
+ timestamp: Math.floor(Date.now() / 1000),
99
+ };
100
+ const session = await runtime.validateHandshake(request);
101
+ (0, vitest_1.expect)(session).toBeTruthy();
102
+ (0, vitest_1.expect)(session.audience).toBe("example.com");
103
+ (0, vitest_1.expect)(session.nonce).toBe("test-nonce-123");
104
+ (0, vitest_1.expect)(session.sessionId).toMatch(/^sess_/);
105
+ });
106
+ (0, vitest_1.it)("should reject invalid handshake", async () => {
107
+ const request = {
108
+ nonce: "test-nonce-old",
109
+ audience: "example.com",
110
+ timestamp: Math.floor(Date.now() / 1000) - 200, // Too old
111
+ };
112
+ const session = await runtime.validateHandshake(request);
113
+ (0, vitest_1.expect)(session).toBeNull();
114
+ });
115
+ });
116
+ (0, vitest_1.describe)("Tool Call Processing", () => {
117
+ let mockSession;
118
+ (0, vitest_1.beforeEach)(async () => {
119
+ runtime = new mcpi_runtime_js_1.MCPIRuntime({
120
+ identity: {
121
+ environment: "development",
122
+ devIdentityPath: ".test-mcpi/identity.json",
123
+ },
124
+ audit: {
125
+ logFunction: mockLogFunction,
126
+ },
127
+ });
128
+ await runtime.initialize();
129
+ // Create a valid session
130
+ const handshakeRequest = {
131
+ nonce: "test-nonce-123",
132
+ audience: "example.com",
133
+ timestamp: Math.floor(Date.now() / 1000),
134
+ };
135
+ mockSession = await runtime.validateHandshake(handshakeRequest);
136
+ });
137
+ (0, vitest_1.it)("should process tool call with proof generation", async () => {
138
+ const toolRequest = {
139
+ method: "test-tool",
140
+ params: { input: "hello" },
141
+ };
142
+ const mockToolHandler = vitest_1.vi.fn().mockResolvedValue({ output: "world" });
143
+ const response = await runtime.processToolCall(toolRequest, mockSession, mockToolHandler);
144
+ (0, vitest_1.expect)(mockToolHandler).toHaveBeenCalledWith(toolRequest);
145
+ (0, vitest_1.expect)(response.data).toEqual({ output: "world" });
146
+ (0, vitest_1.expect)(response.meta?.proof).toBeDefined();
147
+ (0, vitest_1.expect)(response.meta?.proof?.meta.did).toBeTruthy();
148
+ (0, vitest_1.expect)(response.meta?.proof?.jws).toBeTruthy();
149
+ });
150
+ (0, vitest_1.it)("should include scope and delegation in proof", async () => {
151
+ const toolRequest = {
152
+ method: "test-tool",
153
+ params: { input: "hello" },
154
+ };
155
+ const mockToolHandler = vitest_1.vi.fn().mockResolvedValue({ output: "world" });
156
+ const response = await runtime.processToolCall(toolRequest, mockSession, mockToolHandler, {
157
+ scopeId: "orders.create",
158
+ delegationRef: "delegation-123",
159
+ });
160
+ (0, vitest_1.expect)(response.meta?.proof?.meta.scopeId).toBe("orders.create");
161
+ (0, vitest_1.expect)(response.meta?.proof?.meta.delegationRef).toBe("delegation-123");
162
+ });
163
+ (0, vitest_1.it)("should log audit record on tool call", async () => {
164
+ const toolRequest = {
165
+ method: "test-tool",
166
+ params: { input: "hello" },
167
+ };
168
+ const mockToolHandler = vitest_1.vi.fn().mockResolvedValue({ output: "world" });
169
+ await runtime.processToolCall(toolRequest, mockSession, mockToolHandler);
170
+ (0, vitest_1.expect)(mockLogFunction).toHaveBeenCalled();
171
+ const auditLine = mockLogFunction.mock.calls[0][0];
172
+ (0, vitest_1.expect)(auditLine).toContain("audit.v1");
173
+ (0, vitest_1.expect)(auditLine).toContain("verified=yes");
174
+ });
175
+ (0, vitest_1.it)("should handle tool call errors", async () => {
176
+ const toolRequest = {
177
+ method: "failing-tool",
178
+ params: { input: "hello" },
179
+ };
180
+ const mockToolHandler = vitest_1.vi
181
+ .fn()
182
+ .mockRejectedValue(new Error("Tool failed"));
183
+ await (0, vitest_1.expect)(runtime.processToolCall(toolRequest, mockSession, mockToolHandler)).rejects.toThrow("Tool failed");
184
+ // Should still log audit record with verified=no
185
+ (0, vitest_1.expect)(mockLogFunction).toHaveBeenCalled();
186
+ const auditLine = mockLogFunction.mock.calls[0][0];
187
+ (0, vitest_1.expect)(auditLine).toContain("verified=no");
188
+ });
189
+ (0, vitest_1.it)("should fail if runtime not initialized", async () => {
190
+ const uninitializedRuntime = new mcpi_runtime_js_1.MCPIRuntime();
191
+ const toolRequest = {
192
+ method: "test-tool",
193
+ params: { input: "hello" },
194
+ };
195
+ const mockToolHandler = vitest_1.vi.fn().mockResolvedValue({ output: "world" });
196
+ await (0, vitest_1.expect)(uninitializedRuntime.processToolCall(toolRequest, mockSession, mockToolHandler)).rejects.toThrow("Runtime not initialized");
197
+ });
198
+ });
199
+ (0, vitest_1.describe)("Runtime Statistics", () => {
200
+ (0, vitest_1.beforeEach)(async () => {
201
+ runtime = new mcpi_runtime_js_1.MCPIRuntime({
202
+ identity: {
203
+ environment: "development",
204
+ devIdentityPath: ".test-mcpi/identity.json",
205
+ },
206
+ wellKnown: {
207
+ environment: "development",
208
+ baseUrl: "http://localhost:3000",
209
+ },
210
+ });
211
+ await runtime.initialize();
212
+ });
213
+ (0, vitest_1.it)("should provide comprehensive statistics", () => {
214
+ const stats = runtime.getStats();
215
+ (0, vitest_1.expect)(stats.identity.did).toBeTruthy();
216
+ (0, vitest_1.expect)(stats.identity.keyId).toBeTruthy();
217
+ (0, vitest_1.expect)(stats.identity.environment).toBe("development");
218
+ (0, vitest_1.expect)(stats.session.activeSessions).toBe(0);
219
+ (0, vitest_1.expect)(stats.audit.enabled).toBe(true);
220
+ (0, vitest_1.expect)(stats.runtime.initialized).toBe(true);
221
+ (0, vitest_1.expect)(stats.runtime.wellKnownEnabled).toBe(true);
222
+ });
223
+ });
224
+ (0, vitest_1.describe)("Runtime Environment Checks", () => {
225
+ (0, vitest_1.it)("should pass environment checks in Node.js ≥18.18", async () => {
226
+ // This test runs in Node.js, so it should pass
227
+ runtime = new mcpi_runtime_js_1.MCPIRuntime({
228
+ identity: {
229
+ environment: "development",
230
+ devIdentityPath: ".test-mcpi/identity.json",
231
+ },
232
+ });
233
+ await (0, vitest_1.expect)(runtime.initialize()).resolves.not.toThrow();
234
+ });
235
+ (0, vitest_1.it)("should detect Node.js environment", async () => {
236
+ runtime = new mcpi_runtime_js_1.MCPIRuntime({
237
+ identity: {
238
+ environment: "development",
239
+ devIdentityPath: ".test-mcpi/identity.json",
240
+ },
241
+ });
242
+ await runtime.initialize();
243
+ const stats = runtime.getStats();
244
+ (0, vitest_1.expect)(stats.runtime.initialized).toBe(true);
245
+ });
246
+ });
247
+ });
248
+ (0, vitest_1.describe)("Runtime Factory", () => {
249
+ let runtime;
250
+ (0, vitest_1.afterEach)(async () => {
251
+ if (runtime) {
252
+ await runtime.cleanup();
253
+ }
254
+ // Cleanup test directory
255
+ try {
256
+ if ((0, fs_1.existsSync)(".test-mcpi")) {
257
+ await (0, promises_1.rmdir)(".test-mcpi", { recursive: true });
258
+ }
259
+ }
260
+ catch {
261
+ // Ignore cleanup errors
262
+ }
263
+ });
264
+ (0, vitest_1.beforeEach)(() => {
265
+ // Mock console.log to avoid noise in tests
266
+ vitest_1.vi.spyOn(console, "log").mockImplementation(() => { });
267
+ vitest_1.vi.spyOn(console, "error").mockImplementation(() => { });
268
+ });
269
+ (0, vitest_1.afterEach)(() => {
270
+ vitest_1.vi.restoreAllMocks();
271
+ });
272
+ (0, vitest_1.describe)("forDevelopment", () => {
273
+ (0, vitest_1.it)("should create development runtime", async () => {
274
+ runtime = await mcpi_runtime_js_1.RuntimeFactory.forDevelopment({
275
+ identity: {
276
+ devIdentityPath: ".test-mcpi/identity.json",
277
+ },
278
+ });
279
+ const stats = runtime.getStats();
280
+ (0, vitest_1.expect)(stats.identity.environment).toBe("development");
281
+ (0, vitest_1.expect)(stats.runtime.initialized).toBe(true);
282
+ });
283
+ (0, vitest_1.it)("should enable verify link in development", async () => {
284
+ runtime = await mcpi_runtime_js_1.RuntimeFactory.forDevelopment({
285
+ identity: {
286
+ devIdentityPath: ".test-mcpi/identity.json",
287
+ },
288
+ });
289
+ // Should not throw and should be initialized
290
+ (0, vitest_1.expect)(runtime.getStats().runtime.initialized).toBe(true);
291
+ });
292
+ });
293
+ (0, vitest_1.describe)("forProduction", () => {
294
+ (0, vitest_1.it)("should create production runtime with env vars", async () => {
295
+ // Mock production environment variables
296
+ const originalEnv = process.env;
297
+ process.env.AGENT_PRIVATE_KEY = Buffer.from("test-private-key-32-bytes-long!!").toString("base64");
298
+ process.env.AGENT_KEY_ID = "key-prod-123";
299
+ process.env.AGENT_DID = "did:web:example.com:agents:prod-agent";
300
+ process.env.KYA_VOUCHED_API_KEY = "test-api-key";
301
+ try {
302
+ runtime = await mcpi_runtime_js_1.RuntimeFactory.forProduction();
303
+ const stats = runtime.getStats();
304
+ (0, vitest_1.expect)(stats.identity.environment).toBe("production");
305
+ (0, vitest_1.expect)(stats.identity.did).toBe("did:web:example.com:agents:prod-agent");
306
+ (0, vitest_1.expect)(stats.runtime.initialized).toBe(true);
307
+ }
308
+ finally {
309
+ // Restore environment
310
+ process.env = originalEnv;
311
+ }
312
+ });
313
+ });
314
+ (0, vitest_1.describe)("forTesting", () => {
315
+ (0, vitest_1.it)("should create testing runtime", async () => {
316
+ runtime = await mcpi_runtime_js_1.RuntimeFactory.forTesting();
317
+ const stats = runtime.getStats();
318
+ (0, vitest_1.expect)(stats.identity.environment).toBe("development");
319
+ (0, vitest_1.expect)(stats.audit.enabled).toBe(false); // Disabled in tests
320
+ (0, vitest_1.expect)(stats.runtime.initialized).toBe(true);
321
+ });
322
+ (0, vitest_1.it)("should use test identity path", async () => {
323
+ runtime = await mcpi_runtime_js_1.RuntimeFactory.forTesting();
324
+ // Should be initialized without errors
325
+ (0, vitest_1.expect)(runtime.getStats().runtime.initialized).toBe(true);
326
+ });
327
+ });
328
+ });
329
+ (0, vitest_1.describe)("createMCPIRuntime", () => {
330
+ let runtime;
331
+ (0, vitest_1.afterEach)(async () => {
332
+ if (runtime) {
333
+ await runtime.cleanup();
334
+ }
335
+ // Cleanup test directory
336
+ try {
337
+ if ((0, fs_1.existsSync)(".test-mcpi")) {
338
+ await (0, promises_1.rmdir)(".test-mcpi", { recursive: true });
339
+ }
340
+ }
341
+ catch {
342
+ // Ignore cleanup errors
343
+ }
344
+ });
345
+ (0, vitest_1.beforeEach)(() => {
346
+ // Mock console.log to avoid noise in tests
347
+ vitest_1.vi.spyOn(console, "log").mockImplementation(() => { });
348
+ });
349
+ (0, vitest_1.afterEach)(() => {
350
+ vitest_1.vi.restoreAllMocks();
351
+ });
352
+ (0, vitest_1.it)("should create and initialize runtime", async () => {
353
+ runtime = await (0, mcpi_runtime_js_1.createMCPIRuntime)({
354
+ identity: {
355
+ environment: "development",
356
+ devIdentityPath: ".test-mcpi/identity.json",
357
+ },
358
+ });
359
+ (0, vitest_1.expect)(runtime.getStats().runtime.initialized).toBe(true);
360
+ });
361
+ (0, vitest_1.it)("should create runtime with minimal config", async () => {
362
+ runtime = await (0, mcpi_runtime_js_1.createMCPIRuntime)({
363
+ identity: {
364
+ environment: "development",
365
+ devIdentityPath: ".test-mcpi/identity.json",
366
+ },
367
+ });
368
+ const stats = runtime.getStats();
369
+ (0, vitest_1.expect)(stats.runtime.initialized).toBe(true);
370
+ (0, vitest_1.expect)(stats.identity.did).toBeTruthy();
371
+ });
372
+ });
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tests for Detached Proof Generation
3
+ */
4
+ export {};
@@ -0,0 +1,302 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for Detached Proof Generation
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const vitest_1 = require("vitest");
7
+ const proof_js_1 = require("../proof.js");
8
+ (0, vitest_1.describe)("ProofGenerator", () => {
9
+ let proofGenerator;
10
+ let mockIdentity;
11
+ let mockSession;
12
+ (0, vitest_1.beforeEach)(() => {
13
+ // Create mock identity with test keys
14
+ mockIdentity = {
15
+ did: "did:web:example.com:agents:test-agent",
16
+ keyId: "key-test-123",
17
+ privateKey: Buffer.from("test-private-key-32-bytes-long!!").toString("base64"),
18
+ publicKey: Buffer.from("test-public-key-32-bytes-long!!!").toString("base64"),
19
+ createdAt: new Date().toISOString(),
20
+ };
21
+ // Create mock session
22
+ mockSession = {
23
+ sessionId: "sess_test_123",
24
+ audience: "example.com",
25
+ nonce: "test-nonce-456",
26
+ timestamp: Math.floor(Date.now() / 1000),
27
+ createdAt: Math.floor(Date.now() / 1000),
28
+ lastActivity: Math.floor(Date.now() / 1000),
29
+ ttlMinutes: 30,
30
+ };
31
+ proofGenerator = new proof_js_1.ProofGenerator(mockIdentity);
32
+ });
33
+ (0, vitest_1.describe)("Canonical Hash Generation", () => {
34
+ (0, vitest_1.it)("should generate consistent hashes for same request/response", async () => {
35
+ const request = {
36
+ method: "test-tool",
37
+ params: { input: "hello" },
38
+ };
39
+ const response = {
40
+ data: { output: "world" },
41
+ };
42
+ const proof1 = await proofGenerator.generateProof(request, response, mockSession);
43
+ const proof2 = await proofGenerator.generateProof(request, response, mockSession);
44
+ // Hashes should be identical for same input
45
+ (0, vitest_1.expect)(proof1.meta.requestHash).toBe(proof2.meta.requestHash);
46
+ (0, vitest_1.expect)(proof1.meta.responseHash).toBe(proof2.meta.responseHash);
47
+ });
48
+ (0, vitest_1.it)("should generate different hashes for different requests", async () => {
49
+ const request1 = {
50
+ method: "test-tool",
51
+ params: { input: "hello" },
52
+ };
53
+ const request2 = {
54
+ method: "test-tool",
55
+ params: { input: "goodbye" },
56
+ };
57
+ const response = {
58
+ data: { output: "world" },
59
+ };
60
+ const proof1 = await proofGenerator.generateProof(request1, response, mockSession);
61
+ const proof2 = await proofGenerator.generateProof(request2, response, mockSession);
62
+ (0, vitest_1.expect)(proof1.meta.requestHash).not.toBe(proof2.meta.requestHash);
63
+ (0, vitest_1.expect)(proof1.meta.responseHash).toBe(proof2.meta.responseHash); // Same response
64
+ });
65
+ (0, vitest_1.it)("should generate different hashes for different responses", async () => {
66
+ const request = {
67
+ method: "test-tool",
68
+ params: { input: "hello" },
69
+ };
70
+ const response1 = {
71
+ data: { output: "world" },
72
+ };
73
+ const response2 = {
74
+ data: { output: "universe" },
75
+ };
76
+ const proof1 = await proofGenerator.generateProof(request, response1, mockSession);
77
+ const proof2 = await proofGenerator.generateProof(request, response2, mockSession);
78
+ (0, vitest_1.expect)(proof1.meta.requestHash).toBe(proof2.meta.requestHash); // Same request
79
+ (0, vitest_1.expect)(proof1.meta.responseHash).not.toBe(proof2.meta.responseHash);
80
+ });
81
+ (0, vitest_1.it)("should generate SHA-256 hashes with correct format", async () => {
82
+ const request = {
83
+ method: "test-tool",
84
+ params: { input: "hello" },
85
+ };
86
+ const response = {
87
+ data: { output: "world" },
88
+ };
89
+ const proof = await proofGenerator.generateProof(request, response, mockSession);
90
+ (0, vitest_1.expect)(proof.meta.requestHash).toMatch(/^sha256:[a-f0-9]{64}$/);
91
+ (0, vitest_1.expect)(proof.meta.responseHash).toMatch(/^sha256:[a-f0-9]{64}$/);
92
+ });
93
+ (0, vitest_1.it)("should handle requests without params", async () => {
94
+ const request = {
95
+ method: "simple-tool",
96
+ };
97
+ const response = {
98
+ data: { result: "success" },
99
+ };
100
+ const proof = await proofGenerator.generateProof(request, response, mockSession);
101
+ (0, vitest_1.expect)(proof.meta.requestHash).toMatch(/^sha256:[a-f0-9]{64}$/);
102
+ (0, vitest_1.expect)(proof.meta.responseHash).toMatch(/^sha256:[a-f0-9]{64}$/);
103
+ });
104
+ });
105
+ (0, vitest_1.describe)("Proof Metadata", () => {
106
+ (0, vitest_1.it)("should include all required metadata fields", async () => {
107
+ const request = {
108
+ method: "test-tool",
109
+ params: { input: "hello" },
110
+ };
111
+ const response = {
112
+ data: { output: "world" },
113
+ };
114
+ const proof = await proofGenerator.generateProof(request, response, mockSession);
115
+ (0, vitest_1.expect)(proof.meta.did).toBe(mockIdentity.did);
116
+ (0, vitest_1.expect)(proof.meta.kid).toBe(mockIdentity.keyId);
117
+ (0, vitest_1.expect)(proof.meta.ts).toBeTypeOf("number");
118
+ (0, vitest_1.expect)(proof.meta.nonce).toBe(mockSession.nonce);
119
+ (0, vitest_1.expect)(proof.meta.audience).toBe(mockSession.audience);
120
+ (0, vitest_1.expect)(proof.meta.sessionId).toBe(mockSession.sessionId);
121
+ (0, vitest_1.expect)(proof.meta.requestHash).toBeTruthy();
122
+ (0, vitest_1.expect)(proof.meta.responseHash).toBeTruthy();
123
+ });
124
+ (0, vitest_1.it)("should include optional fields when provided", async () => {
125
+ const request = {
126
+ method: "test-tool",
127
+ params: { input: "hello" },
128
+ };
129
+ const response = {
130
+ data: { output: "world" },
131
+ };
132
+ const options = {
133
+ scopeId: "orders.create",
134
+ delegationRef: "delegation-ref-123",
135
+ };
136
+ const proof = await proofGenerator.generateProof(request, response, mockSession, options);
137
+ (0, vitest_1.expect)(proof.meta.scopeId).toBe("orders.create");
138
+ (0, vitest_1.expect)(proof.meta.delegationRef).toBe("delegation-ref-123");
139
+ });
140
+ (0, vitest_1.it)("should bind request and response hashes to same session", async () => {
141
+ const request = {
142
+ method: "test-tool",
143
+ params: { input: "hello" },
144
+ };
145
+ const response = {
146
+ data: { output: "world" },
147
+ };
148
+ const proof = await proofGenerator.generateProof(request, response, mockSession);
149
+ // Both hashes should be bound to the same session and audience
150
+ (0, vitest_1.expect)(proof.meta.sessionId).toBe(mockSession.sessionId);
151
+ (0, vitest_1.expect)(proof.meta.audience).toBe(mockSession.audience);
152
+ (0, vitest_1.expect)(proof.meta.nonce).toBe(mockSession.nonce);
153
+ });
154
+ });
155
+ (0, vitest_1.describe)("Detached JWS Generation", () => {
156
+ (0, vitest_1.it)("should generate detached JWS in correct format", async () => {
157
+ const request = {
158
+ method: "test-tool",
159
+ params: { input: "hello" },
160
+ };
161
+ const response = {
162
+ data: { output: "world" },
163
+ };
164
+ const proof = await proofGenerator.generateProof(request, response, mockSession);
165
+ // Detached JWS should have format: header..signature (empty payload)
166
+ const jwsParts = proof.jws.split(".");
167
+ (0, vitest_1.expect)(jwsParts).toHaveLength(3);
168
+ (0, vitest_1.expect)(jwsParts[1]).toBe(""); // Empty payload for detached format
169
+ (0, vitest_1.expect)(jwsParts[0]).toBeTruthy(); // Header should exist
170
+ (0, vitest_1.expect)(jwsParts[2]).toBeTruthy(); // Signature should exist
171
+ });
172
+ (0, vitest_1.it)("should use EdDSA algorithm", async () => {
173
+ const request = {
174
+ method: "test-tool",
175
+ params: { input: "hello" },
176
+ };
177
+ const response = {
178
+ data: { output: "world" },
179
+ };
180
+ const proof = await proofGenerator.generateProof(request, response, mockSession);
181
+ // Decode header to check algorithm
182
+ const [headerB64] = proof.jws.split(".");
183
+ const header = JSON.parse(Buffer.from(headerB64, "base64url").toString());
184
+ (0, vitest_1.expect)(header.alg).toBe("EdDSA");
185
+ (0, vitest_1.expect)(header.kid).toBe(mockIdentity.keyId);
186
+ });
187
+ });
188
+ (0, vitest_1.describe)("Proof Verification", () => {
189
+ (0, vitest_1.it)("should verify valid proof structure", async () => {
190
+ const request = {
191
+ method: "test-tool",
192
+ params: { input: "hello" },
193
+ };
194
+ const response = {
195
+ data: { output: "world" },
196
+ };
197
+ const proof = await proofGenerator.generateProof(request, response, mockSession);
198
+ const isValid = await proofGenerator.verifyProof(proof, request, response);
199
+ (0, vitest_1.expect)(isValid).toBe(true);
200
+ });
201
+ (0, vitest_1.it)("should reject proof with mismatched request", async () => {
202
+ const request1 = {
203
+ method: "test-tool",
204
+ params: { input: "hello" },
205
+ };
206
+ const request2 = {
207
+ method: "test-tool",
208
+ params: { input: "goodbye" },
209
+ };
210
+ const response = {
211
+ data: { output: "world" },
212
+ };
213
+ const proof = await proofGenerator.generateProof(request1, response, mockSession);
214
+ const isValid = await proofGenerator.verifyProof(proof, request2, response);
215
+ (0, vitest_1.expect)(isValid).toBe(false);
216
+ });
217
+ (0, vitest_1.it)("should reject proof with mismatched response", async () => {
218
+ const request = {
219
+ method: "test-tool",
220
+ params: { input: "hello" },
221
+ };
222
+ const response1 = {
223
+ data: { output: "world" },
224
+ };
225
+ const response2 = {
226
+ data: { output: "universe" },
227
+ };
228
+ const proof = await proofGenerator.generateProof(request, response1, mockSession);
229
+ const isValid = await proofGenerator.verifyProof(proof, request, response2);
230
+ (0, vitest_1.expect)(isValid).toBe(false);
231
+ });
232
+ });
233
+ (0, vitest_1.describe)("JSON Canonicalization", () => {
234
+ (0, vitest_1.it)("should canonicalize objects with sorted keys", () => {
235
+ const canonical = (0, proof_js_1.extractCanonicalData)({ method: "test", params: { b: 2, a: 1 } }, { data: { z: 26, a: 1 } });
236
+ // Keys should be sorted in canonical form
237
+ (0, vitest_1.expect)(canonical.request).toEqual({
238
+ method: "test",
239
+ params: { b: 2, a: 1 },
240
+ });
241
+ (0, vitest_1.expect)(canonical.response).toEqual({ z: 26, a: 1 });
242
+ });
243
+ (0, vitest_1.it)("should handle nested objects and arrays", () => {
244
+ const canonical = (0, proof_js_1.extractCanonicalData)({
245
+ method: "complex-tool",
246
+ params: {
247
+ nested: { c: 3, a: 1 },
248
+ array: [3, 1, 2],
249
+ },
250
+ }, { data: { result: [{ b: 2, a: 1 }] } });
251
+ (0, vitest_1.expect)(canonical.request.params.nested).toEqual({ c: 3, a: 1 });
252
+ (0, vitest_1.expect)(canonical.request.params.array).toEqual([3, 1, 2]);
253
+ (0, vitest_1.expect)(canonical.response.result).toEqual([{ b: 2, a: 1 }]);
254
+ });
255
+ });
256
+ });
257
+ (0, vitest_1.describe)("Utility Functions", () => {
258
+ let mockIdentity;
259
+ let mockSession;
260
+ (0, vitest_1.beforeEach)(() => {
261
+ mockIdentity = {
262
+ did: "did:web:example.com:agents:test-agent",
263
+ keyId: "key-test-123",
264
+ privateKey: Buffer.from("test-private-key-32-bytes-long!!").toString("base64"),
265
+ publicKey: Buffer.from("test-public-key-32-bytes-long!!!").toString("base64"),
266
+ createdAt: new Date().toISOString(),
267
+ };
268
+ mockSession = {
269
+ sessionId: "sess_test_123",
270
+ audience: "example.com",
271
+ nonce: "test-nonce-456",
272
+ timestamp: Math.floor(Date.now() / 1000),
273
+ createdAt: Math.floor(Date.now() / 1000),
274
+ lastActivity: Math.floor(Date.now() / 1000),
275
+ ttlMinutes: 30,
276
+ };
277
+ });
278
+ (0, vitest_1.describe)("createProofResponse", () => {
279
+ (0, vitest_1.it)("should create response with proof metadata", async () => {
280
+ const request = {
281
+ method: "test-tool",
282
+ params: { input: "hello" },
283
+ };
284
+ const data = { output: "world" };
285
+ const response = await (0, proof_js_1.createProofResponse)(request, data, mockIdentity, mockSession);
286
+ (0, vitest_1.expect)(response.data).toEqual(data);
287
+ (0, vitest_1.expect)(response.meta?.proof).toBeDefined();
288
+ (0, vitest_1.expect)(response.meta?.proof?.meta.did).toBe(mockIdentity.did);
289
+ (0, vitest_1.expect)(response.meta?.proof?.jws).toBeTruthy();
290
+ });
291
+ (0, vitest_1.it)("should include optional proof options", async () => {
292
+ const request = {
293
+ method: "test-tool",
294
+ params: { input: "hello" },
295
+ };
296
+ const data = { output: "world" };
297
+ const options = { scopeId: "orders.create" };
298
+ const response = await (0, proof_js_1.createProofResponse)(request, data, mockIdentity, mockSession, options);
299
+ (0, vitest_1.expect)(response.meta?.proof?.meta.scopeId).toBe("orders.create");
300
+ });
301
+ });
302
+ });
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tests for Session Management System
3
+ */
4
+ export {};