Skip to main content
Glama
proxy.ts7.32 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { logger } from './lib/utils.js'; import { cleanupExpiredTokens } from './lib/persistent-auth-config.js'; import { validateNodeVersion } from './lib/node-utils.js'; import { setupFetchPolyfill } from './lib/fetch-utils.js'; import { detectTransportType } from './lib/transport-detection.js'; import { createSessionContext } from './lib/session-utils.js'; import { createWrappedHandler, HANDLER_CONFIGS } from './lib/request-handler-factory.js'; import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourceTemplatesRequestSchema, ReadResourceRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, SetLevelRequestSchema, CompleteRequestSchema, ListRootsRequestSchema, } from './lib/mcp-types.js'; import { InitializeRequestSchema } from '@modelcontextprotocol/sdk/types.js'; // Check Node.js version validateNodeVersion(18); /** * Enhanced Client Message Logging * * This proxy now includes comprehensive logging for all client messages at multiple levels: * * 1. TRANSPORT level: Raw messages from the transport layer * 2. CLIENT level: Processed messages with structured information * 3. TRANSPORT_DETECT level: Initialization and transport detection messages * * Log levels: * - INFO: Basic request/response information with emojis for easy scanning * - DEBUG: Complete message objects and detailed debugging info * - ERROR: Failed requests and transport errors * * To control logging: * - Set LOG_LEVEL=0 (ERROR), 1 (WARN), 2 (INFO), or 3 (DEBUG) * - Set LOG_FILE=path/to/file.log to also log to a file * - In development, DEBUG level is default; in production, INFO level is default */ async function WordPressProxy() { // Setup fetch polyfill before doing anything else await setupFetchPolyfill(); logger.info('Starting WordPress MCP Proxy with enhanced authentication', 'PROXY'); // Clean up any expired tokens on startup try { await cleanupExpiredTokens(); } catch (error) { logger.warn('Error cleaning up expired tokens', 'PROXY', error); } // Create session context const sessionContext = createSessionContext(); // Create server with minimal default info (will be updated with actual WordPress info on first initialize) const server = new Server( { name: 'WordPress MCP Remote Proxy', version: '0.2.17', }, { capabilities: { tools: {}, resources: {}, prompts: {}, logging: {}, completions: {}, }, } ); // Handle initialize request by forwarding client parameters to WordPress (only one call) server.setRequestHandler(InitializeRequestSchema, async (request) => { logger.info('📩 Client Initialize Request received', 'INIT'); logger.debug('Initialize request details:', 'INIT', request); try { // Forward the client's initialize parameters to WordPress server (first and only call) logger.info('🔄 Initializing WordPress connection with client parameters', 'INIT'); const { initResult } = await detectTransportType(sessionContext, request.params); // Return the WordPress server's initialize response const wordpressInitResponse = { protocolVersion: initResult.protocolVersion || '2025-06-18', serverInfo: initResult.serverInfo, capabilities: initResult.capabilities, instructions: initResult.instructions || 'MCP WordPress Remote Proxy Server' }; logger.info('✅ Returning WordPress server initialize response', 'INIT'); logger.debug('Initialize response:', 'INIT', wordpressInitResponse); return wordpressInitResponse; } catch (error) { logger.error('❌ Failed to initialize WordPress connection with client parameters', 'INIT', error); // Return a basic fallback response const fallbackResponse = { protocolVersion: '2025-06-18', serverInfo: { name: 'WordPress MCP Remote Proxy', version: '0.2.17', }, capabilities: { tools: {}, resources: {}, prompts: {}, logging: {}, completions: {}, }, instructions: 'MCP WordPress Remote Proxy Server (Connection Failed)' }; logger.warn('⚠️ Using fallback initialize response', 'INIT'); return fallbackResponse; } }); // Register all other MCP request handlers using the factory server.setRequestHandler(ListToolsRequestSchema, createWrappedHandler(HANDLER_CONFIGS.listTools, sessionContext)); server.setRequestHandler(CallToolRequestSchema, createWrappedHandler(HANDLER_CONFIGS.callTool, sessionContext)); server.setRequestHandler(ListResourcesRequestSchema, createWrappedHandler(HANDLER_CONFIGS.listResources, sessionContext)); server.setRequestHandler(ListResourceTemplatesRequestSchema, createWrappedHandler(HANDLER_CONFIGS.listResourceTemplates, sessionContext)); server.setRequestHandler(ReadResourceRequestSchema, createWrappedHandler(HANDLER_CONFIGS.readResource, sessionContext)); server.setRequestHandler(SubscribeRequestSchema, createWrappedHandler(HANDLER_CONFIGS.subscribe, sessionContext)); server.setRequestHandler(UnsubscribeRequestSchema, createWrappedHandler(HANDLER_CONFIGS.unsubscribe, sessionContext)); server.setRequestHandler(ListPromptsRequestSchema, createWrappedHandler(HANDLER_CONFIGS.listPrompts, sessionContext)); server.setRequestHandler(GetPromptRequestSchema, createWrappedHandler(HANDLER_CONFIGS.getPrompt, sessionContext)); server.setRequestHandler(SetLevelRequestSchema, createWrappedHandler(HANDLER_CONFIGS.setLevel, sessionContext)); server.setRequestHandler(CompleteRequestSchema, createWrappedHandler(HANDLER_CONFIGS.complete, sessionContext)); server.setRequestHandler(ListRootsRequestSchema, createWrappedHandler(HANDLER_CONFIGS.listRoots, sessionContext)); const transport = new StdioServerTransport(); transport.onmessage = (message) => { const msg = message as unknown; const method = typeof (msg as any)?.method === 'string' ? (msg as any).method : 'unknown'; const id = (msg as any)?.id ?? 'none'; const hasParams = Boolean((msg as any)?.params && typeof (msg as any).params === 'object' && Object.keys((msg as any).params).length); logger.info('📥 Raw client message received', 'TRANSPORT', { method, id, hasParams, messageType: method === 'unknown' ? 'response/notification' : 'request', }); logger.debug('Complete raw message:', 'TRANSPORT', message); }; transport.onerror = (error) => { logger.error('❌ Transport error:', 'TRANSPORT', error); }; transport.onclose = () => { logger.info('🔌 Transport connection closed', 'TRANSPORT'); }; // Connect to the transport server .connect(transport) .then(() => { logger.info('MCP server connected to transport successfully', 'PROXY'); }) .catch(error => { logger.error('Error starting MCP server', 'PROXY', error); process.exit(1); }); } WordPressProxy();

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/Automattic/mcp-wordpress-remote'

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