@kya-os/create-mcpi-app 1.7.38-canary.1 → 1.7.38

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 (67) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test$colon$coverage.log +755 -0
  3. package/.turbo/turbo-test.log +200 -0
  4. package/dist/helpers/fetch-cloudflare-mcpi-template.d.ts.map +1 -1
  5. package/dist/helpers/fetch-cloudflare-mcpi-template.js +43 -912
  6. package/dist/helpers/fetch-cloudflare-mcpi-template.js.map +1 -1
  7. package/dist/utils/fetch-remote-config.d.ts.map +1 -1
  8. package/dist/utils/fetch-remote-config.js +2 -2
  9. package/dist/utils/fetch-remote-config.js.map +1 -1
  10. package/package/package.json +77 -0
  11. package/package.json +1 -1
  12. package/ARCHITECTURE_ANALYSIS.md +0 -392
  13. package/CHANGELOG.md +0 -372
  14. package/DEPRECATION_WARNINGS_ANALYSIS.md +0 -192
  15. package/IMPLEMENTATION_SUMMARY.md +0 -108
  16. package/REMEDIATION_PLAN.md +0 -99
  17. package/dist/.tsbuildinfo +0 -1
  18. package/scripts/prepare-pack.js +0 -47
  19. package/scripts/validate-no-workspace.js +0 -79
  20. package/src/__tests__/cloudflare-template.test.ts +0 -490
  21. package/src/__tests__/helpers/fetch-cloudflare-mcpi-template.test.ts +0 -337
  22. package/src/__tests__/helpers/generate-config.test.ts +0 -312
  23. package/src/__tests__/helpers/generate-identity.test.ts +0 -271
  24. package/src/__tests__/helpers/install.test.ts +0 -370
  25. package/src/__tests__/helpers/validate-project-structure.test.ts +0 -467
  26. package/src/__tests__.bak/regression.test.ts +0 -434
  27. package/src/effects/index.ts +0 -80
  28. package/src/helpers/__tests__/config-builder.spec.ts +0 -231
  29. package/src/helpers/apply-identity-preset.ts +0 -209
  30. package/src/helpers/config-builder.ts +0 -165
  31. package/src/helpers/copy-template.ts +0 -11
  32. package/src/helpers/create.ts +0 -239
  33. package/src/helpers/fetch-cloudflare-mcpi-template.ts +0 -2393
  34. package/src/helpers/fetch-cloudflare-template.ts +0 -361
  35. package/src/helpers/fetch-mcpi-template.ts +0 -236
  36. package/src/helpers/fetch-xmcp-template.ts +0 -153
  37. package/src/helpers/generate-config.ts +0 -118
  38. package/src/helpers/generate-identity.ts +0 -163
  39. package/src/helpers/identity-manager.ts +0 -186
  40. package/src/helpers/install.ts +0 -79
  41. package/src/helpers/rename.ts +0 -17
  42. package/src/helpers/validate-project-structure.ts +0 -127
  43. package/src/index.ts +0 -520
  44. package/src/utils/__tests__/fetch-remote-config.test.ts +0 -271
  45. package/src/utils/check-node.ts +0 -17
  46. package/src/utils/fetch-remote-config.ts +0 -179
  47. package/src/utils/is-folder-empty.ts +0 -60
  48. package/src/utils/validate-project-name.ts +0 -132
  49. package/test-cloudflare/README.md +0 -164
  50. package/test-cloudflare/package.json +0 -28
  51. package/test-cloudflare/src/index.ts +0 -341
  52. package/test-cloudflare/src/tools/greet.ts +0 -19
  53. package/test-cloudflare/tests/cache-invalidation.test.ts +0 -410
  54. package/test-cloudflare/tests/cors-security.test.ts +0 -349
  55. package/test-cloudflare/tests/delegation.test.ts +0 -335
  56. package/test-cloudflare/tests/do-routing.test.ts +0 -314
  57. package/test-cloudflare/tests/integration.test.ts +0 -205
  58. package/test-cloudflare/tests/session-management.test.ts +0 -359
  59. package/test-cloudflare/tsconfig.json +0 -16
  60. package/test-cloudflare/vitest.config.ts +0 -9
  61. package/test-cloudflare/wrangler.toml +0 -37
  62. package/test-node/README.md +0 -44
  63. package/test-node/package.json +0 -23
  64. package/test-node/src/tools/greet.ts +0 -25
  65. package/test-node/xmcp.config.ts +0 -20
  66. package/tsconfig.json +0 -26
  67. package/vitest.config.ts +0 -14
