Skip to content

Commit 4c91a76

Browse files
authored
Merge pull request #4 from verygoodplugins/docs/agents-md-canonical
docs: canonicalize AGENTS.md as the agent guide and freshen against code
2 parents c665dcc + 3caef24 commit 4c91a76

2 files changed

Lines changed: 280 additions & 281 deletions

File tree

AGENTS.md

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
# AGENTS.md
2+
3+
This file provides guidance to coding agents (Claude Code, Cursor, Codex, and others) when working with code in this repository. `CLAUDE.md` is a one-line `@AGENTS.md` import so Claude Code picks up this same content.
4+
5+
## Project Overview
6+
7+
This is a WordPress MCP (Model Context Protocol) server that allows interaction with WordPress sites through natural language via MCP-compatible clients like Claude Desktop. The server exposes WordPress REST API functionality as MCP tools.
8+
9+
## Development Commands
10+
11+
### Build and Run
12+
```bash
13+
# Install dependencies
14+
npm install
15+
16+
# Build TypeScript to JavaScript (tsc, outputs to build/)
17+
npm run build
18+
19+
# Run in development mode with hot reload (tsx watch)
20+
npm run dev
21+
22+
# Run the built server
23+
npm start
24+
25+
# Clean build artifacts
26+
npm run clean
27+
```
28+
29+
There is no test script in `package.json`; the repo currently ships no automated test suite. `npm run prepare` runs the build automatically (e.g. on install/publish).
30+
31+
### Environment Setup
32+
33+
#### Single Site Configuration
34+
Create a `.env` file in the project root with:
35+
```env
36+
WORDPRESS_API_URL=https://your-wordpress-site.com
37+
WORDPRESS_USERNAME=wp_username
38+
WORDPRESS_PASSWORD=wp_app_password
39+
```
40+
41+
#### Multi-Site Configuration
42+
For managing multiple WordPress sites (numbered config, read in `src/config/site-manager.ts:48`):
43+
```env
44+
# Site 1 (Production)
45+
WORDPRESS_1_URL=https://production-site.com
46+
WORDPRESS_1_USERNAME=admin
47+
WORDPRESS_1_PASSWORD=app_password_1
48+
WORDPRESS_1_ID=production
49+
WORDPRESS_1_DEFAULT=true
50+
WORDPRESS_1_ALIASES=prod,main
51+
52+
# Site 2 (Staging)
53+
WORDPRESS_2_URL=https://staging-site.com
54+
WORDPRESS_2_USERNAME=admin
55+
WORDPRESS_2_PASSWORD=app_password_2
56+
WORDPRESS_2_ID=staging
57+
WORDPRESS_2_ALIASES=stage,dev
58+
```
59+
60+
If no numbered sites are found, the server falls back to the legacy single-site `WORDPRESS_API_URL`/`WORDPRESS_USERNAME`/`WORDPRESS_PASSWORD` variables. The first configured site is the default unless a `WORDPRESS_N_DEFAULT=true` is set.
61+
62+
The app password can be generated from WordPress admin panel following the [Application Passwords guide](https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide#Getting-Credentials).
63+
64+
#### Optional Environment Variables
65+
- `WORDPRESS_LOG_LEVEL``debug` | `info` | `error` (default `error`). Controls log verbosity (logs go to **stderr**, not a file).
66+
- `DISABLE_LOGGING=true` — silences all logging.
67+
- `WORDPRESS_SQL_ENDPOINT` — override the SQL-query endpoint (default `/mcp/v1/query`); see `src/tools/sql-query.ts:95`.
68+
- `WORDPRESS_CACHE_DURATION` — cache TTL for WordPress lookups.
69+
- `WORDPRESS_PARALLEL_SEARCH` — toggle parallel content-type search.
70+
- `UNIFIED_CONTENT_CACHE_DIR` — directory for the unified-content cache.
71+
72+
## Architecture
73+
74+
### Core Components
75+
76+
1. **MCP Server (`src/server.ts`)**:
77+
- Entry point that initializes the server using the `McpServer` class from the ModelContextProtocol SDK
78+
- Registers every tool from `allTools` with its handler in a loop (`src/server.ts:27`) and logs the registered count
79+
- Uses `StdioServerTransport` for communication with Claude Desktop
80+
- Validates environment variables and establishes WordPress connection on startup
81+
82+
2. **Site Manager (`src/config/site-manager.ts`)**:
83+
- Manages multiple WordPress site configurations
84+
- Lazy loads site configurations from environment variables
85+
- Maintains separate authenticated Axios clients for each site
86+
- Provides site detection from context (domain mentions, aliases, site IDs)
87+
- Supports both numbered multi-site config and legacy single-site config
88+
89+
3. **WordPress Client (`src/wordpress.ts`)**:
90+
- Manages authenticated Axios instance for WordPress REST API calls
91+
- Integrates with SiteManager for multi-site support
92+
- Handles authentication using Basic Auth with application passwords
93+
- Provides `makeWordPressRequest()` wrapper for all API calls with optional `siteId` parameter
94+
- Logs to **stderr** via `logToFile()` (`src/wordpress.ts:20`), gated by `WORDPRESS_LOG_LEVEL` / `DISABLE_LOGGING` — stdout is reserved for the MCP protocol
95+
- Special handler `searchWordPressPluginRepository()` (`src/wordpress.ts:130`) for WordPress.org plugin search
96+
97+
4. **Tool System (`src/tools/`)**:
98+
- Each WordPress entity (posts, pages, media, etc.) has its own module
99+
- Each module exports a tools array and a handlers object
100+
- Tools use Zod schemas for input validation and type safety
101+
- The unified content tools (and the `get_site`/`test_site` site-management tools) accept an optional `site_id` parameter for multi-site targeting; other tool modules operate on the default site
102+
- All tools are aggregated in `src/tools/index.ts` (`allTools` / `toolHandlers`)
103+
104+
5. **CLI Launcher (`src/cli.ts`)**:
105+
- A thin alternate launcher that checks env vars and spawns `server.js`. Note: the package `bin` entry points at `build/server.js` directly, not at this file.
106+
107+
### Tool Pattern
108+
109+
Each tool module follows this pattern:
110+
```typescript
111+
// Define Zod schemas for input validation
112+
const listSchema = z.object({...});
113+
const getSchema = z.object({...});
114+
const createSchema = z.object({...});
115+
const updateSchema = z.object({...});
116+
const deleteSchema = z.object({...});
117+
118+
// Export tools array with MCP tool definitions
119+
export const entityTools: Tool[] = [
120+
{ name: "list_entity", description: "...", inputSchema: {...} },
121+
{ name: "get_entity", description: "...", inputSchema: {...} },
122+
{ name: "create_entity", description: "...", inputSchema: {...} },
123+
{ name: "update_entity", description: "...", inputSchema: {...} },
124+
{ name: "delete_entity", description: "...", inputSchema: {...} }
125+
];
126+
127+
// Export handlers object with async functions
128+
export const entityHandlers = {
129+
list_entity: async (params) => {...},
130+
get_entity: async (params) => {...},
131+
create_entity: async (params) => {...},
132+
update_entity: async (params) => {...},
133+
delete_entity: async (params) => {...}
134+
};
135+
```
136+
137+
### Unified Tool Architecture
138+
139+
The MCP server uses a **unified tool approach** to reduce complexity and tool count (down from ~65 separate per-entity tools). Instead of separate tools for posts, pages, and custom post types, there are unified tools that handle all content types. The server currently registers **41 tools**, aggregated in `src/tools/index.ts:14`.
140+
141+
#### Unified Content Tools (`unified-content.ts`) — 8 tools
142+
Handles ALL content types (posts, pages, custom post types) with a single set of tools:
143+
- `list_content` — List any content type with filtering and pagination
144+
- `get_content` — Get specific content by ID and type
145+
- `create_content` — Create new content of any type
146+
- `update_content` — Update existing content of any type
147+
- `delete_content` — Delete content of any type
148+
- `discover_content_types` — Find all available content types
149+
- `find_content_by_url` — Smart URL resolver with optional update
150+
- `get_content_by_slug` — Search by slug across content types
151+
152+
#### Unified Taxonomy Tools (`unified-taxonomies.ts`) — 8 tools
153+
Handles ALL taxonomies (categories, tags, custom taxonomies) with a single set of tools:
154+
- `discover_taxonomies` — Find all available taxonomies
155+
- `list_terms` — List terms in any taxonomy
156+
- `get_term` — Get specific term by ID
157+
- `create_term` — Create new term in any taxonomy
158+
- `update_term` — Update existing term
159+
- `delete_term` — Delete term from any taxonomy
160+
- `assign_terms_to_content` — Assign terms to any content type
161+
- `get_content_terms` — Get all terms for any content
162+
163+
#### Plugin Tools (`plugins.ts`) — 5 tools
164+
- `list_plugins`, `get_plugin`, `activate_plugin`, `deactivate_plugin`, `create_plugin`
165+
166+
#### Media Tools (`media.ts`) — 4 tools
167+
- `list_media`, `create_media`, `edit_media`, `delete_media`
168+
169+
#### User Tools (`users.ts`) — 5 tools
170+
- `list_users`, `get_user`, `create_user`, `update_user`, `delete_user`
171+
172+
#### Comment Tools (`comments.ts`) — 5 tools
173+
- `list_comments`, `get_comment`, `create_comment`, `update_comment`, `delete_comment`
174+
175+
#### Plugin Repository Tools (`plugin-repository.ts`) — 2 tools
176+
- `search_plugin_repository` — Search WordPress.org for plugins
177+
- `get_plugin_details` — Get details for a WordPress.org plugin
178+
179+
#### SQL Query Tool (`sql-query.ts`) — 1 tool
180+
- `execute_sql_query` — Execute read-only database queries. Requires a custom endpoint on the WordPress side; uses `/mcp/v1/query` by default, overridable via `WORDPRESS_SQL_ENDPOINT`.
181+
182+
#### Site Management Tools (`site-management.ts`) — 3 tools
183+
- `list_sites` — List all configured WordPress sites
184+
- `get_site` — Get details about a specific site
185+
- `test_site` — Test connection to a WordPress site
186+
187+
### Key Features
188+
189+
#### Smart URL Resolution
190+
The `find_content_by_url` tool can:
191+
- Take any WordPress URL and automatically find the corresponding content
192+
- Detect the content type from URL patterns (e.g., `/documentation/` → documentation CPT)
193+
- Optionally update the content in a single operation
194+
- Cache content type information to minimize API calls
195+
196+
Example: Given `https://site.com/documentation/api-guide/`, it will:
197+
1. Extract the slug `api-guide`
198+
2. Detect hints suggesting a documentation content type
199+
3. Search efficiently across relevant content types
200+
4. Return or update the found content
201+
202+
#### Unified Content Management
203+
All content operations use a single `content_type` parameter:
204+
```json
205+
{
206+
"content_type": "post", // for blog posts
207+
"content_type": "page", // for static pages
208+
"content_type": "product", // for custom post types
209+
"content_type": "documentation" // for custom post types
210+
}
211+
```
212+
213+
#### Unified Taxonomy Management
214+
All taxonomy operations use a single `taxonomy` parameter:
215+
```json
216+
{
217+
"taxonomy": "category", // for categories
218+
"taxonomy": "post_tag", // for tags
219+
"taxonomy": "product_category", // for custom taxonomies
220+
"taxonomy": "skill" // for custom taxonomies
221+
}
222+
```
223+
224+
#### Multi-Site Support
225+
The unified content tools (and the `get_site`/`test_site` site-management tools) accept an optional `site_id` parameter to target a specific site:
226+
```json
227+
{
228+
"content_type": "post",
229+
"site_id": "production" // Optional - targets specific site
230+
}
231+
```
232+
233+
If `site_id` is not provided, the default site is used. Sites can be managed via:
234+
- `list_sites` - See all configured sites
235+
- `get_site` - Get details about a site
236+
- `test_site` - Test connection to a site
237+
238+
## TypeScript Configuration
239+
240+
- Target: ES2022 with ESNext modules (`moduleResolution: node`)
241+
- Strict mode enabled
242+
- Source in `src/`, builds to `build/` (`outDir`)
243+
- Declaration files generated
244+
245+
## Claude Desktop Integration
246+
247+
The server integrates with Claude Desktop via the configuration in `claude_desktop_config.json`:
248+
```json
249+
{
250+
"mcpServers": {
251+
"wordpress": {
252+
"command": "npx",
253+
"args": ["-y", "@instawp/mcp-wp"],
254+
"env": {
255+
"WORDPRESS_API_URL": "https://your-site.com",
256+
"WORDPRESS_USERNAME": "username",
257+
"WORDPRESS_PASSWORD": "app_password"
258+
}
259+
}
260+
}
261+
}
262+
```
263+
264+
## Error Handling
265+
266+
- All API requests are wrapped in try-catch blocks
267+
- Errors are logged to **stderr** via `logToFile()` (level `error`) with request/response details
268+
- Process signals (SIGTERM, SIGINT) are handled gracefully
269+
- Uncaught exceptions and rejections trigger proper shutdown
270+
271+
## Key Dependencies
272+
273+
- `@modelcontextprotocol/sdk`: MCP protocol implementation
274+
- `axios`: HTTP client for WordPress REST API
275+
- `zod` + `zod-to-json-schema`: Runtime type validation and JSON-schema generation for tool inputs
276+
- `dotenv`: Environment variable management
277+
- `fs-extra`: Filesystem helpers (e.g. content cache)
278+
- `marked`: Markdown parsing for content handling
279+
- `tsx`: TypeScript execution for development

0 commit comments

Comments
 (0)