# Directory Structure ``` ├── .gitignore ├── README.md └── wp-server-python ├── requirements.txt └── wp.py ``` # Files -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` 1 | build/ 2 | 3 | # Node-generated files 4 | node_modules/ 5 | 6 | # Python-generated files 7 | __pycache__/ 8 | *.py[oc] 9 | dist/ 10 | wheels/ 11 | *.egg-info 12 | 13 | # Virtual environments 14 | .venv 15 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown 1 | # Very much a work in progress that has not progressed 2 | 3 | You should go to https://github.com/Automattic/wordpress-mcp for a fully functional WordPress MCP implementation. 4 | 5 | To try it you currently need a WordPress instance locally on `http://localhost:8888/`. 6 | 7 | It is currently a python app, I used `uv` locally,so you will need to: 8 | 9 | `uv venv` 10 | `source .venv/bin/activate` 11 | `uv pip install -r requirements.txt` 12 | 13 | You can then run the server with `uv run wp.py` to see if you get any errors, but you don't need to run from terminal as Claude will start its own instance. 14 | 15 | You also need to add the following to your `claude_desktop_config.json`: 16 | 17 | ``` 18 | { 19 | "mcpServers": { 20 | "wordpress": { 21 | "command": "uv", 22 | "args": [ 23 | "--directory", 24 | "/FULL/PATH/TO/wp-server-python", 25 | "run", 26 | "wp.py" 27 | ] 28 | } 29 | } 30 | } 31 | ``` 32 | ``` -------------------------------------------------------------------------------- /wp-server-python/requirements.txt: -------------------------------------------------------------------------------- ``` 1 | httpx>=0.25.0 2 | fastmcp>=0.1.0 ``` -------------------------------------------------------------------------------- /wp-server-python/wp.py: -------------------------------------------------------------------------------- ```python 1 | from typing import Any 2 | import httpx 3 | from mcp.server.fastmcp import FastMCP 4 | 5 | # Initialize FastMCP server 6 | mcp = FastMCP("wordpress") 7 | 8 | # Constants 9 | WP_API_BASE = "http://localhost:8888/wp-json/wp/v2" 10 | USER_AGENT = "wp-mcp/1.0" 11 | 12 | async def make_wp_request(url: str) -> dict[str, Any] | None: 13 | """Make a request to the WordPress API with proper error handling.""" 14 | headers = { 15 | "User-Agent": USER_AGENT, 16 | "Accept": "application/json" 17 | } 18 | async with httpx.AsyncClient() as client: 19 | try: 20 | response = await client.get(url, headers=headers, timeout=30.0) 21 | response.raise_for_status() 22 | return response.json() 23 | except Exception as e: 24 | return {"error": str(e)} 25 | 26 | def format_post(post: dict) -> str: 27 | """Format a WordPress post into a readable string.""" 28 | return f""" 29 | Title: {post.get('title', {}).get('rendered', 'Untitled')} 30 | Status: {post.get('status', 'unknown')} 31 | Date: {post.get('date', 'unknown')} 32 | Link: {post.get('link', 'unknown')} 33 | Excerpt: {post.get('excerpt', {}).get('rendered', 'No excerpt available').strip()} 34 | """ 35 | 36 | def format_page(page: dict) -> str: 37 | """Format a WordPress page into a readable string.""" 38 | return f""" 39 | Title: {page.get('title', {}).get('rendered', 'Untitled')} 40 | Status: {page.get('status', 'unknown')} 41 | Date: {page.get('date', 'unknown')} 42 | Link: {page.get('link', 'unknown')} 43 | Parent: {page.get('parent', 0)} 44 | Menu Order: {page.get('menu_order', 0)} 45 | """ 46 | 47 | @mcp.tool() 48 | async def wp_list_posts() -> str: 49 | """Get a list of public posts from WordPress. 50 | 51 | Returns a formatted string containing post information. 52 | """ 53 | url = f"{WP_API_BASE}/posts" 54 | data = await make_wp_request(url) 55 | 56 | if not data: 57 | return "Unable to fetch posts." 58 | 59 | if isinstance(data, dict) and "error" in data: 60 | return f"Error fetching posts: {data['error']}" 61 | 62 | if not data: 63 | return "No posts found." 64 | 65 | posts = [format_post(post) for post in data] 66 | return "\n---\n".join(posts) 67 | 68 | @mcp.tool() 69 | async def wp_list_pages() -> str: 70 | """Get a list of pages from WordPress. 71 | 72 | Returns a formatted string containing page information. 73 | """ 74 | url = f"{WP_API_BASE}/pages" 75 | data = await make_wp_request(url) 76 | 77 | if not data: 78 | return "Unable to fetch pages." 79 | 80 | if isinstance(data, dict) and "error" in data: 81 | return f"Error fetching pages: {data['error']}" 82 | 83 | if not data: 84 | return "No pages found." 85 | 86 | pages = [format_page(page) for page in data] 87 | return "\n---\n".join(pages) 88 | 89 | if __name__ == "__main__": 90 | # Initialize and run the server 91 | mcp.run(transport='stdio') ```