(toolsString?: string)
| 100 | * @returns Parsed tools configuration |
| 101 | */ |
| 102 | export function parseAgentFileTools(toolsString?: string): ParsedAgentTools { |
| 103 | if (!toolsString?.trim()) { |
| 104 | return { tools: [], mcpServers: [], allBuiltIn: false }; |
| 105 | } |
| 106 | |
| 107 | const tools: AgentToolReference[] = []; |
| 108 | const mcpServerSet = new Set<string>(); |
| 109 | let allBuiltIn = false; |
| 110 | |
| 111 | const toolRefs = toolsString |
| 112 | .split(",") |
| 113 | .map((t) => t.trim()) |
| 114 | .filter(Boolean); |
| 115 | |
| 116 | for (const toolRef of toolRefs) { |
| 117 | if (toolRef === "built_in") { |
| 118 | // Special keyword for all built-in tools |
| 119 | allBuiltIn = true; |
| 120 | } else if ( |
| 121 | toolRef.startsWith("http://") || |
| 122 | toolRef.startsWith("https://") |
| 123 | ) { |
| 124 | // URL-based MCP tool reference: "https://mcp.url.com" or "https://mcp.url.com:tool_name" |
| 125 | const protocolEndIndex = toolRef.indexOf("://") + 3; |
| 126 | const lastColonIndex = toolRef.lastIndexOf(":"); |
| 127 | |
| 128 | // Check if there's a colon after the protocol |
| 129 | if (lastColonIndex > protocolEndIndex) { |
| 130 | const afterLastColon = toolRef.substring(lastColonIndex + 1); |
| 131 | |
| 132 | // Check if it's a port number (only digits), empty string, or a tool name |
| 133 | if (/^\d+(?:$|[/?#])/.test(afterLastColon)) { |
| 134 | // It's a port number, treat the whole thing as the server |
| 135 | const mcpServer = toolRef; |
| 136 | tools.push({ mcpServer }); |
| 137 | mcpServerSet.add(mcpServer); |
| 138 | } else if ( |
| 139 | afterLastColon === "" || |
| 140 | /^[a-zA-Z0-9_-]+$/.test(afterLastColon) |
| 141 | ) { |
| 142 | // It's a tool name (or empty string) |
| 143 | // Reject references with whitespace to prevent silent misconfigurations |
| 144 | if (/\s/.test(toolRef)) { |
| 145 | throw new Error( |
| 146 | `Invalid MCP tool reference "${toolRef}": colon-separated tool references cannot contain whitespace. ` + |
| 147 | `Use format "https://server:tool_name" without spaces.`, |
| 148 | ); |
| 149 | } |
| 150 | |
| 151 | const mcpServer = toolRef.substring(0, lastColonIndex); |
| 152 | const toolName = afterLastColon; |
| 153 | |
| 154 | tools.push({ mcpServer, toolName }); |
| 155 | mcpServerSet.add(mcpServer); |
| 156 | } else { |
| 157 | throw new Error( |
| 158 | `Invalid URL-based MCP tool reference "${toolRef}": the part after the last colon must be either a port number or a valid tool name (alphanumeric, underscores, hyphens).`, |
| 159 | ); |
no test coverage detected