Skip to main content
Glama

WordPress MCP Server

by Leonelberio
index.ts8.33 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from '@modelcontextprotocol/sdk/types.js'; import axios from 'axios'; interface WordPressError { message: string; code?: string; } type AxiosError = { response?: { data?: WordPressError; }; message: string; }; const isAxiosError = (error: unknown): error is AxiosError => { return error !== null && typeof error === 'object' && 'message' in error && (error as any).response !== undefined; }; class WordPressServer { private server: Server; constructor() { this.server = new Server( { name: 'wordpress-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); this.setupToolHandlers(); // Error handling this.server.onerror = (error) => console.error('[MCP Error]', error); process.on('SIGINT', async () => { await this.server.close(); process.exit(0); }); } private setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'create_post', description: 'Create a new WordPress post', inputSchema: { type: 'object', properties: { siteUrl: { type: 'string', description: 'WordPress site URL (overrides WORDPRESS_SITE_URL env var)', }, username: { type: 'string', description: 'WordPress username (overrides WORDPRESS_USERNAME env var)', }, password: { type: 'string', description: 'WordPress password (overrides WORDPRESS_PASSWORD env var)', }, title: { type: 'string', description: 'Post title', }, content: { type: 'string', description: 'Post content', }, status: { type: 'string', description: 'Post status (draft, publish, etc.)', default: 'draft', }, }, required: ['title', 'content'], }, }, { name: 'get_posts', description: 'Get WordPress posts', inputSchema: { type: 'object', properties: { siteUrl: { type: 'string', description: 'WordPress site URL (overrides WORDPRESS_SITE_URL env var)', }, username: { type: 'string', description: 'WordPress username (overrides WORDPRESS_USERNAME env var)', }, password: { type: 'string', description: 'WordPress password (overrides WORDPRESS_PASSWORD env var)', }, perPage: { type: 'number', description: 'Number of posts per page', default: 10, }, page: { type: 'number', description: 'Page number', default: 1, }, }, }, }, { name: 'update_post', description: 'Update an existing WordPress post', inputSchema: { type: 'object', properties: { siteUrl: { type: 'string', description: 'WordPress site URL (overrides WORDPRESS_SITE_URL env var)', }, username: { type: 'string', description: 'WordPress username (overrides WORDPRESS_USERNAME env var)', }, password: { type: 'string', description: 'WordPress password (overrides WORDPRESS_PASSWORD env var)', }, postId: { type: 'number', description: 'Post ID to update', }, title: { type: 'string', description: 'New post title', }, content: { type: 'string', description: 'New post content', }, status: { type: 'string', description: 'New post status (draft, publish, etc.)', }, }, required: ['postId'], }, }, ], })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const method = request.params.name; const params = request.params.arguments; try { const result = await this.handleWordPressRequest(method, params); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, error instanceof Error ? error.message : String(error) ); } }); } private async handleWordPressRequest(method: string, params: any): Promise<any> { try { const siteUrl = params.siteUrl || process.env.WORDPRESS_SITE_URL; const username = params.username || process.env.WORDPRESS_USERNAME; const password = params.password || process.env.WORDPRESS_PASSWORD; if (!siteUrl || !username || !password) { throw new McpError( ErrorCode.InvalidParams, 'WordPress credentials not provided in environment variables or request parameters' ); } const auth = Buffer.from(`${username}:${password}`).toString('base64'); const client = axios.create({ baseURL: `${siteUrl}/wp-json/wp/v2`, headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json', }, }); switch (method) { case 'create_post': if (!params.title || !params.content) { throw new McpError( ErrorCode.InvalidParams, 'Title and content are required for creating a post' ); } const createResponse = await client.post('/posts', { title: params.title, content: params.content, status: params.status || 'draft', }); return createResponse.data; case 'get_posts': const getResponse = await client.get('/posts', { params: { per_page: params.perPage || 10, page: params.page || 1, }, }); return getResponse.data; case 'update_post': if (!params.postId) { throw new McpError( ErrorCode.InvalidParams, 'Post ID is required for updating a post' ); } const updateData: Record<string, any> = {}; if (params.title) updateData.title = params.title; if (params.content) updateData.content = params.content; if (params.status) updateData.status = params.status; const updateResponse = await client.post( `/posts/${params.postId}`, updateData ); return updateResponse.data; default: throw new McpError( ErrorCode.MethodNotFound, `Unknown method: ${method}` ); } } catch (error: unknown) { if (isAxiosError(error)) { throw new McpError( ErrorCode.InternalError, `WordPress API error: ${ error.response?.data?.message || error.message }` ); } throw error; } } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('WordPress MCP server running on stdin/stdout'); } } const server = new WordPressServer(); server.run().catch(console.error);

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/Leonelberio/the-wordpress-mcp-server'

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