{"record":{"id":"74862f49aeb279f1","repo":"ruvnet/ruflo","slug":"pod-template-at-path-allowedmcptools-must-have","errorCode":null,"errorMessage":"pod-template at ${path}: allowedMcpTools must have ≥1 entry","messagePattern":"pod-template at (.+?): allowedMcpTools must have ≥1 entry","errorType":"validation","errorClass":"PodTemplateValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/pod-schema.ts","lineNumber":217,"sourceCode":"      'roomId may only contain [A-Za-z0-9_.\\\\-:/@#]',\n      '/',\n    );\n  }\n  const agents = requireArray(json, 'agents', '/', validatePodAgent);\n  if (agents.length === 0) {\n    throw new PodTemplateValidationError('agents must have ≥1 entry', '/');\n  }\n  const allowedMcpTools = requireArray(json, 'allowedMcpTools', '/', (t, tp) => {\n    if (typeof t !== 'string' || t.length === 0) {\n      throw new PodTemplateValidationError(\n        'allowedMcpTools entries must be non-empty strings',\n        tp,\n      );\n    }\n    return t;\n  });\n  if (allowedMcpTools.length === 0) {\n    throw new PodTemplateValidationError('allowedMcpTools must have ≥1 entry', '/');\n  }\n  const bench = validatePodBench(json.bench, '/bench');\n  const piiPolicy = requireString(json, 'piiPolicy', '/');\n  if (!PII_POLICIES.includes(piiPolicy as PiiPolicy)) {\n    throw new PodTemplateValidationError(\n      `piiPolicy must be one of: ${PII_POLICIES.join(', ')}`,\n      '/',\n    );\n  }\n  const budgetUsdMonthly = requireNumber(json, 'budgetUsdMonthly', '/');\n  if (budgetUsdMonthly < 0) {\n    throw new PodTemplateValidationError('budgetUsdMonthly must be ≥0', '/');\n  }\n  const budgetUsdPerRun = requireNumber(json, 'budgetUsdPerRun', '/');\n  if (budgetUsdPerRun < 0) {\n    throw new PodTemplateValidationError('budgetUsdPerRun must be ≥0', '/');\n  }\n  if (budgetUsdMonthly > 0 && budgetUsdPerRun > budgetUsdMonthly) {","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L199-L235","documentation":"Thrown by validatePodTemplate() when the allowedMcpTools array is present and all entries are valid strings, but the array has zero entries. A pod must allow at least one MCP tool — an empty allow-list means agents cannot perform any external actions.","triggerScenarios":"The pod-template JSON has \"allowedMcpTools\": [] — a valid but empty array. Each entry passed the item validator (there are none), then the length check fails.","commonSituations":"All tool entries were removed during a security tightening pass but none were kept; the template was copied from a minimal example that omitted the tools list.","solutions":["Add at least one MCP tool name to the allowedMcpTools array (e.g. 'memory_search', 'task_create')","Review which MCP tools the pod's agents genuinely need and add them"],"exampleFix":"// before\n{ \"allowedMcpTools\": [] }\n\n// after\n{ \"allowedMcpTools\": [\"memory_search\", \"hooks_route\"] }","handlingStrategy":"validation","validationCode":"if (!Array.isArray(template.allowedMcpTools) || template.allowedMcpTools.length === 0) {\n  throw new Error('allowedMcpTools must have at least one entry');\n}","typeGuard":"function hasAllowedMcpTools(template: unknown): boolean {\n  return typeof template === 'object' && template !== null &&\n    Array.isArray((template as Record<string, unknown>).allowedMcpTools) &&\n    ((template as Record<string, unknown>).allowedMcpTools as unknown[]).length > 0;\n}","tryCatchPattern":"try {\n  validatePodTemplate(json);\n} catch (e) {\n  if (e instanceof PodTemplateValidationError && e.message.includes('allowedMcpTools must have')) {\n    // Add at least one MCP tool name\n  }\n}","preventionTips":["Every pod must allow at least one MCP tool — an empty allow-list is invalid","Common safe defaults: 'memory_search', 'task_create', 'hooks_route'","Review the pod's agents to determine which tools they need"],"tags":["pod-template","validation","schema","mcp-tools"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}