Peter Knight Posted 2 hours ago Posted 2 hours ago I wanted a way to chat with my Processwire site and built a Module (PW MCP) and an MCP server to connect into it. It's a private repo at the moment but it can be public if anyone finds it useful. It's basically a way to use the Cursor Chat Ui to query my site, fields, templates and content. Here's part of the readme which explains it better. What Is It? ProcessWire MCP is a bridge between ProcessWire and Cursor IDE (the AI-powered code editor). It lets you query your ProcessWire site's structure and content directly from Cursor's chat interface using natural language. Instead of writing selectors or browsing the admin, you can just ask: "What templates does this site have?" "Show me the fields on the blog-post template" "Search for pages containing 'summer'" "Find all images with 'lake' in the filename" Why I Built It Cursor can see your template files and code in the local directory, but it can't see what's actually in your ProcessWire database — which templates and fields are registered, what pages exist, or what content they contain. With ProcessWire MCP, the AI can: Query the actual database schema (not just parse template files) Look up page content by ID, path, or selector Understand field configurations (types, settings, which templates use them) Search across all text content and find files/images Get RepeaterMatrix content with type labels See file metadata (dimensions, descriptions, URLs) It's the difference between seeing $page->body in code vs. knowing what that page's body actually contains. Architecture Cursor Chat → MCP Server (Node.js) → PHP CLI → ProcessWire API The module consists of: PwMcp — A ProcessWire module with a CLI interface mcp-server — A Node.js server that speaks the Model Context Protocol The CLI can also be used standalone for quick queries from terminal. Available Commands Command Description health Check connection and get site info list-templates List all templates with field counts get-template [name] Get template details and fields list-fields List all fields with types get-field [name] Get field details and usage get-page [id\|path] Get page by ID or path with all field values query-pages [selector] Query pages using PW selectors search [query] Search content across all text fields search-files [query] Search files by name/extension export-schema Export complete site schema Example: Health Check php site/modules/PwMcp/bin/pw-mcp.php health --pretty { "status": "ok", "pwVersion": "3.0.241", "siteName": "www.example.com", "moduleLoaded": true, "counts": { "templates": 45, "fields": 72, "pages": 960 } } Example: Content Search Ask Cursor: "Search for pages containing 'summer'" { "query": "summer", "count": 5, "results": [ { "id": 1764, "title": "Lake District walks in summer", "path": "/guides/lake-district-summer/", "template": "page-guide", "matchedField": "Body", "snippet": "The Lake District offers some of the best walking trails in summer. From gentle lakeside strolls to challenging fell walks..." } ] } Example: File Search Ask Cursor: "Find images with 'lake' in the filename" { "query": "lake", "count": 5, "results": [ { "filename": "lake-windermere-sunset.jpg", "url": "/site/assets/files/1070/lake-windermere-sunset.jpg", "size": 31207, "sizeStr": "30.5 kB", "description": "Sunset over Lake Windermere", "field": "Images", "page": { "id": 1070, "title": "Lake District walks in summer", "path": "/guides/lake-district-summer/" }, "width": 500, "height": 626 } ] } Example: Get Page with All Fields Ask Cursor: "Get the page at /about/" { "id": 1050, "name": "about", "path": "/about/", "url": "/about/", "template": "basic-page", "status": 1, "statusName": "published", "parent": { "id": 1, "path": "/", "title": "Home" }, "numChildren": 5, "created": "2023-05-15T10:30:00+00:00", "modified": "2024-11-20T14:22:00+00:00", "fields": { "title": "About Us", "body": "<p>We are a team of dedicated professionals...</p>", "Images": { "_count": 2, "_files": ["team-photo.jpg", "office.jpg"] } } } Example: RepeaterMatrix Support The module fully supports RepeaterMatrix fields, returning the actual content with type labels: { "matrix": { "_count": 3, "_items": [ { "_typeId": 1, "_typeLabel": "Body", "Body": "<h2>Welcome to our guide</h2><p>This guide covers...</p>", "Images": null }, { "_typeId": 2, "_typeLabel": "FAQs", "faq_question": "What is the best time to visit?", "faq_answer": "The summer months offer the best weather for walking..." }, { "_typeId": 3, "_typeLabel": "Call to Action", "cta_title": "Plan Your Visit", "cta_link": "/contact/" } ] } } So thats the first part done and working. My next plan is to be able to 1. PULL / convert a databse page into a local text file which lists all page properties, fields, template etc 2. edit the file as a local text file 3 PUSH the text file back into PW so that the original content picks up the changes Just having fun and building something useful. Very likely there are similar solutions or better ways to handle this but this suits my workflow ATM. Cheers P 2
Peter Knight Posted 2 hours ago Author Posted 2 hours ago I should clarify - I used Cursor itself to build this with Opus. I gave it a comprehensive PRD and built it in plan mode.
Peter Knight Posted 1 hour ago Author Posted 1 hour ago Ok, Phase 2 is working.... I can now say to Cursor Get any page with "Lake Windermere" in the title Processwire will create 2 local files in site/syncs 1 x a YAML version of the file listing all fields, content etc 1 x a sidecar file listing the meta data In the site/syn folder these pages are created using the matching directory structure of the page paths so it's essentially like the PW tree I can then edit the YAML and tell Cursor to push the page back to PW and the page is updated
Peter Knight Posted 1 hour ago Author Posted 1 hour ago I always ask Cusror to summarise the changes because it's much better at writing than me so here they are: Quote What We Built Today The Problem Previously, to edit ProcessWire content, you had to either: Log into the admin panel and use the web interface Or ask the AI to read page content, but it couldn't write back The Solution We added Pull/Push sync — a Git-like workflow for ProcessWire content: Pull a page from ProcessWire → saves it as an editable YAML file Edit the YAML in your IDE (or have AI edit it) Push the changes back → updates the live page Key Features Feature Description Natural language Just say "Pull the About page" in Cursor chat Mirrored folders Pages save to site/syncs/[page-path]/ matching your site structure Readable YAML Content is human-editable, not database dumps Readable dates Dates show as 2026-01-27 not Unix timestamps Dry-run by default Push shows what would change before applying Conflict detection Warns if someone else edited the page since you pulled Revision tracking Each pull stores a hash to detect remote changes What Works Now Pull any page by path or ID Edit text fields, titles, SEO fields, dates Push changes back to ProcessWire Re-pull to get latest version What's Not Yet Implemented Editing RepeaterMatrix content (the complex page builders) Uploading/changing images and files Bulk pull/push of multiple pages Creating new pages Example Workflow > You: "Pull the blog post about the Lake District" > AI: Finds and pulls it to site/syncs/news/posts/lake-district-walks/page.yaml > You: Edit the YAML file, save > You: "Push the Lake District walks page" > AI: Shows preview, then applies changes to ProcessWire
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now