complered tools 2 and guide
This commit is contained in:
398
EXTERNAL_WP_CLI_TESTING_IMPLEMENTATION.md
Normal file
398
EXTERNAL_WP_CLI_TESTING_IMPLEMENTATION.md
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
# External WP-CLI Testing - Implementation Reference
|
||||||
|
|
||||||
|
## Complete Data Flow
|
||||||
|
|
||||||
|
### 1. User Enables Toggle in Builder
|
||||||
|
|
||||||
|
**File:** `chat/public/builder.js`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Line ~36
|
||||||
|
builderState.externalTestingEnabled = false // default
|
||||||
|
|
||||||
|
// User clicks toggle → sets to true
|
||||||
|
builderState.externalTestingEnabled = true
|
||||||
|
|
||||||
|
// When sending message (line ~3967)
|
||||||
|
const payload = {
|
||||||
|
content: messageContent,
|
||||||
|
model,
|
||||||
|
cli,
|
||||||
|
externalTestingEnabled: !!builderState.externalTestingEnabled
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Chat Server Receives Message
|
||||||
|
|
||||||
|
**File:** `chat/server.js`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Line ~8804
|
||||||
|
const wpCliMcpEnabled = message?.externalTestingEnabled === true
|
||||||
|
|
||||||
|
// Line ~8885-8901: If enabled, inject MCP server
|
||||||
|
if (wpCliMcpEnabled) {
|
||||||
|
const wpMcpServerPath = path.resolve(__dirname, '../opencode/mcp-servers/wp-cli-testing/index.js')
|
||||||
|
|
||||||
|
executionEnv.OPENCODE_EXTRA_MCP_SERVERS = JSON.stringify([
|
||||||
|
{
|
||||||
|
name: 'wp-cli-testing',
|
||||||
|
command: 'node',
|
||||||
|
args: [wpMcpServerPath],
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
delete executionEnv.OPENCODE_EXTRA_MCP_SERVERS // Safety gate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass env to OpenCode
|
||||||
|
await opencodeManager.executeInSession(..., { env: executionEnv })
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. OpenCode Reads Environment Variable
|
||||||
|
|
||||||
|
**File:** `opencode/packages/opencode/src/config/config.ts`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Line ~233-294: Parse OPENCODE_EXTRA_MCP_SERVERS
|
||||||
|
const extraMcpRaw = process.env.OPENCODE_EXTRA_MCP_SERVERS
|
||||||
|
if (extraMcpRaw && typeof extraMcpRaw === "string") {
|
||||||
|
const parsed = JSON.parse(extraMcpRaw)
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
result.mcp ??= {}
|
||||||
|
for (const entry of parsed) {
|
||||||
|
result.mcp[entry.name] = {
|
||||||
|
type: "local",
|
||||||
|
command: [...commandParts, ...argsParts],
|
||||||
|
env: envRecord,
|
||||||
|
enabled: true,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: OpenCode config now has `mcp['wp-cli-testing']` configured
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. OpenCode Starts MCP Server
|
||||||
|
|
||||||
|
**File:** `opencode/packages/opencode/src/mcp/index.ts`
|
||||||
|
|
||||||
|
OpenCode's MCP system automatically:
|
||||||
|
1. Reads `config.mcp['wp-cli-testing']`
|
||||||
|
2. Spawns: `node opencode/mcp-servers/wp-cli-testing/index.js`
|
||||||
|
3. Connects via stdio transport
|
||||||
|
4. Calls `listTools()` to get available tools
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. MCP Server Registers Tools
|
||||||
|
|
||||||
|
**File:** `opencode/mcp-servers/wp-cli-testing/index.js`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||||
|
return {
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
name: "test_plugin_external_wp",
|
||||||
|
description: "Run WP-CLI based verification...",
|
||||||
|
inputSchema: { ... }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "external_wp_testing_config",
|
||||||
|
description: "Return resolved config...",
|
||||||
|
inputSchema: { ... }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 6. AI Invokes test_plugin_external_wp Tool
|
||||||
|
|
||||||
|
**File:** `opencode/packages/opencode/src/session/prompt.ts`
|
||||||
|
|
||||||
|
OpenCode's session handler:
|
||||||
|
1. Tool calls go through `resolveTools()` (line ~668)
|
||||||
|
2. MCP tools added via `MCP.tools()` (line ~745)
|
||||||
|
3. AI invokes tool with parameters
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
test_plugin_external_wp({
|
||||||
|
plugin_path: "/workspace/my-plugin",
|
||||||
|
plugin_slug: "my-plugin",
|
||||||
|
test_scenarios: [...]
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. MCP Server Handles Tool Call
|
||||||
|
|
||||||
|
**File:** `opencode/mcp-servers/wp-cli-testing/index.js`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
||||||
|
const toolName = req.params.name
|
||||||
|
const args = req.params.arguments
|
||||||
|
|
||||||
|
// Import external-wp-testing module
|
||||||
|
const externalTesting = await import("../../../chat/external-wp-testing.js")
|
||||||
|
const mod = externalTesting.default ?? externalTesting
|
||||||
|
|
||||||
|
const tester = mod.createExternalWpTester({})
|
||||||
|
|
||||||
|
const result = await tester.runTest(
|
||||||
|
{
|
||||||
|
plugin_path: args.plugin_path,
|
||||||
|
plugin_slug: args.plugin_slug,
|
||||||
|
...
|
||||||
|
},
|
||||||
|
{ configOverrides: {} }
|
||||||
|
)
|
||||||
|
|
||||||
|
return { content: [{ type: "text", text: JSON.stringify(result) }] }
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. External WP Testing Executes
|
||||||
|
|
||||||
|
**File:** `chat/external-wp-testing.js`
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function runTest(input, opts) {
|
||||||
|
const config = getExternalTestingConfig(opts.configOverrides)
|
||||||
|
|
||||||
|
// Queue the test
|
||||||
|
return queue.enqueue(async () => {
|
||||||
|
// 1. Create subsite (if multisite enabled)
|
||||||
|
if (config.enableMultisite) {
|
||||||
|
subsite = await createSubsite(config, sessionId)
|
||||||
|
// Runs: wp site create --slug=test-abc123
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Upload plugin via SCP
|
||||||
|
if (pluginPath) {
|
||||||
|
await installPluginFromLocal(config, pluginPath, pluginSlug, sessionId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Install required plugins
|
||||||
|
const installedPlugins = await installRequiredPlugins(config, subsite.url, requiredPlugins)
|
||||||
|
|
||||||
|
// 4. Activate test plugin
|
||||||
|
if (pluginSlug) {
|
||||||
|
await runSshCommand(config,
|
||||||
|
buildWpCliCommand(config, subsite.url, `plugin activate ${pluginSlug}`)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Run test scenarios
|
||||||
|
const cliTests = await runTestScenarios(config, subsite.url, scenarios)
|
||||||
|
|
||||||
|
// 6. Schedule cleanup
|
||||||
|
if (config.autoCleanup && subsite.slug) {
|
||||||
|
setTimeout(() => { deleteSubsite(config, subsite.slug) }, config.cleanupDelayMs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ok: true, test_results: { cli_tests: cliTests }, ... }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9. SSH Commands Execute on WordPress Server
|
||||||
|
|
||||||
|
**Functions:**
|
||||||
|
- `buildWpCliCommand(config, url, command)` → `wp --path=/var/www/html --url=https://site.com/test-abc command`
|
||||||
|
- `runSshCommand(config, command)` → Executes via SSH with key auth
|
||||||
|
|
||||||
|
**Example Commands Executed:**
|
||||||
|
```bash
|
||||||
|
# Create subsite
|
||||||
|
ssh -i ~/.ssh/wp-key wordpress@wp-test.com "wp --path=/var/www/html site create --slug=test-abc123"
|
||||||
|
|
||||||
|
# Copy plugin
|
||||||
|
scp -i ~/.ssh/wp-key -r /local/plugin wordpress@wp-test.com:/var/www/html/wp-content/plugins/
|
||||||
|
|
||||||
|
# Activate plugin
|
||||||
|
ssh -i ~/.ssh/wp-key wordpress@wp-test.com "wp --path=/var/www/html --url=https://wp-test.com/test-abc123 plugin activate my-plugin"
|
||||||
|
|
||||||
|
# Run test
|
||||||
|
ssh -i ~/.ssh/wp-key wordpress@wp-test.com "wp --path=/var/www/html --url=https://wp-test.com/test-abc123 plugin status my-plugin"
|
||||||
|
|
||||||
|
# Later: Delete subsite
|
||||||
|
ssh -i ~/.ssh/wp-key wordpress@wp-test.com "wp --path=/var/www/html site delete --slug=test-abc123 --yes"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10. Results Return to AI
|
||||||
|
|
||||||
|
**Return Path:**
|
||||||
|
```
|
||||||
|
WordPress Server (via SSH)
|
||||||
|
↓ command output
|
||||||
|
external-wp-testing.js runTest()
|
||||||
|
↓ formatted result
|
||||||
|
MCP Server CallToolRequestSchema handler
|
||||||
|
↓ JSON response
|
||||||
|
OpenCode MCP client
|
||||||
|
↓ tool result
|
||||||
|
AI Session Handler
|
||||||
|
↓ assistant message
|
||||||
|
Chat Server
|
||||||
|
↓ SSE stream
|
||||||
|
Builder UI
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result Format:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"session_id": "abc123",
|
||||||
|
"subsite_url": "https://wp-test.example.com/test-abc123",
|
||||||
|
"test_results": {
|
||||||
|
"mode": "cli",
|
||||||
|
"cli_tests": {
|
||||||
|
"passed": 3,
|
||||||
|
"failed": 0,
|
||||||
|
"results": [...]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installed_plugins": [...],
|
||||||
|
"duration": 15230,
|
||||||
|
"cleanup_scheduled": "2026-02-08T11:30:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `chat/public/builder.js` | Builder UI toggle state |
|
||||||
|
| `chat/server.js` | Gate MCP injection via env var |
|
||||||
|
| `opencode/packages/opencode/src/config/config.ts` | Parse OPENCODE_EXTRA_MCP_SERVERS |
|
||||||
|
| `opencode/packages/opencode/src/mcp/index.ts` | Load and connect MCP servers |
|
||||||
|
| `opencode/mcp-servers/wp-cli-testing/index.js` | MCP server implementation |
|
||||||
|
| `chat/external-wp-testing.js` | Core testing logic |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Environment Variables Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Host Environment
|
||||||
|
↓
|
||||||
|
Chat Server process.env
|
||||||
|
↓
|
||||||
|
executionEnv = {...process.env, OPENCODE_EXTRA_MCP_SERVERS: "..."}
|
||||||
|
↓
|
||||||
|
OpenCode spawned with executionEnv
|
||||||
|
↓
|
||||||
|
process.env.TEST_WP_HOST → external-wp-testing.js getExternalTestingConfig()
|
||||||
|
↓
|
||||||
|
SSH connection using TEST_WP_SSH_KEY
|
||||||
|
↓
|
||||||
|
Commands execute on WordPress server
|
||||||
|
```
|
||||||
|
|
||||||
|
**Required Environment Variables:**
|
||||||
|
- `TEST_WP_HOST`
|
||||||
|
- `TEST_WP_SSH_USER`
|
||||||
|
- `TEST_WP_SSH_KEY`
|
||||||
|
- `TEST_WP_PATH`
|
||||||
|
- `TEST_WP_BASE_URL`
|
||||||
|
- etc. (see EXTERNAL_WP_CLI_TESTING_SETUP.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Gates
|
||||||
|
|
||||||
|
1. **Builder Toggle** - User must explicitly enable
|
||||||
|
2. **Environment Variable Gate** - Only set when toggle is on
|
||||||
|
3. **MCP Loading** - Only loads when env var present
|
||||||
|
4. **SSH Key Auth** - Requires valid key file
|
||||||
|
5. **Tool Gating** - Tools not available if toggle off
|
||||||
|
|
||||||
|
When toggle is OFF:
|
||||||
|
- `externalTestingEnabled: false` in payload
|
||||||
|
- `wpCliMcpEnabled = false` on server
|
||||||
|
- `OPENCODE_EXTRA_MCP_SERVERS` is deleted from env
|
||||||
|
- MCP server never loads
|
||||||
|
- Tools never available to AI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing The Flow
|
||||||
|
|
||||||
|
### 1. Check Environment
|
||||||
|
```bash
|
||||||
|
echo $TEST_WP_HOST
|
||||||
|
echo $TEST_WP_SSH_KEY
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Test SSH Connection
|
||||||
|
```bash
|
||||||
|
ssh -i $TEST_WP_SSH_KEY $TEST_WP_SSH_USER@$TEST_WP_HOST "wp site list"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Enable Toggle in Builder
|
||||||
|
- Open Builder
|
||||||
|
- Enable "External WP CLI testing"
|
||||||
|
- Verify toggle shows enabled state
|
||||||
|
|
||||||
|
### 4. Check Server Logs
|
||||||
|
```bash
|
||||||
|
tail -f logs/chat-server.log | grep "WP CLI Testing"
|
||||||
|
# Should see: "Enabling WP CLI Testing MCP server"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Ask AI to Test
|
||||||
|
```
|
||||||
|
"Create a plugin and test it on the external WordPress server"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Verify Subsite Created
|
||||||
|
```bash
|
||||||
|
ssh -i $TEST_WP_SSH_KEY $TEST_WP_SSH_USER@$TEST_WP_HOST "wp site list | grep test-"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Multisite Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
WordPress Multisite Network
|
||||||
|
├── Main Site (/)
|
||||||
|
│ └── Core WP, Plugins, Themes (shared)
|
||||||
|
├── Subsite: /test-abc123 (Session 1)
|
||||||
|
│ ├── Isolated content/options
|
||||||
|
│ ├── Test Plugin A activated
|
||||||
|
│ └── Tests running
|
||||||
|
├── Subsite: /test-def456 (Session 2)
|
||||||
|
│ ├── Isolated content/options
|
||||||
|
│ ├── Test Plugin B activated
|
||||||
|
│ └── Tests running
|
||||||
|
└── Subsite: /test-xyz789 (Session 3)
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
**Concurrency:** 20+ simultaneous tests via queue system + isolated subsites
|
||||||
|
|
||||||
|
**Cleanup:** Each subsite auto-deleted after 1 hour (configurable via `TEST_CLEANUP_DELAY`)
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -128,12 +128,22 @@ async function createSubsite(config, sessionId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = resolveSubsiteUrl(config, slug);
|
const url = resolveSubsiteUrl(config, slug);
|
||||||
const configureCmd = buildWpCliCommand(
|
|
||||||
|
// Configure permalink structure
|
||||||
|
const permalinkCmd = buildWpCliCommand(
|
||||||
config,
|
config,
|
||||||
url,
|
url,
|
||||||
'option update permalink_structure "/%postname%/" && wp rewrite flush'
|
'option update permalink_structure "/%postname%/"'
|
||||||
);
|
);
|
||||||
await runSshCommand(config, configureCmd, { timeout: config.testTimeoutMs });
|
await runSshCommand(config, permalinkCmd, { timeout: config.testTimeoutMs });
|
||||||
|
|
||||||
|
// Flush rewrite rules
|
||||||
|
const rewriteCmd = buildWpCliCommand(
|
||||||
|
config,
|
||||||
|
url,
|
||||||
|
'rewrite flush'
|
||||||
|
);
|
||||||
|
await runSshCommand(config, rewriteCmd, { timeout: config.testTimeoutMs });
|
||||||
|
|
||||||
return { slug, url, adminUrl: `${url.replace(/\/$/, '')}/wp-admin` };
|
return { slug, url, adminUrl: `${url.replace(/\/$/, '')}/wp-admin` };
|
||||||
}
|
}
|
||||||
@@ -460,7 +470,11 @@ function createExternalWpTester(options = {}) {
|
|||||||
|
|
||||||
const installedPlugins = await installRequiredPlugins(config, subsite.url, requiredPlugins);
|
const installedPlugins = await installRequiredPlugins(config, subsite.url, requiredPlugins);
|
||||||
if (pluginSlug) {
|
if (pluginSlug) {
|
||||||
await runSshCommand(config, buildWpCliCommand(config, subsite.url, `plugin activate ${pluginSlug}`));
|
const activateCmd = buildWpCliCommand(config, subsite.url, `plugin activate ${pluginSlug}`);
|
||||||
|
const activateRes = await runSshCommand(config, activateCmd, { timeout: config.testTimeoutMs });
|
||||||
|
if (activateRes.code !== 0) {
|
||||||
|
errors.push(`Failed to activate plugin ${pluginSlug}: ${activateRes.stderr || activateRes.stdout}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const scenarios = normalizeTestScenarios(input, pluginSlug, config);
|
const scenarios = normalizeTestScenarios(input, pluginSlug, config);
|
||||||
|
|||||||
106
opencode/mcp-servers/wp-cli-testing/README.md
Normal file
106
opencode/mcp-servers/wp-cli-testing/README.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# WP-CLI Testing MCP Server
|
||||||
|
|
||||||
|
This MCP server provides tools for testing WordPress plugins on an external WordPress multisite installation via WP-CLI over SSH.
|
||||||
|
|
||||||
|
## Tools Provided
|
||||||
|
|
||||||
|
### 1. test_plugin_external_wp
|
||||||
|
|
||||||
|
Runs automated CLI tests on an external WordPress installation with full isolation via multisite subsites.
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Automatic subsite provisioning (`wp site create`)
|
||||||
|
- Plugin upload and activation
|
||||||
|
- Dependency installation (WooCommerce, ACF, etc.)
|
||||||
|
- WP-CLI based test execution
|
||||||
|
- Automatic cleanup after delay
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plugin_path": "/workspace/my-plugin",
|
||||||
|
"plugin_slug": "my-plugin",
|
||||||
|
"test_mode": "cli",
|
||||||
|
"required_plugins": [
|
||||||
|
{"plugin_slug": "woocommerce", "activate": true}
|
||||||
|
],
|
||||||
|
"test_scenarios": [
|
||||||
|
{
|
||||||
|
"name": "Plugin activates",
|
||||||
|
"type": "custom",
|
||||||
|
"wp_cli_command": "plugin activate my-plugin",
|
||||||
|
"assertions": {"wp_cli_success": true}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. external_wp_testing_config
|
||||||
|
|
||||||
|
Returns the resolved configuration and validates required environment variables.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```json
|
||||||
|
{}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"missing": [],
|
||||||
|
"config": {
|
||||||
|
"wpHost": "wp-test.example.com",
|
||||||
|
"wpSshUser": "wordpress",
|
||||||
|
"enableMultisite": true,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It's Loaded
|
||||||
|
|
||||||
|
This server is **NOT** loaded automatically. It's injected dynamically by the chat server only when:
|
||||||
|
1. The Builder "External WP CLI testing" toggle is enabled
|
||||||
|
2. The chat server sets `OPENCODE_EXTRA_MCP_SERVERS` environment variable
|
||||||
|
3. OpenCode reads that variable and adds this MCP server to its configuration
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
All configuration is via environment variables (see EXTERNAL_WP_CLI_TESTING_SETUP.md):
|
||||||
|
|
||||||
|
- `TEST_WP_HOST` - WordPress server hostname
|
||||||
|
- `TEST_WP_SSH_USER` - SSH username
|
||||||
|
- `TEST_WP_SSH_KEY` - Path to SSH private key
|
||||||
|
- `TEST_WP_PATH` - WordPress installation path
|
||||||
|
- `TEST_WP_BASE_URL` - Base URL of site
|
||||||
|
- `TEST_WP_MULTISITE` - Enable multisite (default: true)
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
OpenCode (when toggle enabled)
|
||||||
|
↓ loads MCP server via OPENCODE_EXTRA_MCP_SERVERS
|
||||||
|
wp-cli-testing MCP Server
|
||||||
|
↓ imports ../../../chat/external-wp-testing.js
|
||||||
|
External WP Testing Module
|
||||||
|
↓ SSH connection
|
||||||
|
WordPress Multisite Test Server
|
||||||
|
↓ creates subsite
|
||||||
|
Isolated Test Environment
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
This MCP server relies on:
|
||||||
|
- `@modelcontextprotocol/sdk` (provided by OpenCode)
|
||||||
|
- `zod` (provided by OpenCode)
|
||||||
|
- `../../../chat/external-wp-testing.js` (CommonJS module)
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Only `test_mode: "cli"` is implemented (visual mode not yet supported)
|
||||||
|
- Requires WordPress multisite configured on external server
|
||||||
|
- All plugin operations happen on isolated subsites
|
||||||
|
- Automatic cleanup scheduled after test completion
|
||||||
@@ -153,19 +153,26 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|||||||
const args = (req.params.arguments ?? {})
|
const args = (req.params.arguments ?? {})
|
||||||
|
|
||||||
// Lazy-load to avoid paying cost unless tool is actually invoked.
|
// Lazy-load to avoid paying cost unless tool is actually invoked.
|
||||||
// Note: external-wp-testing.js is CommonJS; import default gives module.exports.
|
// Note: external-wp-testing.js is CommonJS; when imported from ESM,
|
||||||
const externalTesting = await import("../../../chat/external-wp-testing.js")
|
// exports are on .default for Node.js CommonJS modules
|
||||||
const mod = externalTesting.default ?? externalTesting
|
let createExternalWpTester
|
||||||
const createExternalWpTester = mod?.createExternalWpTester
|
let getExternalTestingConfig
|
||||||
const getExternalTestingConfig = mod?.getExternalTestingConfig
|
|
||||||
|
|
||||||
if (typeof createExternalWpTester !== "function" || typeof getExternalTestingConfig !== "function") {
|
try {
|
||||||
|
const externalTesting = await import("../../../chat/external-wp-testing.js")
|
||||||
|
const mod = externalTesting.default ?? externalTesting
|
||||||
|
createExternalWpTester = mod?.createExternalWpTester
|
||||||
|
getExternalTestingConfig = mod?.getExternalTestingConfig
|
||||||
|
|
||||||
|
if (typeof createExternalWpTester !== "function" || typeof getExternalTestingConfig !== "function") {
|
||||||
|
throw new Error("Required exports not found on module")
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text:
|
text: `wp-cli-testing MCP server error: Failed to load chat/external-wp-testing.js - ${error.message}`,
|
||||||
"wp-cli-testing MCP server misconfigured: could not load chat/external-wp-testing.js exports.",
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
isError: true,
|
isError: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user