@kya-os/create-mcpi-app 1.7.38-canary.2 → 1.7.39-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-test$colon$coverage.log +378 -0
  3. package/.turbo/turbo-test.log +164 -0
  4. package/dist/helpers/config-builder.d.ts +4 -10
  5. package/dist/helpers/config-builder.d.ts.map +1 -1
  6. package/dist/helpers/config-builder.js +7 -64
  7. package/dist/helpers/config-builder.js.map +1 -1
  8. package/dist/helpers/fetch-cloudflare-mcpi-template.d.ts.map +1 -1
  9. package/dist/helpers/fetch-cloudflare-mcpi-template.js +35 -914
  10. package/dist/helpers/fetch-cloudflare-mcpi-template.js.map +1 -1
  11. package/dist/utils/fetch-remote-config.d.ts.map +1 -1
  12. package/dist/utils/fetch-remote-config.js +2 -2
  13. package/dist/utils/fetch-remote-config.js.map +1 -1
  14. package/package/package.json +77 -0
  15. package/package.json +5 -3
  16. package/ARCHITECTURE_ANALYSIS.md +0 -392
  17. package/CHANGELOG.md +0 -372
  18. package/DEPRECATION_WARNINGS_ANALYSIS.md +0 -192
  19. package/IMPLEMENTATION_SUMMARY.md +0 -108
  20. package/REMEDIATION_PLAN.md +0 -99
  21. package/dist/.tsbuildinfo +0 -1
  22. package/scripts/prepare-pack.js +0 -47
  23. package/scripts/validate-no-workspace.js +0 -79
  24. package/src/__tests__/cloudflare-template.test.ts +0 -490
  25. package/src/__tests__/helpers/fetch-cloudflare-mcpi-template.test.ts +0 -337
  26. package/src/__tests__/helpers/generate-config.test.ts +0 -312
  27. package/src/__tests__/helpers/generate-identity.test.ts +0 -271
  28. package/src/__tests__/helpers/install.test.ts +0 -370
  29. package/src/__tests__/helpers/validate-project-structure.test.ts +0 -467
  30. package/src/__tests__.bak/regression.test.ts +0 -434
  31. package/src/effects/index.ts +0 -80
  32. package/src/helpers/__tests__/config-builder.spec.ts +0 -231
  33. package/src/helpers/apply-identity-preset.ts +0 -209
  34. package/src/helpers/config-builder.ts +0 -165
  35. package/src/helpers/copy-template.ts +0 -11
  36. package/src/helpers/create.ts +0 -239
  37. package/src/helpers/fetch-cloudflare-mcpi-template.ts +0 -2404
  38. package/src/helpers/fetch-cloudflare-template.ts +0 -361
  39. package/src/helpers/fetch-mcpi-template.ts +0 -236
  40. package/src/helpers/fetch-xmcp-template.ts +0 -153
  41. package/src/helpers/generate-config.ts +0 -118
  42. package/src/helpers/generate-identity.ts +0 -163
  43. package/src/helpers/identity-manager.ts +0 -186
  44. package/src/helpers/install.ts +0 -79
  45. package/src/helpers/rename.ts +0 -17
  46. package/src/helpers/validate-project-structure.ts +0 -127
  47. package/src/index.ts +0 -520
  48. package/src/utils/__tests__/fetch-remote-config.test.ts +0 -271
  49. package/src/utils/check-node.ts +0 -17
  50. package/src/utils/fetch-remote-config.ts +0 -179
  51. package/src/utils/is-folder-empty.ts +0 -60
  52. package/src/utils/validate-project-name.ts +0 -132
  53. package/test-cloudflare/README.md +0 -164
  54. package/test-cloudflare/package.json +0 -28
  55. package/test-cloudflare/src/index.ts +0 -341
  56. package/test-cloudflare/src/tools/greet.ts +0 -19
  57. package/test-cloudflare/tests/cache-invalidation.test.ts +0 -410
  58. package/test-cloudflare/tests/cors-security.test.ts +0 -349
  59. package/test-cloudflare/tests/delegation.test.ts +0 -335
  60. package/test-cloudflare/tests/do-routing.test.ts +0 -314
  61. package/test-cloudflare/tests/integration.test.ts +0 -205
  62. package/test-cloudflare/tests/session-management.test.ts +0 -359
  63. package/test-cloudflare/tsconfig.json +0 -16
  64. package/test-cloudflare/vitest.config.ts +0 -9
  65. package/test-cloudflare/wrangler.toml +0 -37
  66. package/test-node/README.md +0 -44
  67. package/test-node/package.json +0 -23
  68. package/test-node/src/tools/greet.ts +0 -25
  69. package/test-node/xmcp.config.ts +0 -20
  70. package/tsconfig.json +0 -26
  71. package/vitest.config.ts +0 -14
