@kya-os/create-mcpi-app 1.3.5-canary.0 → 1.3.5-canary.10

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",
27
- "kv:create-nonce": `wrangler kv namespace create NONCE_CACHE`,
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'",
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
+ "kv:create-nonce": `wrangler kv namespace create ${className.toUpperCase()}_NONCE_CACHE`,
28
+ "kv:create-proof": `wrangler kv namespace create ${className.toUpperCase()}_PROOF_ARCHIVE`,
29
+ "kv:create-identity": `wrangler kv namespace create ${className.toUpperCase()}_IDENTITY_STORAGE`,
30
+ "kv:create-delegation": `wrangler kv namespace create ${className.toUpperCase()}_DELEGATION_STORAGE`,
31
+ "kv:create-tool-protection": `wrangler kv namespace create ${className.toUpperCase()}_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=${className.toUpperCase()}_NONCE_CACHE`,
34
+ "kv:keys-proof": `wrangler kv key list --binding=${className.toUpperCase()}_PROOF_ARCHIVE`,
35
+ "kv:keys-identity": `wrangler kv key list --binding=${className.toUpperCase()}_IDENTITY_STORAGE`,
36
+ "kv:keys-delegation": `wrangler kv key list --binding=${className.toUpperCase()}_DELEGATION_STORAGE`,
37
+ "kv:keys-tool-protection": `wrangler kv key list --binding=${className.toUpperCase()}_TOOL_PROTECTION_KV`,
38
+ "kv:delete-nonce": `wrangler kv namespace delete --binding=${className.toUpperCase()}_NONCE_CACHE`,
39
+ "kv:delete-proof": `wrangler kv namespace delete --binding=${className.toUpperCase()}_PROOF_ARCHIVE`,
40
+ "kv:delete-identity": `wrangler kv namespace delete --binding=${className.toUpperCase()}_IDENTITY_STORAGE`,
41
+ "kv:delete-delegation": `wrangler kv namespace delete --binding=${className.toUpperCase()}_DELEGATION_STORAGE`,
42
+ "kv:delete-tool-protection": `wrangler kv namespace delete --binding=${className.toUpperCase()}_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-canary.8",
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,135 @@ 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
+
274
+ // Create CloudflareEnv adapter to map prefixed KV bindings to expected names
275
+ // This allows multiple agents to be deployed without KV namespace conflicts
276
+ const mappedEnv: CloudflareEnv = {
277
+ // Map prefixed bindings to standard names expected by createCloudflareRuntime
278
+ NONCE_CACHE: (env as any).${className.toUpperCase()}_NONCE_CACHE,
279
+ PROOF_ARCHIVE: (env as any).${className.toUpperCase()}_PROOF_ARCHIVE,
280
+ IDENTITY_STORAGE: (env as any).${className.toUpperCase()}_IDENTITY_STORAGE,
281
+ TOOL_PROTECTION_KV: (env as any).${className.toUpperCase()}_TOOL_PROTECTION_KV,
282
+ // Pass through environment variables unchanged
283
+ MCP_IDENTITY_PRIVATE_KEY: (env as any).MCP_IDENTITY_PRIVATE_KEY,
284
+ MCP_IDENTITY_PUBLIC_KEY: (env as any).MCP_IDENTITY_PUBLIC_KEY,
285
+ MCP_IDENTITY_AGENT_DID: (env as any).MCP_IDENTITY_AGENT_DID,
286
+ };
287
+
97
288
  // Initialize MCP-I runtime for cryptographic proofs and identity
98
289
  this.mcpiRuntime = createCloudflareRuntime({
99
- env: env,
290
+ env: mappedEnv,
100
291
  audit: {
101
- enabled: true,
102
- logFunction: (record) => console.log('[MCP-I Audit]', record)
292
+ enabled: runtimeConfig.audit?.enabled ?? true,
293
+ logFunction: runtimeConfig.audit?.logFunction || ((record) => console.log('[MCP-I Audit]', record))
103
294
  }
104
295
  });
105
296
 
106
297
  // Initialize proof archive if PROOF_ARCHIVE KV is available
107
- if (env.PROOF_ARCHIVE) {
108
- 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');
298
+ if (mappedEnv.PROOF_ARCHIVE) {
299
+ this.proofArchive = new KVProofArchive(mappedEnv.PROOF_ARCHIVE);
300
+ console.log('[MCP-I] Proof archive enabled');
301
+ }
302
+
303
+ // Load AgentShield config for proof submission
304
+ if (runtimeConfig.proofing?.enabled && runtimeConfig.proofing.batchQueue) {
305
+ const agentShieldDest = runtimeConfig.proofing.batchQueue.destinations?.find(
306
+ (dest) => dest.type === "agentshield" && dest.apiKey
307
+ );
308
+ if (agentShieldDest) {
309
+ this.agentShieldConfig = {
310
+ apiUrl: agentShieldDest.apiUrl,
311
+ apiKey: agentShieldDest.apiKey!
312
+ };
313
+ console.log('[MCP-I] AgentShield enabled:', agentShieldDest.apiUrl);
314
+ }
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Submit proof to AgentShield API
320
+ * Uses the proof.jws directly (full JWS format from CloudflareRuntime)
321
+ *
322
+ * Also submits optional context for AgentShield dashboard integration.
323
+ * Context provides plaintext tool/args data while proof provides cryptographic verification.
324
+ */
325
+ private async submitProofToAgentShield(
326
+ proof: DetachedProof,
327
+ session: any,
328
+ toolName: string,
329
+ args: any,
330
+ result: any
331
+ ): Promise<void> {
332
+ if (!this.agentShieldConfig || !proof.jws || !proof.meta) return;
333
+
334
+ const { apiUrl, apiKey } = this.agentShieldConfig;
335
+
336
+ // Get tool call context from runtime (if available)
337
+ const toolCallContext = this.mcpiRuntime?.getLastToolCallContext();
338
+
339
+ // Proof already has correct format from CloudflareRuntime
340
+ // Adding optional context for AgentShield dashboard (Option A architecture)
341
+ const requestBody = {
342
+ session_id: session.id,
343
+ delegation_id: null,
344
+ proofs: [{
345
+ jws: proof.jws, // Already in full JWS format
346
+ meta: proof.meta // Already has all required fields
347
+ }],
348
+ // ✅ NEW: Optional context for dashboard integration
349
+ context: toolCallContext ? {
350
+ toolCalls: [toolCallContext]
351
+ } : {
352
+ // Fallback if context not available from runtime
353
+ toolCalls: [{
354
+ tool: toolName,
355
+ args: args,
356
+ result: result,
357
+ scopeId: proof.meta.scopeId || \`\${toolName}:execute\`
358
+ }]
359
+ }
360
+ };
361
+
362
+ console.log('[AgentShield] Submitting proof with context:', {
363
+ did: proof.meta.did,
364
+ sessionId: proof.meta.sessionId,
365
+ jwsFormat: proof.jws.split('.').length === 3 ? 'valid (3 parts)' : 'invalid',
366
+ contextTool: requestBody.context.toolCalls[0]?.tool,
367
+ contextScopeId: requestBody.context.toolCalls[0]?.scopeId
368
+ });
369
+
370
+ const response = await fetch(\`\${apiUrl}/api/v1/bouncer/proofs\`, {
371
+ method: 'POST',
372
+ headers: {
373
+ 'Content-Type': 'application/json',
374
+ 'Authorization': \`Bearer \${apiKey}\`
375
+ },
376
+ body: JSON.stringify(requestBody)
377
+ });
378
+
379
+ if (!response.ok) {
380
+ const errorText = await response.text();
381
+ console.error('[AgentShield] Submission failed:', response.status, errorText);
382
+ throw new Error(\`AgentShield error: \${response.status}\`);
383
+ }
384
+
385
+ const responseData = await response.json() as any;
386
+ console.log('[AgentShield] Response:', responseData);
387
+
388
+ if (responseData.accepted) {
389
+ console.log('[AgentShield] ✅ Proofs accepted:', responseData.accepted);
390
+ }
391
+ if (responseData.rejected) {
392
+ console.log('[AgentShield] ❌ Proofs rejected:', responseData.rejected);
112
393
  }
113
394
  }
114
395
 
@@ -131,7 +412,7 @@ export class ${pascalClassName}MCP extends McpAgent {
131
412
  const timestamp = Date.now();
132
413
  const session = {
133
414
  id: \`ephemeral-\${timestamp}-\${Math.random().toString(36).substring(2, 10)}\`,
134
- audience: 'mcp-client',
415
+ audience: 'https://kya.vouched.id', // CRITICAL: Must match AgentShield domain
135
416
  agentDid: (await this.mcpiRuntime.getIdentity()).did,
136
417
  createdAt: timestamp,
137
418
  expiresAt: timestamp + (30 * 60 * 1000) // 30 minutes
@@ -145,41 +426,52 @@ export class ${pascalClassName}MCP extends McpAgent {
145
426
  session
146
427
  );
147
428
 
148
- // Get the proof that was just generated
149
- const proof = this.mcpiRuntime.getLastProof();
429
+ // Get proof in DetachedProof format
430
+ const proof = this.mcpiRuntime.getLastProof() as DetachedProof;
150
431
 
151
- if (proof) {
432
+ if (proof && proof.jws && proof.meta) {
433
+ // Log proof details (using DetachedProof format)
152
434
  console.log('[MCP-I Proof]', {
153
435
  tool: greetTool.name,
154
- did: proof.did,
155
- timestamp: proof.timestamp,
156
- signature: proof.signature.substring(0, 20) + '...'
436
+ did: proof.meta.did,
437
+ timestamp: proof.meta.ts,
438
+ jws: proof.jws.substring(0, 50) + '...',
439
+ jwsValid: proof.jws.split('.').length === 3
157
440
  });
158
441
 
159
- // Store proof in KV archive (if configured)
442
+ // Store in KV archive
160
443
  if (this.proofArchive) {
161
444
  try {
162
445
  await this.proofArchive.store(proof, {
163
- toolName: greetTool.name,
164
- sessionId: session.id
446
+ toolName: greetTool.name
165
447
  });
166
- console.log('[MCP-I] Proof stored in PROOF_ARCHIVE KV');
448
+ console.log('[MCP-I] Proof stored in archive');
167
449
  } catch (archiveError) {
168
- console.error('[MCP-I] Failed to store proof in archive:', archiveError);
169
- // Continue even if archiving fails
450
+ console.error('[MCP-I] Archive error:', archiveError);
451
+ }
452
+ }
453
+
454
+ // Submit to AgentShield with context
455
+ if (this.agentShieldConfig) {
456
+ try {
457
+ await this.submitProofToAgentShield(proof, session, greetTool.name, args, result);
458
+ } catch (err: any) {
459
+ console.error('[MCP-I] AgentShield failed:', err.message);
170
460
  }
171
461
  }
172
462
 
173
- // Attach proof to result for MCP Inspector and clients
174
- // Following MCP-I pattern: { content: [...], _meta: { proof: {...} } }
463
+ // Attach proof to result for MCP Inspector
175
464
  if (result && typeof result === 'object') {
176
465
  (result as any)._meta = {
177
466
  proof: {
178
- did: proof.did,
179
- signature: proof.signature,
180
- timestamp: proof.timestamp,
181
- nonce: proof.nonce,
182
- algorithm: proof.algorithm
467
+ jws: proof.jws,
468
+ did: proof.meta.did,
469
+ kid: proof.meta.kid,
470
+ timestamp: proof.meta.ts,
471
+ nonce: proof.meta.nonce,
472
+ sessionId: proof.meta.sessionId,
473
+ requestHash: proof.meta.requestHash,
474
+ responseHash: proof.meta.responseHash
183
475
  }
184
476
  };
185
477
  }
@@ -221,7 +513,7 @@ app.mount("/mcp", ${pascalClassName}MCP.serve("/mcp").fetch, { replaceRequest: f
221
513
  export default app;
222
514
  `;
