localwp-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +229 -0
  3. package/dist/backup.d.ts +72 -0
  4. package/dist/backup.js +351 -0
  5. package/dist/backup.js.map +1 -0
  6. package/dist/config.d.ts +24 -0
  7. package/dist/config.js +58 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/environment-check.d.ts +187 -0
  10. package/dist/environment-check.js +174 -0
  11. package/dist/environment-check.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +14 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/local-doctor.d.ts +42 -0
  16. package/dist/local-doctor.js +224 -0
  17. package/dist/local-doctor.js.map +1 -0
  18. package/dist/local-sites.d.ts +103 -0
  19. package/dist/local-sites.js +234 -0
  20. package/dist/local-sites.js.map +1 -0
  21. package/dist/local-tooling.d.ts +2 -0
  22. package/dist/local-tooling.js +23 -0
  23. package/dist/local-tooling.js.map +1 -0
  24. package/dist/logs.d.ts +144 -0
  25. package/dist/logs.js +208 -0
  26. package/dist/logs.js.map +1 -0
  27. package/dist/mysql.d.ts +17 -0
  28. package/dist/mysql.js +229 -0
  29. package/dist/mysql.js.map +1 -0
  30. package/dist/permissions.d.ts +4 -0
  31. package/dist/permissions.js +129 -0
  32. package/dist/permissions.js.map +1 -0
  33. package/dist/platform-paths.d.ts +10 -0
  34. package/dist/platform-paths.js +95 -0
  35. package/dist/platform-paths.js.map +1 -0
  36. package/dist/process-utils.d.ts +13 -0
  37. package/dist/process-utils.js +128 -0
  38. package/dist/process-utils.js.map +1 -0
  39. package/dist/prompts.d.ts +2 -0
  40. package/dist/prompts.js +64 -0
  41. package/dist/prompts.js.map +1 -0
  42. package/dist/resources.d.ts +2 -0
  43. package/dist/resources.js +110 -0
  44. package/dist/resources.js.map +1 -0
  45. package/dist/results.d.ts +15 -0
  46. package/dist/results.js +26 -0
  47. package/dist/results.js.map +1 -0
  48. package/dist/server.d.ts +2 -0
  49. package/dist/server.js +23 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/tool-schemas.d.ts +14 -0
  52. package/dist/tool-schemas.js +20 -0
  53. package/dist/tool-schemas.js.map +1 -0
  54. package/dist/tools/backup-site.d.ts +2 -0
  55. package/dist/tools/backup-site.js +42 -0
  56. package/dist/tools/backup-site.js.map +1 -0
  57. package/dist/tools/db-export.d.ts +2 -0
  58. package/dist/tools/db-export.js +40 -0
  59. package/dist/tools/db-export.js.map +1 -0
  60. package/dist/tools/db-import.d.ts +2 -0
  61. package/dist/tools/db-import.js +42 -0
  62. package/dist/tools/db-import.js.map +1 -0
  63. package/dist/tools/execute-wp-cli.d.ts +2 -0
  64. package/dist/tools/execute-wp-cli.js +34 -0
  65. package/dist/tools/execute-wp-cli.js.map +1 -0
  66. package/dist/tools/index.d.ts +2 -0
  67. package/dist/tools/index.js +29 -0
  68. package/dist/tools/index.js.map +1 -0
  69. package/dist/tools/list-local-sites.d.ts +2 -0
  70. package/dist/tools/list-local-sites.js +32 -0
  71. package/dist/tools/list-local-sites.js.map +1 -0
  72. package/dist/tools/local-doctor.d.ts +2 -0
  73. package/dist/tools/local-doctor.js +23 -0
  74. package/dist/tools/local-doctor.js.map +1 -0
  75. package/dist/tools/local-environment-check.d.ts +2 -0
  76. package/dist/tools/local-environment-check.js +32 -0
  77. package/dist/tools/local-environment-check.js.map +1 -0
  78. package/dist/tools/local-logs.d.ts +2 -0
  79. package/dist/tools/local-logs.js +31 -0
  80. package/dist/tools/local-logs.js.map +1 -0
  81. package/dist/tools/local-site-info.d.ts +2 -0
  82. package/dist/tools/local-site-info.js +46 -0
  83. package/dist/tools/local-site-info.js.map +1 -0
  84. package/dist/tools/mysql-execute.d.ts +2 -0
  85. package/dist/tools/mysql-execute.js +46 -0
  86. package/dist/tools/mysql-execute.js.map +1 -0
  87. package/dist/tools/mysql-query.d.ts +2 -0
  88. package/dist/tools/mysql-query.js +43 -0
  89. package/dist/tools/mysql-query.js.map +1 -0
  90. package/dist/tools/mysql-schema.d.ts +2 -0
  91. package/dist/tools/mysql-schema.js +50 -0
  92. package/dist/tools/mysql-schema.js.map +1 -0
  93. package/dist/tools/restore-backup.d.ts +2 -0
  94. package/dist/tools/restore-backup.js +52 -0
  95. package/dist/tools/restore-backup.js.map +1 -0
  96. package/dist/types.d.ts +84 -0
  97. package/dist/types.js +2 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/wp-cli.d.ts +14 -0
  100. package/dist/wp-cli.js +140 -0
  101. package/dist/wp-cli.js.map +1 -0
  102. package/package.json +61 -0