@@ -1,314 +0,0 @@
1
- import { describe, test, expect, beforeEach } from 'vitest';
2
-
3
- /**
4
- * Durable Object Routing Tests
5
- * Tests the multi-instance DO routing for horizontal scaling
6
- */
7
- describe('Durable Object Multi-Instance Routing', () => {
8
-
9
- // Mock the getDoInstanceId function
10
- function getDoInstanceId(request: Request, env: any): string {
11
- const strategy = env.DO_ROUTING_STRATEGY || 'session';
12
- const headers = request.headers;
13
-
14
- switch (strategy) {
15
- case 'session': {
16
- const sessionId = headers.get('mcp-session-id') ||
17
- headers.get('Mcp-Session-Id') ||
18
- crypto.randomUUID();
19
- return `session:${sessionId}`;
20
- }
21
-
22
- case 'shard': {
23
- const identifier = headers.get('mcp-session-id') || Math.random().toString();
24
- let hash = 0;
25
- for (let i = 0; i < identifier.length; i++) {
26
- hash = ((hash << 5) - hash) + identifier.charCodeAt(i);
27
- hash = hash & hash;
28
- }
29
- const shardCount = parseInt(env.DO_SHARD_COUNT || '10');
30
- // Validate shard count - must be a valid positive number
31
- const validShardCount = (!isNaN(shardCount) && shardCount > 0) ? shardCount : 10;
32
- const shard = Math.abs(hash) % validShardCount;
33
- return `shard:${shard}`;
34
- }
35
-
36
- default:
37
- return 'default';
38
- }
39
- }
40
-
41
- describe('Session-Based Routing', () => {
42
- const env = {
43
- DO_ROUTING_STRATEGY: 'session',
44
- DO_SHARD_COUNT: '10'
45
- };
46
-
47
- test('should route to different instances for different sessions', () => {
48
- const req1 = new Request('http://test/mcp', {
49
- headers: { 'mcp-session-id': 'session-123' }
50
- });
51
- const req2 = new Request('http://test/mcp', {
52
- headers: { 'mcp-session-id': 'session-456' }
53
- });
54
-
55
- const id1 = getDoInstanceId(req1, env);
56
- const id2 = getDoInstanceId(req2, env);
57
-
58
- expect(id1).toBe('session:session-123');
59
- expect(id2).toBe('session:session-456');
60
- expect(id1).not.toBe(id2);
61
- });
62
-
63
- test('should route to same instance for same session', () => {
64
- const sessionId = 'consistent-session';
65
- const req1 = new Request('http://test/mcp', {
66
- headers: { 'mcp-session-id': sessionId }
67
- });
68
- const req2 = new Request('http://test/mcp', {
69
- headers: { 'mcp-session-id': sessionId }
70
- });
71
-
72
- const id1 = getDoInstanceId(req1, env);
73
- const id2 = getDoInstanceId(req2, env);
74
-
75
- expect(id1).toBe(id2);
76
- expect(id1).toBe(`session:${sessionId}`);
77
- });
78
-
79
- test('should handle both mcp-session-id header casings', () => {
80
- const sessionId = 'case-test-session';
81
- const req1 = new Request('http://test/mcp', {
82
- headers: { 'mcp-session-id': sessionId }
83
- });
84
- const req2 = new Request('http://test/mcp', {
85
- headers: { 'Mcp-Session-Id': sessionId }
86
- });
87
-
88
- const id1 = getDoInstanceId(req1, env);
89
- const id2 = getDoInstanceId(req2, env);
90
-
91
- expect(id1).toBe(`session:${sessionId}`);
92
- expect(id2).toBe(`session:${sessionId}`);
93
- });
94
-
95
- test('should generate random session if header missing', () => {
96
- const req = new Request('http://test/mcp', {
97
- headers: {}
98
- });
99
-
100
- const id = getDoInstanceId(req, env);
101
-
102
- expect(id).toMatch(/^session:[0-9a-f-]+$/);
103
- });
104
- });
105
-
106
- describe('Shard-Based Routing', () => {
107
- const env = {
108
- DO_ROUTING_STRATEGY: 'shard',
109
- DO_SHARD_COUNT: '10'
110
- };
111
-
112
- test('should distribute requests across shards', () => {
113
- const distribution = new Map<string, number>();
114
-
115
- // Generate 1000 requests with different sessions
116
- for (let i = 0; i < 1000; i++) {
117
- const req = new Request('http://test/mcp', {
118
- headers: { 'mcp-session-id': `session-${i}` }
119
- });
120
-
121
- const instanceId = getDoInstanceId(req, env);
122
- const shard = instanceId.split(':')[1];
123
-
124
- distribution.set(shard, (distribution.get(shard) || 0) + 1);
125
- }
126
-
127
- // Verify reasonable distribution across 10 shards
128
- expect(distribution.size).toBeGreaterThanOrEqual(8); // At least 8 shards used
129
-
130
- // Each shard should get 50-150 requests (allowing for hash variance)
131
- for (const count of distribution.values()) {
132
- expect(count).toBeGreaterThan(50);
133
- expect(count).toBeLessThan(150);
134
- }
135
- });
136
-
137
- test('should consistently route same session to same shard', () => {
138
- const sessionId = 'shard-consistent-session';
139
- const results = new Set<string>();
140
-
141
- // Make 10 requests with same session
142
- for (let i = 0; i < 10; i++) {
143
- const req = new Request('http://test/mcp', {
144
- headers: { 'mcp-session-id': sessionId }
145
- });
146
- const instanceId = getDoInstanceId(req, env);
147
- results.add(instanceId);
148
- }
149
-
150
- // Should all go to same shard
151
- expect(results.size).toBe(1);
152
- });
153
-
154
- test('should respect custom shard count', () => {
155
- const customEnv = {
156
- DO_ROUTING_STRATEGY: 'shard',
157
- DO_SHARD_COUNT: '5'
158
- };
159
-
160
- const shards = new Set<number>();
161
-
162
- for (let i = 0; i < 100; i++) {
163
- const req = new Request('http://test/mcp', {
164
- headers: { 'mcp-session-id': `test-${i}` }
165
- });
166
-
167
- const instanceId = getDoInstanceId(req, customEnv);
168
- const shardNum = parseInt(instanceId.split(':')[1]);
169
- shards.add(shardNum);
170
-
171
- // Shard should be 0-4 for 5 shards
172
- expect(shardNum).toBeGreaterThanOrEqual(0);
173
- expect(shardNum).toBeLessThan(5);
174
- }
175
-
176
- // Should use most shards
177
- expect(shards.size).toBeGreaterThanOrEqual(4);
178
- });
179
- });
180
-
181
- describe('Default Fallback', () => {
182
- test('should fall back to default when strategy unknown', () => {
183
- const env = {
184
- DO_ROUTING_STRATEGY: 'unknown-strategy',
185
- DO_SHARD_COUNT: '10'
186
- };
187
-
188
- const req = new Request('http://test/mcp', {
189
- headers: { 'mcp-session-id': 'test-session' }
190
- });
191
-
192
- const instanceId = getDoInstanceId(req, env);
193
-
194
- expect(instanceId).toBe('default');
195
- });
196
-
197
- test('should use session strategy when not configured', () => {
198
- const env = {}; // No configuration
199
-
200
- const req = new Request('http://test/mcp', {
201
- headers: { 'mcp-session-id': 'test-session' }
202
- });
203
-
204
- const instanceId = getDoInstanceId(req, env);
205
-
206
- expect(instanceId).toBe('session:test-session');
207
- });
208
- });
209
-
210
- describe('Performance Characteristics', () => {
211
- test('session routing should have O(1) complexity', () => {
212
- const env = { DO_ROUTING_STRATEGY: 'session' };
213
- const sessionId = 'perf-test-session';
214
-
215
- const start = performance.now();
216
-
217
- for (let i = 0; i < 10000; i++) {
218
- const req = new Request('http://test/mcp', {
219
- headers: { 'mcp-session-id': sessionId }
220
- });
221
- getDoInstanceId(req, env);
222
- }
223
-
224
- const duration = performance.now() - start;
225
-
226
- // Should complete 10k operations in < 300ms (relaxed for CI environments)
227
- expect(duration).toBeLessThan(300);
228
- });
229
-
230
- test('shard routing should have O(n) complexity for hash', () => {
231
- const env = {
232
- DO_ROUTING_STRATEGY: 'shard',
233
- DO_SHARD_COUNT: '100'
234
- };
235
-
236
- const shortId = 'abc';
237
- const longId = 'a'.repeat(1000);
238
-
239
- const start1 = performance.now();
240
- for (let i = 0; i < 1000; i++) {
241
- const req = new Request('http://test/mcp', {
242
- headers: { 'mcp-session-id': shortId }
243
- });
244
- getDoInstanceId(req, env);
245
- }
246
- const shortDuration = performance.now() - start1;
247
-
248
- const start2 = performance.now();
249
- for (let i = 0; i < 1000; i++) {
250
- const req = new Request('http://test/mcp', {
251
- headers: { 'mcp-session-id': longId }
252
- });
253
- getDoInstanceId(req, env);
254
- }
255
- const longDuration = performance.now() - start2;
256
-
257
- // Longer IDs should take proportionally more time (but allow for timing variance)
258
- // Note: O(n) complexity is hard to measure reliably in JavaScript due to V8 optimizations
259
- // Instead, we just verify that both operations complete successfully
260
- expect(longDuration).toBeGreaterThan(0);
261
- expect(shortDuration).toBeGreaterThan(0);
262
- // Both operations should complete in reasonable time (< 100ms total for 1000 iterations)
263
- expect(longDuration + shortDuration).toBeLessThan(100);
264
- });
265
- });
266
-
267
- describe('Edge Cases', () => {
268
- test('should handle empty session ID', () => {
269
- const env = { DO_ROUTING_STRATEGY: 'session' };
270
-
271
- const req = new Request('http://test/mcp', {
272
- headers: { 'mcp-session-id': '' }
273
- });
274
-
275
- const instanceId = getDoInstanceId(req, env);
276
-
277
- // Should generate new session
278
- expect(instanceId).toMatch(/^session:[0-9a-f-]+$/);
279
- });
280
-
281
- test('should handle non-numeric shard count', () => {
282
- const env = {
283
- DO_ROUTING_STRATEGY: 'shard',
284
- DO_SHARD_COUNT: 'invalid'
285
- };
286
-
287
- const req = new Request('http://test/mcp', {
288
- headers: { 'mcp-session-id': 'test' }
289
- });
290
-
291
- // Should default to 10 shards
292
- const instanceId = getDoInstanceId(req, env);
293
- const shard = parseInt(instanceId.split(':')[1]);
294
-
295
- expect(shard).toBeGreaterThanOrEqual(0);
296
- expect(shard).toBeLessThan(10);
297
- });
298
-
299
- test('should handle special characters in session ID', () => {
300
- const env = { DO_ROUTING_STRATEGY: 'shard' };
301
- const specialId = '!@#$%^&*()_+-=[]{}|;:,.<>?';
302
-
303
- const req = new Request('http://test/mcp', {
304
- headers: { 'mcp-session-id': specialId }
305
- });
306
-
307
- // Should not throw and produce valid shard
308
- expect(() => getDoInstanceId(req, env)).not.toThrow();
309
-
310
- const instanceId = getDoInstanceId(req, env);
311
- expect(instanceId).toMatch(/^shard:\d+$/);
312
- });
313
- });
314
- });
@@ -1,205 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
- import { unstable_dev } from 'wrangler';
3
- import type { UnstableDevWorker } from 'wrangler';
4
-
5
- describe('MCP-I Cloudflare Integration', () => {
6
- let worker: UnstableDevWorker;
7
- let baseUrl: string;
8
-
9
- beforeAll(async () => {
10
- worker = await unstable_dev('src/index.ts', {
11
- experimental: { disableExperimentalWarning: true },
12
- });
13
- baseUrl = `http://localhost:${worker.port}`;
14
- });
15
-
16
- afterAll(async () => {
17
- await worker.stop();
18
- });
19
-
20
- it('should return healthy status from /health', async () => {
21
- const response = await fetch(`${baseUrl}/health`);
22
- expect(response.status).toBe(200);
23
-
24
- const data = await response.json();
25
- expect(data).toHaveProperty('status', 'healthy');
26
- expect(data).toHaveProperty('timestamp');
27
- expect(data).toHaveProperty('transport');
28
- expect(data.transport).toHaveProperty('sse', '/sse');
29
- expect(data.transport).toHaveProperty('streamableHttp', '/mcp');
30
- });
31
-
32
- it('should stream proofs via SSE and verify them', async () => {
33
- const sessionId = `test-${Date.now()}`;
34
- let proofReceived = false;
35
- let proofData: any = null;
36
-
37
- // Open SSE connection
38
- const response = await fetch(`${baseUrl}/proofs?session=${sessionId}`);
39
- expect(response.headers.get('content-type')).toMatch(/^text\/event-stream/);
40
- expect(response.status).toBe(200);
41
-
42
- // Create promise to track proof reception
43
- const proofPromise = new Promise<void>((resolve, reject) => {
44
- const timeout = setTimeout(() => {
45
- reject(new Error('Timeout waiting for proof event'));
46
- }, 10000);
47
-
48
- if (!response.body) {
49
- clearTimeout(timeout);
50
- reject(new Error('No response body'));
51
- return;
52
- }
53
-
54
- const reader = response.body.getReader();
55
- const decoder = new TextDecoder();
56
-
57
- const readChunk = async () => {
58
- try {
59
- const { done, value } = await reader.read();
60
- if (done) {
61
- clearTimeout(timeout);
62
- reject(new Error('Stream ended without receiving proof'));
63
- return;
64
- }
65
-
66
- const chunk = decoder.decode(value);
67
- const lines = chunk.split('\n');
68
-
69
- for (const line of lines) {
70
- if (line.startsWith('data: ')) {
71
- const data = line.slice(6);
72
- try {
73
- proofData = JSON.parse(data);
74
- proofReceived = true;
75
- clearTimeout(timeout);
76
- reader.cancel();
77
- resolve();
78
- return;
79
- } catch (e) {
80
- // Not valid JSON, continue reading
81
- }
82
- }
83
- }
84
-
85
- // Continue reading
86
- readChunk();
87
- } catch (error) {
88
- clearTimeout(timeout);
89
- reject(error);
90
- }
91
- };
92
-
93
- readChunk();
94
- });
95
-
96
- // Call the greet tool to generate a proof
97
- const toolResponse = await fetch(`${baseUrl}/mcp`, {
98
- method: 'POST',
99
- headers: {
100
- 'Content-Type': 'application/json',
101
- 'mcp-session-id': sessionId,
102
- },
103
- body: JSON.stringify({
104
- jsonrpc: '2.0',
105
- id: 1,
106
- method: 'tools/call',
107
- params: {
108
- name: 'greet',
109
- arguments: {
110
- name: 'Test User',
111
- },
112
- },
113
- }),
114
- });
115
-
116
- expect(toolResponse.status).toBe(200);
117
- const toolResult = await toolResponse.json();
118
- expect(toolResult).toHaveProperty('result');
119
-
120
- // Wait for proof to arrive via SSE
121
- await proofPromise;
122
- expect(proofReceived).toBe(true);
123
- expect(proofData).toBeDefined();
124
- expect(proofData).toHaveProperty('proof');
125
- expect(proofData).toHaveProperty('data');
126
-
127
- // Verify the proof
128
- const verifyResponse = await fetch(`${baseUrl}/verify`, {
129
- method: 'POST',
130
- headers: {
131
- 'Content-Type': 'application/json',
132
- },
133
- body: JSON.stringify({
134
- data: proofData.data,
135
- proof: proofData.proof,
136
- }),
137
- });
138
-
139
- expect(verifyResponse.status).toBe(200);
140
- const verifyResult = await verifyResponse.json();
141
- expect(verifyResult).toHaveProperty('valid', true);
142
- });
143
-
144
- it('should expose identity via well-known endpoint', async () => {
145
- const response = await fetch(`${baseUrl}/.well-known/mcp-identity`);
146
- expect(response.status).toBe(200);
147
-
148
- const identity = await response.json();
149
- expect(identity).toHaveProperty('did');
150
- expect(identity).toHaveProperty('publicKey');
151
- expect(identity).toHaveProperty('serviceName', 'test-cloudflare');
152
- expect(identity).toHaveProperty('serviceEndpoint');
153
- expect(identity).toHaveProperty('timestamp');
154
- expect(identity.did).toMatch(/^did:(key|web):/);
155
- });
156
-
157
- it('should expose W3C DID document at /.well-known/did.json', async () => {
158
- const response = await fetch(`${baseUrl}/.well-known/did.json`);
159
- expect(response.status).toBe(200);
160
- expect(response.headers.get('content-type')).toBe('application/did+json');
161
- expect(response.headers.get('access-control-allow-origin')).toBe('*');
162
- expect(response.headers.get('vary')).toBe('Origin');
163
-
164
- const didDoc = await response.json();
165
- expect(didDoc).toHaveProperty('@context');
166
- expect(didDoc).toHaveProperty('id');
167
- expect(didDoc.id).toMatch(/^did:key:z/);
168
- expect(didDoc).toHaveProperty('verificationMethod');
169
- expect(Array.isArray(didDoc.verificationMethod)).toBe(true);
170
- expect(didDoc.verificationMethod.length).toBeGreaterThan(0);
171
-
172
- const vm = didDoc.verificationMethod[0];
173
- expect(vm).toHaveProperty('id');
174
- expect(vm).toHaveProperty('type', 'Ed25519VerificationKey2020');
175
- expect(vm).toHaveProperty('controller');
176
- expect(vm).toHaveProperty('publicKeyBase64');
177
-
178
- expect(didDoc).toHaveProperty('authentication');
179
- expect(Array.isArray(didDoc.authentication)).toBe(true);
180
- expect(didDoc).toHaveProperty('assertionMethod');
181
- expect(Array.isArray(didDoc.assertionMethod)).toBe(true);
182
- });
183
-
184
- it('should expose MCP-I capabilities at /.well-known/agent.json', async () => {
185
- const response = await fetch(`${baseUrl}/.well-known/agent.json`);
186
- expect(response.status).toBe(200);
187
- expect(response.headers.get('content-type')).toBe('application/json');
188
- expect(response.headers.get('access-control-allow-origin')).toBe('*');
189
- expect(response.headers.get('vary')).toBe('Origin');
190
-
191
- const agentDoc = await response.json();
192
- expect(agentDoc).toHaveProperty('id');
193
- expect(agentDoc.id).toMatch(/^did:key:z/);
194
- expect(agentDoc).toHaveProperty('capabilities');
195
- expect(agentDoc.capabilities).toHaveProperty('mcp-i');
196
- expect(Array.isArray(agentDoc.capabilities['mcp-i'])).toBe(true);
197
- expect(agentDoc.capabilities['mcp-i']).toContain('handshake');
198
- expect(agentDoc.capabilities['mcp-i']).toContain('signing');
199
- expect(agentDoc.capabilities['mcp-i']).toContain('verification');
200
-
201
- expect(agentDoc).toHaveProperty('metadata');
202
- expect(agentDoc.metadata).toHaveProperty('name', 'test-cloudflare');
203
- expect(agentDoc.metadata).toHaveProperty('serviceEndpoint');
204
- });
205
- });