@@ -1,164 +0,0 @@
1
- # test-cloudflare
2
-
3
- MCP-I server running on Cloudflare Workers with identity verification.
4
-
5
- ## Quick Start
6
-
7
- ### 1. Install Dependencies
8
-
9
- ```bash
10
- npm install
11
- ```
12
-
13
- ### 2. Create KV Namespace
14
-
15
- ```bash
16
- npm run kv:create
17
- ```
18
-
19
- This runs: `wrangler kv namespace create NONCE_CACHE`
20
-
21
- Copy the `id` from the output and update `wrangler.toml`:
22
-
23
- ```toml
24
- [[kv_namespaces]]
25
- binding = "NONCE_CACHE"
26
- id = "your-actual-kv-id-here" # ← Update this
27
- ```
28
-
29
- ### 3. Test Locally
30
-
31
- ```bash
32
- npm run dev
33
- ```
34
-
35
- **Endpoints:**
36
- - MCP: http://localhost:8787/mcp
37
- - Verify: http://localhost:8787/verify
38
- - Health: http://localhost:8787/health
39
-
40
- ### 4. Deploy to Cloudflare
41
-
42
- ```bash
43
- # Login to Cloudflare (first time only)
44
- npx wrangler login
45
-
46
- # Deploy to development
47
- npm run deploy
48
-
49
- # Deploy to production
50
- npm run deploy --env production
51
- ```
52
-
53
- ## Connect with Claude Desktop
54
-
55
- Add to your `claude_desktop_config.json`:
56
-
57
- ```json
58
- {
59
- "mcpServers": {
60
- "test-cloudflare": {
61
- "command": "npx",
62
- "args": [
63
- "mcp-remote",
64
- "https://your-worker.workers.dev/mcp"
65
- ]
66
- }
67
- }
68
- }
69
- ```
70
-
71
- ## Adding Tools
72
-
73
- Create new tools in `src/tools/`:
74
-
75
- ```typescript
76
- // src/tools/example.ts
77
- import { z } from "zod";
78
- import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/types.js";
79
-
80
- export const exampleTool = {
81
- name: "example",
82
- description: "Example tool description",
83
- inputSchema: z.object({
84
- input: z.string().describe("Input parameter"),
85
- }),
86
- handler: async (args: { [key: string]: any }, extra: RequestHandlerExtra<any, any>) => {
87
- const { input } = args as { input: string };
88
- return {
89
- content: [
90
- {
91
- type: "text" as const,
92
- text: `Result: ${input}`
93
- }
94
- ],
95
- };
96
- },
97
- };
98
- ```
99
-
100
- Register in `src/index.ts`:
101
-
102
- ```typescript
103
- import { exampleTool } from "./tools/example";
104
-
105
- async init() {
106
- this.server.tool(
107
- exampleTool.name,
108
- exampleTool.description,
109
- exampleTool.inputSchema.shape,
110
- exampleTool.handler
111
- );
112
- }
113
- ```
114
-
115
- ## API Endpoints
116
-
117
- ### `GET /health`
118
- Health check endpoint.
119
-
120
- **Response:**
121
- ```json
122
- {
123
- "status": "healthy",
124
- "timestamp": "2024-10-10T12:00:00.000Z"
125
- }
126
- ```
127
-
128
- ### `POST /mcp`
129
- MCP protocol endpoint for tool calls.
130
-
131
- ### `POST /verify`
132
- Verify MCP-I cryptographic proofs.
133
-
134
- **Request:**
135
- ```json
136
- {
137
- "proof": {
138
- "agentDid": "did:web:example.com",
139
- "timestamp": 1234567890,
140
- "nonce": "abc123",
141
- "signature": "...",
142
- "publicKey": "..."
143
- }
144
- }
145
- ```
146
-
147
- **Response:**
148
- ```json
149
- {
150
- "verified": true,
151
- "agent": {
152
- "did": "did:web:example.com",
153
- "keyId": "key-123",
154
- "scopes": ["read", "write"],
155
- "session": "session-456"
156
- }
157
- }
158
- ```
159
-
160
- ## Learn More
161
-
162
- - [MCP-I Documentation](https://github.com/kya-os/xmcp-i)
163
- - [Cloudflare Workers](https://developers.cloudflare.com/workers/)
164
- - [agents/mcp](https://www.npmjs.com/package/agents)
@@ -1,28 +0,0 @@
1
- {
2
- "name": "test-cloudflare",
3
- "version": "0.1.0",
4
- "private": true,
5
- "scripts": {
6
- "deploy": "wrangler deploy",
7
- "dev": "wrangler dev",
8
- "start": "wrangler dev",
9
- "test": "vitest run",
10
- "test:watch": "vitest",
11
- "kv:create": "wrangler kv namespace create NONCE_CACHE",
12
- "kv:list": "wrangler kv namespace list",
13
- "type-check": "tsc --noEmit"
14
- },
15
- "dependencies": {
16
- "@kya-os/mcp-i-cloudflare": "^1.0.0",
17
- "@modelcontextprotocol/sdk": "^1.19.1",
18
- "agents": "^0.2.8",
19
- "hono": "^4.9.10",
20
- "zod": "^3.25.76"
21
- },
22
- "devDependencies": {
23
- "@cloudflare/workers-types": "^4.20240925.0",
24
- "typescript": "^5.6.2",
25
- "vitest": "^2.1.8",
26
- "wrangler": "^4.42.2"
27
- }
28
- }
@@ -1,341 +0,0 @@
1
- /// <reference types="@cloudflare/workers-types" />
2
- import { McpAgent } from "agents/mcp";
3
- import { Hono } from "hono";
4
- import { cors } from "hono/cors";
5
- import { createCloudflareRuntime, KVProofArchive } from "@kya-os/mcp-i-cloudflare";
6
- import type { MCPIRuntimeBase } from "@kya-os/mcp-i-core";
7
- import { WELL_KNOWN_CORS_HEADERS } from "@kya-os/mcp-i-core";
8
- import { greetTool } from "./tools/greet";
9
-
10
- interface Env {
11
- MCP_OBJECT: DurableObjectNamespace;
12
- NONCE_CACHE: KVNamespace;
13
- PROOF_ARCHIVE?: KVNamespace;
14
- XMCP_I_TS_SKEW_SEC?: string;
15
- XMCP_I_SESSION_TTL?: string;
16
- ADMIN_PROOFS_ENABLED?: string;
17
- MCP_IDENTITY_PRIVATE_KEY?: string;
18
- MCP_IDENTITY_PUBLIC_KEY?: string;
19
- MCP_IDENTITY_AGENT_DID?: string;
20
- }
21
-
22
- export class CloudflareMCP extends McpAgent {
23
- private mcpiRuntime?: MCPIRuntimeBase;
24
- private proofArchive?: KVProofArchive;
25
- private sessionId?: string;
26
-
27
- constructor(state: DurableObjectState, env: Env) {
28
- super(state, env);
29
-
30
- this.mcpiRuntime = createCloudflareRuntime({
31
- env: env as any,
32
- environment: 'development',
33
- timestampSkewSeconds: parseInt(env.XMCP_I_TS_SKEW_SEC || '120'),
34
- sessionTtlMinutes: parseInt(env.XMCP_I_SESSION_TTL || '1800') / 60,
35
- audit: {
36
- enabled: true
37
- }
38
- });
39
-
40
- if (env.PROOF_ARCHIVE) {
41
- this.proofArchive = new KVProofArchive(env.PROOF_ARCHIVE, {
42
- ttl: 86400 * 30
43
- });
44
- }
45
- }
46
-
47
- async init() {
48
- await this.mcpiRuntime?.initialize();
49
-
50
- this.server.tool(
51
- greetTool.name,
52
- greetTool.description,
53
- greetTool.inputSchema.shape,
54
- async (args: any) => {
55
- const identity = await this.mcpiRuntime!.getIdentity();
56
- const sessionId = await this.ensureSessionId();
57
- const establishedAt = await this.state.storage.get<number>("establishedAt") ?? Date.now();
58
- const nonce = await this.mcpiRuntime!.issueNonce(sessionId);
59
-
60
- const sessionContext = {
61
- sessionId,
62
- agentDid: identity.did,
63
- kid: identity.kid,
64
- establishedAt,
65
- lastActivityAt: Date.now(),
66
- nonce,
67
- };
68
-
69
- const result = await this.mcpiRuntime!.processToolCall(
70
- greetTool.name,
71
- args,
72
- greetTool.handler,
73
- sessionContext
74
- );
75
-
76
- if (this.proofArchive) {
77
- const proof = this.mcpiRuntime!.getLastProof();
78
- if (proof) {
79
- await this.proofArchive.store(proof, { toolName: greetTool.name, sessionId });
80
- }
81
- }
82
-
83
- return result;
84
- }
85
- );
86
- }
87
-
88
- private async ensureSessionId(): Promise<string> {
89
- if (!this.sessionId) {
90
- this.sessionId = await this.state.storage.get<string>("sessionId");
91
- if (!this.sessionId) {
92
- this.sessionId = crypto.randomUUID();
93
- await this.state.storage.put("sessionId", this.sessionId);
94
- await this.state.storage.put("establishedAt", Date.now());
95
- }
96
- }
97
- return this.sessionId;
98
- }
99
-
100
- async fetch(request: Request): Promise<Response> {
101
- const url = new URL(request.url);
102
-
103
- if (url.pathname === '/_internal/identity') {
104
- const identity = await this.mcpiRuntime!.getIdentity();
105
- return new Response(JSON.stringify({
106
- did: identity.did,
107
- publicKey: identity.publicKey,
108
- kid: identity.kid
109
- }), {
110
- headers: { 'Content-Type': 'application/json' }
111
- });
112
- }
113
-
114
- if (url.pathname.startsWith('/_internal/well-known/')) {
115
- const handler = this.mcpiRuntime!.createWellKnownHandler({
116
- serviceName: 'test-cloudflare',
117
- serviceEndpoint: request.headers.get('X-Service-Origin') || url.origin
118
- });
119
- const path = url.pathname.replace('/_internal/well-known/', '/.well-known/');
120
- const result = await handler(path);
121
-
122
- if (result?.status && result?.headers && result?.body) {
123
- return new Response(result.body, {
124
- status: result.status,
125
- headers: result.headers
126
- });
127
- }
128
-
129
- return new Response(JSON.stringify(result), {
130
- headers: { 'Content-Type': 'application/json' }
131
- });
132
- }
133
-
134
- if (url.pathname === '/_internal/verify') {
135
- const body = await request.json() as { data: any; proof: any };
136
- const isValid = await this.mcpiRuntime!.verifyProof(body.data, body.proof);
137
- return new Response(JSON.stringify({ valid: isValid }), {
138
- headers: { 'Content-Type': 'application/json' }
139
- });
140
- }
141
-
142
- if (url.pathname === '/_internal/proofs') {
143
- if (!this.proofArchive) {
144
- return new Response(JSON.stringify({ error: 'Proof archive not initialized' }), {
145
- status: 500,
146
- headers: { 'Content-Type': 'application/json' }
147
- });
148
- }
149
-
150
- const limit = parseInt(url.searchParams.get('limit') || '10');
151
- const sessionId = url.searchParams.get('sessionId');
152
-
153
- const proofs = sessionId
154
- ? await this.proofArchive.getBySession(sessionId, limit)
155
- : await this.proofArchive.getRecent(limit);
156
-
157
- return new Response(JSON.stringify({ proofs }), {
158
- headers: { 'Content-Type': 'application/json' }
159
- });
160
- }
161
-
162
- if (url.pathname === '/_internal/proofs/tail') {
163
- if (!this.proofArchive) {
164
- return new Response(JSON.stringify({ error: 'Proof archive not initialized' }), {
165
- status: 500,
166
- headers: { 'Content-Type': 'application/json' }
167
- });
168
- }
169
-
170
- const sessionId = url.searchParams.get('session') ?? '';
171
- const limit = parseInt(url.searchParams.get('limit') || '10');
172
- let iv: ReturnType<typeof setInterval> | undefined;
173
-
174
- const stream = new ReadableStream({
175
- start: async (controller) => {
176
- const enc = new TextEncoder();
177
- let lastSeenId: string | null = null;
178
-
179
- const send = (p: any) => {
180
- const data = `event: mcpi-proof\ndata: ${JSON.stringify(p)}\n\n`;
181
- controller.enqueue(enc.encode(data));
182
- };
183
-
184
- const poll = async () => {
185
- try {
186
- const list = sessionId
187
- ? await this.proofArchive!.getBySession(sessionId, limit)
188
- : await this.proofArchive!.getRecent(limit);
189
-
190
- for (const p of list) {
191
- if (!lastSeenId || p.id > lastSeenId) {
192
- send(p);
193
- lastSeenId = p.id;
194
- }
195
- }
196
- } catch (error) {
197
- console.error('Error polling proofs:', error);
198
- }
199
- };
200
-
201
- await poll();
202
- iv = setInterval(poll, 500);
203
- },
204
- cancel() {
205
- if (iv) clearInterval(iv);
206
- }
207
- });
208
-
209
- return new Response(stream, {
210
- headers: {
211
- 'Content-Type': 'text/event-stream',
212
- 'Cache-Control': 'no-cache',
213
- 'Connection': 'keep-alive'
214
- }
215
- });
216
- }
217
-
218
- return super.fetch(request);
219
- }
220
- }
221
-
222
- const app = new Hono<{ Bindings: Env }>();
223
-
224
- app.use("/*", cors({
225
- origin: "*",
226
- allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
227
- allowHeaders: ["Content-Type", "Authorization", "mcp-session-id", "mcp-protocol-version"],
228
- exposeHeaders: ["mcp-session-id"],
229
- }));
230
-
231
- app.get("/health", (c) => c.json({
232
- status: 'healthy',
233
- timestamp: new Date().toISOString(),
234
- transport: { sse: '/sse', streamableHttp: '/mcp' }
235
- }));
236
-
237
- app.get("/.well-known/did.json", async (c) => {
238
- const stub = c.env.MCP_OBJECT.get(c.env.MCP_OBJECT.idFromName("singleton"));
239
- const origin = new URL(c.req.url).origin;
240
- const response = await stub.fetch("https://do/_internal/well-known/did.json", {
241
- headers: { 'X-Service-Origin': origin }
242
- });
243
-
244
- return new Response(response.body, {
245
- status: response.status,
246
- headers: {
247
- ...Object.fromEntries(response.headers),
248
- ...WELL_KNOWN_CORS_HEADERS
249
- }
250
- });
251
- });
252
-
253
- app.get("/.well-known/agent.json", async (c) => {
254
- const stub = c.env.MCP_OBJECT.get(c.env.MCP_OBJECT.idFromName("singleton"));
255
- const origin = new URL(c.req.url).origin;
256
- const response = await stub.fetch("https://do/_internal/well-known/agent.json", {
257
- headers: { 'X-Service-Origin': origin }
258
- });
259
-
260
- return new Response(response.body, {
261
- status: response.status,
262
- headers: {
263
- ...Object.fromEntries(response.headers),
264
- ...WELL_KNOWN_CORS_HEADERS
265
- }
266
- });
267
- });
268
-
269
- app.get("/.well-known/mcp-identity", async (c) => {
270
- const stub = c.env.MCP_OBJECT.get(c.env.MCP_OBJECT.idFromName("singleton"));
271
- const origin = new URL(c.req.url).origin;
272
- const response = await stub.fetch("https://do/_internal/well-known/mcp-identity", {
273
- headers: { 'X-Service-Origin': origin }
274
- });
275
-
276
- return new Response(response.body, {
277
- status: response.status,
278
- headers: {
279
- ...Object.fromEntries(response.headers),
280
- ...WELL_KNOWN_CORS_HEADERS
281
- }
282
- });
283
- });
284
-
285
- app.post("/verify", async (c) => {
286
- const stub = c.env.MCP_OBJECT.get(c.env.MCP_OBJECT.idFromName("singleton"));
287
- const body = await c.req.json();
288
-
289
- const response = await stub.fetch("https://do/_internal/verify", {
290
- method: 'POST',
291
- headers: { 'Content-Type': 'application/json' },
292
- body: JSON.stringify(body)
293
- });
294
-
295
- return c.json(await response.json());
296
- });
297
-
298
- app.get("/admin/proofs", async (c) => {
299
- if (c.env.ADMIN_PROOFS_ENABLED !== 'true') {
300
- return c.json({ error: 'Admin endpoint disabled' }, 403);
301
- }
302
-
303
- const stub = c.env.MCP_OBJECT.get(c.env.MCP_OBJECT.idFromName("singleton"));
304
- const limit = c.req.query('limit') || '10';
305
- const sessionId = c.req.query('sessionId');
306
-
307
- const url = new URL("https://do/_internal/proofs");
308
- url.searchParams.set('limit', limit);
309
- if (sessionId) {
310
- url.searchParams.set('sessionId', sessionId);
311
- }
312
-
313
- const response = await stub.fetch(url.toString());
314
- return c.json(await response.json());
315
- });
316
-
317
- app.get("/proofs", async (c) => {
318
- const stub = c.env.MCP_OBJECT.get(c.env.MCP_OBJECT.idFromName("singleton"));
319
- const sessionId = c.req.query('session') ?? '';
320
- const limit = c.req.query('limit') || '10';
321
-
322
- const url = new URL("https://do/_internal/proofs/tail");
323
- url.searchParams.set('session', sessionId);
324
- url.searchParams.set('limit', limit);
325
-
326
- const response = await stub.fetch(url.toString());
327
-
328
- return new Response(response.body, {
329
- headers: {
330
- 'Content-Type': 'text/event-stream',
331
- 'Cache-Control': 'no-cache',
332
- 'Connection': 'keep-alive',
333
- 'Access-Control-Allow-Origin': '*'
334
- }
335
- });
336
- });
337
-
338
- app.mount("/sse", CloudflareMCP.serveSSE("/sse").fetch, { replaceRequest: false });
339
- app.mount("/mcp", CloudflareMCP.serve("/mcp").fetch, { replaceRequest: false });
340
-
341
- export default app;
@@ -1,19 +0,0 @@
1
- import { z } from "zod";
2
-
3
- export const greetTool = {
4
- name: "greet",
5
- description: "Greet a user by name",
6
- inputSchema: z.object({
7
- name: z.string().describe("The name of the user to greet")
8
- }),
9
- handler: async ({ name }: { name: string }) => {
10
- return {
11
- content: [
12
- {
13
- type: "text" as const,
14
- text: `Hello, ${name}! Welcome to your Cloudflare MCP server.`
15
- }
16
- ]
17
- };
18
- }
19
- };