Skip to content

MCP Server

@loopress/mcp is an MCP server that exposes Loopress CLI operations as tool calls, so an AI agent (Claude Code, Claude Desktop, or any MCP client) can pull and push snippets, API routes, hooks, ACF objects, forms, nav menus, custom post types, taxonomies, post meta, roles, block patterns, options, Global Styles, plugins, themes and Composer dependencies on a WordPress site (plus push, list and diff static pages and block templates and parts, which don’t support pull, and deploy single-page apps), one resource at a time or all at once, and check project status. It ships as the lps-mcp binary.

It doesn’t reimplement any sync logic: every tool runs the CLI installed alongside it (both installed globally with npm install -g), falling back to the lps binary on your PATH.

  • The Loopress CLI installed and on PATH
  • A loopress.json already set up in the directory your MCP client will launch the server from (lps init), since tools resolve paths the same way lps does when run by hand
  • WordPress authentication already done via the CLI (lps project config). The MCP server never handles auth itself, it only calls lps, which reads the stored Application Password.
Terminal window
npm install -g @loopress/mcp

Then point your MCP client at the lps-mcp binary. In Claude Code:

Terminal window
claude mcp add loopress -- lps-mcp

In a JSON-based client config (Claude Desktop and similar):

{
"mcpServers": {
"loopress": {
"command": "lps-mcp"
}
}
}

On Windows, npm installs lps-mcp as a .cmd shim, so launch it through cmd: claude mcp add loopress -- cmd /c lps-mcp, or "command": "cmd", "args": ["/c", "lps-mcp"] in a JSON config.

The server communicates over stdio from the directory your client launches it in, and takes no arguments of its own.

When an agent connects, the server tells it what a Loopress project is and links the documentation page of each file format (hooks, API routes, ACF and the others). An agent asked for a feature then writes a Loopress hook, not plain WordPress code that push would refuse.

