@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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/helpers/create.d.ts +1 -0
- package/dist/helpers/create.d.ts.map +1 -1
- package/dist/helpers/create.js +2 -1
- package/dist/helpers/create.js.map +1 -1
- package/dist/helpers/fetch-cloudflare-mcpi-template.d.ts +1 -0
- package/dist/helpers/fetch-cloudflare-mcpi-template.d.ts.map +1 -1
- package/dist/helpers/fetch-cloudflare-mcpi-template.js +485 -47
- package/dist/helpers/fetch-cloudflare-mcpi-template.js.map +1 -1
- package/dist/helpers/fetch-cloudflare-template.js +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -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:
|
|
30
|
-
"kv:
|
|
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.
|
|
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
|
|
110
|
-
}
|
|
111
|
-
|
|
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: '
|
|
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
|
|
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.
|
|
156
|
-
|
|
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
|
|
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
|
|
410
|
+
console.log('[MCP-I] Proof stored in archive');
|
|
167
411
|
} catch (archiveError) {
|
|
168
|
-
console.error('[MCP-I]
|
|
169
|
-
// Continue even if archiving fails
|
|
412
|
+
console.error('[MCP-I] Archive error:', archiveError);
|
|
170
413
|
}
|
|
171
414
|
}
|
|
172
415
|
|
|
173
|
-
//
|
|
174
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
|
627
|
+
#### Create All KV Namespaces (Recommended)
|
|
323
628
|
|
|
324
629
|
\`\`\`bash
|
|
325
|
-
${packageManager === "npm" ? "npm run" : packageManager} kv:create
|
|
630
|
+
${packageManager === "npm" ? "npm run" : packageManager} kv:create
|
|
326
631
|
\`\`\`
|
|
327
632
|
|
|
328
|
-
|
|
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
|
-
|
|
339
|
-
|
|
340
|
-
|
|
647
|
+
[[kv_namespaces]]
|
|
648
|
+
binding = "PROOF_ARCHIVE"
|
|
649
|
+
id = "your-proof-kv-id-here" # ← Update this
|
|
341
650
|
|
|
342
|
-
|
|
651
|
+
[[kv_namespaces]]
|
|
652
|
+
binding = "IDENTITY_STORAGE"
|
|
653
|
+
id = "your-identity-kv-id-here" # ← Update this
|
|
343
654
|
|
|
344
|
-
|
|
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 = "
|
|
349
|
-
id = "your-
|
|
660
|
+
binding = "TOOL_PROTECTION_KV"
|
|
661
|
+
id = "your-tool-protection-kv-id-here" # ← Update this
|
|
350
662
|
\`\`\`
|
|
351
663
|
|
|
352
|
-
**Note:**
|
|
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);
|