223
515
  fs.writeFileSync(path.join(srcDir, "index.ts"), indexContent);
224
- // Create wrangler.toml
516
+ // Create wrangler.toml with optional API key
225
517
  const wranglerContent = `#:schema node_modules/wrangler/config-schema.json
226
518
  name = "${projectName}"
227
519
  main = "src/index.ts"
@@ -246,8 +538,8 @@ new_sqlite_classes = ["${pascalClassName}MCP"]
246
538
  #
247
539
  # Then replace the id below with the namespace ID from the output
248
540
  [[kv_namespaces]]
249
- binding = "NONCE_CACHE" # Binding name must match runtime expectation
250
- id = "your-nonce-kv-namespace-id" # Replace with actual namespace ID
541
+ binding = "${className.toUpperCase()}_NONCE_CACHE"
542
+ id = "your_nonce_kv_namespace_id" # Replace with actual namespace ID
251
543
 
252
544
  # KV Namespace for proof archive (RECOMMENDED for auditability)
253
545
  #
@@ -259,12 +551,63 @@ id = "your-nonce-kv-namespace-id" # Replace with actual namespace ID
259
551
  #
260
552
  # Note: Comment out if you don't need proof archiving
261
553
  [[kv_namespaces]]
262
- binding = "PROOF_ARCHIVE" # Binding name must match runtime expectation
263
- id = "your-proof-kv-namespace-id" # Replace with actual namespace ID
554
+ binding = "${className.toUpperCase()}_PROOF_ARCHIVE"
555
+ id = "your_proof_kv_namespace_id" # Replace with actual namespace ID
556
+
557
+ # KV Namespace for identity storage (RECOMMENDED for persistent agent identity)
558
+ #
559
+ # Stores the agent's cryptographic identity (DID, keys) in KV
560
+ # Ensures consistent identity across Worker restarts and deployments
561
+ #
562
+ # Run: npm run kv:create-identity (creates IDENTITY_STORAGE namespace)
563
+ # Then replace the id below with the namespace ID from the output
564
+ #
565
+ [[kv_namespaces]]
566
+ binding = "${className.toUpperCase()}_IDENTITY_STORAGE"
567
+ id = "your_identity_kv_namespace_id" # Replace with actual namespace ID
568
+
569
+ # KV Namespace for delegation storage (REQUIRED for OAuth/delegation flows)
570
+ #
571
+ # Stores active delegations from users to agents
572
+ # Enables OAuth consent flows and scope-based authorization
573
+ #
574
+ # Run: npm run kv:create-delegation (creates DELEGATION_STORAGE namespace)
575
+ # Then replace the id below with the namespace ID from the output
576
+ #
577
+ [[kv_namespaces]]
578
+ binding = "${className.toUpperCase()}_DELEGATION_STORAGE"
579
+ id = "your_delegation_kv_namespace_id" # Replace with actual namespace ID
580
+
581
+ # KV Namespace for tool protection config (OPTIONAL for dashboard-controlled delegation)
582
+ #
583
+ # 🆕 NEW: Enables dynamic tool protection configuration from AgentShield dashboard
584
+ # Caches which tools require user delegation based on dashboard toggle switches
585
+ #
586
+ # Benefits:
587
+ # - Control tool permissions from AgentShield dashboard without code changes
588
+ # - Update delegation requirements in real-time
589
+ # - 5-minute cache reduces API calls while staying fresh
590
+ #
591
+ # Run: npm run kv:create-tool-protection (creates TOOL_PROTECTION_KV namespace)
592
+ # Then replace the id below with the namespace ID from the output
593
+ #
594
+ # Note: This is OPTIONAL. Comment out if you prefer hardcoded tool protections
595
+ # in mcpi-runtime-config.ts (see toolProtections section below)
596
+ #
597
+ [[kv_namespaces]]
598
+ binding = "${className.toUpperCase()}_TOOL_PROTECTION_KV"
599
+ id = "your_tool_protection_kv_id" # Replace with actual namespace ID
264
600
 
265
601
  [vars]
266
602
  XMCP_I_TS_SKEW_SEC = "120"
267
603
  XMCP_I_SESSION_TTL = "1800"
604
+
605
+ # AgentShield Integration (https://kya.vouched.id)
606
+ # ${apikey ? 'Configure' : 'Uncomment and configure'} these variables to enable proof submission to AgentShield
607
+ AGENTSHIELD_API_URL = "https://kya.vouched.id"
608
+ ${apikey ? `AGENTSHIELD_API_KEY = "${apikey}" # Provided via --apikey flag` : '# AGENTSHIELD_API_KEY = "sk_your_api_key_here" # Get from https://kya.vouched.id/dashboard'}
609
+ # AGENTSHIELD_PROJECT_ID = "your-project-id"
610
+ MCPI_ENV = "development"
268
611
  `;
269
612
  fs.writeFileSync(path.join(projectPath, "wrangler.toml"), wranglerContent);
270
613
  // Create tsconfig.json
@@ -319,37 +662,49 @@ ${packageManager} install
319
662
 
320
663
  ### 2. Create KV Namespaces
321
664
 
322
- #### Create Nonce Cache (Required)
665
+ #### Create All KV Namespaces (Recommended)
323
666
 
324
667
  \`\`\`bash
325
- ${packageManager === "npm" ? "npm run" : packageManager} kv:create-nonce
668
+ ${packageManager === "npm" ? "npm run" : packageManager} kv:create
326
669
  \`\`\`
327
670
 
328
- Copy the \`id\` from the output and update \`wrangler.toml\`:
671
+ This creates all 5 KV namespaces at once:
672
+ - \`NONCE_CACHE\` - Replay attack prevention (Required)
673
+ - \`PROOF_ARCHIVE\` - Cryptographic proof storage (Recommended)
674
+ - \`IDENTITY_STORAGE\` - Agent identity persistence (Recommended)
675
+ - \`DELEGATION_STORAGE\` - OAuth delegation storage (Required for delegation)
676
+ - \`TOOL_PROTECTION_KV\` - Dashboard-controlled permissions (Optional)
677
+
678
+ Copy the namespace IDs from the output and update each one in \`wrangler.toml\`:
329
679
 
330
680
  \`\`\`toml
331
681
  [[kv_namespaces]]
332
682
  binding = "NONCE_CACHE"
333
- id = "your-nonce-kv-id-here" # ← Update this
334
- \`\`\`
335
-
336
- #### Create Proof Archive (Recommended)
683
+ id = "your_nonce_kv_id_here" # ← Update this
337
684
 
338
- \`\`\`bash
339
- ${packageManager === "npm" ? "npm run" : packageManager} kv:create-proof
340
- \`\`\`
685
+ [[kv_namespaces]]
686
+ binding = "PROOF_ARCHIVE"
687
+ id = "your_proof_kv_id_here" # ← Update this
341
688
 
342
- This runs: \`wrangler kv namespace create PROOF_ARCHIVE\`
689
+ [[kv_namespaces]]
690
+ binding = "IDENTITY_STORAGE"
691
+ id = "your_identity_kv_id_here" # ← Update this
343
692
 
344
- Copy the \`id\` from the output and update \`wrangler.toml\`:
693
+ [[kv_namespaces]]
694
+ binding = "DELEGATION_STORAGE"
695
+ id = "your_delegation_kv_id_here" # ← Update this
345
696
 
346
- \`\`\`toml
347
697
  [[kv_namespaces]]
348
- binding = "PROOF_ARCHIVE"
349
- id = "your-proof-kv-id-here" # ← Update this
698
+ binding = "TOOL_PROTECTION_KV"
699
+ id = "your_tool_protection_kv_id_here" # ← Update this
350
700
  \`\`\`
351
701
 
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\`.
702
+ **Note:** You can also create namespaces individually:
703
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-nonce\` - Create nonce cache only
704
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-proof\` - Create proof archive only
705
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-identity\` - Create identity storage only
706
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-delegation\` - Create delegation storage only
707
+ - \`${packageManager === "npm" ? "npm run" : packageManager} kv:create-tool-protection\` - Create tool protection cache only
353
708
 
354
709
  ### 3. Test Locally
355
710
 
@@ -444,10 +799,10 @@ If you configured the \`PROOF_ARCHIVE\` KV namespace, proofs are also stored for
444
799
 
445
800
  \`\`\`bash
446
801
  # List all proofs
447
- wrangler kv:key list --namespace-id=your-proof-kv-id
802
+ wrangler kv:key list --namespace-id=your_proof_kv_id
448
803
 
449
804
  # View a specific proof
450
- wrangler kv:key get "proof_1234567890_abcd" --namespace-id=your-proof-kv-id
805
+ wrangler kv:key get "proof_1234567890_abcd" --namespace-id=your_proof_kv_id
451
806
  \`\`\`
452
807
 
453
808
  ## Identity Management
@@ -462,6 +817,105 @@ The identity includes:
462
817
  - \`publicKey\`: Ed25519 public key for signature verification
463
818
  - \`privateKey\`: Ed25519 private key (secured in Durable Object state)
464
819
 
820
+ ## AgentShield Integration
821
+
822
+ This project is configured to send cryptographic proofs to AgentShield for audit trails and compliance monitoring.
823
+
824
+ ### Setup
825
+
826
+ 1. **Get your AgentShield API key**:
827
+ - Sign up at https://kya.vouched.id
828
+ - Create a project
829
+ - Copy your API key from the dashboard
830
+
831
+ 2. **Update \`wrangler.toml\`**:
832
+ \`\`\`toml
833
+ [vars]
834
+ AGENTSHIELD_API_URL = "https://kya.vouched.id"
835
+ AGENTSHIELD_API_KEY = "sk_your_actual_key_here" # ← Replace this
836
+ AGENTSHIELD_PROJECT_ID = "your-project-id" # ← Replace this
837
+ MCPI_ENV = "development"
838
+ \`\`\`
839
+
840
+ 3. **Test proof submission**:
841
+ \`\`\`bash
842
+ ${packageManager === "npm" ? "npm run" : packageManager} dev
843
+ \`\`\`
844
+
845
+ Call a tool and check the logs:
846
+ \`\`\`
847
+ [AgentShield] Submitting proof: { did: 'did:web:...', sessionId: '...', jwsFormat: 'valid (3 parts)' }
848
+ [AgentShield] ✅ Proofs accepted: 1
849
+ \`\`\`
850
+
851
+ 4. **View proofs in dashboard**:
852
+ - Go to https://kya.vouched.id/dashboard
853
+ - Select your project
854
+ - Click "Interactions" tab
855
+ - See your proofs in real-time
856
+
857
+ ### Configuration
858
+
859
+ The AgentShield integration is configured in \`src/mcpi-runtime-config.ts\`. You can customize:
860
+ - Proof batch size (\`maxBatchSize\`)
861
+ - Flush interval (\`flushIntervalMs\`)
862
+ - Retry policy (\`maxRetries\`)
863
+ - Tool protection rules (\`toolProtections\`)
864
+
865
+ ### Dashboard-Controlled Tool Protection (Advanced)
866
+
867
+ 🆕 **NEW**: Control which tools require user delegation directly from the AgentShield dashboard - no code changes needed!
868
+
869
+ Instead of hardcoding \`requiresDelegation\` in your config, enable dynamic tool protection:
870
+
871
+ 1. **Create Tool Protection KV namespace**:
872
+ \`\`\`bash
873
+ ${packageManager === "npm" ? "npm run" : packageManager} kv:create-tool-protection
874
+ \`\`\`
875
+
876
+ 2. **Uncomment TOOL_PROTECTION_KV in \`wrangler.toml\`**:
877
+ \`\`\`toml
878
+ [[kv_namespaces]]
879
+ binding = "TOOL_PROTECTION_KV"
880
+ id = "your_tool_protection_kv_id" # ← Add the ID from step 1
881
+ \`\`\`
882
+
883
+ 3. **Enable Tool Protection Service in \`src/mcpi-runtime-config.ts\`**:
884
+ - Uncomment the import: \`import { CloudflareRuntime } from "@kya-os/mcp-i-cloudflare";\`
885
+ - Uncomment the \`toolProtectionService\` configuration block
886
+
887
+ 4. **Deploy and test**:
888
+ \`\`\`bash
889
+ ${packageManager === "npm" ? "npm run" : packageManager} deploy
890
+ \`\`\`
891
+
892
+ 5. **Control delegation from dashboard**:
893
+ - Go to https://kya.vouched.id/dashboard
894
+ - Select your project → "Tools" tab
895
+ - Toggle "Require Delegation" for any tool
896
+ - Changes apply in real-time (5-minute cache)
897
+
898
+ **Benefits:**
899
+ - Update tool permissions without redeploying
900
+ - Test delegation flows instantly
901
+ - Different requirements per environment (dev vs prod)
902
+ - Automatic tool discovery from proof submissions
903
+
904
+ **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.
905
+
906
+ ### Disable AgentShield (Optional)
907
+
908
+ If you don't want to use AgentShield, edit \`src/mcpi-runtime-config.ts\`:
909
+
910
+ \`\`\`typescript
911
+ proofing: {
912
+ enabled: false, // Disable proof submission
913
+ // ...
914
+ }
915
+ \`\`\`
916
+
917
+ Or simply don't configure the \`AGENTSHIELD_API_KEY\` environment variable.
918
+
465
919
  ## References
466
920
 
467
921
  - [Cloudflare Agents MCP](https://developers.cloudflare.com/agents/model-context-protocol/)
@@ -470,6 +924,28 @@ The identity includes:
470
924
  `;
