* Validates and normalizes server configuration * @param config The server configuration to validate * @param serverName Optional server name for error messages * @returns The validated configuration * @throws Error if the configuration is invalid
(config: any, serverName?: string)
| 222 | * @throws Error if the configuration is invalid |
| 223 | */ |
| 224 | private validateServerConfig(config: any, serverName?: string): z.infer<typeof ServerConfigSchema> { |
| 225 | // Detect configuration issues before validation |
| 226 | const hasStdioFields = config.command !== undefined |
| 227 | const hasUrlFields = config.url !== undefined // Covers sse and streamable-http |
| 228 | |
| 229 | // Check for mixed fields (stdio vs url-based) |
| 230 | if (hasStdioFields && hasUrlFields) { |
| 231 | throw new Error(mixedFieldsErrorMessage) |
| 232 | } |
| 233 | |
| 234 | // Infer type for stdio if not provided |
| 235 | if (!config.type && hasStdioFields) { |
| 236 | config.type = "stdio" |
| 237 | } |
| 238 | |
| 239 | // For url-based configs, type must be provided by the user |
| 240 | if (hasUrlFields && !config.type) { |
| 241 | throw new Error("Configuration with 'url' must explicitly specify 'type' as 'sse' or 'streamable-http'.") |
| 242 | } |
| 243 | |
| 244 | // Validate type if provided |
| 245 | if (config.type && !["stdio", "sse", "streamable-http"].includes(config.type)) { |
| 246 | throw new Error(typeErrorMessage) |
| 247 | } |
| 248 | |
| 249 | // Check for type/field mismatch |
| 250 | if (config.type === "stdio" && !hasStdioFields) { |
| 251 | throw new Error(stdioFieldsErrorMessage) |
| 252 | } |
| 253 | if (config.type === "sse" && !hasUrlFields) { |
| 254 | throw new Error(sseFieldsErrorMessage) |
| 255 | } |
| 256 | if (config.type === "streamable-http" && !hasUrlFields) { |
| 257 | throw new Error(streamableHttpFieldsErrorMessage) |
| 258 | } |
| 259 | |
| 260 | // If neither command nor url is present (type alone is not enough) |
| 261 | if (!hasStdioFields && !hasUrlFields) { |
| 262 | throw new Error(missingFieldsErrorMessage) |
| 263 | } |
| 264 | |
| 265 | // Validate the config against the schema |
| 266 | try { |
| 267 | return ServerConfigSchema.parse(config) |
| 268 | } catch (validationError) { |
| 269 | if (validationError instanceof z.ZodError) { |
| 270 | // Extract and format validation errors |
| 271 | const errorMessages = validationError.errors |
| 272 | .map((err) => `${err.path.join(".")}: ${err.message}`) |
| 273 | .join("; ") |
| 274 | throw new Error( |
| 275 | serverName |
| 276 | ? `Invalid configuration for server "${serverName}": ${errorMessages}` |
| 277 | : `Invalid server configuration: ${errorMessages}`, |
| 278 | ) |
| 279 | } |
| 280 | throw validationError |
| 281 | } |
no test coverage detected