@kya-os/create-mcpi-app 1.7.16 → 1.7.19

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.
@@ -7,7 +7,7 @@ import { generateIdentity } from "./generate-identity.js";
7
7
  * Uses McpAgent from agents/mcp for MCP protocol support
8
8
  */
9
9
  export async function fetchCloudflareMcpiTemplate(projectPath, options = {}) {
10
- const { packageManager = "npm", projectName = path.basename(projectPath), apikey, skipIdentity = false, } = options;
10
+ const { packageManager = "npm", projectName = path.basename(projectPath), apikey, projectId, skipIdentity = false, } = options;
11
11
  // Sanitize project name for class names
12
12
  const className = projectName
13
13
  .replace(/[^a-zA-Z0-9]/g, "")
@@ -518,7 +518,7 @@ describe('Delegation Management', () => {
518
518
  */
519
519
  describe('DO Multi-Instance Routing', () => {
520
520
 
521
- function getDoInstanceId(request: Request, env: any): string {
521
+ function getDoInstanceId(request: Request, env: { DO_ROUTING_STRATEGY?: string; DO_SHARD_COUNT?: string }): string {
522
522
  const strategy = env.DO_ROUTING_STRATEGY || 'session';
523
523
  const headers = request.headers;
524
524
 
@@ -602,7 +602,7 @@ describe('DO Multi-Instance Routing', () => {
602
602
  */
603
603
  describe('Security Configuration', () => {
604
604
 
605
- function getCorsOrigin(requestOrigin: string | null, env: any): string | null {
605
+ function getCorsOrigin(requestOrigin: string | null, env: { ALLOWED_ORIGINS?: string; MCPI_ENV?: string }): string | null {
606
606
  const allowedOrigins = env.ALLOWED_ORIGINS?.split(',').map((o: string) => o.trim()) || [
607
607
  'https://claude.ai',
608
608
  'https://app.anthropic.com'
@@ -738,8 +738,12 @@ export const greetTool = {
738
738
  `;
739
739
  fs.writeFileSync(path.join(toolsDir, "greet.ts"), greetToolContent);
740
740
  // Create mcpi-runtime-config.ts for AgentShield integration
741
- const runtimeConfigContent = `import type { MCPIRuntimeConfig } from "@kya-os/mcp-i-cloudflare";
742
- ${apikey ? 'import { CloudflareRuntime } from "@kya-os/mcp-i-cloudflare"; // Auto-enabled: Tool Protection Service' : '// import { CloudflareRuntime } from "@kya-os/mcp-i-cloudflare"; // Uncomment to enable Tool Protection Service'}
741
+ const runtimeConfigContent = `import type { MCPIConfig } from '@kya-os/contracts/config';
742
+ import type { CloudflareRuntimeConfig } from '@kya-os/mcp-i-cloudflare/config';
743
+ import type { CloudflareEnv } from '@kya-os/mcp-i-cloudflare';
744
+ import { buildBaseConfig } from '@kya-os/create-mcpi-app/config-builder';
745
+ // Always import CloudflareRuntime for tool protection service creation
746
+ import { CloudflareRuntime } from "@kya-os/mcp-i-cloudflare";
743
747
 
744
748
  /**
745
749
  * Runtime configuration for MCP-I server
@@ -755,151 +759,112 @@ ${apikey ? 'import { CloudflareRuntime } from "@kya-os/mcp-i-cloudflare"; // Au
755
759
  *
756
760
  * Note: The service fetches tool protection config by agent DID automatically.
757
761
  * No project ID configuration needed!
762
+ *
763
+ * This config uses the unified MCPIConfig architecture, ensuring the same
764
+ * base configuration shape across all platforms (Cloudflare, Node.js, Vercel).
758
765
  */
759
- export function getRuntimeConfig(env: any): MCPIRuntimeConfig {
760
- // Accept env parameter to work in both Node.js (process.env) and Cloudflare Workers (worker env)
766
+ export function getRuntimeConfig(env: CloudflareEnv): CloudflareRuntimeConfig {
767
+ // Build base config that works across all platforms
768
+ const baseConfig = buildBaseConfig(env);
761
769
 
770
+ // Extend with Cloudflare-specific properties
762
771
  return {
772
+ ...baseConfig,
763
773
  // Identity configuration
764
774
  identity: {
765
- environment: (env.MCPI_ENV as "development" | "production") || "development",
766
- devIdentityPath: ".mcpi/identity.json"
775
+ ...baseConfig.identity,
776
+ enabled: true,
777
+ environment: (env.ENVIRONMENT || env.MCPI_ENV || 'development') as 'development' | 'production'
767
778
  },
768
-
769
- // Proof submission configuration
779
+ // Proofing configuration
770
780
  proofing: {
771
781
  enabled: true,
772
782
  batchQueue: {
773
783
  destinations: [
774
784
  {
775
785
  type: "agentshield" as const,
776
- apiUrl: env.AGENTSHIELD_API_URL || "https://kya.vouched.id",
777
- apiKey: env.AGENTSHIELD_API_KEY || ""
786
+ apiUrl: env.AGENTSHIELD_API_URL || 'https://kya.vouched.id',
787
+ apiKey: env.AGENTSHIELD_API_KEY || ''
778
788
  }
779
789
  ],
780
790
  maxBatchSize: 10,
781
791
  flushIntervalMs: 5000,
782
792
  maxRetries: 3,
783
- debug: env.MCPI_ENV === "development"
793
+ debug: (env.ENVIRONMENT || env.MCPI_ENV || 'development') === 'development'
784
794
  }
785
795
  },
786
-
787
- // Delegation verification (AgentShield API)
796
+ // Delegation configuration
788
797
  delegation: {
789
- enabled: true,
790
- enforceDelegations: true, // ✅ NEW: Enable enforcement of delegation requirements
791
- verifier: {
792
- type: "agentshield-api",
793
- agentshield: {
794
- apiUrl: env.AGENTSHIELD_API_URL || "https://kya.vouched.id",
795
- apiKey: env.AGENTSHIELD_API_KEY || ""
796
- },
797
- cacheTtl: 60000, // 1 minute cache
798
- debug: env.MCPI_ENV === "development"
799
- },
800
- authorization: {
801
- authorizationUrl: env.AUTHORIZATION_URL || \`\${env.AGENTSHIELD_API_URL}/authorize\`,
802
- resumeTokenTtl: 600000, // 10 minutes
803
- minReputationScore: 76
798
+ ...baseConfig.delegation
799
+ },
800
+ // Audit configuration
801
+ audit: {
802
+ ...baseConfig.audit
803
+ },
804
+ // Cloudflare Workers-specific configuration
805
+ workers: {
806
+ cpuMs: 50,
807
+ memoryMb: 128
808
+ },
809
+ // KV namespace bindings
810
+ kv: env.TOOL_PROTECTION_KV ? [{
811
+ name: 'TOOL_PROTECTION_KV',
812
+ purpose: 'cache' as const
813
+ }] : [],
814
+ // Environment variable bindings
815
+ vars: {
816
+ ENVIRONMENT: env.ENVIRONMENT || env.MCPI_ENV || 'development',
817
+ AGENTSHIELD_API_KEY: env.AGENTSHIELD_API_KEY
818
+ },
819
+ // Tool protection service (Cloudflare-specific)
820
+ toolProtection: env.TOOL_PROTECTION_KV && env.AGENTSHIELD_API_KEY ? {
821
+ source: 'agentshield' as const,
822
+ agentShield: {
823
+ apiUrl: env.AGENTSHIELD_API_URL || 'https://kya.vouched.id',
824
+ apiKey: env.AGENTSHIELD_API_KEY,
825
+ projectId: env.AGENTSHIELD_PROJECT_ID,
826
+ cacheTtl: 300000 // 5 minutes
804
827
  },
805
- // ⚠️ DEPRECATED (if using dynamic tool protection):
806
- // Tool protection rules - Configure scopes for auto-discovery in AgentShield
807
- //
808
- // NOTE: These are now managed via AgentShield dashboard and fetched dynamically
809
- // when you enable the Tool Protection Service (see below). This fallback config
810
- // is only used if:
811
- // 1. Tool Protection Service is not configured, OR
812
- // 2. AgentShield API is unavailable
813
- toolProtections: {
814
- // Example: Public tool with execution scope
828
+ fallback: {
815
829
  greet: {
816
- requiresDelegation: false, // No delegation needed for low-risk tool
817
- requiredScopes: ["greet:execute"] // ✅ Enables tool discovery in AgentShield
830
+ requiresDelegation: false,
831
+ requiredScopes: ['greet:execute']
818
832
  }
819
- // Add more tools as needed:
820
- // High-risk tool requiring delegation:
821
- // checkout: {
822
- // requiresDelegation: true, // User must explicitly delegate
823
- // requiredScopes: ["checkout:execute"] // Scope for tool discovery
824
- // },
825
- // delete_file: {
826
- // requiresDelegation: true,
827
- // requiredScopes: ["files:delete"] // Action-based scope for better categorization
828
- // }
829
833
  }
830
- },
831
-
832
- // 🆕 Dynamic Tool Protection Service (Dashboard-Controlled)
833
- //
834
- // When AgentShield API key is configured, tool delegation requirements
835
- // are fetched from the dashboard in real-time (5-minute cache).
836
- //
837
- // Benefits:
838
- // - Toggle "Require Delegation" for any tool in dashboard - no code changes
839
- // - Changes apply in real-time (5-minute cache via KV)
840
- // - Automatic tool discovery from proof submissions
841
- //
842
- // Performance: 1 API call per 5 minutes, all other requests use KV cache
843
- ${apikey
844
- ? `toolProtectionService: env.TOOL_PROTECTION_KV
845
- ? CloudflareRuntime.createToolProtectionService(
846
- env.TOOL_PROTECTION_KV, // KV namespace from wrangler.toml
847
- {
848
- apiUrl: env.AGENTSHIELD_API_URL || "https://kya.vouched.id",
849
- apiKey: env.AGENTSHIELD_API_KEY || "",
850
- projectId: env.AGENTSHIELD_PROJECT_ID, // Optional: Use projectId endpoint (preferred) if available
851
- cacheTtl: 300000, // 5 minutes (in milliseconds)
852
- debug: env.MCPI_ENV === "development",
853
- // Fallback to local config if API unavailable
854
- fallbackConfig: {
855
- toolProtections: {
856
- greet: {
857
- requiresDelegation: false,
858
- requiredScopes: ["greet:execute"],
859
- },
860
- },
861
- },
862
- }
863
- )
864
- : undefined,`
865
- : `// toolProtectionService: env.TOOL_PROTECTION_KV
866
- // ? CloudflareRuntime.createToolProtectionService(
867
- // env.TOOL_PROTECTION_KV,
868
- // {
869
- // apiUrl: env.AGENTSHIELD_API_URL || "https://kya.vouched.id",
870
- // apiKey: env.AGENTSHIELD_API_KEY || "",
871
- // projectId: env.AGENTSHIELD_PROJECT_ID, // Optional: Use projectId endpoint (preferred) if available
872
- // cacheTtl: 300000, // 5 minutes
873
- // debug: env.MCPI_ENV === "development",
874
- // fallbackConfig: {
875
- // toolProtections: {
876
- // greet: {
877
- // requiresDelegation: false,
878
- // requiredScopes: ["greet:execute"],
879
- // },
880
- // },
881
- // },
882
- // }
883
- // )
884
- // : undefined,`}
885
-
886
- // Audit logging
887
- audit: {
888
- enabled: true
889
- }
890
- };
834
+ } : undefined
835
+ } as CloudflareRuntimeConfig;
891
836
  }
892
837
  `;
893
838
  fs.writeFileSync(path.join(srcDir, "mcpi-runtime-config.ts"), runtimeConfigContent);
894
839
  // Create main index.ts using McpAgent with MCP-I runtime
895
840
  const indexContent = `import { McpAgent } from "agents/mcp";
896
841
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
897
- import { createCloudflareRuntime, type CloudflareEnv, KVProofArchive, type DetachedProof, createOAuthCallbackHandler } from "@kya-os/mcp-i-cloudflare";
842
+ import { createCloudflareRuntime, type CloudflareEnv, KVProofArchive, type DetachedProof, createOAuthCallbackHandler, CloudflareRuntime } from "@kya-os/mcp-i-cloudflare";
898
843
  import { DelegationRequiredError } from "@kya-os/mcp-i-core";
844
+ import type { ToolProtectionService } from "@kya-os/mcp-i-core";
899
845
  import { Hono } from "hono";
900
846
  import { cors } from "hono/cors";
901
847
  import { greetTool } from "./tools/greet";
902
848
  import { getRuntimeConfig } from "./mcpi-runtime-config";
849
+ import type { CloudflareRuntimeConfig } from "@kya-os/mcp-i-cloudflare/config";
850
+
851
+ /**
852
+ * Extended CloudflareEnv with prefixed KV bindings for multi-agent deployments
853
+ * This allows multiple agents to share the same Cloudflare account without conflicts
854
+ */
855
+ interface PrefixedCloudflareEnv extends CloudflareEnv {
856
+ // Prefixed KV bindings (e.g., MYAGENT_NONCE_CACHE, MYAGENT_PROOF_ARCHIVE)
857
+ [key: string]: KVNamespace | string | DurableObjectState | undefined;
858
+ // Optional routing configuration
859
+ DO_ROUTING_STRATEGY?: string;
860
+ DO_SHARD_COUNT?: string;
861
+ // Prefixed KV namespaces (dynamically accessed)
862
+ ${className.toUpperCase()}_NONCE_CACHE?: KVNamespace;
863
+ ${className.toUpperCase()}_PROOF_ARCHIVE?: KVNamespace;
864
+ ${className.toUpperCase()}_IDENTITY_STORAGE?: KVNamespace;
865
+ ${className.toUpperCase()}_DELEGATION_STORAGE?: KVNamespace;
866
+ ${className.toUpperCase()}_TOOL_PROTECTION_KV?: KVNamespace;
867
+ }
903
868
 
904
869
  export class ${pascalClassName}MCP extends McpAgent {
905
870
  server = new McpServer({
@@ -907,13 +872,13 @@ export class ${pascalClassName}MCP extends McpAgent {
907
872
  version: "1.0.0"
908
873
  });
909
874
 
910
- private mcpiRuntime?: any;
875
+ private mcpiRuntime?: ReturnType<typeof createCloudflareRuntime>;
911
876
  private proofArchive?: KVProofArchive;
912
877
  private agentShieldConfig?: { apiUrl: string; apiKey: string };
913
- private env: CloudflareEnv;
878
+ private env: PrefixedCloudflareEnv;
914
879
  private mcpServerUrl?: string;
915
880
 
916
- constructor(state: DurableObjectState, env: CloudflareEnv) {
881
+ constructor(state: DurableObjectState, env: PrefixedCloudflareEnv) {
917
882
  super(state, env);
918
883
  this.env = env;
919
884
 
@@ -921,29 +886,29 @@ export class ${pascalClassName}MCP extends McpAgent {
921
886
  // This allows multiple agents to be deployed without KV namespace conflicts
922
887
  const mappedEnv: CloudflareEnv = {
923
888
  // Map prefixed bindings to standard names expected by createCloudflareRuntime
924
- NONCE_CACHE: (env as any).${className.toUpperCase()}_NONCE_CACHE,
925
- PROOF_ARCHIVE: (env as any).${className.toUpperCase()}_PROOF_ARCHIVE,
926
- IDENTITY_STORAGE: (env as any).${className.toUpperCase()}_IDENTITY_STORAGE,
927
- DELEGATION_STORAGE: (env as any).${className.toUpperCase()}_DELEGATION_STORAGE,
928
- TOOL_PROTECTION_KV: (env as any).${className.toUpperCase()}_TOOL_PROTECTION_KV,
889
+ NONCE_CACHE: env.${className.toUpperCase()}_NONCE_CACHE,
890
+ PROOF_ARCHIVE: env.${className.toUpperCase()}_PROOF_ARCHIVE,
891
+ IDENTITY_STORAGE: env.${className.toUpperCase()}_IDENTITY_STORAGE,
892
+ DELEGATION_STORAGE: env.${className.toUpperCase()}_DELEGATION_STORAGE,
893
+ TOOL_PROTECTION_KV: env.${className.toUpperCase()}_TOOL_PROTECTION_KV,
929
894
  // Pass through environment variables unchanged
930
- MCP_IDENTITY_PRIVATE_KEY: (env as any).MCP_IDENTITY_PRIVATE_KEY,
931
- MCP_IDENTITY_PUBLIC_KEY: (env as any).MCP_IDENTITY_PUBLIC_KEY,
932
- MCP_IDENTITY_AGENT_DID: (env as any).MCP_IDENTITY_AGENT_DID,
895
+ MCP_IDENTITY_PRIVATE_KEY: env.MCP_IDENTITY_PRIVATE_KEY,
896
+ MCP_IDENTITY_PUBLIC_KEY: env.MCP_IDENTITY_PUBLIC_KEY,
897
+ MCP_IDENTITY_AGENT_DID: env.MCP_IDENTITY_AGENT_DID,
933
898
  // Pass through other env vars for runtime config
934
- AGENTSHIELD_API_URL: (env as any).AGENTSHIELD_API_URL,
935
- AGENTSHIELD_API_KEY: (env as any).AGENTSHIELD_API_KEY,
936
- AGENTSHIELD_PROJECT_ID: (env as any).AGENTSHIELD_PROJECT_ID,
937
- MCPI_ENV: (env as any).MCPI_ENV,
938
- MCP_SERVER_URL: (env as any).MCP_SERVER_URL,
899
+ AGENTSHIELD_API_URL: env.AGENTSHIELD_API_URL,
900
+ AGENTSHIELD_API_KEY: env.AGENTSHIELD_API_KEY,
901
+ AGENTSHIELD_PROJECT_ID: env.AGENTSHIELD_PROJECT_ID,
902
+ MCPI_ENV: env.MCPI_ENV,
903
+ MCP_SERVER_URL: env.MCP_SERVER_URL,
939
904
  // Pass Durable Object state for identity persistence
940
905
  // NOTE: Without this, identity will be ephemeral (new DID every call)!
941
- // TODO: Implement KV-based identity provider for shared identity across DO instances
906
+ // Note: createCloudflareRuntime will automatically use KVIdentityProvider if IDENTITY_STORAGE KV is available
942
907
  _durableObjectState: state,
943
908
  };
944
909
 
945
910
  // Store MCP server URL for proof submission context
946
- this.mcpServerUrl = (env as any).MCP_SERVER_URL;
911
+ this.mcpServerUrl = env.MCP_SERVER_URL;
947
912
  if (this.mcpServerUrl) {
948
913
  console.log('[MCP-I] MCP Server URL configured:', this.mcpServerUrl);
949
914
  } else {
@@ -954,14 +919,44 @@ export class ${pascalClassName}MCP extends McpAgent {
954
919
  // Pass mappedEnv so it can access KV bindings with standard names
955
920
  const runtimeConfig = getRuntimeConfig(mappedEnv);
956
921
 
922
+ // ✅ Create tool protection service helper function
923
+ // Always import CloudflareRuntime but conditionally instantiate
924
+ function createToolProtectionService(env: CloudflareEnv, runtimeConfig: CloudflareRuntimeConfig): ToolProtectionService | undefined {
925
+ if (!runtimeConfig.toolProtection) {
926
+ return undefined;
927
+ }
928
+
929
+ if (!env.TOOL_PROTECTION_KV || !env.AGENTSHIELD_API_KEY) {
930
+ console.log('[MCP-I] Tool protection disabled - configure TOOL_PROTECTION_KV and AGENTSHIELD_API_KEY to enable');
931
+ return undefined;
932
+ }
933
+
934
+ return CloudflareRuntime.createToolProtectionService(
935
+ env.TOOL_PROTECTION_KV,
936
+ {
937
+ apiUrl: runtimeConfig.toolProtection.agentShield?.apiUrl || env.AGENTSHIELD_API_URL || 'https://kya.vouched.id',
938
+ apiKey: env.AGENTSHIELD_API_KEY,
939
+ projectId: runtimeConfig.toolProtection.agentShield?.projectId || env.AGENTSHIELD_PROJECT_ID,
940
+ cacheTtl: runtimeConfig.toolProtection.agentShield?.cacheTtl || 300000,
941
+ debug: runtimeConfig.environment === 'development',
942
+ fallbackConfig: runtimeConfig.toolProtection.fallback
943
+ }
944
+ );
945
+ }
946
+
947
+ // Create tool protection service if configured
948
+ // Note: createCloudflareRuntime will automatically use KVIdentityProvider if IDENTITY_STORAGE KV is available
949
+ const toolProtectionService = createToolProtectionService(mappedEnv, runtimeConfig);
950
+
957
951
  // Initialize MCP-I runtime for cryptographic proofs and identity
958
952
  this.mcpiRuntime = createCloudflareRuntime({
959
953
  env: mappedEnv,
954
+ environment: runtimeConfig.environment,
960
955
  audit: {
961
956
  enabled: runtimeConfig.audit?.enabled ?? true,
962
957
  logFunction: runtimeConfig.audit?.logFunction || ((record) => console.log('[MCP-I Audit]', record))
963
958
  },
964
- toolProtectionService: runtimeConfig.toolProtectionService
959
+ toolProtectionService
965
960
  });
966
961
 
967
962
  // Initialize proof archive if PROOF_ARCHIVE KV is available
@@ -1001,7 +996,7 @@ export class ${pascalClassName}MCP extends McpAgent {
1001
996
  const sessionId = this.getSessionId();
1002
997
 
1003
998
  // Get routing strategy from environment (default: session)
1004
- const strategy = (this.env as any).DO_ROUTING_STRATEGY || 'session';
999
+ const strategy = this.env.DO_ROUTING_STRATEGY || 'session';
1005
1000
 
1006
1001
  if (strategy === 'session') {
1007
1002
  // One DO instance per MCP session (recommended for most use cases)
@@ -1010,7 +1005,7 @@ export class ${pascalClassName}MCP extends McpAgent {
1010
1005
  } else if (strategy === 'shard') {
1011
1006
  // Hash-based sharding across N DO instances (for high load)
1012
1007
  // Distributes load evenly while maintaining session affinity
1013
- const shardCount = parseInt((this.env as any).DO_SHARD_COUNT || '10');
1008
+ const shardCount = parseInt(this.env.DO_SHARD_COUNT || '10');
1014
1009
  // Validate shard count - must be a valid positive number
1015
1010
  const validShardCount = (!isNaN(shardCount) && shardCount > 0) ? shardCount : 10;
1016
1011
 
@@ -1042,7 +1037,7 @@ export class ${pascalClassName}MCP extends McpAgent {
1042
1037
  * @returns Delegation token if found, null otherwise
1043
1038
  */
1044
1039
  private async getDelegationToken(sessionId?: string): Promise<string | null> {
1045
- const delegationStorage = (this.env as any).${className.toUpperCase()}_DELEGATION_STORAGE;
1040
+ const delegationStorage = this.env.${className.toUpperCase()}_DELEGATION_STORAGE;
1046
1041
 
1047
1042
  if (!delegationStorage) {
1048
1043
  console.log('[Delegation] No delegation storage configured');
@@ -1116,7 +1111,7 @@ export class ${pascalClassName}MCP extends McpAgent {
1116
1111
  */
1117
1112
  private async verifyDelegationWithAgentShield(token: string): Promise<boolean> {
1118
1113
  // Check verification cache first (1 minute TTL for verified tokens)
1119
- const verificationCache = (this.env as any).TOOL_PROTECTION_KV;
1114
+ const verificationCache = this.env.TOOL_PROTECTION_KV;
1120
1115
  if (verificationCache) {
1121
1116
  const cacheKey = \`verified:\${token.substring(0, 16)}\`; // Use prefix to avoid key size issues
1122
1117
  const cached = await verificationCache.get(cacheKey);
@@ -1127,8 +1122,8 @@ export class ${pascalClassName}MCP extends McpAgent {
1127
1122
  }
1128
1123
 
1129
1124
  try {
1130
- const agentShieldUrl = (this.env as any).AGENTSHIELD_API_URL || 'https://hobbs.work';
1131
- const apiKey = (this.env as any).AGENTSHIELD_API_KEY;
1125
+ const agentShieldUrl = this.env.AGENTSHIELD_API_URL || 'https://kya.vouched.id';
1126
+ const apiKey = this.env.AGENTSHIELD_API_KEY;
1132
1127
 
1133
1128
  if (!apiKey) {
1134
1129
  console.warn('[Delegation] No AgentShield API key configured, skipping verification');
@@ -1178,8 +1173,8 @@ export class ${pascalClassName}MCP extends McpAgent {
1178
1173
  * @param agentDid - Agent DID to clear
1179
1174
  */
1180
1175
  private async invalidateDelegationCache(sessionId?: string, token?: string, agentDid?: string): Promise<void> {
1181
- const delegationStorage = (this.env as any).${className.toUpperCase()}_DELEGATION_STORAGE;
1182
- const verificationCache = (this.env as any).TOOL_PROTECTION_KV;
1176
+ const delegationStorage = this.env.${className.toUpperCase()}_DELEGATION_STORAGE;
1177
+ const verificationCache = this.env.TOOL_PROTECTION_KV;
1183
1178
 
1184
1179
  if (!delegationStorage) return;
1185
1180
 
@@ -1216,10 +1211,10 @@ export class ${pascalClassName}MCP extends McpAgent {
1216
1211
  */
1217
1212
  private async submitProofToAgentShield(
1218
1213
  proof: DetachedProof,
1219
- session: any,
1214
+ session: { id: string },
1220
1215
  toolName: string,
1221
- args: any,
1222
- result: any
1216
+ args: Record<string, unknown>,
1217
+ result: unknown
1223
1218
  ): Promise<void> {
1224
1219
  if (!this.agentShieldConfig || !proof.jws || !proof.meta) return;
1225
1220
 
@@ -1275,7 +1270,7 @@ export class ${pascalClassName}MCP extends McpAgent {
1275
1270
  throw new Error(\`AgentShield error: \${response.status}\`);
1276
1271
  }
1277
1272
 
1278
- const responseData = await response.json() as any;
1273
+ const responseData = await response.json() as { success?: boolean; received?: number; processed?: number; accepted?: number; rejected?: number; errors?: Array<{ proofId: string; error: string }> };
1279
1274
  console.log('[AgentShield] Response:', responseData);
1280
1275
 
1281
1276
  if (responseData.accepted) {
@@ -1297,7 +1292,7 @@ export class ${pascalClassName}MCP extends McpAgent {
1297
1292
  greetTool.name,
1298
1293
  greetTool.description,
1299
1294
  greetTool.inputSchema.shape,
1300
- async (args: any) => {
1295
+ async (args: { name: string }) => {
1301
1296
  // Use MCP-I runtime's processToolCall for automatic proof generation
1302
1297
  if (this.mcpiRuntime) {
1303
1298
  try {
@@ -1358,8 +1353,8 @@ export class ${pascalClassName}MCP extends McpAgent {
1358
1353
  toolName: greetTool.name
1359
1354
  }).then(() => {
1360
1355
  console.log('[MCP-I] Proof stored in archive');
1361
- }).catch((archiveError: any) => {
1362
- console.error('[MCP-I] Archive error:', archiveError);
1356
+ }).catch((archiveError: unknown) => {
1357
+ console.error('[MCP-I] Archive error:', archiveError instanceof Error ? archiveError.message : String(archiveError));
1363
1358
  })
1364
1359
  );
1365
1360
  }
@@ -1368,8 +1363,8 @@ export class ${pascalClassName}MCP extends McpAgent {
1368
1363
  if (this.agentShieldConfig) {
1369
1364
  proofOperations.push(
1370
1365
  this.submitProofToAgentShield(proof, session, greetTool.name, args, result)
1371
- .catch((err: any) => {
1372
- console.error('[MCP-I] AgentShield failed:', err.message);
1366
+ .catch((err: unknown) => {
1367
+ console.error('[MCP-I] AgentShield failed:', err instanceof Error ? err.message : String(err));
1373
1368
  })
1374
1369
  );
1375
1370
  }
@@ -1380,8 +1375,8 @@ export class ${pascalClassName}MCP extends McpAgent {
1380
1375
  }
1381
1376
 
1382
1377
  // Attach proof to result for MCP Inspector
1383
- if (result && typeof result === 'object') {
1384
- (result as any)._meta = {
1378
+ if (result && typeof result === 'object' && result !== null) {
1379
+ (result as Record<string, unknown>)._meta = {
1385
1380
  proof: {
1386
1381
  jws: proof.jws,
1387
1382
  did: proof.meta.did,
@@ -1397,10 +1392,10 @@ export class ${pascalClassName}MCP extends McpAgent {
1397
1392
  }
1398
1393
 
1399
1394
  return result;
1400
- } catch (error: any) {
1395
+ } catch (error: unknown) {
1401
1396
  // If this is a DelegationRequiredError, re-throw it so the MCP framework can handle it properly
1402
1397
  // The agents/mcp framework will format it as a proper error response to Claude Desktop
1403
- if (error instanceof DelegationRequiredError || error?.name === 'DelegationRequiredError') {
1398
+ if (error instanceof DelegationRequiredError) {
1404
1399
  console.warn('[MCP-I] Delegation required, propagating error:', {
1405
1400
  tool: error.toolName,
1406
1401
  requiredScopes: error.requiredScopes,
@@ -1408,6 +1403,16 @@ export class ${pascalClassName}MCP extends McpAgent {
1408
1403
  });
1409
1404
  throw error;
1410
1405
  }
1406
+ // Check for DelegationRequiredError by name (for cases where error is not instanceof)
1407
+ if (error && typeof error === 'object' && 'name' in error && error.name === 'DelegationRequiredError') {
1408
+ const delegationError = error as DelegationRequiredError;
1409
+ console.warn('[MCP-I] Delegation required, propagating error:', {
1410
+ tool: delegationError.toolName,
1411
+ requiredScopes: delegationError.requiredScopes,
1412
+ consentUrl: delegationError.consentUrl
1413
+ });
1414
+ throw error;
1415
+ }
1411
1416
 
1412
1417
  // For other errors, log and fallback to direct execution
1413
1418
  console.error('[MCP-I] Failed to process tool with runtime:', error);
@@ -1472,7 +1477,7 @@ app.get("/health", (c) => c.json({
1472
1477
  * { "success": true, "message": "Cache cleared", "agent_did": "..." }
1473
1478
  */
1474
1479
  app.post("/admin/clear-cache", async (c) => {
1475
- const env = c.env as any;
1480
+ const env = c.env as PrefixedCloudflareEnv;
1476
1481
 
1477
1482
  // Parse request body first to get agent_did
1478
1483
  const body = await c.req.json().catch(() => ({}));
@@ -1584,7 +1589,7 @@ app.post("/admin/clear-cache", async (c) => {
1584
1589
  * 4. Returns success page to user
1585
1590
  */
1586
1591
  app.get('/oauth/callback', (c) => {
1587
- const env = c.env as any;
1592
+ const env = c.env as PrefixedCloudflareEnv;
1588
1593
  return createOAuthCallbackHandler({
1589
1594
  agentShieldApiUrl: env.AGENTSHIELD_API_URL || 'https://kya.vouched.id',
1590
1595
  delegationStorage: env.${className.toUpperCase()}_DELEGATION_STORAGE,
@@ -1680,9 +1685,11 @@ id = "your_delegation_kv_namespace_id" # Auto-filled by setup script
1680
1685
  # If you need to recreate it: npm run kv:create-tool-protection
1681
1686
  # After deployment, toggle delegation requirements in AgentShield dashboard
1682
1687
  #
1683
- ${apikey ? "" : "# "}[[kv_namespaces]]
1684
- ${apikey ? "" : "# "}binding = "${className.toUpperCase()}_TOOL_PROTECTION_KV"
1685
- ${apikey ? "" : "# "}id = "your_tool_protection_kv_id" # Auto-filled by setup script
1688
+ # Note: This namespace is REQUIRED when using AgentShield API key (--apikey)
1689
+ # It will be automatically created by the setup script (npm run setup)
1690
+ [[kv_namespaces]]
1691
+ binding = "${className.toUpperCase()}_TOOL_PROTECTION_KV"
1692
+ id = "your_tool_protection_kv_id" # Auto-filled by setup script
1686
1693
 
1687
1694
  [vars]
1688
1695
  XMCP_I_TS_SKEW_SEC = "120"
@@ -1695,12 +1702,12 @@ AGENTSHIELD_API_URL = "https://kya.vouched.id"
1695
1702
  # Production: wrangler secret put AGENTSHIELD_API_KEY
1696
1703
  AGENTSHIELD_API_KEY = ""
1697
1704
  # AGENTSHIELD_PROJECT_ID - Your project ID from AgentShield dashboard (e.g., "batman-txh0ae")
1698
- # Required for project-scoped tool protection configuration
1705
+ # Required for project-scoped tool protection configuration (recommended)
1699
1706
  # Find it in your dashboard URL: https://kya.vouched.id/dashboard/projects/{PROJECT_ID}
1700
1707
  # Or in your project settings
1701
- # Development: Add to .dev.vars file
1708
+ # Development: Add to .dev.vars file${projectId ? ` (already configured: ${projectId})` : ""}
1702
1709
  # Production: wrangler secret put AGENTSHIELD_PROJECT_ID
1703
- AGENTSHIELD_PROJECT_ID = ""
1710
+ AGENTSHIELD_PROJECT_ID = "${projectId || ""}"
1704
1711
  MCPI_ENV = "development"
1705
1712
 
1706
1713
  # Optional: MCP Server URL for tool discovery
@@ -1747,7 +1754,9 @@ DO_SHARD_COUNT = "10" # Number of shards if using shard strategy
1747
1754
  // Build API key declarations only for variables that don't already exist
1748
1755
  // Cloudflare Workers REQUIRE variables to be declared in [vars] for .dev.vars to work
1749
1756
  const apiKeyVarsParts = [];
1750
- if (!hasAgentshieldApiKey || !hasAgentshieldProjectId || !hasAdminApiKey) {
1757
+ if (!hasAgentshieldApiKey ||
1758
+ !hasAgentshieldProjectId ||
1759
+ !hasAdminApiKey) {
1751
1760
  apiKeyVarsParts.push(`# API keys - MUST be declared here for .dev.vars to work!`);
1752
1761
  apiKeyVarsParts.push(`# Development: Values in .dev.vars will override these empty strings`);
1753
1762
  apiKeyVarsParts.push(`# Production: Use wrangler secret put to set these`);
@@ -1761,7 +1770,9 @@ DO_SHARD_COUNT = "10" # Number of shards if using shard strategy
1761
1770
  if (!hasAgentshieldProjectId) {
1762
1771
  apiKeyVarsParts.push(`AGENTSHIELD_PROJECT_ID = ""`);
1763
1772
  }
1764
- const apiKeyVars = apiKeyVarsParts.length > 0 ? `\n${apiKeyVarsParts.join('\n')}\n` : '';
1773
+ const apiKeyVars = apiKeyVarsParts.length > 0
1774
+ ? `\n${apiKeyVarsParts.join("\n")}\n`
1775
+ : "";
1765
1776
  wranglerTomlContent =
1766
1777
  wranglerTomlContent.slice(0, insertPosition) +
1767
1778
  identityVars +
@@ -1787,7 +1798,7 @@ MCP_IDENTITY_PUBLIC_KEY="${identity.publicKey}"
1787
1798
  AGENTSHIELD_API_KEY="${apikey || ""}"${apikey ? " # Provided via --apikey flag" : ""}
1788
1799
 
1789
1800
  # AgentShield Project ID (from dashboard URL: /dashboard/projects/{PROJECT_ID})
1790
- AGENTSHIELD_PROJECT_ID=""
1801
+ AGENTSHIELD_PROJECT_ID="${projectId || ""}"${projectId ? " # Provided via --project flag" : ""}
1791
1802
 
1792
1803
  # Admin API key for protected endpoints
1793
1804
  ADMIN_API_KEY=""