471
925
  fs.writeFileSync(path.join(projectPath, "README.md"), readmeContent);
472
926
  console.log(chalk.green("✅ Cloudflare Worker MCP server created"));
927
+ console.log();
928
+ if (apikey) {
929
+ console.log(chalk.green("🔑 AgentShield API key configured in wrangler.toml"));
930
+ console.log(chalk.dim(" Your API key has been added to the [vars] section"));
931
+ console.log(chalk.dim(" Remember to add your AGENTSHIELD_PROJECT_ID before deployment"));
932
+ console.log();
933
+ }
934
+ else {
935
+ console.log(chalk.yellow("⚠️ No AgentShield API key provided"));
936
+ console.log(chalk.dim(" Add your API key to wrangler.toml [vars] section before deployment"));
937
+ console.log(chalk.dim(" Get your key at: https://kya.vouched.id/dashboard"));
938
+ console.log();
939
+ }
940
+ console.log(chalk.bold("📦 All KV Namespaces Configured"));
941
+ console.log(chalk.dim(" - NONCE_CACHE: Replay attack prevention"));
942
+ console.log(chalk.dim(" - PROOF_ARCHIVE: Cryptographic proof storage"));
943
+ console.log(chalk.dim(" - IDENTITY_STORAGE: Agent identity persistence"));
944
+ console.log(chalk.dim(" - DELEGATION_STORAGE: OAuth delegation storage"));
945
+ console.log(chalk.dim(" - TOOL_PROTECTION_KV: Dashboard-controlled permissions"));
946
+ console.log();
947
+ console.log(chalk.cyan(" Run 'npm run kv:create' to create all namespaces"));
948
+ console.log();
473
949
  }
474
950
  catch (error) {
475
951
  console.error(chalk.red("Failed to set up Cloudflare Worker MCP server:"), error);