关于 MCP Local WP
MCP Local WP 是一个 MCP 服务,让 AI 助手以只读方式访问 Local by Flywheel 管理的 WordPress 数据库。它可执行 MySQL 查询并查看表结构,适合 WordPress 开发者在编写 SQL 前先核对真实数据结构。
主要功能
- 01只读执行 MySQL 查询
- 02查看表结构、列与索引
- 03自动识别 Local 站点与 MySQL 实例
- 04支持按站点名称或 ID 选择站点
- 05查看当前连接站点信息
适用场景
- 01让 AI 助手核对 WordPress 表结构后再编写查询
- 02调试 LearnDash、WooCommerce 等插件的自定义表
- 03在 Claude Code 或 Cursor 中按当前目录连接对应站点数据库
MCP 相关
该项目是一个 MCP 服务,向 MCP 客户端暴露 mysql_query、mysql_schema、mysql_current_site 和 mysql_list_sites 等工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
4收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sql | string | 是 | 一条 SQL 语句;禁止使用可执行注释。 |
| params | array | 否 | SQL 占位符 (?) 的值。 |
详细介绍
MCP Server Local WP
🎯 如果你的 AI 助手真的能看到你的 WordPress 数据库,会怎样?
一个模型上下文协议(MCP)服务,可让 Claude 和 Cursor 等 AI 助手直接以只读方式访问你的 Local by Flywheel WordPress 数据库。不再猜测表结构,不再盲目编写 SQL 查询。现在,你的 AI 可以了解你的实际数据。
升级到 2.0
2.0 版本要求使用 Node.js 24 或更高版本,并使用 MCP SDK v2。现有工具名称和站点选择器仍然可用。查询结果现在为 { "rows": [...] };架构列表返回 { "tables": [...], "hasMore": false, "nextAfter": null },其中表名分页有数量限制。成功调用的工具会返回相匹配的结构化结果和 JSON 文本结果;失败时会设置 isError: true。
数据库和 Local 配置会延迟解析,因此即使没有正在运行的站点,也可以发现 MCP 工具。显式设置 MYSQL_HOST 或 MYSQL_SOCKET_PATH 会选择手动连接。请保持 stdin 打开,直到收到所有工具响应;EOF 会关闭会话。父级 watchdog 也会清理已弃用的 stdio 服务。
🤔 什么是 MCP 服务?
可以把 MCP(模型上下文协议)看作 AI 助手与开发工具之间的安全桥梁。无需复制粘贴数据库架构或查询结果,MCP 服务就能让 AI 助手直接与你的工具交互,同时让你完全掌控整个过程。
不使用 MCP:“嘿,AI,我觉得有个表叫 wp_something,其中可能有个列名是 user_meta……你能写个查询吗?”
使用 MCP:“嘿,AI,看看我的数据库里有什么,并写出我需要的准确查询。”
💡 WordPress 开发者的两难
想象一下:你正在调试 LearnDash 集成问题。测验结果无法正常同步。你启动 Cursor 来帮忙诊断问题,但没有数据库访问权限,即使是最先进的 AI,也只能根据表结构做出有根据的猜测。
真实影响
下面是我们处理过的一张实际支持工单。任务很简单:从 LearnDash 表中获取测验活动数据。
❌ 使用 MCP 服务前(AI 盲目摸索):
AI 尽力尝试,给出了这个查询建议:
$quiz_activities = $wpdb->get_results(
$wpdb->prepare(
'SELECT post_id, activity_meta FROM ' . esc_sql( LDLMS_DB::get_table_name( 'user_activity' ) ) . '
WHERE user_id=%d AND activity_type=%s AND activity_status=1 AND activity_completed IS NOT NULL',
$user_id,
'quiz'
),
ARRAY_A
);
问题在哪? activity_meta 列并不存在!LearnDash 将元数据存储在一个结构完全不同的独立表中。由于无法访问数据库,AI 做出了合理但错误的假设。你接下来得花 20 分钟手动修正表名、找出表之间的关系,并重写查询。
✅ 使用 MCP 服务后(AI 如同拥有 X 射线视力):
有了数据库访问权限,AI 立即看到了实际的表结构,并写出了:
$quiz_activities = $wpdb->get_results(
$wpdb->prepare(
'SELECT ua.post_id, ua.activity_id, uam.activity_meta_key, uam.activity_meta_value
FROM ' . esc_sql( LDLMS_DB::get_table_name( 'user_activity' ) ) . ' ua
LEFT JOIN ' . esc_sql( LDLMS_DB::get_table_name( 'user_activity_meta' ) ) . ' uam
ON ua.activity_id = uam.activity_id
WHERE ua.user_id=%d AND ua.activity_type=%s AND ua.activity_completed IS NOT NULL
AND uam.activity_meta_key IN (%s, %s, %s)',
$user_id,
'quiz',
'percentage',
'points',
'total_points'
),
ARRAY_A
);
区别在哪? AI 能看到元数据存储在独立的 user_activity_meta 表中,理解它们通过 activity_id 关联,也清楚有哪些 meta 键。一次成功,无需猜测。问题解决。
🚀 为什么这会改变一切
当你的 AI 助手可以读取数据库时:
- 不再猜测架构 — 它能看到实际的表和列
- 准确执行 JOIN 操作 — 它能理解表之间的关系
- 验证真实数据 — 在建议查询前,它可以确认数据是否存在
- 适配插件开发 — 它能适应任何插件的自定义表(WooCommerce、LearnDash 等)
- 即时调试 — “显示所有尚未完成 ID 为 42 的测验的用户”只需 5 秒
🔧 我们解决的 Local by Flywheel 难题
在 Local by Flywheel 中使用原版 mcp-server-mysql 时,开发者会遇到几个难题:
- 动态路径:Local by Flywheel 会为每个站点生成唯一标识符(例如
lx97vbzE7),站点重启后标识符会改变 - 套接字与端口混淆:Local 同时使用 Unix 套接字和 TCP 端口,但配置起来可能比较棘手
- 硬编码配置:大多数设置都要求每次 Local 重启后手动更新路径
我们的解决方案
此 MCP 服务会自动检测当前运行的 Local by Flywheel MySQL 实例,方法如下:
- 进程检测:扫描正在运行的进程,查找活动的
mysqld实例 - 配置解析:从活动的 Local 站点中提取 MySQL 配置
- 动态连接:自动使用正确的套接字路径或端口进行连接
- 回退支持:对于非 Local 设置,回退使用环境变量
多站点支持
当你有多个 Local 站点时,服务会使用基于优先级的站点选择,确保始终连接到正确的数据库:
选择优先级
SITE_ID环境变量 - 直接指定站点 ID(最高优先级)SITE_NAME环境变量 - 根据易读的站点名称查找- 工作目录检测 - 如果当前工作目录位于 Local 站点路径下,则使用该站点
- 进程检测 - 使用找到的第一个正在运行的 Local mysqld
- 文件系统回退 - 使用最近修改的套接字
明确选择站点
在 MCP 配置中指定要连接的站点:
{
"mcpServers": {
"wordpress-dev": {
"command": "npx",
"args": ["-y", "@verygoodplugins/mcp-local-wp@latest"],
"env": {
"SITE_NAME": "dev"
}
}
}
}
或者直接使用站点 ID:
{
"env": {
"SITE_ID": "lx97vbzE7"
}
}
工作目录检测
使用 Claude Code 或 Cursor 时,服务会根据当前目录自动检测你正在使用的站点。如果你正在编辑 /Users/.../Local Sites/dev/app/public/wp-content/plugins/my-plugin/ 中的文件,服务会自动连接到“dev”站点的数据库。
验证连接
使用 mysql_current_site 工具查看当前连接的站点:
{
"siteName": "dev",
"siteId": "lx97vbzE7",
"sitePath": "/Users/.../Local Sites/dev",
"domain": "dev.local",
"selectionMethod": "cwd_detection",
}
使用 mysql_list_sites 查看所有可用站点及其状态。
可用工具
mysql_query
对 Local WordPress 数据库执行只读 SQL 查询。
输入字段:
sql(string):单条只读语句(SELECT,包括 WITH CTE,或 SHOW/DESCRIBE/EXPLAIN)params((string | number | boolean | null)[]):可选的?占位符参数值
使用示例:
-- With parameters
SELECT * FROM wp_posts WHERE post_status = ? ORDER BY post_date DESC LIMIT ?;
-- params: ["publish", "5"]
-- Direct queries
SELECT option_name, option_value FROM wp_options WHERE option_name LIKE '%theme%';
SHOW TABLES;
DESCRIBE wp_users;
-- Common table expression (CTE)
WITH published AS (SELECT ID, post_title FROM wp_posts WHERE post_status = ?)
SELECT * FROM published LIMIT 10;
-- params: ["publish"]
mysql_schema
使用 INFORMATION_SCHEMA 检查数据库架构。
- 无参数:按二进制名称排序,最多列出 100 个表名,并返回
hasMore和nextAfter - 列表选项:
prefix(区分大小写的字面前缀)、limit(1–200)、after(上一页的nextAfter)和includeStats(默认为 false) - 使用
table:返回该表的列和索引
当 hasMore 为 true 时,将 nextAfter 作为 after 传入,并保持使用相同的前缀,以获取下一页。最后一页的 hasMore 为 false,且 nextAfter 为 null。默认情况下,列表行仅包含 table_name;includeStats: true 会额外返回引擎、估算行数、数据字节数和索引字节数。前缀中的 % 和 _ 是字面字符。使用 table 单独进行详细检查;它不能与列表选项组合使用。每一页反映的是当前架构,因此请求之间的表变更可能会影响列表。
示例:
// First page of table names
{
"tool": "mysql_schema",
"args": {}
}
// Filter to WordPress tables and include statistics
{
"tool": "mysql_schema",
"args": { "prefix": "wp_", "limit": 50, "includeStats": true }
}
// Continue a filtered listing using the previous response's nextAfter
{
"tool": "mysql_schema",
"args": { "prefix": "wp_", "limit": 50, "after": "wp_posts" }
}
// Inspect a specific table
{
"tool": "mysql_schema",
"args": { "table": "wp_posts" }
}
mysql_current_site
获取当前连接的 Local WordPress 站点信息。
返回站点名称、ID、路径、域名、套接字路径,以及站点的选择方式(环境变量、当前工作目录检测或自动检测)。
{
"tool": "mysql_current_site",
"args": {},
}
// Returns:
// {
// "siteName": "dev",
// "siteId": "lx97vbzE7",
// "sitePath": "/Users/.../Local Sites/dev",
// "domain": "dev.local",
// "selectionMethod": "cwd_detection",
// "socketPath": "/Users/.../Local/run/lx97vbzE7/mysql/mysqld.sock"
// }
mysql_list_sites
列出所有可用的 Local WordPress 站点及其运行状态。
{
"tool": "mysql_list_sites",
"args": {},
}
// Returns:
// {
// "sites": [
// { "id": "lx97vbzE7", "name": "dev", "domain": "dev.local", "running": true },
// { "id": "WP7lolWDi", "name": "staging", "domain": "staging.local", "running": false }
// ],
// "currentSiteId": "lx97vbzE7"
// }
安装
先决条件
- 已安装并运行 Local by Flywheel
- 有一个正在运行的活动 Local 站点
- Node.js 24+
快速设置(推荐)
最简单的入门方式——无需安装:
Cursor IDE 配置
将以下内容添加到 Cursor MCP 配置文件(.cursor/mcp.json)中:
{
"mcpServers": {
"mcp-local-wp": {
"command": "npx",
"args": ["-y", "@verygoodplugins/mcp-local-wp@latest"]
}
}
}
Claude Desktop 配置
将以下内容添加到 Claude Desktop 配置文件中:
macOS:~/Library/Application Support/Claude/claude_desktop_config.json
Windows:%APPDATA%\\Claude\\claude_desktop_config.json
{
"mcpServers": {
"mcp-local-wp": {
"command": "npx",
"args": ["-y", "@verygoodplugins/mcp-local-wp@latest"]
}
}
}
高级设置(本地开发)
如需自定义或进行本地开发:
从源代码安装
git clone https://github.com/verygoodplugins/mcp-local-wp.git
cd mcp-local-wp
npm install
npm run build
本地配置
{
"mcpServers": {
"mcp-local-wp": {
"command": "node",
"args": ["/full/path/to/mcp-local-wp/dist/index.js"]
}
}
}
自定义环境变量
用于非 Local 设置或自定义配置:
{
"mcpServers": {
"mcp-local-wp": {
"command": "npx",
"args": ["-y", "@verygoodplugins/mcp-local-wp@latest"],
"env": {
"MYSQL_DB": "local",
"MYSQL_HOST": "localhost",
"MYSQL_PORT": "3306",
"MYSQL_USER": "root",
"MYSQL_PASS": "root"
}
}
}
}
站点选择变量
| 变量 | 说明 | 示例 |
|---|---|---|
SITE_ID | 显式指定站点 ID(优先级最高) | lx97vbzE7 |
SITE_NAME | 用于查找的站点名称 | dev |
LOCAL_SITES_JSON | 覆盖 Local 的 sites.json 路径 | /custom/path/sites.json |
LOCAL_RUN_DIR | 覆盖 Local 的运行目录 | /custom/run/path |
与 Local by Flywheel 的工作原理
创建此 MCP 服务,是因为使用现有 MCP 服务连接到 Local by Flywheel MySQL “有点难以正常运行”。以下是我们解决问题的过程:
最初的问题
首次尝试将 mcp-server-mysql 与 Local by Flywheel 配合使用时,我们遇到了几个问题:
- 动态套接字路径:Local 会生成类似
/Users/.../Local/run/lx97vbzE7/mysql/mysqld.sock的路径,其中lx97vbzE7会在每次重启 Local 时发生变化 - 配置复杂:原始服务需要写死路径,每次重启 Local 都会导致路径失效
- 主机/端口混淆:Local 的 MySQL 配置可能比较棘手,因为它同时支持套接字和 TCP 连接
我们的解决过程
我们逐步解决了这些问题:
1. 基于进程进行检测
我们不再猜测路径,而是扫描实际运行的 MySQL 进程:
ps aux | grep mysqld | grep -v grep
这样可以找到活动的 MySQL 实例并提取其配置文件路径。
2. 动态解析路径
// From the process args: --defaults-file=/Users/.../Local/run/lx97vbzE7/conf/mysql/my.cnf
// We extract the site directory and build the socket path
const configPath = extractFromProcess();
const siteDir = path.dirname(path.dirname(path.dirname(configPath)));
const socketPath = path.join(siteDir, 'mysql/mysqld.sock');
3. 自动配置
服务会自动完成以下配置:
- 为活动的 Local 站点设置正确的套接字路径
- 设置正确的数据库名称(
local) - 设置默认凭据(
root/root) - 必要时回退到环境变量
此方法为何有效
✅ 重启后仍可使用:每次重启 Local by Flywheel 后都能正常工作
✅ 切换站点:在不同 Local 站点之间切换时会自动适配
✅ 无需维护:再也不必手动更新路径
✅ 错误处理:MySQL 未运行时会提供清晰的错误消息
我们处理的 Local 目录结构
~/Library/Application Support/Local/run/
├── lx97vbzE7/ # Dynamic site ID (changes on restart)
│ ├── conf/mysql/my.cnf # We read this for port info
│ └── mysql/mysqld.sock # We connect via this socket
└── WP7lolWDi/ # Another site (if multiple running)
├── conf/mysql/my.cnf
└── mysql/mysqld.sock
服务会智能地找到活动站点,并连接到正确的 MySQL 实例。
使用示例
连接后,可以使用 mysql_query 工具,对 Local WordPress 数据库执行允许的只读 SQL 查询:
获取最近发布的文章
SELECT ID, post_title, post_date, post_status
FROM wp_posts
WHERE post_type = 'post' AND post_status = 'publish'
ORDER BY post_date DESC
LIMIT 5;
探索数据库结构
-- See all tables
SHOW TABLES;
-- Examine a table structure
DESCRIBE wp_posts;
-- Get table info
SHOW TABLE STATUS LIKE 'wp_%';
WordPress 专用查询
-- Get site options
SELECT option_name, option_value
FROM wp_options
WHERE option_name IN ('blogname', 'blogdescription', 'admin_email');
-- Find active plugins
SELECT option_value
FROM wp_options
WHERE option_name = 'active_plugins';
-- Get user information
SELECT user_login, user_email, display_name
FROM wp_users
LIMIT 10;
-- Post meta data
SELECT p.post_title, pm.meta_key, pm.meta_value
FROM wp_posts p
JOIN wp_postmeta pm ON p.ID = pm.post_id
WHERE p.post_type = 'post' AND pm.meta_key = '_edit_last';
开发设置
从源代码运行
-
启动 Local 站点:确保有一个正在运行的 Local by Flywheel 活动站点
-
克隆并构建:
git clone https://github.com/verygoodplugins/mcp-local-wp.git cd mcp-local-wp npm install npm run build -
测试连接:
node dist/index.js
开发模式
npm run dev
此模式会运行服务,并使用 TypeScript 监视更改。
代码检查与格式化
- 代码检查:
npm run lint - 修复代码检查问题:
npm run lint:fix - 格式化:
npm run format - 检查格式:
npm run format:check
通过 ESLint + Prettier 统一 MCP 服务的规范。
故障排除
常见问题
-
“未找到正在运行的 MySQL 进程”
- 确保 Local by Flywheel 正在运行
- 确保 Local 中至少有一个站点已启动
- 检查该站点的数据库是否正在运行
-
“未找到 MySQL 套接字”
- 确认 Local 站点已完全启动
- 尝试在 Local 中停止并重新启动该站点
- 检查 Local 日志,查看是否存在 MySQL 启动问题
-
连接被拒绝
- 确保 Local 站点的 MySQL 服务正在运行
- 检查是否有其他进程正在使用 MySQL 端口
- 尝试重新启动 Local by Flywheel
-
权限被拒绝
- 确保 MySQL 套接字文件具有正确的权限
- 检查你的用户是否有权访问 Local 目录
手动配置
如果自动检测失败,你可以手动配置连接:
export MYSQL_SOCKET_PATH="/path/to/your/local/site/mysql/mysqld.sock"
export MYSQL_DB="local"
export MYSQL_USER="root"
export MYSQL_PASS="root"
调试
通过设置 DEBUG 启用调试日志:
DEBUG=mcp-local-wp mcp-local-wp
安全
mysql_query 接受一条 SELECT/SHOW/DESCRIBE/DESC/EXPLAIN 语句,包括以 WITH 或 WITH RECURSIVE 开头的 SELECT 查询。CTE 查询体和最终查询表达式必须解析为 SELECT,包括嵌套的 WITH … SELECT 和带括号的查询;WITH … UPDATE/DELETE 会被拒绝。支持 MariaDB 的 CYCLE … RESTRICT 子句用于循环检测。分词器会根据连接的 SQL 模式检查实际 SQL 词元。整条语句中的可执行 MySQL/MariaDB 注释、优化器提示、文件输出、SELECT INTO、锁定读取、咨询锁函数和 EXPLAIN ANALYZE 都会被拒绝,包括 CTE 查询体。支持普通注释和带引号值中的分号。
每次读取都在专用连接上、由数据库强制执行的只读事务中运行。设置失败会停止执行;清理失败则会丢弃该连接。MYSQL_ALLOW_WRITES=true 会在单独的连接上启用 mysql_write;它不会取消对 mysql_query 的保护。写入语句允许 INSERT/UPDATE/DELETE。UPDATE/DELETE 的 WHERE 子句中必须使用列与绑定参数进行比较,且可选择用 AND/OR 组合;IN、BETWEEN 和 LIKE 也支持绑定值。仅包含裸占位符或字面值的谓词会被拒绝。架构操作和写入子查询仍会被禁止。
为获得额外保护,请配置一个仅对所选数据库具有 SELECT 权限且不具备 FILE 或 EXECUTE 权限的专用账户。MYSQL_USER 和 MYSQL_PASS 同样适用于自动检测到的 Local 站点和手动连接。服务端不会创建用户或更改授权。只读事务无法隔离临时表或任意原生扩展;对于不受信任的数据库,请使用最小权限凭据。
此服务支持本地开发;可用时使用 Unix 套接字,显式连接则使用 TCP。请通过 GitHub Security Advisories 或 [email protected] 私下报告漏洞。
贡献
欢迎贡献!欢迎提交 Pull Request。
开发指南
- Fork 此仓库
- 创建功能分支:
git checkout -b feature/your-feature-name - 进行更改并添加测试
- 确保 TypeScript 编译通过:
npm run build - 提交 pull request
许可证
GPL-3.0-or-later——详情请参阅 LICENSE 文件。作为一款面向 WordPress 的工具,我们秉持 copyleft 理念,确保它继续免费向社区开放。
支持
- GitHub Issues:报告错误或请求功能
- 文档:本 README 和内联代码文档
- 社区:参与 Model Context Protocol 社区讨论
相关项目
- mcp-server-mysql — 启发了这个 WordPress 专用版本的原始 MySQL MCP 服务
- Local by Flywheel — 本服务专为其设计的本地 WordPress 开发环境
- Model Context Protocol — 协议规范
由 Jack Arturo 在 Very Good Plugins 倾情打造 🧡 · 满怀热忱地献给开源社区
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。