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

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.
@@ -6,7 +6,7 @@ import chalk from "chalk";
6
6
  * Uses McpAgent from agents/mcp for MCP protocol support
7
7
  */
8
8
  export async function fetchCloudflareMcpiTemplate(projectPath, options = {}) {
9
- const { packageManager = "npm", projectName = path.basename(projectPath) } = options;
9
+ const { packageManager = "npm", projectName = path.basename(projectPath), apikey } = options;
10
10
  // Sanitize project name for class names
11
11
  const className = projectName
12
12
  .replace(/[^a-zA-Z0-9]/g, "")
@@ -23,16 +23,31 @@ export async function fetchCloudflareMcpiTemplate(projectPath, options = {}) {
23
23
  deploy: "wrangler deploy",
24
24
  dev: "wrangler dev",
25
25
  start: "wrangler dev",
26
- "kv:create": "npm run kv:create-nonce && npm run kv:create-proof",
26
+ "kv:create": "npm run kv:create-nonce && npm run kv:create-proof && npm run kv:create-identity && npm run kv:create-delegation && npm run kv:create-tool-protection",
27
27
  "kv:create-nonce": `wrangler kv namespace create NONCE_CACHE`,
28
28
  "kv:create-proof": `wrangler kv namespace create PROOF_ARCHIVE`,
29
- "kv:list": "wrangler kv namespace list | grep -E '(NONCE|PROOF|MCPI)' || wrangler kv namespace list",
30
- "kv:setup": "echo 'Run npm run kv:list to find existing namespaces, or npm run kv:create to create both, or use kv:create-nonce and kv:create-proof individually'",
29
+ "kv:create-identity": `wrangler kv namespace create IDENTITY_STORAGE`,
30
+ "kv:create-delegation": `wrangler kv namespace create DELEGATION_STORAGE`,
31
+ "kv:create-tool-protection": `wrangler kv namespace create TOOL_PROTECTION_KV`,
32
+ "kv:list": "wrangler kv namespace list | grep -E '(NONCE|PROOF|IDENTITY|DELEGATION|TOOL_PROTECTION|MCPI)' || wrangler kv namespace list",
33
+ "kv:keys-nonce": "wrangler kv key list --binding=NONCE_CACHE",
34
+ "kv:keys-proof": "wrangler kv key list --binding=PROOF_ARCHIVE",
35
+ "kv:keys-identity": "wrangler kv key list --binding=IDENTITY_STORAGE",
36
+ "kv:keys-delegation": "wrangler kv key list --binding=DELEGATION_STORAGE",
37
+ "kv:keys-tool-protection": "wrangler kv key list --binding=TOOL_PROTECTION_KV",
38
+ "kv:delete-nonce": "wrangler kv namespace delete --binding=NONCE_CACHE",
39
+ "kv:delete-proof": "wrangler kv namespace delete --binding=PROOF_ARCHIVE",
40
+ "kv:delete-identity": "wrangler kv namespace delete --binding=IDENTITY_STORAGE",
41
+ "kv:delete-delegation": "wrangler kv namespace delete --binding=DELEGATION_STORAGE",
42
+ "kv:delete-tool-protection": "wrangler kv namespace delete --binding=TOOL_PROTECTION_KV",
43
+ "kv:delete": "npm run kv:delete-nonce && npm run kv:delete-proof && npm run kv:delete-identity && npm run kv:delete-delegation && npm run kv:delete-tool-protection",
44
+ "kv:reset": "npm run kv:delete && npm run kv:create",
45
+ "kv:setup": "echo 'KV Commands: kv:create (create all), kv:list (list all), kv:keys-* (view keys), kv:delete (delete all), kv:reset (delete+recreate)'",
31
46
  "cf-typegen": "wrangler types",
32
47
  "type-check": "tsc --noEmit",
33
48
  },
34
49
  dependencies: {
35
- "@kya-os/mcp-i-cloudflare": "^1.1.1",
50
+ "@kya-os/mcp-i-cloudflare": "^1.2.3",
36
51
  "@modelcontextprotocol/sdk": "^1.19.1",
37
52
  "agents": "^0.2.8",
38
53
  "hono": "^4.9.10",
@@ -53,6 +68,31 @@ export async function fetchCloudflareMcpiTemplate(projectPath, options = {}) {
53
68
  // Create greet tool
54
69
  const greetToolContent = `import { z } from "zod";
55
70
 
71
+ /**
72
+ * Greet Tool - Example MCP tool with AgentShield integration
73
+ *
74
+ * This tool demonstrates proper scopeId configuration for tool auto-discovery.
75
+ *
76
+ * Configure the corresponding scope in mcpi-runtime-config.ts:
77
+ * \`\`\`typescript
78
+ * toolProtections: {
79
+ * greet: {
80
+ * requiresDelegation: false,
81
+ * requiredScopes: ["greet:execute"], // ← This becomes the scopeId in proofs
82
+ * }
83
+ * }
84
+ * \`\`\`
85
+ *
86
+ * The scopeId format is "toolName:action":
87
+ * - Tool name: "greet" (extracted before the ":")
88
+ * - Action: "execute" (extracted after the ":")
89
+ * - Risk level: Auto-determined from action keyword (execute = high)
90
+ *
91
+ * Other scopeId examples:
92
+ * - "files:read" → Medium risk
93
+ * - "files:write" → High risk
94
+ * - "database:delete" → Critical risk
95
+ */
56
96
  export const greetTool = {
57
97
  name: "greet",
58
98
  description: "Greet a user by name",
@@ -72,13 +112,146 @@ export const greetTool = {
72
112
  };
73
113
  `;
74
114
  fs.writeFileSync(path.join(toolsDir, "greet.ts"), greetToolContent);
115
+ // Create mcpi-runtime-config.ts for AgentShield integration
116
+ const runtimeConfigContent = `import type { MCPIRuntimeConfig } from "@kya-os/mcp-i-cloudflare";
117
+ // import { CloudflareRuntime } from "@kya-os/mcp-i-cloudflare"; // Uncomment to enable Tool Protection Service
118
+
119
+ /**
120
+ * Runtime configuration for MCP-I server
121
+ *
122
+ * This file configures runtime features like proof submission to AgentShield,
123
+ * delegation verification, and audit logging.
124
+ *
125
+ * Environment variables are automatically injected from wrangler.toml (Cloudflare)
126
+ * or .env (Node.js). Configure them there:
127
+ * - AGENTSHIELD_API_URL: AgentShield API base URL
128
+ * - AGENTSHIELD_API_KEY: Your AgentShield API key
129
+ * - AGENTSHIELD_PROJECT_ID: Your AgentShield project ID
130
+ * - MCPI_ENV: "development" or "production"
131
+ */
132
+ export function getRuntimeConfig(): MCPIRuntimeConfig {
133
+ const env = process.env;
134
+
135
+ return {
136
+ // Identity configuration
137
+ identity: {
138
+ environment: (env.MCPI_ENV as "development" | "production") || "development",
139
+ devIdentityPath: ".mcpi/identity.json"
140
+ },
141
+
142
+ // Proof submission configuration
143
+ proofing: {
144
+ enabled: true,
145
+ batchQueue: {
146
+ destinations: [
147
+ {
148
+ type: "agentshield" as const,
149
+ apiUrl: env.AGENTSHIELD_API_URL || "https://kya.vouched.id",
150
+ apiKey: env.AGENTSHIELD_API_KEY || ""
151
+ }
152
+ ],
153
+ maxBatchSize: 10,
154
+ flushIntervalMs: 5000,
155
+ maxRetries: 3,
156
+ debug: env.MCPI_ENV === "development"
157
+ }
158
+ },
159
+
160
+ // Delegation verification (AgentShield API)
161
+ delegation: {
162
+ enabled: true,
163
+ verifier: {
164
+ type: "agentshield-api",
165
+ agentshield: {
166
+ apiUrl: env.AGENTSHIELD_API_URL || "https://kya.vouched.id",
167
+ apiKey: env.AGENTSHIELD_API_KEY || ""
168
+ },
169
+ cacheTtl: 60000, // 1 minute cache
170
+ debug: env.MCPI_ENV === "development"
171
+ },
172
+ authorization: {
173
+ authorizationUrl: env.AUTHORIZATION_URL || \`\${env.AGENTSHIELD_API_URL}/authorize\`,
174
+ resumeTokenTtl: 600000, // 10 minutes
175
+ minReputationScore: 76
176
+ },
177
+ // ⚠️ DEPRECATED (if using dynamic tool protection):
178
+ // Tool protection rules - Configure scopes for auto-discovery in AgentShield
179
+ //
180
+ // NOTE: These are now managed via AgentShield dashboard and fetched dynamically
181
+ // when you enable the Tool Protection Service (see below). This fallback config
182
+ // is only used if:
183
+ // 1. Tool Protection Service is not configured, OR
184
+ // 2. AgentShield API is unavailable
185
+ toolProtections: {
186
+ // Example: Public tool with execution scope
187
+ greet: {
188
+ requiresDelegation: false, // No delegation needed for low-risk tool
189
+ requiredScopes: ["greet:execute"] // ✅ Enables tool discovery in AgentShield
190
+ }
191
+ // Add more tools as needed:
192
+ // High-risk tool requiring delegation:
193
+ // checkout: {
194
+ // requiresDelegation: true, // User must explicitly delegate
195
+ // requiredScopes: ["checkout:execute"] // Scope for tool discovery
196
+ // },
197
+ // delete_file: {
198
+ // requiresDelegation: true,
199
+ // requiredScopes: ["files:delete"] // Action-based scope for better categorization
200
+ // }
201
+ }
202
+ },
203
+
204
+ // 🆕 NEW: Dynamic Tool Protection Service (Dashboard-Controlled)
205
+ //
206
+ // Uncomment to enable dashboard-controlled tool delegation requirements:
207
+ // - Toggle "Require Delegation" for any tool in AgentShield dashboard
208
+ // - Changes apply in real-time (5-minute cache)
209
+ // - No code changes or redeployments needed
210
+ //
211
+ // Setup:
212
+ // 1. Create TOOL_PROTECTION_KV namespace: npm run kv:create-tool-protection
213
+ // 2. Uncomment the KV namespace in wrangler.toml
214
+ // 3. Uncomment the code below
215
+ // 4. Deploy and test by toggling delegation in the dashboard
216
+ //
217
+ // toolProtectionService: CloudflareRuntime.createToolProtectionService(
218
+ // env.TOOL_PROTECTION_KV, // KV namespace from wrangler.toml
219
+ // {
220
+ // apiUrl: env.AGENTSHIELD_API_URL || "https://kya.vouched.id",
221
+ // apiKey: env.AGENTSHIELD_API_KEY || "",
222
+ // projectId: env.AGENTSHIELD_PROJECT_ID || "",
223
+ // cacheTtl: 300000, // 5 minutes (in milliseconds)
224
+ // debug: env.MCPI_ENV === "development",
225
+ // // Fallback to local config if API unavailable
226
+ // fallbackConfig: {
227
+ // toolProtections: {
228
+ // greet: {
229
+ // requiresDelegation: false,
230
+ // requiredScopes: ["greet:execute"],
231
+ // },
232
+ // },
233
+ // },
234
+ // }
235
+ // ),
236
+
237
+ // Audit logging
238
+ audit: {
239
+ enabled: true
240
+ }
241
+ };
242
+ }
243
+
244
+ export default getRuntimeConfig();
245
+ `;
246
+ fs.writeFileSync(path.join(srcDir, "mcpi-runtime-config.ts"), runtimeConfigContent);
75
247
  // Create main index.ts using McpAgent with MCP-I runtime
76
248
  const indexContent = `import { McpAgent } from "agents/mcp";
77
249
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
78
- import { createCloudflareRuntime, type CloudflareEnv, KVProofArchive } from "@kya-os/mcp-i-cloudflare";
250
+ import { createCloudflareRuntime, type CloudflareEnv, KVProofArchive, type DetachedProof } from "@kya-os/mcp-i-cloudflare";
79
251
  import { Hono } from "hono";
80
252
  import { cors } from "hono/cors";
81
253
  import { greetTool } from "./tools/greet";
254
+ import { getRuntimeConfig } from "./mcpi-runtime-config";
82
255
 
83
256
  export class ${pascalClassName}MCP extends McpAgent {
84
257
  server = new McpServer({
@@ -88,27 +261,97 @@ export class ${pascalClassName}MCP extends McpAgent {
88
261
 
89
262
  private mcpiRuntime?: any;
90
263
  private proofArchive?: KVProofArchive;
264
+ private agentShieldConfig?: { apiUrl: string; apiKey: string };
91
265
  private env: CloudflareEnv;
92
266
 
93
267
  constructor(state: DurableObjectState, env: CloudflareEnv) {
94
268
  super(state, env);
95
269
  this.env = env;
96
270
 
271
+ // Load runtime configuration for AgentShield integration
272
+ const runtimeConfig = getRuntimeConfig();
273
+
97
274
  // Initialize MCP-I runtime for cryptographic proofs and identity
98
275
  this.mcpiRuntime = createCloudflareRuntime({
99
276
  env: env,
100
277
  audit: {
101
- enabled: true,
102
- logFunction: (record) => console.log('[MCP-I Audit]', record)
278
+ enabled: runtimeConfig.audit?.enabled ?? true,
279
+ logFunction: runtimeConfig.audit?.logFunction || ((record) => console.log('[MCP-I Audit]', record))
103
280
  }
104
281
  });
105
282
 
106
283
  // Initialize proof archive if PROOF_ARCHIVE KV is available
107
284
  if (env.PROOF_ARCHIVE) {
108
285
  this.proofArchive = new KVProofArchive(env.PROOF_ARCHIVE);
109
- console.log('[MCP-I] Proof archive enabled - proofs will be stored in KV');
110
- } else {
111
- console.warn('[MCP-I] PROOF_ARCHIVE KV not configured - proofs will only be logged');
286
+ console.log('[MCP-I] Proof archive enabled');
287
+ }
288
+
289
+ // Load AgentShield config for proof submission
290
+ if (runtimeConfig.proofing?.enabled && runtimeConfig.proofing.batchQueue) {
291
+ const agentShieldDest = runtimeConfig.proofing.batchQueue.destinations?.find(
292
+ (dest) => dest.type === "agentshield" && dest.apiKey
293
+ );
294
+ if (agentShieldDest) {
295
+ this.agentShieldConfig = {
296
+ apiUrl: agentShieldDest.apiUrl,
297
+ apiKey: agentShieldDest.apiKey!
298
+ };
299
+ console.log('[MCP-I] AgentShield enabled:', agentShieldDest.apiUrl);
300
+ }
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Submit proof to AgentShield API
306
+ * Uses the proof.jws directly (full JWS format from CloudflareRuntime)
307
+ */
308
+ private async submitProofToAgentShield(
309
+ proof: DetachedProof,
310
+ session: any
311
+ ): Promise<void> {
312
+ if (!this.agentShieldConfig || !proof.jws || !proof.meta) return;
313
+
314
+ const { apiUrl, apiKey } = this.agentShieldConfig;
315
+
316
+ // Proof already has correct format from CloudflareRuntime
317
+ const requestBody = {
318
+ session_id: session.id,
319
+ delegation_id: null,
320
+ proofs: [{
321
+ jws: proof.jws, // Already in full JWS format
322
+ meta: proof.meta // Already has all required fields
323
+ }]
324
+ };
325
+
326
+ console.log('[AgentShield] Submitting proof:', {
327
+ did: proof.meta.did,
328
+ sessionId: proof.meta.sessionId,
329
+ jwsFormat: proof.jws.split('.').length === 3 ? 'valid (3 parts)' : 'invalid'
330
+ });
331
+
332
+ const response = await fetch(\`\${apiUrl}/api/v1/bouncer/proofs\`, {
333
+ method: 'POST',
334
+ headers: {
335
+ 'Content-Type': 'application/json',
336
+ 'Authorization': \`Bearer \${apiKey}\`
337
+ },
338
+ body: JSON.stringify(requestBody)
339
+ });
340
+
341
+ if (!response.ok) {
342
+ const errorText = await response.text();
343
+ console.error('[AgentShield] Submission failed:', response.status, errorText);
344
+ throw new Error(\`AgentShield error: \${response.status}\`);
345
+ }
346
+
347
+ const responseData = await response.json() as any;
348
+ console.log('[AgentShield] Response:', responseData);
349
+
350
+ if (responseData.accepted) {
351
+ console.log('[AgentShield] ✅ Proofs accepted:', responseData.accepted);
352
+ }
353
+ if (responseData.rejected) {
354
+ console.log('[AgentShield] ❌ Proofs rejected:', responseData.rejected);
112
355
  }
113
356
  }
114
357
 
@@ -131,7 +374,7 @@ export class ${pascalClassName}MCP extends McpAgent {
131
374
  const timestamp = Date.now();
132
375
  const session = {
133
376
  id: \`ephemeral-\${timestamp}-\${Math.random().toString(36).substring(2, 10)}\`,
134
- audience: 'mcp-client',
377
+ audience: 'https://kya.vouched.id', // CRITICAL: Must match AgentShield domain
135
378
  agentDid: (await this.mcpiRuntime.getIdentity()).did,
136
379
  createdAt: timestamp,
137
380
  expiresAt: timestamp + (30 * 60 * 1000) // 30 minutes
@@ -145,41 +388,52 @@ export class ${pascalClassName}MCP extends McpAgent {
145
388
  session
146
389
  );
147
390
 
148
- // Get the proof that was just generated
149
- const proof = this.mcpiRuntime.getLastProof();
391
+ // Get proof in DetachedProof format
392
+ const proof = this.mcpiRuntime.getLastProof() as DetachedProof;
150
393
 
151
- if (proof) {
394
+ if (proof && proof.jws && proof.meta) {
395
+ // Log proof details (using DetachedProof format)
152
396
  console.log('[MCP-I Proof]', {
153
397
  tool: greetTool.name,
154
- did: proof.did,
155
- timestamp: proof.timestamp,
156
- signature: proof.signature.substring(0, 20) + '...'
398
+ did: proof.meta.did,
399
+ timestamp: proof.meta.ts,
400
+ jws: proof.jws.substring(0, 50) + '...',
401
+ jwsValid: proof.jws.split('.').length === 3
157
402
  });
158
403
 
159
- // Store proof in KV archive (if configured)
404
+ // Store in KV archive
160
405
  if (this.proofArchive) {
161
406
  try {
162
407
  await this.proofArchive.store(proof, {
163
- toolName: greetTool.name,
164
- sessionId: session.id
408
+ toolName: greetTool.name
165
409
  });
166
- console.log('[MCP-I] Proof stored in PROOF_ARCHIVE KV');
410
+ console.log('[MCP-I] Proof stored in archive');
167
411
  } catch (archiveError) {
168
- console.error('[MCP-I] Failed to store proof in archive:', archiveError);
169
- // Continue even if archiving fails
412
+ console.error('[MCP-I] Archive error:', archiveError);
170
413
  }
171
414
  }
172
415
 
173
- // Attach proof to result for MCP Inspector and clients
174
- // Following MCP-I pattern: { content: [...], _meta: { proof: {...} } }
416
+ // Submit to AgentShield
417
+ if (this.agentShieldConfig) {
418
+ try {
419
+ await this.submitProofToAgentShield(proof, session);
420
+ } catch (err: any) {
421
+ console.error('[MCP-I] AgentShield failed:', err.message);
422
+ }
423
+ }
424
+
425
+ // Attach proof to result for MCP Inspector
175
426
  if (result && typeof result === 'object') {
176
427
  (result as any)._meta = {
177
428
  proof: {
178
- did: proof.did,
179
- signature: proof.signature,
180
- timestamp: proof.timestamp,
181
- nonce: proof.nonce,
182
- algorithm: proof.algorithm
429
+ jws: proof.jws,
430
+ did: proof.meta.did,
431
+ kid: proof.meta.kid,
432
+ timestamp: proof.meta.ts,
433
+ nonce: proof.meta.nonce,
434
+ sessionId: proof.meta.sessionId,
435
+ requestHash: proof.meta.requestHash,
436
+ responseHash: proof.meta.responseHash
183
437
  }
184
438
  };
185
439
  }
@@ -221,7 +475,7 @@ app.mount("/mcp", ${pascalClassName}MCP.serve("/mcp").fetch, { replaceRequest: f
221
475
  export default app;
222
476
  `;
223
477
  fs.writeFileSync(path.join(srcDir, "index.ts"), indexContent);
224
- // Create wrangler.toml
478
+ // Create wrangler.toml with optional API key
225
479
  const wranglerContent = `#:schema node_modules/wrangler/config-schema.json
226
480
  name = "${projectName}"
227
481
  main = "src/index.ts"
@@ -262,9 +516,60 @@ id = "your-nonce-kv-namespace-id" # Replace with actual namespace ID
262
516
  binding = "PROOF_ARCHIVE" # Binding name must match runtime expectation
263
517
  id = "your-proof-kv-namespace-id" # Replace with actual namespace ID
264
518
 
519
+ # KV Namespace for identity storage (RECOMMENDED for persistent agent identity)
520
+ #
521
+ # Stores the agent's cryptographic identity (DID, keys) in KV
522
+ # Ensures consistent identity across Worker restarts and deployments
523
+ #
524
+ # Run: npm run kv:create-identity (creates IDENTITY_STORAGE namespace)
525
+ # Then replace the id below with the namespace ID from the output
526
+ #
527
+ [[kv_namespaces]]
528
+ binding = "IDENTITY_STORAGE" # Binding name must match runtime expectation
529
+ id = "your-identity-kv-namespace-id" # Replace with actual namespace ID
530
+
531
+ # KV Namespace for delegation storage (REQUIRED for OAuth/delegation flows)
532
+ #
533
+ # Stores active delegations from users to agents
534
+ # Enables OAuth consent flows and scope-based authorization
535
+ #
536
+ # Run: npm run kv:create-delegation (creates DELEGATION_STORAGE namespace)
537
+ # Then replace the id below with the namespace ID from the output
538
+ #
539
+ [[kv_namespaces]]
540
+ binding = "DELEGATION_STORAGE" # Binding name must match runtime expectation
541
+ id = "your-delegation-kv-namespace-id" # Replace with actual namespace ID
542
+
543
+ # KV Namespace for tool protection config (OPTIONAL for dashboard-controlled delegation)
544
+ #
545
+ # 🆕 NEW: Enables dynamic tool protection configuration from AgentShield dashboard
546
+ # Caches which tools require user delegation based on dashboard toggle switches
547
+ #
548
+ # Benefits:
549
+ # - Control tool permissions from AgentShield dashboard without code changes
550
+ # - Update delegation requirements in real-time
551
+ # - 5-minute cache reduces API calls while staying fresh
552
+ #
553
+ # Run: npm run kv:create-tool-protection (creates TOOL_PROTECTION_KV namespace)
554
+ # Then replace the id below with the namespace ID from the output
555
+ #
556
+ # Note: This is OPTIONAL. Comment out if you prefer hardcoded tool protections
557
+ # in mcpi-runtime-config.ts (see toolProtections section below)
558
+ #
559
+ [[kv_namespaces]]
560
+ binding = "TOOL_PROTECTION_KV" # Binding name for dynamic tool protection cache
561
+ id = "your-tool-protection-kv-id" # Replace with actual namespace ID
562
+
265
563
  [vars]
266
564
  XMCP_I_TS_SKEW_SEC = "120"
267
565
  XMCP_I_SESSION_TTL = "1800"
566
+
567
+ # AgentShield Integration (https://kya.vouched.id)
568
+ # ${apikey ? 'Configure' : 'Uncomment and configure'} these variables to enable proof submission to AgentShield
569
+ AGENTSHIELD_API_URL = "https://kya.vouched.id"
570
+ ${apikey ? `AGENTSHIELD_API_KEY = "${apikey}" # Provided via --apikey flag` : '# AGENTSHIELD_API_KEY = "sk_your_api_key_here" # Get from https://kya.vouched.id/dashboard'}
571
+ # AGENTSHIELD_PROJECT_ID = "your-project-id"
572
+ MCPI_ENV = "development"
268
573
  `;
269
574
  fs.writeFileSync(path.join(projectPath, "wrangler.toml"), wranglerContent);
270
575
  // Create tsconfig.json
@@ -319,37 +624,49 @@ ${packageManager} install
319
624
 
320
625
  ### 2. Create KV Namespaces
321
626
 
322
- #### Create Nonce Cache (Required)
627
+ #### Create All KV Namespaces (Recommended)
323
628
 
324
629
  \`\`\`bash
325
- ${packageManager === "npm" ? "npm run" : packageManager} kv:create-nonce
630
+ ${packageManager === "npm" ? "npm run" : packageManager} kv:create
326
631
  \`\`\`
327
632
 
328
- Copy the \`id\` from the output and update \`wrangler.toml\`:
633
+ This creates all 5 KV namespaces at once:
634
+ - \`NONCE_CACHE\` - Replay attack prevention (Required)
635
+ - \`PROOF_ARCHIVE\` - Cryptographic proof storage (Recommended)
636
+ - \`IDENTITY_STORAGE\` - Agent identity persistence (Recommended)
637
+ - \`DELEGATION_STORAGE\` - OAuth delegation storage (Required for delegation)
638
+ - \`TOOL_PROTECTION_KV\` - Dashboard-controlled permissions (Optional)
639
+
640
+ Copy the namespace IDs from the output and update each one in \`wrangler.toml\`:
329
641
 
330
642
  \`\`\`toml
331
643
  [[kv_namespaces]]
332
644
  binding = "NONCE_CACHE"
333
645
  id = "your-nonce-kv-id-here" # ← Update this
334
- \`\`\`
335
-
336
- #### Create Proof Archive (Recommended)
337
646
 
338
- \`\`\`bash
339
- ${packageManager === "npm" ? "npm run" : packageManager} kv:create-proof
340
- \`\`\`
647
+ [[kv_namespaces]]
648
+ binding = "PROOF_ARCHIVE"
649
+ id = "your-proof-kv-id-here" # ← Update this
341
650
 
342
- This runs: \`wrangler kv namespace create PROOF_ARCHIVE\`
651
+ [[kv_namespaces]]
652
+ binding = "IDENTITY_STORAGE"
653
+ id = "your-identity-kv-id-here" # ← Update this
343
654
 
344
- Copy the \`id\` from the output and update \`wrangler.toml\`:
655
+ [[kv_namespaces]]
656
+ binding = "DELEGATION_STORAGE"
657
+ id = "your-delegation-kv-id-here" # ← Update this
345
658
 
346
- \`\`\`toml
347
659
  [[kv_namespaces]]
348
- binding = "PROOF_ARCHIVE"
349
- id = "your-proof-kv-id-here" # ← Update this
660
+ binding = "TOOL_PROTECTION_KV"
661
+ id = "your-tool-protection-kv-id-here" # ← Update this
350
662
  \`\`\`
351
663
 
352
- **Note:** The PROOF_ARCHIVE stores cryptographic proofs for auditability. If you don't need proof archiving, you can comment out this namespace in \`wrangler.toml\`.
664
+ **Note:** You can also create namespaces individually:
665
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-nonce\` - Create nonce cache only
666
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-proof\` - Create proof archive only
667
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-identity\` - Create identity storage only
668
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-delegation\` - Create delegation storage only
669
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-tool-protection\` - Create tool protection cache only
353
670
 
354
671
  ### 3. Test Locally
355
672
 
@@ -462,6 +779,105 @@ The identity includes:
462
779
  - \`publicKey\`: Ed25519 public key for signature verification
463
780
  - \`privateKey\`: Ed25519 private key (secured in Durable Object state)
464
781
 
782
+ ## AgentShield Integration
783
+
784
+ This project is configured to send cryptographic proofs to AgentShield for audit trails and compliance monitoring.
785
+
786
+ ### Setup
787
+
788
+ 1. **Get your AgentShield API key**:
789
+ - Sign up at https://kya.vouched.id
790
+ - Create a project
791
+ - Copy your API key from the dashboard
792
+
793
+ 2. **Update \`wrangler.toml\`**:
794
+ \`\`\`toml
795
+ [vars]
796
+ AGENTSHIELD_API_URL = "https://kya.vouched.id"
797
+ AGENTSHIELD_API_KEY = "sk_your_actual_key_here" # ← Replace this
798
+ AGENTSHIELD_PROJECT_ID = "your-project-id" # ← Replace this
799
+ MCPI_ENV = "development"
800
+ \`\`\`
801
+
802
+ 3. **Test proof submission**:
803
+ \`\`\`bash
804
+ ${packageManager === "npm" ? "npm run" : packageManager} dev
805
+ \`\`\`
806
+
807
+ Call a tool and check the logs:
808
+ \`\`\`
809
+ [AgentShield] Submitting proof: { did: 'did:web:...', sessionId: '...', jwsFormat: 'valid (3 parts)' }
810
+ [AgentShield] ✅ Proofs accepted: 1
811
+ \`\`\`
812
+
813
+ 4. **View proofs in dashboard**:
814
+ - Go to https://kya.vouched.id/dashboard
815
+ - Select your project
816
+ - Click "Interactions" tab
817
+ - See your proofs in real-time
818
+
819
+ ### Configuration
820
+
821
+ The AgentShield integration is configured in \`src/mcpi-runtime-config.ts\`. You can customize:
822
+ - Proof batch size (\`maxBatchSize\`)
823
+ - Flush interval (\`flushIntervalMs\`)
824
+ - Retry policy (\`maxRetries\`)
825
+ - Tool protection rules (\`toolProtections\`)
826
+
827
+ ### Dashboard-Controlled Tool Protection (Advanced)
828
+
829
+ 🆕 **NEW**: Control which tools require user delegation directly from the AgentShield dashboard - no code changes needed!
830
+
831
+ Instead of hardcoding \`requiresDelegation\` in your config, enable dynamic tool protection:
832
+
833
+ 1. **Create Tool Protection KV namespace**:
834
+ \`\`\`bash
835
+ ${packageManager === "npm" ? "npm run" : packageManager} kv:create-tool-protection
836
+ \`\`\`
837
+
838
+ 2. **Uncomment TOOL_PROTECTION_KV in \`wrangler.toml\`**:
839
+ \`\`\`toml
840
+ [[kv_namespaces]]
841
+ binding = "TOOL_PROTECTION_KV"
842
+ id = "your-tool-protection-kv-id" # ← Add the ID from step 1
843
+ \`\`\`
844
+
845
+ 3. **Enable Tool Protection Service in \`src/mcpi-runtime-config.ts\`**:
846
+ - Uncomment the import: \`import { CloudflareRuntime } from "@kya-os/mcp-i-cloudflare";\`
847
+ - Uncomment the \`toolProtectionService\` configuration block
848
+
849
+ 4. **Deploy and test**:
850
+ \`\`\`bash
851
+ ${packageManager === "npm" ? "npm run" : packageManager} deploy
852
+ \`\`\`
853
+
854
+ 5. **Control delegation from dashboard**:
855
+ - Go to https://kya.vouched.id/dashboard
856
+ - Select your project → "Tools" tab
857
+ - Toggle "Require Delegation" for any tool
858
+ - Changes apply in real-time (5-minute cache)
859
+
860
+ **Benefits:**
861
+ - Update tool permissions without redeploying
862
+ - Test delegation flows instantly
863
+ - Different requirements per environment (dev vs prod)
864
+ - Automatic tool discovery from proof submissions
865
+
866
+ **Note:** The first time a tool is called, it auto-discovers in the dashboard. The \`requiresDelegation\` toggle will appear after the first proof is submitted.
867
+
868
+ ### Disable AgentShield (Optional)
869
+
870
+ If you don't want to use AgentShield, edit \`src/mcpi-runtime-config.ts\`:
871
+
872
+ \`\`\`typescript
873
+ proofing: {
874
+ enabled: false, // Disable proof submission
875
+ // ...
876
+ }
877
+ \`\`\`
878
+
879
+ Or simply don't configure the \`AGENTSHIELD_API_KEY\` environment variable.
880
+
465
881
  ## References
466
882
 
467
883
  - [Cloudflare Agents MCP](https://developers.cloudflare.com/agents/model-context-protocol/)
@@ -470,6 +886,28 @@ The identity includes:
470
886
  `;
471
887
  fs.writeFileSync(path.join(projectPath, "README.md"), readmeContent);
472
888
  console.log(chalk.green("✅ Cloudflare Worker MCP server created"));
889
+ console.log();
890
+ if (apikey) {
891
+ console.log(chalk.green("🔑 AgentShield API key configured in wrangler.toml"));
892
+ console.log(chalk.dim(" Your API key has been added to the [vars] section"));
893
+ console.log(chalk.dim(" Remember to add your AGENTSHIELD_PROJECT_ID before deployment"));
894
+ console.log();
895
+ }
896
+ else {
897
+ console.log(chalk.yellow("⚠️ No AgentShield API key provided"));
898
+ console.log(chalk.dim(" Add your API key to wrangler.toml [vars] section before deployment"));
899
+ console.log(chalk.dim(" Get your key at: https://kya.vouched.id/dashboard"));
900
+ console.log();
901
+ }
902
+ console.log(chalk.bold("📦 All KV Namespaces Configured"));
903
+ console.log(chalk.dim(" - NONCE_CACHE: Replay attack prevention"));
904
+ console.log(chalk.dim(" - PROOF_ARCHIVE: Cryptographic proof storage"));
905
+ console.log(chalk.dim(" - IDENTITY_STORAGE: Agent identity persistence"));
906
+ console.log(chalk.dim(" - DELEGATION_STORAGE: OAuth delegation storage"));
907
+ console.log(chalk.dim(" - TOOL_PROTECTION_KV: Dashboard-controlled permissions"));
908
+ console.log();
909
+ console.log(chalk.cyan(" Run 'npm run kv:create' to create all namespaces"));
910
+ console.log();
473
911
  }
474
912
  catch (error) {
475
913
  console.error(chalk.red("Failed to set up Cloudflare Worker MCP server:"), error);