Tool Mutating Description
snippet_push Yes Push local snippet files to WordPress
snippet_pull No Pull snippets from WordPress into local files
snippet_list No List snippets currently on WordPress
snippet_rollback Yes Restore snippets to the snapshot saved automatically before an earlier snippet_push (list shows what’s available)
api_push Yes Push local custom API route files to WordPress (prune also removes server-side files absent locally)
api_pull No Pull custom API route files from WordPress
api_list No List custom API route files currently on WordPress (flags each route public when it needs no authentication)
api_rm Yes Remove one custom API route file from WordPress
api_rollback Yes Restore API route files to the snapshot saved automatically before an earlier api_push (list shows what’s available)
hook_push Yes Push local hook files to WordPress (prune also removes server-side files absent locally)
hook_pull No Pull hook files from WordPress
hook_list No List hook files (WordPress actions, filters, and cron jobs) currently on WordPress
hook_rm Yes Remove one hook file (action, filter, cron) from WordPress
hook_rollback Yes Restore hook files to the snapshot saved automatically before an earlier hook_push (list shows what’s available)
page_push Yes Push local static HTML pages to WordPress, or only one (slug)
page_list No List the static pages managed by Loopress on WordPress
page_diff No Show what differs between the local pages and WordPress
template_push Yes Push local block templates, parts and theme CSS as the files of the Loopress child theme
template_list No Show the Loopress child theme: active or not, its templates and parts, and Site Editor edits
template_diff No Show what differs between the local templates and parts and WordPress, Site Editor edits included
app_push Yes Build and push single-page app bundles to WordPress
app_pull No Pull single-page app bundles from WordPress into local files
app_list No List single-page apps currently deployed to WordPress
app_remove Yes Remove a single-page app from WordPress
acf_push Yes Push local ACF field groups, post types, taxonomies and options pages to WordPress
acf_pull No Pull ACF objects from WordPress into local files
acf_list No List ACF objects currently on WordPress
acf_rollback Yes Restore ACF objects to the snapshot saved automatically before an earlier acf_push (list shows what’s available)
menu_push Yes Push local nav menus and the active theme menu locations to WordPress
menu_pull No Pull nav menus and the active theme menu locations from WordPress into local files
menu_list No List nav menus and the active theme menu locations currently on WordPress
menu_rollback Yes Restore nav menus and menu locations to the snapshot saved automatically before an earlier menu_push (list shows what’s available)
cpt_push Yes Push local cpt/<slug>.json custom post types to WordPress (create or update only)
cpt_pull No Pull the custom post types Loopress manages into cpt/<slug>.json files
cpt_list No List the post types registered on WordPress and where each comes from
cpt_rm Yes Stop registering a Loopress custom post type (its posts stay in the database, hidden)
cpt_rollback Yes Restore custom post types to the snapshot saved automatically before an earlier cpt_push (list shows what’s available)
taxonomy_push Yes Push local taxonomies/<slug>.json taxonomies to WordPress (create or update only, never their terms)
taxonomy_pull No Pull the taxonomies Loopress manages into taxonomies/<slug>.json files
taxonomy_list No List the taxonomies registered on WordPress, where each comes from and the post types it attaches to
taxonomy_rm Yes Stop registering a Loopress taxonomy (its terms stay in the database, hidden)
taxonomy_rollback Yes Restore taxonomies to the snapshot saved automatically before an earlier taxonomy_push (list shows what’s available)
meta_push Yes Push local meta/<post-type>.json meta keys to WordPress (create or update only, never their values)
meta_pull No Pull the post meta keys Loopress manages into meta/<post-type>.json files
meta_list No List the meta keys registered for each post type on WordPress, and whether Loopress declares them
meta_rm Yes Stop registering the Loopress meta keys of one post type (their values stay in the database)
meta_rollback Yes Restore post meta keys to the snapshot saved automatically before an earlier meta_push (list shows what’s available)
role_push Yes Push local roles/<slug>.json roles to WordPress (create or update only, never changes which users have them)
role_pull No Pull the roles Loopress manages into roles/<slug>.json files
role_list No List the user roles on WordPress, where each comes from and how many users have it
role_rm Yes Stop registering a Loopress role (its users keep it, with no capability)
role_rollback Yes Restore roles to the snapshot saved automatically before an earlier role_push (list shows what’s available)
pattern_push Yes Push local patterns/<slug>.html block patterns to WordPress, registered as loopress/<slug> (create or update only)
pattern_pull No Pull the block patterns Loopress manages into patterns/<slug>.html files
pattern_list No List the block patterns registered by Loopress, the theme and plugins
pattern_rm Yes Stop registering a Loopress block pattern (references to it render nothing)
pattern_rollback Yes Restore block patterns to the snapshot saved automatically before an earlier pattern_push (list shows what’s available)
option_push Yes Push locally tracked, non-readonly options to WordPress
option_pull No Refresh locally tracked options from WordPress
option_list No List WordPress option names and autoload flags currently on the site (names only, never values)
option_add No Fetch a WordPress option by name and start tracking it locally
option_remove Yes Stop tracking an option locally and delete it from WordPress
option_rollback Yes Restore tracked options to the snapshot saved automatically before an earlier option_push (list shows what’s available)
form_push Yes Push local form files to WordPress
form_pull No Pull forms from WordPress into local files
form_list No List forms currently on WordPress
form_rollback Yes Restore forms to the snapshot saved automatically before an earlier form_push (list shows what’s available)
plugin_add No Add a WordPress.org plugin to loopress.json, or change its pinned version (local file only)
plugin_push Yes Install WordPress.org plugins to match loopress.json (active state included), or push the whole composer.json when there is one, via Composer + WPackagist
plugin_pull No Refresh the tracked plugins from WordPress into loopress.json (or composer.json), pinned to their live versions; other installed plugins are reported as untracked unless named in plugins
plugin_status No Compare the plugins on WordPress against loopress.json and report drift
plugin_audit No Check loopress.json plugins for known vulnerabilities and health issues
theme_add No Add a WordPress.org theme to loopress.json, or change its pinned version (local file only)
theme_version_push Yes Install WordPress.org themes to match loopress.json (never switches the active theme)
theme_push Yes Push everything theme related: versions, then templates and parts, then Global Styles
theme_version_pull No Pull installed themes from WordPress into loopress.json, pinned to their live versions
theme_pull No Pull everything theme related: versions, then Global Styles
theme_status No Compare the themes on WordPress against loopress.json and report version drift
theme_styles_push Yes Push the local Global Styles file to the active block theme’s Site Editor > Styles on WordPress
theme_styles_pull No Pull the active block theme’s Global Styles customizations from WordPress into a local file
theme_styles_rollback Yes Restore Global Styles to the snapshot saved automatically before an earlier theme_styles_push (list shows what’s available)
composer_push Yes Push composer.json and run Composer on WordPress to resolve and install dependencies
composer_pull No Pull composer.json/composer.lock from WordPress
push_all Yes Push every local resource to WordPress in one run, like lps push
pull_all No Pull every resource from WordPress into local files in one run, like lps pull
project_promote Yes Copy every tracked resource from one environment (from) to another (to), pulling then pushing, like lps promote
content_copy Yes Replace the local site’s posts, pages and terms with those of from, then push the project to local, like lps content copy
project_status No Show which project and environment the other tools will target
project_diff No Show what differs between local tracked files and a WordPress environment, or between two environments (against)
project_doctor No Diagnose connectivity, plugin, credential and hook problems for the targeted environment
validate_local No Check local tracked files are well formed and push-ready, without contacting WordPress

