Skip to main content
Glama
ConfigurationSchema.ts7.57 kB
import { z } from "zod"; /** * Zod schema for WordPress authentication methods */ const AuthMethodSchema = z.enum(["app-password", "jwt", "basic", "api-key", "cookie"] as const); /** * Zod schema for URL validation with security checks */ const UrlSchema = z .string() .url("Must be a valid URL") .refine((url) => { const parsed = new URL(url); return parsed.protocol === "http:" || parsed.protocol === "https:"; }, "URL must use http or https protocol") .refine((url) => { // Additional security checks const parsed = new URL(url); const hostname = parsed.hostname.toLowerCase(); // In production, block localhost and private IPs if (process.env.NODE_ENV === "production") { if ( hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.match(/^10\./) || hostname.match(/^172\.(1[6-9]|2[0-9]|3[01])\./) || hostname.match(/^192\.168\./) ) { return false; } } return true; }, "Private/localhost URLs not allowed in production"); /** * Zod schema for WordPress site configuration */ const SiteConfigSchema = z.object({ WORDPRESS_SITE_URL: UrlSchema, WORDPRESS_USERNAME: z .string() .min(1, "Username is required") .max(60, "Username must be 60 characters or less") .regex(/^[a-zA-Z0-9._@-]+$/, "Username contains invalid characters"), WORDPRESS_APP_PASSWORD: z .string() .min(1, "Password is required") .refine((password) => { // WordPress app passwords are typically 24 characters with spaces // But we'll be flexible to support different auth methods return password.length >= 8; }, "Password must be at least 8 characters"), WORDPRESS_AUTH_METHOD: AuthMethodSchema.optional().default("app-password"), }); /** * Zod schema for site configuration with metadata */ const SiteSchema = z.object({ id: z .string() .min(1, "Site ID is required") .max(50, "Site ID must be 50 characters or less") .regex(/^[a-zA-Z0-9_-]+$/, "Site ID can only contain letters, numbers, underscores, and hyphens"), name: z.string().min(1, "Site name is required").max(100, "Site name must be 100 characters or less"), config: SiteConfigSchema, }); /** * Zod schema for multi-site configuration file */ const MultiSiteConfigSchema = z.object({ sites: z .array(SiteSchema) .min(1, "At least one site must be configured") .max(50, "Maximum of 50 sites supported") .refine((sites) => { const ids = sites.map((site) => site.id); const uniqueIds = new Set(ids); return ids.length === uniqueIds.size; }, "Site IDs must be unique") .refine((sites) => { const names = sites.map((site) => site.name); const uniqueNames = new Set(names); return names.length === uniqueNames.size; }, "Site names must be unique") .refine((sites) => { const urls = sites.map((site) => site.config.WORDPRESS_SITE_URL); const uniqueUrls = new Set(urls); return urls.length === uniqueUrls.size; }, "Site URLs must be unique"), }); /** * Zod schema for environment variables (single-site mode) */ const EnvironmentConfigSchema = z.object({ WORDPRESS_SITE_URL: UrlSchema, WORDPRESS_USERNAME: SiteConfigSchema.shape.WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD: SiteConfigSchema.shape.WORDPRESS_APP_PASSWORD, WORDPRESS_AUTH_METHOD: AuthMethodSchema.optional().default("app-password"), // Optional environment variables NODE_ENV: z.enum(["development", "production", "test", "dxt", "ci"]).optional(), DEBUG: z.string().optional(), DISABLE_CACHE: z.string().optional(), LOG_LEVEL: z.enum(["error", "warn", "info", "debug"]).optional(), }); /** * Zod schema for MCP configuration passed from client */ const McpConfigSchema = z .object({ wordpressSiteUrl: UrlSchema.optional(), wordpressUsername: SiteConfigSchema.shape.WORDPRESS_USERNAME.optional(), wordpressAppPassword: SiteConfigSchema.shape.WORDPRESS_APP_PASSWORD.optional(), wordpressAuthMethod: AuthMethodSchema.optional(), }) .optional(); /** * Type definitions derived from Zod schemas */ export type SiteConfigType = z.infer<typeof SiteConfigSchema>; export type SiteType = z.infer<typeof SiteSchema>; export type MultiSiteConfigType = z.infer<typeof MultiSiteConfigSchema>; export type EnvironmentConfigType = z.infer<typeof EnvironmentConfigSchema>; export type McpConfigType = z.infer<typeof McpConfigSchema>; /** * Configuration validation utilities */ export class ConfigurationValidator { /** * Validate multi-site configuration from JSON file */ static validateMultiSiteConfig(config: unknown): MultiSiteConfigType { try { return MultiSiteConfigSchema.parse(config); } catch (_error) { if (_error instanceof z.ZodError) { const messages = _error.issues.map((err: z.ZodIssue) => `${err.path.join(".")}: ${err.message}`).join("; "); throw new Error(`Multi-site configuration validation failed: ${messages}`); } throw _error; } } /** * Validate environment configuration for single-site mode */ static validateEnvironmentConfig(env: Record<string, string | undefined>): EnvironmentConfigType { try { return EnvironmentConfigSchema.parse(env); } catch (_error) { if (_error instanceof z.ZodError) { const messages = _error.issues.map((err: z.ZodIssue) => `${err.path.join(".")}: ${err.message}`).join("; "); throw new Error(`Environment configuration validation failed: ${messages}`); } throw _error; } } /** * Validate MCP configuration passed from client */ static validateMcpConfig(config: unknown): McpConfigType { try { return McpConfigSchema.parse(config); } catch (_error) { if (_error instanceof z.ZodError) { const messages = _error.issues.map((err: z.ZodIssue) => `${err.path.join(".")}: ${err.message}`).join("; "); throw new Error(`MCP configuration validation failed: ${messages}`); } throw _error; } } /** * Validate a single site configuration */ static validateSiteConfig(config: unknown): SiteType { try { return SiteSchema.parse(config); } catch (_error) { if (_error instanceof z.ZodError) { const messages = _error.issues.map((err: z.ZodIssue) => `${err.path.join(".")}: ${err.message}`).join("; "); throw new Error(`Site configuration validation failed: ${messages}`); } throw _error; } } /** * Check if a configuration file structure is valid without throwing */ static isValidMultiSiteConfig(config: unknown): boolean { const result = MultiSiteConfigSchema.safeParse(config); return result.success; } /** * Check if environment configuration is valid without throwing */ static isValidEnvironmentConfig(env: Record<string, string | undefined>): boolean { const result = EnvironmentConfigSchema.safeParse(env); return result.success; } /** * Get validation errors without throwing */ static getValidationErrors(schema: z.ZodSchema, data: unknown): string[] { const result = schema.safeParse(data); if (result.success) { return []; } return result.error.issues.map((err: z.ZodIssue) => `${err.path.join(".")}: ${err.message}`); } } // Export schemas for direct use if needed export { SiteConfigSchema, SiteSchema, MultiSiteConfigSchema, EnvironmentConfigSchema, McpConfigSchema, AuthMethodSchema, UrlSchema, };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/docdyhr/mcp-wordpress'

If you have feedback or need assistance with the MCP directory API, please join our Discord server