Create your personal MCP Server to regulate WordPress website hosting with AI

by | Mar 3, 2026 | Etcetera | 0 comments

While you prepare a lot of WordPress web pages, you could be all the time on the lookout for the next easy method to restrict the time frame you spend having access to dashboards and clicking by way of a chain of buttons.

MCPs (Style Context Protocols) had been making a lot of waves in recent times, and we decided to find how MCPs, alongside the Kinsta API might have the same opinion an corporation managing such a large amount of internet websites.

In this article, we walk you by way of a sensible example of setting up an MCP server that connects AI assistants like Claude to the Kinsta API to keep watch over WordPress website hosting tasks corporations already perform on a daily basis.

What we’re development

We’re development an MCP server that exposes a collection of apparatus, so AI assistants can perform actions like:

  • Document all WordPress web pages beneath your account
  • Show environments for a decided on internet web page
  • Clear the cache in a given atmosphere
  • Clone an provide internet web page to spin up a brand spanking new one
  • See which plugins and topic issues are old-fashioned or vulnerable
  • Purpose plugin updates on specific environments

As quickly because the server is able up, it’s hooked as much as an MCP host/consumer (in this case, Claude for Desktop):

Claude calling MCP tools to retrieve external data during a prompt.
Claude calling MCP apparatus to retrieve external knowledge all the way through a steered.

Understand how it calls reasonably numerous apparatus and then returns the following response:

Claude displaying a structured response generated from retrieved tool data.
Claude appearing a structured response generated from retrieved tool knowledge.

Getting started

Previous to jumping into the code, it’s serving to to understand a few basics about how MCP fits into this setup.

An MCP server sits between an AI assistant and an provide API. It doesn’t change the API or business how it works. As an alternative, it exposes a collection of apparatus that the AI can identify when sought after. Every tool maps to a decided on movement, like document web pages or clearing your internet web page’s cache.

When you ask a question in an AI assistant, it makes a decision whether or not or now not one of those apparatus is said. If it is, the assistant calls the tool all the way through the MCP server, the server talks to the API, and the outcome’s returned as a simple response. No longer anything else runs routinely without your approval, and only the apparatus you expose are available.

In this example, the MCP server communicates with the Kinsta API and exposes a limited set of WordPress website online website hosting actions. No custom designed UI, background automation, or specific AI setup is wanted.

Must haves

To follow along, you need a few problems in place:

  • A powerful Node.js setup
  • Elementary familiarity with TypeScript
  • A Kinsta account with API get right to use enabled
  • Your Kinsta API key and company ID

You don’t need any prior experience with MCP, and in addition you don’t want to assemble or teach an AI taste. We focal point only on wiring provide apparatus together.

Setting up the enterprise

Get began by the use of rising a brand spanking new checklist for the enterprise and initializing a Node.js app:

mkdir kinsta-mcp
cd kinsta-mcp
npm init -y

Next, arrange the MCP SDK and the small set of dependencies we use:

npm arrange @modelcontextprotocol/sdk zod@3
npm arrange -D typescript @sorts/node

Create a elementary enterprise development:

mkdir src
touch src/index.ts

Then change your package deal deal.json so Node can run the built server:

{
  "determine": "kinsta-mcp-server",
  "style": "1.0.0",
  "description": "MCP server for managing WordPress web pages by the use of the Kinsta API",
  "type": "module",
  "scripts": {
    "assemble": "tsc"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0",
    "zod": "^3.24.0"
  },
  "devDependencies": {
    "@sorts/node": "^22.0.0",
    "typescript": "^5.0.0"
  }
}

Finally, add a tsconfig.json at the root of the enterprise:

