@wp-playground/mcp 3.1.5 → 3.1.9
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.
- package/LICENSE +339 -0
- package/README.md +27 -21
- package/bridge-client.d.ts +27 -0
- package/bridge-server.d.ts +42 -0
- package/client.cjs +2 -0
- package/client.cjs.map +1 -0
- package/client.js +105 -0
- package/client.js.map +1 -0
- package/index.cjs +190 -0
- package/index.cjs.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +12303 -0
- package/index.js.map +1 -0
- package/mcp-server.d.ts +2 -0
- package/package.json +79 -45
- package/tool-executors-ecXfLzk7.cjs +9 -0
- package/tool-executors-ecXfLzk7.cjs.map +1 -0
- package/tool-executors-pMxJ1GXT.js +100 -0
- package/tool-executors-pMxJ1GXT.js.map +1 -0
- package/tools/register-mcp-server-tools.d.ts +3 -0
- package/tools/tool-definitions.d.ts +42 -0
- package/tools/tool-executors.d.ts +63 -0
- package/.eslintrc.json +0 -24
- package/e2e/mcp-tools.spec.ts +0 -679
- package/playwright.config.ts +0 -35
- package/project.json +0 -64
- package/src/bridge-client.ts +0 -196
- package/src/bridge-server.spec.ts +0 -228
- package/src/bridge-server.ts +0 -485
- package/src/index.ts +0 -28
- package/src/mcp-server.ts +0 -34
- package/src/tools/register-mcp-server-tools.ts +0 -347
- package/src/tools/tool-definitions.ts +0 -527
- package/src/tools/tool-executors.ts +0 -205
- package/tsconfig.json +0 -15
- package/tsconfig.lib.json +0 -10
- package/vite.config.ts +0 -49
- /package/{src/client.ts → client.d.ts} +0 -0
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared tool executor functions.
|
|
3
|
-
*
|
|
4
|
-
* Both the MCP server and WebMCP call these executors so that tool
|
|
5
|
-
* output shapes are defined in exactly one place. Each transport
|
|
6
|
-
* provides its own ToolClient implementation that normalises I/O
|
|
7
|
-
* differences (e.g. byte decoding).
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { PlaygroundClient } from '@wp-playground/remote';
|
|
11
|
-
import type { PHPRequest } from '@php-wasm/universal';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Minimal client interface consumed by tool executors.
|
|
15
|
-
*
|
|
16
|
-
* - WebMCP implements this by wrapping PlaygroundClient (decoding
|
|
17
|
-
* response bytes via TextDecoder).
|
|
18
|
-
* - The MCP server implements this by wrapping bridge.sendCommand
|
|
19
|
-
* (bytes are already decoded at the bridge-client boundary).
|
|
20
|
-
*/
|
|
21
|
-
export interface ToolClient {
|
|
22
|
-
run(options: {
|
|
23
|
-
code: string;
|
|
24
|
-
}): Promise<{ text: string; errors: string; exitCode: number }>;
|
|
25
|
-
request(options: {
|
|
26
|
-
url: string;
|
|
27
|
-
method: string;
|
|
28
|
-
headers?: Record<string, string>;
|
|
29
|
-
body?: string;
|
|
30
|
-
}): Promise<{
|
|
31
|
-
text: string;
|
|
32
|
-
httpStatusCode: number;
|
|
33
|
-
headers: Record<string, string[]>;
|
|
34
|
-
}>;
|
|
35
|
-
goTo(path: string): Promise<void>;
|
|
36
|
-
getCurrentURL(): Promise<string>;
|
|
37
|
-
readFileAsText(path: string): Promise<string>;
|
|
38
|
-
writeFile(path: string, contents: string): Promise<void>;
|
|
39
|
-
listFiles(path: string): Promise<string[]>;
|
|
40
|
-
mkdirTree(path: string): Promise<void>;
|
|
41
|
-
unlink(path: string): Promise<void>;
|
|
42
|
-
rmdir(path: string, options: { recursive: boolean }): Promise<void>;
|
|
43
|
-
fileExists(path: string): Promise<boolean>;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface SiteInfo {
|
|
47
|
-
url: string;
|
|
48
|
-
documentRoot: string;
|
|
49
|
-
siteUrl: string;
|
|
50
|
-
wpVersion: string;
|
|
51
|
-
phpVersion: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function executeSiteInfo(client: ToolClient): Promise<SiteInfo> {
|
|
55
|
-
const [url, infoText] = await Promise.all([
|
|
56
|
-
client.getCurrentURL(),
|
|
57
|
-
client
|
|
58
|
-
.run({
|
|
59
|
-
code: `<?php
|
|
60
|
-
require_once "/wordpress/wp-load.php";
|
|
61
|
-
echo json_encode([
|
|
62
|
-
"documentRoot" => ABSPATH,
|
|
63
|
-
"wpVersion" => get_bloginfo("version"),
|
|
64
|
-
"siteUrl" => get_site_url(),
|
|
65
|
-
"phpVersion" => phpversion(),
|
|
66
|
-
]);`,
|
|
67
|
-
})
|
|
68
|
-
.then((resp) => resp.text),
|
|
69
|
-
]);
|
|
70
|
-
|
|
71
|
-
let info: Partial<Omit<SiteInfo, 'url'>>;
|
|
72
|
-
try {
|
|
73
|
-
info = JSON.parse(infoText);
|
|
74
|
-
} catch {
|
|
75
|
-
info = {};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
url: String(url),
|
|
80
|
-
documentRoot: info.documentRoot ?? '/wordpress',
|
|
81
|
-
siteUrl: info.siteUrl ?? String(url),
|
|
82
|
-
wpVersion: info.wpVersion ?? 'unknown',
|
|
83
|
-
phpVersion: info.phpVersion ?? 'unknown',
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export const toolExecutors: Record<
|
|
88
|
-
string,
|
|
89
|
-
(client: ToolClient, input: Record<string, unknown>) => Promise<unknown>
|
|
90
|
-
> = {
|
|
91
|
-
playground_execute_php: (client, input) =>
|
|
92
|
-
client.run({ code: input['code'] as string }),
|
|
93
|
-
|
|
94
|
-
playground_request: async (client, input) => {
|
|
95
|
-
const options: {
|
|
96
|
-
url: string;
|
|
97
|
-
method: string;
|
|
98
|
-
headers?: Record<string, string>;
|
|
99
|
-
body?: string;
|
|
100
|
-
} = {
|
|
101
|
-
url: input['url'] as string,
|
|
102
|
-
method: (input['method'] as string) ?? 'GET',
|
|
103
|
-
};
|
|
104
|
-
if (input['headers']) {
|
|
105
|
-
options.headers = input['headers'] as Record<string, string>;
|
|
106
|
-
}
|
|
107
|
-
if (input['body']) {
|
|
108
|
-
options.body = input['body'] as string;
|
|
109
|
-
}
|
|
110
|
-
return await client.request(options);
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
playground_navigate: async (client, input) => {
|
|
114
|
-
await client.goTo(input['path'] as string);
|
|
115
|
-
return { url: await client.getCurrentURL() };
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
playground_get_current_url: async (client) => ({
|
|
119
|
-
url: await client.getCurrentURL(),
|
|
120
|
-
}),
|
|
121
|
-
|
|
122
|
-
playground_get_site_info: (client): Promise<SiteInfo> =>
|
|
123
|
-
executeSiteInfo(client),
|
|
124
|
-
|
|
125
|
-
playground_read_file: async (client, input) => ({
|
|
126
|
-
contents: await client.readFileAsText(input['path'] as string),
|
|
127
|
-
}),
|
|
128
|
-
|
|
129
|
-
playground_write_file: async (client, input) => {
|
|
130
|
-
await client.writeFile(
|
|
131
|
-
input['path'] as string,
|
|
132
|
-
input['contents'] as string
|
|
133
|
-
);
|
|
134
|
-
return { success: true };
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
playground_list_files: async (client, input) => ({
|
|
138
|
-
files: await client.listFiles(input['path'] as string),
|
|
139
|
-
}),
|
|
140
|
-
|
|
141
|
-
playground_mkdir: async (client, input) => {
|
|
142
|
-
await client.mkdirTree(input['path'] as string);
|
|
143
|
-
return { success: true };
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
playground_delete_file: async (client, input) => {
|
|
147
|
-
await client.unlink(input['path'] as string);
|
|
148
|
-
return { success: true };
|
|
149
|
-
},
|
|
150
|
-
|
|
151
|
-
playground_delete_directory: async (client, input) => {
|
|
152
|
-
await client.rmdir(input['path'] as string, {
|
|
153
|
-
recursive: (input['recursive'] as boolean) ?? false,
|
|
154
|
-
});
|
|
155
|
-
return { success: true };
|
|
156
|
-
},
|
|
157
|
-
|
|
158
|
-
playground_file_exists: async (client, input) => ({
|
|
159
|
-
exists: await client.fileExists(input['path'] as string),
|
|
160
|
-
}),
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Wrap a PlaygroundClient as a ToolClient.
|
|
165
|
-
*
|
|
166
|
-
* Most methods pass through directly. Only `run` and `request`
|
|
167
|
-
* are intercepted to decode PHP/HTTP response bytes into plain
|
|
168
|
-
* strings via TextDecoder.
|
|
169
|
-
*/
|
|
170
|
-
export function createToolClient(client: PlaygroundClient): ToolClient {
|
|
171
|
-
const decoder = new TextDecoder();
|
|
172
|
-
const overrides: Partial<ToolClient> = {
|
|
173
|
-
async run(options) {
|
|
174
|
-
const resp = await client.run(options);
|
|
175
|
-
return {
|
|
176
|
-
text: decoder.decode(resp.bytes),
|
|
177
|
-
errors: resp.errors,
|
|
178
|
-
exitCode: resp.exitCode,
|
|
179
|
-
};
|
|
180
|
-
},
|
|
181
|
-
async request(options) {
|
|
182
|
-
const resp = await client.request({
|
|
183
|
-
url: options.url,
|
|
184
|
-
method: options.method as PHPRequest['method'],
|
|
185
|
-
headers: options.headers,
|
|
186
|
-
body: options.body,
|
|
187
|
-
});
|
|
188
|
-
return {
|
|
189
|
-
text: decoder.decode(resp.bytes),
|
|
190
|
-
httpStatusCode: resp.httpStatusCode,
|
|
191
|
-
headers: resp.headers,
|
|
192
|
-
};
|
|
193
|
-
},
|
|
194
|
-
};
|
|
195
|
-
return new Proxy(client as unknown as ToolClient, {
|
|
196
|
-
get: (target, prop: string) => {
|
|
197
|
-
const override = (overrides as Record<string, unknown>)[prop];
|
|
198
|
-
if (override !== undefined) {
|
|
199
|
-
return override;
|
|
200
|
-
}
|
|
201
|
-
const val = (target as unknown as Record<string, unknown>)[prop];
|
|
202
|
-
return typeof val === 'function' ? val.bind(target) : val;
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"module": "ES2022",
|
|
5
|
-
"forceConsistentCasingInFileNames": true,
|
|
6
|
-
"strict": true,
|
|
7
|
-
"noImplicitOverride": true,
|
|
8
|
-
"noPropertyAccessFromIndexSignature": true,
|
|
9
|
-
"noImplicitReturns": true,
|
|
10
|
-
"noFallthroughCasesInSwitch": true
|
|
11
|
-
},
|
|
12
|
-
"files": [],
|
|
13
|
-
"include": [],
|
|
14
|
-
"references": [{ "path": "./tsconfig.lib.json" }]
|
|
15
|
-
}
|
package/tsconfig.lib.json
DELETED
package/vite.config.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
|
|
3
|
-
import dts from 'vite-plugin-dts';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
|
|
6
|
-
// eslint-disable-next-line @nx/enforce-module-boundaries
|
|
7
|
-
import { viteTsConfigPaths } from '../../vite-extensions/vite-ts-config-paths';
|
|
8
|
-
// eslint-disable-next-line @nx/enforce-module-boundaries
|
|
9
|
-
import { getExternalModules } from '../../vite-extensions/vite-external-modules';
|
|
10
|
-
// eslint-disable-next-line @nx/enforce-module-boundaries
|
|
11
|
-
import viteGlobalExtensions from '../../vite-extensions/vite-global-extensions';
|
|
12
|
-
|
|
13
|
-
export default defineConfig({
|
|
14
|
-
root: __dirname,
|
|
15
|
-
cacheDir: '../../../node_modules/.vite/playground-mcp',
|
|
16
|
-
|
|
17
|
-
plugins: [
|
|
18
|
-
dts({
|
|
19
|
-
entryRoot: 'src',
|
|
20
|
-
tsconfigPath: join(__dirname, 'tsconfig.lib.json'),
|
|
21
|
-
pathsToAliases: false,
|
|
22
|
-
}),
|
|
23
|
-
|
|
24
|
-
viteTsConfigPaths({
|
|
25
|
-
root: '../../../',
|
|
26
|
-
}),
|
|
27
|
-
|
|
28
|
-
...viteGlobalExtensions,
|
|
29
|
-
],
|
|
30
|
-
|
|
31
|
-
build: {
|
|
32
|
-
lib: {
|
|
33
|
-
entry: {
|
|
34
|
-
index: 'src/index.ts',
|
|
35
|
-
client: 'src/client.ts',
|
|
36
|
-
},
|
|
37
|
-
name: 'playground-mcp',
|
|
38
|
-
formats: ['es', 'cjs'],
|
|
39
|
-
},
|
|
40
|
-
sourcemap: true,
|
|
41
|
-
rollupOptions: {
|
|
42
|
-
external: getExternalModules(),
|
|
43
|
-
output: {
|
|
44
|
-
banner: (chunk) =>
|
|
45
|
-
chunk.fileName === 'index.js' ? '#!/usr/bin/env node' : '',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
});
|
|
File without changes
|