Every tool accepts an optional env to target a specific environment instead of the project’s default one (local, or its only environment). The _push, _pull, _list and _rollback tools that sync files also accept an optional path to override the directory configured in loopress.json. The ACF tools take an optional type array to scope the operation, mirroring the CLI’s --type flag. project_diff also takes optional only/skip resource-name arrays (the same names as lps diff --only, including template, part and page) and an against environment name to compare two environments instead of an environment against local files. Push tools that check for changes made outside Loopress (push_all, page_push and every resource with a _rollback tool) take an optional overwrite boolean, the CLI’s --overwrite: without it, a confirmed push over such a change fails and names what it would overwrite. Each _rollback tool restores the snapshot its resource’s _push tool saved automatically right before the last real push; pass list: true to see what’s available instead (id, timestamp, environment) or to to pick an older one. The preview result’s drift field reports whether the environment changed since that push, and if it changes again between the preview and the confirmed call, the confirmed call is refused rather than applied, the same staleness check every other mutating tool’s confirmation handshake now does.

Every mutating tool requires two calls before it touches WordPress:

  1. Call without confirmToken: takes a private copy of the working directory, runs a dry-run preview against it, and returns a single-use confirmToken (expires after 5 minutes) instead of making any change. Most push previews list each item they write under changes, as created, changed or unchanged against the site (see dry runs), so the agent can tell you what will change. The plugin, theme version, composer and app pushes don’t: their preview has its own shape.
  2. Call again with that confirmToken: re-runs that same dry-run once more, from the same private copy, right before applying. If it now reports anything different, meaning the environment changed since the preview, the call is refused instead of applying against stale data; call again without a confirmToken for a fresh preview. Otherwise it applies from that same copy, so a file edited on disk between the two calls cannot change what gets pushed either.

This handshake can’t be skipped, so an agent can never push a real change without a human-reviewable preview first. Mutating tools also refuse an environment named production outright, run those changes with lps, where they are confirmed interactively. When env is omitted, the preview call resolves the default environment and pins it, so this refusal covers the default environment too, and the confirmed call applies to the environment that was previewed even if the configuration changes in between. Two known gaps: an lps --path that points outside the working directory, or a loopress.json that maps a resource directory to an absolute path elsewhere, is still read live when the change is applied; and the revalidation dry-run and the real apply are still two separate requests rather than one atomic check-and-write, so a WordPress change landing in that (much narrower) window can still be overwritten, closing that fully needs a conditional write enforced by WordPress itself, tracked separately.

The server also exposes loopress://project/config as a resource: the raw contents of loopress.json in the current directory, for an agent to inspect without shelling out itself.