{
  "compilerOptions": {
    "purpose": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./assemble",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

With that all the way through place, you’re ready to begin out development the MCP server itself.

Building the MCP server

Now that the enterprise is able up, it’s time to build the MCP server itself.

We begin by the use of importing the desired programs and rising the server instance. Then add a small helper for talking to the API. After that, we join apparatus that map straight away to WordPress website online website hosting actions.

See also  Recommendation and Sources for AAPI Trade Homeowners, From AAPI Trade Homeowners

Importing programs and rising the server

Open src/index.ts and add the following imports at the top of the document:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

The ones do 3 problems:

  • McpServer is the core server that registers apparatus and handles requests from the AI consumer
  • StdioServerTransport shall we the server keep up a correspondence over standard input/output, which is how most desktop AI shoppers connect
  • zod is used to stipulate and validate the input each tool accepts

Next, define a few constants for the API and credentials:

const KINSTA_API_BASE = "https://api.kinsta.com/v2";
const KINSTA_API_KEY = process.env.KINSTA_API_KEY;
const KINSTA_COMPANY_ID = process.env.KINSTA_COMPANY_ID;

Now create the MCP server instance:

const server = new McpServer({
  determine: "kinsta",
  style: "1.0.0",
});

The determine is how the server turns out inside an MCP consumer. The style isn’t necessary, then again useful while you get began iterating.

Together with a helper for API requests

Numerous the apparatus we assemble want to make HTTP requests to the API. Moderately than repeating that excellent judgment far and wide, create a single helper function. Add this underneath the server setup:

async function kinstaRequest(
  endpoint: string,
  possible choices: RequestInit = {}
): Promise {
  const url = `${KINSTA_API_BASE}${endpoint}`;
  const headers = {
    Authorization: `Bearer ${KINSTA_API_KEY}`,
    "Content material material-Type": "tool/json",
    ...possible choices.headers,
  };

  const response = look forward to fetch(url, { ...possible choices, headers });

  if (!response.excellent sufficient) {
    const errorText = look forward to response.text();
    throw new Error(`Kinsta API error (${response.status}): ${errorText}`);
  }

  return response.json() as Promise;
}

Imposing tool execution

Tools are the principle issue an MCP server exposes. Every tool is a function an AI assistant can identify, together with your approval, to perform a decided on procedure.

In this server, each tool follows the identical development:

  • A tool determine (like list_sites)
  • A short lived description (that is serving to the assistant know when to use it)
  • An input schema (so the tool only runs with official input)
  • A handler function (where we identify the API and format the output)

We format responses as easy text on function. AI assistants artwork highest when apparatus return blank, readable output as a substitute of dumping raw JSON.

Device 1: Document web pages

This tool retrieves all WordPress web pages beneath your business account. It’s generally the first thing you want when running with multiple web pages, since most other actions get began with a internet web page ID.

The API response contains elementary information about each internet web page, so we define a simple shape to artwork with:

interface Website online {
  identity: string;
  determine: string;
  display_name: string;
  status: string;
  site_labels: Array;
}

interface ListSitesResponse {
  company: {
    web pages: Website online[];
  };
}

With that all the way through place, we will be able to join the tool:

server.registerTool(
  "list_sites",
  {
    description:
      "Get all WordPress web pages in your business. Returns internet web page IDs, names, and status.",
    inputSchema: {},
  },
  async () => {
    const knowledge = look forward to kinstaRequest(
      `/web pages?company=${KINSTA_COMPANY_ID}`
    );

    const web pages = knowledge.company.web pages;

    if (!web pages || web pages.period === 0) {
      return {
        content material materials: [
          { type: "text", text: "No sites found for this company." }
        ],
      };
    }

    const siteList = web pages
      .map((internet web page) => {
        const labels =
          internet web page.site_labels?.map((l) => l.determine).join(", ") || "none";

        return `• ${internet web page.display_name} (${internet web page.determine})
  ID: ${internet web page.identity}
  Status: ${internet web page.status}
  Labels: ${labels}`;
      })
      .join("nn");

    return {
      content material materials: [
        {
          type: "text",
          text: `Found ${sites.length} site(s):nn${siteList}`,
        },
      ],
    };
  }
);

This tool doesn’t require any input, so the input schema is empty. All over the handler, we identify the API, check out for an empty result, and then format the response as readable text.

As an alternative of returning raw JSON, we return a temporary summary that works well in a chat interface. This makes it easy for an AI assistant to reply to questions like “What web pages do I’ve?” or “Show me all my WordPress web pages” without any additional parsing.

Device 2: Get environments

Once you have a internet web page ID, the next now not bizarre step is checking its environments. This tool returns all environments for a given internet web page, along side are living, staging, and most sensible elegance staging environments.

interface Environment {
  identity: string;
  determine: string;
  display_name: string;
  is_premium: boolean;
  primaryDomain?: {
    identity: string;
    determine: string;
  };
  container_info?: {
    php_engine_version: string;
  };
}

interface GetEnvironmentsResponse {
  internet web page: {
    environments: Environment[];
  };
}

Some fields don’t seem to be necessary, like the main house or PHP style, so that they’re marked accordingly. The tool itself takes only the internet web page ID:

server.registerTool(
  "get_environments",
  {
    description:
      "Get environments (are living, staging) for a decided on internet web page. Requires the internet web page ID.",
    inputSchema: {
      site_id: z.string().describe("The internet web page ID to get environments for"),
    },
  },
  async ({ site_id }) => {
    const knowledge = look forward to kinstaRequest(
      `/web pages/${site_id}/environments`
    );

    const envs = knowledge.internet web page.environments;

    if (!envs || envs.period === 0) {
      return {
        content material materials: [
          { type: "text", text: "No environments found for this site." }
        ],
      };
    }

    const envList = envs
      .map((env) => {
        const house = env.primaryDomain?.determine || "No house";
        const php = env.container_info?.php_engine_version || "Unknown";
        const type = env.is_premium
          ? "Best fee Staging"
          : env.determine === "are living"
            ? "Reside"
            : "Staging";

        return `• ${env.display_name} (${type})
  ID: ${env.identity}
  Space: ${house}
  PHP: ${php}`;
      })
      .join("nn");

    return {
      content material materials: [
        {
          type: "text",
          text: `Found ${envs.length} environment(s):nn${envList}`,
        },
      ],
    };
  }
);

This is generally the next step previous than actions similar to clearing cache, cloning a internet web page, or updating plugins.

Device 3: Clear internet web page cache

Clearing cache is a routine procedure, then again it’s moreover an asynchronous operation. When you reason it, the API responds instantly with an operation ID, while the cache blank continues inside the background.

See also  What’s new in WordPress 6.7: Zoom Out mode, Meta containers, Block Development API, and a lot more

Right here’s the sort definition and tool function:

interface OperationResponse {
  operation_id: string;
  message: string;
  status: amount;
}

server.registerTool(
  "clear_site_cache",
  {
    description:
      "Clear the cache for a internet web page atmosphere. Requires the environment ID.",
    inputSchema: {
      environment_id: z
        .string()
        .describe("The environment ID to wash cache for"),
    },
  },
  async ({ environment_id }) => {
    const knowledge = look forward to kinstaRequest(
      "/web pages/apparatus/clear-cache",
      {
        approach: "POST",
        body: JSON.stringify({ environment_id }),
      }
    );

    return {
      content material materials: [
        {
          type: "text",
          text: `Cache clear initiated!

Operation ID: ${data.operation_id}
Message: ${data.message}

Use get_operation_status to check progress.`,
        },
      ],
    };
  }
);

As an alternative of having a look ahead to the operation to finish, the tool instantly returns the operation ID. This helps to keep the interaction speedy and shall we within the AI assistant to follow up later if sought after.

Device 4: Clone internet web page

Cloning a internet web page is one of those actions corporations use all the time, specifically when running from templates or spinning up new consumer web pages. As an alternative of starting from scratch, you’re taking an provide atmosphere and create a brand spanking new internet web page in line with it.

The response uses the identical operation shape we spotted earlier, so no want to define it over again. The tool requires a display determine for the new internet web page and the environment ID to clone from:

server.registerTool(
  "clone_site",
  {
    description:
      "Clone an provide internet web page atmosphere to create a brand spanking new internet web page. Great for spinning up new consumer web pages from a template.",
    inputSchema: {
      display_name: z
        .string()
        .describe("Name for the new cloned internet web page"),
      source_env_id: z
        .string()
        .describe("The environment ID to clone from"),
    },
  },
  async ({ display_name, source_env_id }) => {
    const knowledge = look forward to kinstaRequest(
      "/web pages/clone",
      {
        approach: "POST",
        body: JSON.stringify({
          company: KINSTA_COMPANY_ID,
          display_name,
          source_env_id,
        }),
      }
    );

    return {
      content material materials: [
        {
          type: "text",
          text: `Site clone initiated!

New site: ${display_name}
Operation ID: ${data.operation_id}
Message: ${data.message}

Use get_operation_status to check progress.`,
        },
      ],
    };
  }
);

This tool is especially useful when paired with other apparatus. As an example, an AI assistant can clone a internet web page after which immediately tick list environments or check out plugin status as quickly because the operation completes.

Device 5: Get operation status

On account of some actions run asynchronously, we’d like an answer to check out their expansion. That’s what this tool is for.

interface OperationStatusResponse {
  status?: amount;
  message?: string;
}

server.registerTool(
  "get_operation_status",
  {
    description:
      "Check out the status of an async operation (cache blank, internet web page clone, and so on.)",
    inputSchema: {
      operation_id: z
        .string()
        .describe("The operation ID to check"),
    },
  },
  async ({ operation_id }) => {
    const response = look forward to fetch(
      `${KINSTA_API_BASE}/operations/${encodeURIComponent(operation_id)}`,
      {
        headers: {
          Authorization: `Bearer ${KINSTA_API_KEY}`,
        },
      }
    );

    const knowledge: OperationStatusResponse = look forward to response.json();

    if (response.status === 200) {
      return {
        content material materials: [
          {
            type: "text",
            text: `Operation completed successfully!

Message: $ "Operation finished"`,
          },
        ],
      };
    }

    if (response.status === 202) {
      return {
        content material materials: [
          {
            type: "text",
            text: `Operation still in progress...

Message: $ "Processing"`,
          },
        ],
      };
    }

    return {
      content material materials: [
        {
          type: "text",
          text: `Operation status: ${response.status}

Message: $ "Unknown status"`,
        },
      ],
    };
  }
);

Device 6: Get plugins all the way through all web pages

When you prepare many WordPress web pages, plugins are generally where problems start to glide. This tool solves that by the use of taking a look at plugins all the way through the entire company account, not one internet web page at a time.

The API returns a lot of information, along side which environments each plugin is installed in, whether or not or now not updates are available, and whether or not or now not a style is marked as vulnerable. To artwork with that knowledge, we define the following shapes:

interface PluginEnvironment  null;
  plugin_version: string;
  is_plugin_version_vulnerable: boolean;
  plugin_update_version: string 

interface Plugin  null;
  is_latest_version_vulnerable: boolean;
  environment_count: amount;
  update_count: amount;
  environments: PluginEnvironment[];


interface GetPluginsResponse {
  company: {
    plugins: {
      common: amount;
      items: Plugin[];
    };
  };
}

The tool itself doesn’t take any input:

server.registerTool(
  "get_plugins",
  {
    description:
      "Get all WordPress plugins all the way through all web pages. Shows which plugins have updates available or protection vulnerabilities.",
    inputSchema: {},
  },
  async () => {
    const knowledge = look forward to kinstaRequest(
      `/company/${KINSTA_COMPANY_ID}/wp-plugins`
    );

    const plugins = knowledge.company.plugins.items;

    if (!plugins || plugins.period === 0) {
      return {
        content material materials: [
          { type: "text", text: "No plugins found." }
        ],
      };
    }

    const sorted = [...plugins].kind(
      (a, b) => b.update_count - a.update_count
    );

    const pluginList = sorted.slice(0, 20).map((plugin) => {
      const status =
        plugin.update_count > 0
          ? `⚠ ${plugin.update_count} internet web page(s) need change`
          : "✅ Up-to-the-minute";

      const vulnerable =
        plugin.is_latest_version_vulnerable ? " 🔴 VULNERABLE" : "";

      return `• ${plugin.identify} (${plugin.determine})${vulnerable}
  Latest: $ "unknown"
  Installed on: ${plugin.environment_count} atmosphere(s)
  ${status}`;
    }).join("nn");

    const outdatedCount = plugins.filter(
      (p) => p.update_count > 0
    ).period;

    return {
      content material materials: [
        {
          type: "text",
          text: `Found ${data.company.plugins.total} plugins (${outdatedCount} have updates available):nn${pluginList}`,
        },
      ],
    };
  }
);

Device 7: Get topic issues all the way through all web pages

Subjects have identical problems to plugins, then again they’re without end checked even a lot much less steadily. This tool works the identical method since the plugin tool, then again focuses on WordPress topic issues as a substitute.

The response development mirrors the plugin endpoint, merely with theme-specific fields:

interface ThemeEnvironment  null;
  theme_version: string;
  is_theme_version_vulnerable: boolean;
  theme_update_version: string 

interface Theme  null;
  is_latest_version_vulnerable: boolean;
  environment_count: amount;
  update_count: amount;
  environments: ThemeEnvironment[];


interface GetThemesResponse {
  company: {
    topic issues: {
      common: amount;
      items: Theme[];
    };
  };
}

Device 8: Change plugin

Listing problems comes in handy, then again after all you need to fix them. This tool allows you to change a decided on plugin on a decided on atmosphere.

The change endpoint returns the identical async operation shape used earlier, so we will be able to skip it. Proper right here’s the tool definition:

server.registerTool(
  "update_plugin",
  {
    description:
      "Change a decided on plugin to a brand spanking new style on a internet web page atmosphere.",
    inputSchema: {
      environment_id: z
        .string()
        .describe("The environment ID where the plugin is installed"),
      plugin_name: z
        .string()
        .describe("The plugin determine/slug (e.g., 'akismet', 'elementor')"),
      update_version: z
        .string()
        .describe("The style to exchange to (e.g., '5.3')"),
    },
  },
  async ({ environment_id, plugin_name, update_version }) => {
    const knowledge = look forward to kinstaRequest(
      `/web pages/environments/${environment_id}/plugins`,
      {
        approach: "PUT",
        body: JSON.stringify({
          determine: plugin_name,
          update_version,
        }),
      }
    );

    return {
      content material materials: [
        {
          type: "text",
          text: `Plugin update initiated!

Plugin: ${plugin_name}
Target version: ${update_version}
Operation ID: ${data.operation_id}
Message: ${data.message}

Use get_operation_status to check progress.`,
        },
      ],
    };
  }
);

Like cache clears and internet web page clones, updates run asynchronously. Returning the operation ID shall we the AI assistant follow expansion as a substitute of assuming the change finished straight away.

See also  8 Highest WordPress Occasions Calendar Plugins in 2023

Working the server

With all apparatus registered, the general step is to begin out the MCP server and make it available to an AI consumer.

At the bottom of your document, add the principle function that connects the server the usage of the STDIO delivery:

async function number one() {
  const supply = new StdioServerTransport();
  look forward to server.connect(supply);
  console.error("Kinsta MCP Server running on stdio");
}

number one().catch((error) => {
  console.error("Fatal error:", error);
  process.move out(1);
});

This tells the MCP server to pay attention for requests over standard input and output. It makes the server discoverable by the use of MCP-compatible desktop shoppers.

One very important part right here’s logging. On account of this server communicates over STDIO, all logs should move to stderr. Writing to stdout can interfere with MCP messages and wreck the connection.

Next, assemble the enterprise:

npm run assemble

This compiles the TypeScript knowledge into the assemble checklist and makes the get admission to stage executable.

As quickly because the assemble finishes, the server is in a position to be offered by the use of an MCP consumer. You’ll have the ability to get right to use the complete code on GitHub.

Testing your server with Claude for Desktop

To use your MCP server, Claude for Desktop should know how to unencumber it. Open the Claude Desktop configuration document:

~/Library/Tool Support/Claude/claude_desktop_config.json

Create the document if it doesn’t already exist. While you’re the usage of VS Code, you’ll have the ability to open it straight away from the terminal:

code ~/Library/Tool Support/Claude/claude_desktop_config.json

All over the document, add your MCP server beneath the mcpServers key. As an example:

{
  "mcpServers": {
    "kinsta": {
      "command": "node",
      "args": ["/ABSOLUTE/PATH/TO/mcp-server-demo-kinsta-api/build/index.js"],
      "env": {
        "KINSTA_API_KEY": "your-api-key-here",
        "KINSTA_COMPANY_ID": "your-company-id-here"
      }
    }
  }
}

This configuration tells Claude for Desktop that there’s an MCP server named kinsta, it should be offered the usage of Node.js, and the get admission to stage is the built index.js document.

Ensure the path problems to the compiled document inside the assemble checklist, not the TypeScript provide. Save the document and restart Claude for Desktop.

Verifying the connection

Once Claude restarts, open a brand spanking new chat. Click on at the + icon next to the input field, then hover over Connectors. You should see your MCP server listed.

Registering an MCP server in Claude to enable tool access.
Registering an MCP server in Claude.

With the server connected, you’ll have the ability to get began the usage of it straight away. Claude makes a decision which tool to use, passes the desired input, and returns the result as easy text.

Updating a WordPress plugin using an MCP-powered workflow in Claude.
Updating a WordPress plugin the usage of an MCP-powered workflow in Claude.

A novel method to artwork with the apparatus you already have

What’s changing right now isn’t the underlying apparatus. APIs are however APIs. Internet website hosting platforms however artwork the identical method. What’s changing is how we interact with them.

AI apparatus are starting to in reality really feel a lot much less like chat packing containers and further like interfaces. This MCP server is a small example of that shift. It doesn’t introduce new options. It exposes provide ones someway that fits how folks if truth be told artwork.

Where that is going next is up to you. You want to keep problems simple and read-only. You want to add additional automation with approvals and guardrails. Or you might connect the identical server to other apparatus to your workflow.

As you find new apparatus and workflows like this, having a forged website online website hosting foundation problems. The last thing you want is to lose time dealing with downtime or potency issues as a substitute of setting up and making improvements to your web pages.

Kinsta provides managed website online website hosting for WordPress that keeps your web pages running reliably, even when you’re offline. You’ll have the ability to uncover our website hosting plans or communicate to our gross sales workforce to hunt out the most efficient plan for you.

The publish Create your personal MCP Server to regulate WordPress website hosting with AI seemed first on Kinsta®.

WP Hosting

[ continue ]

WordPress Maintenance Plans | WordPress Hosting

read more

0 Comments

Submit a Comment

DON'T LET YOUR WEBSITE GET DESTROYED BY HACKERS!

Get your FREE copy of our Cyber Security for WordPress® whitepaper.

You'll also get exclusive access to discounts that are only found at the bottom of our WP CyberSec whitepaper.

You have Successfully Subscribed!