@@ -0,0 +1,129 @@
1
+ import { config } from "./config.js";
2
+ const restrictedWpFlags = new Set(["--path", "--ssh", "--http"]);
3
+ const wpCliAlwaysBlockedPrefixes = [
4
+ ["db", "query"],
5
+ ["eval"],
6
+ ["eval-file"],
7
+ ["package", "install"],
8
+ ["package", "uninstall"],
9
+ ["package", "update"],
10
+ ["shell"],
11
+ ];
12
+ const wpCliSafePrefixes = [
13
+ ["cap", "list"],
14
+ ["cli", "check-update"],
15
+ ["cli", "cmd-dump"],
16
+ ["cli", "info"],
17
+ ["cli", "param-dump"],
18
+ ["cli", "version"],
19
+ ["comment", "get"],
20
+ ["comment", "list"],
21
+ ["config", "get"],
22
+ ["config", "has"],
23
+ ["config", "list"],
24
+ ["core", "check-update"],
25
+ ["core", "is-installed"],
26
+ ["core", "verify-checksums"],
27
+ ["core", "version"],
28
+ ["cron", "event", "list"],
29
+ ["cron", "test"],
30
+ ["db", "check"],
31
+ ["db", "columns"],
32
+ ["db", "prefix"],
33
+ ["db", "search"],
34
+ ["db", "size"],
35
+ ["db", "tables"],
36
+ ["embed", "fetch"],
37
+ ["language", "core", "list"],
38
+ ["language", "plugin", "list"],
39
+ ["language", "theme", "list"],
40
+ ["media", "get"],
41
+ ["media", "image-size"],
42
+ ["menu", "item", "list"],
43
+ ["menu", "list"],
44
+ ["network", "meta", "get"],
45
+ ["network", "meta", "list"],
46
+ ["option", "get"],
47
+ ["option", "list"],
48
+ ["package", "browse"],
49
+ ["package", "list"],
50
+ ["plugin", "get"],
51
+ ["plugin", "is-active"],
52
+ ["plugin", "is-installed"],
53
+ ["plugin", "list"],
54
+ ["plugin", "path"],
55
+ ["plugin", "status"],
56
+ ["plugin", "verify-checksums"],
57
+ ["post", "get"],
58
+ ["post", "list"],
59
+ ["post", "url"],
60
+ ["profile", "hook"],
61
+ ["profile", "stage"],
62
+ ["rewrite", "list"],
63
+ ["role", "exists"],
64
+ ["role", "get"],
65
+ ["role", "list"],
66
+ ["site", "archive", "list"],
67
+ ["site", "empty", "list"],
68
+ ["site", "list"],
69
+ ["site", "meta", "get"],
70
+ ["site", "meta", "list"],
71
+ ["super-admin", "list"],
72
+ ["taxonomy", "get"],
73
+ ["taxonomy", "list"],
74
+ ["term", "get"],
75
+ ["term", "list"],
76
+ ["theme", "get"],
77
+ ["theme", "is-active"],
78
+ ["theme", "is-installed"],
79
+ ["theme", "list"],
80
+ ["theme", "path"],
81
+ ["theme", "status"],
82
+ ["transient", "get"],
83
+ ["transient", "type"],
84
+ ["user", "application-password", "list"],
85
+ ["user", "cap", "list"],
86
+ ["user", "get"],
87
+ ["user", "list"],
88
+ ["user", "meta", "get"],
89
+ ["user", "meta", "list"],
90
+ ["user", "session", "list"],
91
+ ["widget", "list"],
92
+ ["widget", "type", "list"],
93
+ ];
94
+ export function assertAllowedWpFlags(args) {
95
+ for (const arg of args) {
96
+ const flag = arg.split("=")[0];
97
+ if (restrictedWpFlags.has(flag)) {
98
+ throw new Error(`The '${flag}' flag is not allowed here because the MCP selects the Local site for you.`);
99
+ }
100
+ }
101
+ }
102
+ export function assertWpCliPermissions(args) {
103
+ return assertWpCliPermissionsForProfile(config.profile, args);
104
+ }
105
+ export function assertWpCliPermissionsForProfile(profile, args) {
106
+ if (matchesAnyPrefix(args, wpCliAlwaysBlockedPrefixes)) {
107
+ throw new Error("This WP-CLI command is blocked in this MCP because it behaves like arbitrary code execution or unrestricted SQL.");
108
+ }
109
+ if (profile === "full-access") {
110
+ return;
111
+ }
112
+ if (startsWithCommand(args, ["search-replace"]) &&
113
+ args.includes("--dry-run")) {
114
+ return;
115
+ }
116
+ if (!matchesAnyPrefix(args, wpCliSafePrefixes)) {
117
+ throw new Error("This WP-CLI command is not allowed in the 'safe' profile. Switch to LOCALWP_MCP_PROFILE=full-access for broad WP-CLI access.");
118
+ }
119
+ }
120
+ function matchesAnyPrefix(args, prefixes) {
121
+ return prefixes.some((prefix) => startsWithCommand(args, prefix));
122
+ }
123
+ function startsWithCommand(args, prefix) {
124
+ if (prefix.length > args.length) {
125
+ return false;
126
+ }
127
+ return prefix.every((token, index) => args[index] === token);
128
+ }
129
+ //# sourceMappingURL=permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions.js","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare function dedupePaths(paths: string[]): string[];
2
+ export declare function getDefaultLocalAppSupportDir(platform: NodeJS.Platform, homeDir: string, env: NodeJS.ProcessEnv): string;
3
+ export declare function getDefaultLocalExtraResourcesDirs(platform: NodeJS.Platform, homeDir: string, env: NodeJS.ProcessEnv): string[];
4
+ export declare function getDefaultLocalLightningServiceDirs(localAppSupportDir: string, extraResourcesDirs: string[]): string[];
5
+ export declare function getLegacySiteBinariesDirs(platform: NodeJS.Platform, extraResourcesDirs: string[]): string[];
6
+ export declare function getWpCliPharCandidates(platform: NodeJS.Platform, extraResourcesDirs: string[]): string[];
7
+ export declare function getWpCliConfigCandidates(extraResourcesDirs: string[]): string[];
8
+ export declare function getHelperBinDirCandidates(platform: NodeJS.Platform, extraResourcesDirs: string[]): string[];
9
+ export declare function getPlatformBinDirCandidates(platform: NodeJS.Platform, arch: string): string[];
10
+ export declare function getExecutableCandidates(binaryName: string, platform: NodeJS.Platform): string[];
@@ -0,0 +1,95 @@
1
+ import path from "path";
2
+ export function dedupePaths(paths) {
3
+ return [...new Set(paths.filter(Boolean))];
4
+ }
5
+ function getPathApi(platform) {
6
+ return platform === "win32" ? path.win32 : path.posix;
7
+ }
8
+ export function getDefaultLocalAppSupportDir(platform, homeDir, env) {
9
+ const pathApi = getPathApi(platform);
10
+ if (platform === "win32") {
11
+ return pathApi.join(env.APPDATA || pathApi.join(homeDir, "AppData", "Roaming"), "Local");
12
+ }
13
+ if (platform === "linux") {
14
+ return pathApi.join(env.XDG_CONFIG_HOME || pathApi.join(homeDir, ".config"), "Local");
15
+ }
16
+ return pathApi.join(homeDir, "Library", "Application Support", "Local");
17
+ }
18
+ export function getDefaultLocalExtraResourcesDirs(platform, homeDir, env) {
19
+ const pathApi = getPathApi(platform);
20
+ if (platform === "win32") {
21
+ return dedupePaths([
22
+ pathApi.join(env.LOCALAPPDATA || pathApi.join(homeDir, "AppData", "Local"), "Programs", "Local", "resources", "extraResources"),
23
+ pathApi.join(env["ProgramFiles(x86)"] || "C:\\Program Files (x86)", "Local", "resources", "extraResources"),
24
+ pathApi.join(env.ProgramFiles || "C:\\Program Files", "Local", "resources", "extraResources"),
25
+ ]);
26
+ }
27
+ if (platform === "linux") {
28
+ return ["/opt/Local/resources/extraResources"];
29
+ }
30
+ return ["/Applications/Local.app/Contents/Resources/extraResources"];
31
+ }
32
+ export function getDefaultLocalLightningServiceDirs(localAppSupportDir, extraResourcesDirs) {
33
+ return dedupePaths([
34
+ path.join(localAppSupportDir, "lightning-services"),
35
+ ...extraResourcesDirs.map((directory) => {
36
+ const pathApi = directory.includes("\\") ? path.win32 : path.posix;
37
+ return pathApi.join(directory, "lightning-services");
38
+ }),
39
+ ]);
40
+ }
41
+ function joinPlatformPath(basePath, ...parts) {
42
+ const pathApi = basePath.includes("\\") ? path.win32 : path.posix;
43
+ return pathApi.join(basePath, ...parts);
44
+ }
45
+ export function getLegacySiteBinariesDirs(platform, extraResourcesDirs) {
46
+ const directoryName = platform === "win32"
47
+ ? "site-binaries-win32"
48
+ : platform === "linux"
49
+ ? "site-binaries-linux"
50
+ : "site-binaries";
51
+ return dedupePaths(extraResourcesDirs.map((directory) => joinPlatformPath(directory, directoryName)));
52
+ }
53
+ export function getWpCliPharCandidates(platform, extraResourcesDirs) {
54
+ const legacySiteBinariesDirs = getLegacySiteBinariesDirs(platform, extraResourcesDirs);
55
+ return dedupePaths([
56
+ ...extraResourcesDirs.map((directory) => joinPlatformPath(directory, "bin", "wp-cli", "wp-cli.phar")),
57
+ ...legacySiteBinariesDirs.map((directory) => platform === "darwin"
58
+ ? joinPlatformPath(directory, "wp-cli", "wp-cli.phar")
59
+ : joinPlatformPath(directory, "wp-cli.phar")),
60
+ ]);
61
+ }
62
+ export function getWpCliConfigCandidates(extraResourcesDirs) {
63
+ return dedupePaths(extraResourcesDirs.map((directory) => joinPlatformPath(directory, "bin", "wp-cli", "config.yaml")));
64
+ }
65
+ export function getHelperBinDirCandidates(platform, extraResourcesDirs) {
66
+ const platformSpecificHelperDirs = platform === "win32"
67
+ ? [
68
+ ["bin", "composer", "win32"],
69
+ ["bin", "wp-cli", "win32"],
70
+ ]
71
+ : [
72
+ ["bin", "composer", "posix"],
73
+ ["bin", "wp-cli", "posix"],
74
+ ];
75
+ return dedupePaths(extraResourcesDirs.flatMap((directory) => [
76
+ joinPlatformPath(directory, "bin"),
77
+ ...platformSpecificHelperDirs.map((parts) => joinPlatformPath(directory, ...parts)),
78
+ ]));
79
+ }
80
+ export function getPlatformBinDirCandidates(platform, arch) {
81
+ if (platform === "win32") {
82
+ return arch === "x64" ? ["win64", "win32"] : ["win32", "win64"];
83
+ }
84
+ if (platform === "linux") {
85
+ return arch === "arm64" ? ["linux-arm64", "linux"] : ["linux", "linux-arm64"];
86
+ }
87
+ return arch === "arm64" ? ["darwin-arm64", "darwin"] : ["darwin", "darwin-arm64"];
88
+ }
89
+ export function getExecutableCandidates(binaryName, platform) {
90
+ if (platform === "win32") {
91
+ return [`${binaryName}.exe`, binaryName];
92
+ }
93
+ return [binaryName];
94
+ }
95
+ //# sourceMappingURL=platform-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-paths.js","sourceRoot":"","sources":["../src/platform-paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { SpawnResult } from "./types.js";
2
+ export declare function assertReadable(filePath: string, message: string): Promise<void>;
3
+ export declare function ensureReadableDirectory(directoryPath: string, message: string): Promise<void>;
4
+ export declare function ensureExecutable(filePath: string, message: string): Promise<void>;
5
+ export declare function isReadablePath(filePath: string): Promise<boolean>;
6
+ export declare function isExecutablePath(filePath: string): Promise<boolean>;
7
+ export declare function filterReadableDirectories(paths: string[]): Promise<string[]>;
8
+ export declare function findFirstReadablePath(paths: string[]): Promise<string | null>;
9
+ export declare function spawnCommand(command: string, args: string[], options: {
10
+ cwd: string;
11
+ env: NodeJS.ProcessEnv;
12
+ stdinFilePath?: string;
13
+ }): Promise<SpawnResult>;
@@ -0,0 +1,128 @@
1
+ import { spawn } from "child_process";
2
+ import { constants as fsConstants, createReadStream } from "fs";
3
+ import { access } from "fs/promises";
4
+ import { config } from "./config.js";
5
+ export async function assertReadable(filePath, message) {
6
+ if (!(await isReadablePath(filePath))) {
7
+ throw new Error(`${message}: ${filePath}`);
8
+ }
9
+ }
10
+ export async function ensureReadableDirectory(directoryPath, message) {
11
+ if (!(await isReadablePath(directoryPath))) {
12
+ throw new Error(`${message}: ${directoryPath}`);
13
+ }
14
+ }
15
+ export async function ensureExecutable(filePath, message) {
16
+ if (!(await isExecutablePath(filePath))) {
17
+ throw new Error(`${message}: ${filePath}`);
18
+ }
19
+ }
20
+ export async function isReadablePath(filePath) {
21
+ try {
22
+ await access(filePath, fsConstants.R_OK);
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ export async function isExecutablePath(filePath) {
30
+ try {
31
+ await access(filePath, process.platform === "win32" ? fsConstants.R_OK : fsConstants.X_OK);
32
+ return true;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ export async function filterReadableDirectories(paths) {
39
+ const readableDirectories = [];
40
+ for (const candidate of paths) {
41
+ if (await isReadablePath(candidate)) {
42
+ readableDirectories.push(candidate);
43
+ }
44
+ }
45
+ return readableDirectories;
46
+ }
47
+ export async function findFirstReadablePath(paths) {
48
+ for (const candidate of paths) {
49
+ if (await isReadablePath(candidate)) {
50
+ return candidate;
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+ export function spawnCommand(command, args, options) {
56
+ return new Promise((resolve, reject) => {
57
+ const child = spawn(command, args, {
58
+ ...options,
59
+ shell: false,
60
+ stdio: [options.stdinFilePath ? "pipe" : "ignore", "pipe", "pipe"],
61
+ });
62
+ let stdout = "";
63
+ let stderr = "";
64
+ let timedOut = false;
65
+ let settled = false;
66
+ const timer = setTimeout(() => {
67
+ timedOut = true;
68
+ child.kill("SIGTERM");
69
+ }, config.defaultTimeoutMs);
70
+ const stdoutStream = child.stdout;
71
+ const stderrStream = child.stderr;
72
+ const stdinStream = child.stdin;
73
+ if (!stdoutStream || !stderrStream) {
74
+ settled = true;
75
+ clearTimeout(timer);
76
+ reject(new Error(`Failed to capture stdio for '${command}'.`));
77
+ return;
78
+ }
79
+ stdoutStream.setEncoding("utf8");
80
+ stderrStream.setEncoding("utf8");
81
+ stdoutStream.on("data", (chunk) => {
82
+ stdout += chunk;
83
+ });
84
+ stderrStream.on("data", (chunk) => {
85
+ stderr += chunk;
86
+ });
87
+ if (options.stdinFilePath) {
88
+ const inputStream = createReadStream(options.stdinFilePath);
89
+ inputStream.on("error", (error) => {
90
+ if (settled) {
91
+ return;
92
+ }
93
+ settled = true;
94
+ clearTimeout(timer);
95
+ reject(error);
96
+ });
97
+ if (!stdinStream) {
98
+ settled = true;
99
+ clearTimeout(timer);
100
+ reject(new Error(`Failed to open stdin for '${command}'.`));
101
+ return;
102
+ }
103
+ inputStream.pipe(stdinStream);
104
+ }
105
+ child.on("error", (error) => {
106
+ if (settled) {
107
+ return;
108
+ }
109
+ settled = true;
110
+ clearTimeout(timer);
111
+ reject(error);
112
+ });
113
+ child.on("close", (exitCode) => {
114
+ if (settled) {
115
+ return;
116
+ }
117
+ settled = true;
118
+ clearTimeout(timer);
119
+ resolve({
120
+ stdout: stdout.trimEnd(),
121
+ stderr: stderr.trimEnd(),
122
+ exitCode: exitCode ?? 0,
123
+ timedOut,
124
+ });
125
+ });
126
+ });
127
+ }
128
+ //# sourceMappingURL=process-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-utils.js","sourceRoot":"","sources":["../src/process-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerPrompts(server: McpServer): void;
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ export function registerPrompts(server) {
3
+ server.registerPrompt("diagnose_local_site", {
4
+ title: "Diagnose Local Site",
5
+ description: "Guides an AI agent through diagnosing a LocalWP site using the MCP's doctor, logs, and inspection tools.",
6
+ argsSchema: {
7
+ siteName: z
8
+ .string()
9
+ .optional()
10
+ .describe("Optional Local site name, for example 'woo'."),
11
+ },
12
+ }, async ({ siteName }) => {
13
+ const target = siteName
14
+ ? `the Local site '${siteName}'`
15
+ : "the relevant Local site";
16
+ return {
17
+ messages: [
18
+ {
19
+ role: "user",
20
+ content: {
21
+ type: "text",
22
+ text: [
23
+ `Diagnose ${target} using localwp-mcp.`,
24
+ "Start with local_doctor and local_environment_check.",
25
+ "Then inspect local_logs and, if needed, use execute_wp_cli, mysql_query, and mysql_schema to narrow down the issue.",
26
+ "Summarize the root cause, supporting evidence, and the safest next actions.",
27
+ ].join(" "),
28
+ },
29
+ },
30
+ ],
31
+ };
32
+ });
33
+ server.registerPrompt("restore_local_site", {
34
+ title: "Restore Local Site",
35
+ description: "Guides an AI agent through restoring a LocalWP site from a SQL dump or a backup_site directory.",
36
+ argsSchema: {
37
+ siteName: z
38
+ .string()
39
+ .describe("Local site name to restore, for example 'woo'."),
40
+ sourcePath: z
41
+ .string()
42
+ .describe("Path to the .sql file or backup_site directory to restore."),
43
+ },
44
+ }, async ({ siteName, sourcePath }) => {
45
+ return {
46
+ messages: [
47
+ {
48
+ role: "user",
49
+ content: {
50
+ type: "text",
51
+ text: [
52
+ `Restore the Local site '${siteName}' from '${sourcePath}'.`,
53
+ "Use local_doctor first to confirm the site is healthy enough for restore work.",
54
+ "Then use restore_backup with a pre-restore backup enabled.",
55
+ "After the restore, verify the site with local_doctor, local_logs, execute_wp_cli, and a simple mysql_query.",
56
+ "Report exactly what was restored, whether a restart is recommended, and any follow-up checks.",
57
+ ].join(" "),
58
+ },
59
+ },
60
+ ],
61
+ };
62
+ });
63
+ }
64
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,cAAc,CACnB,qBAAqB,EACrB;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,0GAA0G;QAC5G,UAAU,EAAE;YACV,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,8CAA8C,CAAC;SAC5D;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,MAAM,GAAG,QAAQ;YACrB,CAAC,CAAC,mBAAmB,QAAQ,GAAG;YAChC,CAAC,CAAC,yBAAyB,CAAC;QAE9B,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE;4BACJ,YAAY,MAAM,qBAAqB;4BACvC,sDAAsD;4BACtD,qHAAqH;4BACrH,6EAA6E;yBAC9E,CAAC,IAAI,CAAC,GAAG,CAAC;qBACZ;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,oBAAoB,EACpB;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,iGAAiG;QACnG,UAAU,EAAE;YACV,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,CAAC,gDAAgD,CAAC;YAC7D,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,CAAC,4DAA4D,CAAC;SAC1E;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;QACjC,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE;4BACJ,2BAA2B,QAAQ,WAAW,UAAU,IAAI;4BAC5D,gFAAgF;4BAChF,4DAA4D;4BAC5D,6GAA6G;4BAC7G,+FAA+F;yBAChG,CAAC,IAAI,CAAC,GAAG,CAAC;qBACZ;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerResources(server: McpServer): void;
@@ -0,0 +1,110 @@
1
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { runEnvironmentCheck } from "./environment-check.js";
3
+ import { loadLocalSites, summarizeSite } from "./local-sites.js";
4
+ import { runLocalDoctor } from "./local-doctor.js";
5
+ import { collectLocalLogs } from "./logs.js";
6
+ const siteSummaryTemplate = new ResourceTemplate("localwp://sites/{siteName}/summary", {
7
+ list: async () => {
8
+ const sites = await loadLocalSites();
9
+ return {
10
+ resources: sites.map((site) => ({
11
+ uri: `localwp://sites/${encodeURIComponent(site.name)}/summary`,
12
+ name: `${site.name} summary`,
13
+ })),
14
+ };
15
+ },
16
+ complete: {
17
+ siteName: completeSiteNames,
18
+ },
19
+ });
20
+ const siteDoctorTemplate = new ResourceTemplate("localwp://sites/{siteName}/doctor", {
21
+ list: async () => {
22
+ const sites = await loadLocalSites();
23
+ return {
24
+ resources: sites.map((site) => ({
25
+ uri: `localwp://sites/${encodeURIComponent(site.name)}/doctor`,
26
+ name: `${site.name} doctor`,
27
+ })),
28
+ };
29
+ },
30
+ complete: {
31
+ siteName: completeSiteNames,
32
+ },
33
+ });
34
+ const siteLogsTemplate = new ResourceTemplate("localwp://sites/{siteName}/logs", {
35
+ list: async () => {
36
+ const sites = await loadLocalSites();
37
+ return {
38
+ resources: sites.map((site) => ({
39
+ uri: `localwp://sites/${encodeURIComponent(site.name)}/logs`,
40
+ name: `${site.name} logs`,
41
+ })),
42
+ };
43
+ },
44
+ complete: {
45
+ siteName: completeSiteNames,
46
+ },
47
+ });
48
+ export function registerResources(server) {
49
+ server.registerResource("local-sites-catalog", "localwp://sites", {
50
+ title: "Local Sites Catalog",
51
+ description: "JSON catalog of LocalWP sites discovered on this machine.",
52
+ mimeType: "application/json",
53
+ }, async (uri) => {
54
+ const sites = await loadLocalSites();
55
+ return createJsonResourceResult(uri.toString(), sites.map((site) => summarizeSite(site)));
56
+ });
57
+ server.registerResource("local-site-summary", siteSummaryTemplate, {
58
+ title: "Local Site Summary",
59
+ description: "Machine-readable Local site summary and runtime resolution details.",
60
+ mimeType: "application/json",
61
+ }, async (uri, variables) => {
62
+ const siteName = getTemplateVariable(variables.siteName);
63
+ const payload = await runEnvironmentCheck({ siteName }, { probeWpCli: false, probeMysql: false });
64
+ return createJsonResourceResult(uri.toString(), payload);
65
+ });
66
+ server.registerResource("local-site-doctor", siteDoctorTemplate, {
67
+ title: "Local Site Doctor",
68
+ description: "Health summary and next steps for one LocalWP site.",
69
+ mimeType: "application/json",
70
+ }, async (uri, variables) => {
71
+ const siteName = getTemplateVariable(variables.siteName);
72
+ const payload = await runLocalDoctor({ siteName });
73
+ return createJsonResourceResult(uri.toString(), payload);
74
+ });
75
+ server.registerResource("local-site-logs", siteLogsTemplate, {
76
+ title: "Local Site Logs",
77
+ description: "Recent site and Local app logs for one LocalWP site.",
78
+ mimeType: "application/json",
79
+ }, async (uri, variables) => {
80
+ const siteName = getTemplateVariable(variables.siteName);
81
+ const payload = await collectLocalLogs({ siteName }, { scope: "all", lines: 40 });
82
+ return createJsonResourceResult(uri.toString(), payload);
83
+ });
84
+ }
85
+ async function completeSiteNames(value) {
86
+ const sites = await loadLocalSites();
87
+ const query = value.trim().toLowerCase();
88
+ return sites
89
+ .map((site) => site.name)
90
+ .filter((siteName) => query ? siteName.toLowerCase().includes(query) : true)
91
+ .sort();
92
+ }
93
+ function createJsonResourceResult(uri, payload) {
94
+ return {
95
+ contents: [
96
+ {
97
+ uri,
98
+ mimeType: "application/json",
99
+ text: JSON.stringify(payload, null, 2),
100
+ },
101
+ ],
102
+ };
103
+ }
104
+ function getTemplateVariable(value) {
105
+ if (Array.isArray(value)) {
106
+ return decodeURIComponent(value[0] || "");
107
+ }
108
+ return decodeURIComponent(value || "");
109
+ }
110
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export declare function createJsonToolResult<T extends Record<string, unknown>>(payload: T): {
2
+ structuredContent: T;
3
+ content: {
4
+ type: "text";
5
+ text: string;
6
+ }[];
7
+ };
8
+ export declare function createErrorToolResult(error: unknown): {
9
+ isError: boolean;
10
+ content: {
11
+ type: "text";
12
+ text: string;
13
+ }[];
14
+ };
15
+ export declare function formatError(error: unknown): string;
@@ -0,0 +1,26 @@
1
+ export function createJsonToolResult(payload) {
2
+ return {
3
+ structuredContent: payload,
4
+ content: [
5
+ {
6
+ type: "text",
7
+ text: JSON.stringify(payload, null, 2),
8
+ },
9
+ ],
10
+ };
11
+ }
12
+ export function createErrorToolResult(error) {
13
+ return {
14
+ isError: true,
15
+ content: [
16
+ {
17
+ type: "text",
18
+ text: formatError(error),
19
+ },
20
+ ],
21
+ };
22
+ }
23
+ export function formatError(error) {
24
+ return error instanceof Error ? error.message : String(error);
25
+ }
26
+ //# sourceMappingURL=results.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.js","sourceRoot":"","sources":["../src/results.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB,CAClC,OAAU;IAEV,OAAO;QACL,iBAAiB,EAAE,OAAO;QAC1B,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;aACvC;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC;aACzB;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}