Skip to main content
Glama
index.ts5.56 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { fileURLToPath } from "url"; import { WordPressClient } from "./client/api.js"; import { ServerConfiguration, SiteConfig } from "./config/ServerConfiguration.js"; import { ToolRegistry } from "./server/ToolRegistry.js"; import { ConnectionTester } from "./server/ConnectionTester.js"; import { getErrorMessage } from "./utils/error.js"; import { LoggerFactory } from "./utils/logger.js"; import { ConfigHelpers } from "./config/Config.js"; import { McpConfigType } from "./config/ServerConfiguration.js"; import { getVersion, getDisplayVersion } from "./utils/version.js"; // --- Main Server Class --- class MCPWordPressServer { private server: McpServer; private wordpressClients: Map<string, WordPressClient> = new Map(); private initialized: boolean = false; private siteConfigs: SiteConfig[] = []; private toolRegistry!: ToolRegistry; private logger = LoggerFactory.server(); constructor(private mcpConfig?: McpConfigType) { // Server initialization will happen in run() method this.server = new McpServer({ name: "mcp-wordpress", version: getVersion(), }); } private async loadConfiguration(mcpConfig?: McpConfigType) { const serverConfig = ServerConfiguration.getInstance(); const { clients, configs } = await serverConfig.loadClientConfigurations(mcpConfig); this.wordpressClients = clients; this.siteConfigs = configs; } private setupTools() { this.toolRegistry.registerAllTools(); } private async testClientConnections(): Promise<void> { // Use optimized connection testing with timeouts and concurrency control await ConnectionTester.testClientConnections(this.wordpressClients, { timeout: ConfigHelpers.getTimeout("test"), maxConcurrent: ConfigHelpers.isCI() ? 2 : 3, // Reduce concurrency in CI }); this.initialized = true; } async run() { // Load configuration asynchronously await this.loadConfiguration(this.mcpConfig); if (this.wordpressClients.size === 0) { // In test environments, don't exit the process if ( ConfigHelpers.isCI() || ConfigHelpers.isTest() || (globalThis as Record<string, unknown>).__EXECUTION_CONTEXT__ === "jest" ) { this.logger.warn("No WordPress sites configured in test environment"); // Create a dummy client for testing this.wordpressClients.set("test", {} as WordPressClient); } else { this.logger.fatal("No WordPress sites configured. Server cannot start.", { expectedEnvVars: ["WORDPRESS_SITE_URL", "WORDPRESS_USERNAME", "WORDPRESS_APP_PASSWORD"], }); process.exit(1); } } this.toolRegistry = new ToolRegistry(this.server, this.wordpressClients); this.setupTools(); // Skip connection testing in DXT environment to prevent timeouts const isDXTMode = ConfigHelpers.isDXT() || process.argv[0]?.includes("dxt-entry"); if (!this.initialized && !isDXTMode) { this.logger.info("Testing connections to configured WordPress sites...", { siteCount: this.wordpressClients.size, }); try { await this.testClientConnections(); } catch (_error) { this.logger.warn("Connection test failed - continuing with server startup", { _error: getErrorMessage(_error), }); } } else if (isDXTMode) { this.logger.info("DXT mode detected - skipping connection tests for faster startup"); this.initialized = true; } this.logger.info("Starting MCP WordPress Server...", { version: getDisplayVersion(), sites: this.wordpressClients.size, }); // Connect to stdio transport with timeout const transport = new StdioServerTransport(); // Add timeout protection for server connection const connectionTimeout = setTimeout(() => { this.logger.fatal("Server connection timed out", { timeoutMs: 30000 }); process.exit(1); }, 30000); try { await this.server.connect(transport); clearTimeout(connectionTimeout); this.logger.info("Server started and connected successfully", { sites: this.wordpressClients.size, }); // Keep the process alive process.stdin.resume(); } catch (_error) { clearTimeout(connectionTimeout); throw _error; } } async shutdown() { this.logger.info("Shutting down MCP WordPress Server..."); await this.server.close(); this.logger.info("Server stopped"); } } // --- Main Execution --- async function main() { const mainLogger = LoggerFactory.server(); try { const mcpServer = new MCPWordPressServer(); await mcpServer.run(); const shutdown = async () => { await mcpServer.shutdown(); process.exit(0); }; process.on("SIGINT", shutdown); process.on("SIGTERM", shutdown); } catch (_error) { mainLogger.fatal("Failed to start server", { _error: getErrorMessage(_error) }); process.exit(1); } } // Check if running as main module - handle both direct execution and DXT entry point const isMainModule = process.argv[1] === fileURLToPath(import.meta.url) || process.argv[1]?.endsWith("/index.js") || process.argv[1]?.endsWith("\\index.js") || !process.argv[1]; // When run through DXT, process.argv[1] might be undefined if (isMainModule) { main(); } export default MCPWordPressServer; export { MCPWordPressServer };

Implementation Reference

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