Created
April 28, 2026 08:20
-
-
Save vapvarun/862c17f05a6f6d54c3afa2e19e73c48e to your computer and use it in GitHub Desktop.
MCP Servers for WordPress (vapvarun.com) - Server patterns, REST API handlers, agentic loops
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // MCP Server Skeleton for WordPress Agencies | |
| // Pattern used in wp-blog, wpcs, and wp-malware-cleanup servers | |
| // See: https://vapvarun.com/mcp-servers-wordpress-plugin-development/ | |
| import { Server } from "@modelcontextprotocol/sdk/server/index.js"; | |
| import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | |
| import { | |
| CallToolRequestSchema, | |
| ListToolsRequestSchema, | |
| } from "@modelcontextprotocol/sdk/types.js"; | |
| const server = new Server( | |
| { name: "wp-example-mcp", version: "1.0.0" }, | |
| { capabilities: { tools: {} } } | |
| ); | |
| // 1. Declare what tools your server exposes | |
| server.setRequestHandler(ListToolsRequestSchema, async () => ({ | |
| tools: [ | |
| { | |
| name: "wp_run_cli", | |
| description: "Run a safe WP-CLI command on the target site", | |
| inputSchema: { | |
| type: "object", | |
| properties: { | |
| site_id: { type: "string", description: "Site identifier from config" }, | |
| command: { type: "string", description: "WP-CLI command (without 'wp' prefix)" }, | |
| }, | |
| required: ["site_id", "command"], | |
| }, | |
| }, | |
| ], | |
| })); | |
| // 2. Implement the handlers | |
| server.setRequestHandler(CallToolRequestSchema, async (request) => { | |
| const { name, arguments: args } = request.params; | |
| if (name === "wp_run_cli") { | |
| const { site_id, command } = args; | |
| // Validate against allowlist, connect to site, run command | |
| const result = await runWpCli(site_id, command); | |
| return { | |
| content: [{ type: "text", text: JSON.stringify(result, null, 2) }], | |
| }; | |
| } | |
| throw new Error(`Unknown tool: ${name}`); | |
| }); | |
| // 3. Start the server | |
| const transport = new StdioServerTransport(); | |
| await server.connect(transport); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // WordPress REST API Tool Handler Pattern | |
| // Used in wp-blog MCP server for post operations | |
| // See: https://vapvarun.com/mcp-servers-wordpress-plugin-development/ | |
| import fetch from "node-fetch"; | |
| // Site config loaded from config/sites.json | |
| const SITES = { | |
| vapvarun: { | |
| url: "https://vapvarun.com", | |
| auth: process.env.VAPVARUN_APP_PASSWORD, // Never hardcode credentials | |
| }, | |
| }; | |
| /** | |
| * Generic WordPress REST API caller. | |
| * Returns structured output the AI model can read. | |
| */ | |
| async function wpApiCall(site_id, endpoint, method = "GET", body = null) { | |
| const site = SITES[site_id]; | |
| if (!site) throw new Error(`Unknown site: ${site_id}`); | |
| const res = await fetch(`${site.url}/wp-json/wp/v2/${endpoint}`, { | |
| method, | |
| headers: { | |
| Authorization: `Basic ${Buffer.from(site.auth).toString("base64")}`, | |
| "Content-Type": "application/json", | |
| }, | |
| body: body ? JSON.stringify(body) : undefined, | |
| }); | |
| if (!res.ok) { | |
| const err = await res.json().catch(() => ({ message: res.statusText })); | |
| throw new Error(`WordPress API error ${res.status}: ${err.message}`); | |
| } | |
| return res.json(); | |
| } | |
| // Example: get a post | |
| export async function getPost(site_id, post_id) { | |
| return wpApiCall(site_id, `posts/${post_id}`); | |
| } | |
| // Example: update a post | |
| export async function updatePost(site_id, post_id, data) { | |
| return wpApiCall(site_id, `posts/${post_id}`, "POST", data); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Agentic Loop Pattern for Multi-Step WordPress Operations | |
| // How the wp-malware-cleanup server runs scan-then-remediate loops | |
| // See: https://vapvarun.com/mcp-servers-wordpress-plugin-development/ | |
| /** | |
| * The key insight: instead of scripting a fixed sequence, | |
| * expose atomic tools and let the AI decide the order. | |
| * | |
| * The AI will: | |
| * 1. Run wp_scan_site | |
| * 2. Read the scan results | |
| * 3. Decide which wp_quarantine_file / wp_clean_injection calls to make | |
| * 4. Run a verification scan to confirm remediation | |
| * 5. Generate a report | |
| * | |
| * No script needed -- the model orchestrates the loop. | |
| */ | |
| // Tool definitions the AI can call (simplified) | |
| const SECURITY_TOOLS = [ | |
| { | |
| name: "wp_quick_scan", | |
| description: "Fast threat signature scan. Returns array of threat objects with file paths and confidence scores.", | |
| }, | |
| { | |
| name: "wp_quarantine_file", | |
| description: "Move a suspicious file to quarantine. Pass the absolute path returned by wp_quick_scan.", | |
| }, | |
| { | |
| name: "wp_regenerate_salts", | |
| description: "Regenerate WordPress security salts and keys in wp-config.php.", | |
| }, | |
| { | |
| name: "wp_verify_core", | |
| description: "Check all WordPress core files against official checksums. Returns modified/missing files.", | |
| }, | |
| { | |
| name: "wp_generate_report", | |
| description: "Generate a cleanup report summarizing threats found, actions taken, and current site status.", | |
| }, | |
| ]; | |
| // The AI prompt that drives the loop (used internally) | |
| const CLEANUP_PROMPT = ` | |
| You have access to security tools for this WordPress site. | |
| Goal: clean and reharden the site. | |
| 1. Run wp_quick_scan to find threats | |
| 2. For each threat above 0.7 confidence, call wp_quarantine_file | |
| 3. Run wp_verify_core to check for modified core files | |
| 4. Regenerate salts | |
| 5. Run wp_quick_scan again to verify clean state | |
| 6. Generate a final report | |
| Adapt based on what you find. Do not skip verification. | |
| `; | |
| export { SECURITY_TOOLS, CLEANUP_PROMPT }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment