WordPress MCP Server
WordPress REST API를 MCP(Model Context Protocol)로 래핑한 Node.js 서버.AI 에이전트에서 WordPress 게시글을 조회, 생성, 수정, 삭제할 수 있다.
프로젝트 구조
├── src/
│ ├── config.ts # 환경 변수 로드 및 설정 타입 정의
│ ├── logger.ts # stderr 기반 로거 (STDIO 모드 안전)
│ ├── wordpress-client.ts # WordPress REST API 클라이언트
│ ├── server.ts # MCP 서버 생성 + Tool 등록 (공통 로직)
│ ├── stdio.ts # STDIO 전송 방식 진입점
│ └── sse.ts # Streamable HTTP + 레거시 SSE 전송 방식 진입점
├── dist/ # TypeScript 빌드 출력
├── .env.example # 환경 변수 예시
├── package.json
└── tsconfig.json
아키텍처
┌─────────────┐ ┌──────────────────────────┐
│ stdio.ts │ │ sse.ts │
│ (StdioTx) │ │ (Express) │
│ │ │ ┌─────────────────────┐ │
│ │ │ │ Streamable HTTP │ │
│ │ │ │ POST|GET|DELETE /mcp │ │
│ │ │ ├─────────────────────┤ │
│ │ │ │ Legacy SSE │ │
│ │ │ │ GET /sse │ │
│ │ │ │ POST /messages │ │
│ │ │ └─────────────────────┘ │
└──────┬──────┘ └────────────┬─────────────┘
│ │
└───────────┬─────────────┘
│
┌───────▼───────┐
│ server.ts │
│ (McpServer + │
│ Tool 정의) │
└───────┬───────┘
│
┌─────────▼─────────┐
│ wordpress-client │
│ (REST API 호출) │
└─────────┬─────────┘
│
┌───────▼───────┐
│ WordPress │
│ /wp-json/v2 │
└───────────────┘
server.ts의 createServer()가 공통 로직 레이어이며, STDIO와 SSE 양쪽에서 동일하게 사용된다.
사전 요구사항
- Node.js 18+
- WordPress 사이트 (REST API 활성화 상태)
- WordPress Application Password 또는 Bearer Token
WordPress Application Password 발급
- WordPress 관리자 > 사용자 > 프로필
- "애플리케이션 비밀번호" 섹션에서 이름을 입력하고 생성
- 표시되는 비밀번호를 복사 (공백 포함 그대로 사용)
설치
npm install
npm run build
환경 변수 설정
cp .env.example .env
.env 파일을 편집한다:
# WordPress 사이트 URL (trailing slash 없이)
WORDPRESS_BASE_URL=https://your-wordpress-site.com
# 인증 방식 1: Application Password (권장)
WORDPRESS_USERNAME=admin
WORDPRESS_APP_PASSWORD=xxxx xxxx xxxx xxxx xxxx xxxx
# 인증 방식 2: Bearer Token (Application Password 대신 사용)
# WORDPRESS_TOKEN=your-bearer-token
# SSE 서버 포트 (기본값: 3000)
SSE_PORT=3000
# 자체 서명 인증서 허용 (로컬 HTTPS 개발 환경에서 사용)
# WORDPRESS_TLS_REJECT_UNAUTHORIZED=false
| 변수 | 필수 | 설명 |
|---|---|---|
WORDPRESS_BASE_URL |
O | WordPress 사이트 URL |
WORDPRESS_USERNAME |
△ | Application Password 사용 시 |
WORDPRESS_APP_PASSWORD |
△ | Application Password 사용 시 |
WORDPRESS_TOKEN |
△ | Bearer Token 사용 시 |
SSE_PORT |
X | SSE 서버 포트 (기본값: 3000) |
WORDPRESS_TLS_REJECT_UNAUTHORIZED |
X | false 설정 시 자체 서명 인증서 허용 |
WORDPRESS_TOKEN이 설정되면 Bearer 인증을 사용하고, 없으면 WORDPRESS_USERNAME + WORDPRESS_APP_PASSWORD로 Basic 인증을 사용한다.
실행
STDIO 모드
로컬 MCP 클라이언트(Claude Desktop, Claude Code 등)에서 사용하는 방식.
# 빌드 후 실행
npm run start:stdio
# 개발 모드 (tsx 직접 실행)
npm run dev:stdio
SSE(HTTP) 모드
원격 MCP 클라이언트에서 HTTP로 접속하는 방식. Streamable HTTP(최신)와 레거시 SSE(구버전 클라이언트 호환) 두 가지 프로토콜을 동시에 지원한다.
# 빌드 후 실행
npm run start:sse
# 개발 모드
npm run dev:sse
서버 시작 후 사용 가능한 엔드포인트:
Streamable HTTP (최신 프로토콜)
| 메서드 | 경로 | 설명 |
|---|---|---|
POST |
/mcp |
JSON-RPC 요청 처리 (초기화 + 도구 호출) |
GET |
/mcp |
SSE 스트림 (서버→클라이언트 알림) |
DELETE |
/mcp |
세션 종료 |
Legacy SSE (구버전 클라이언트 호환)
| 메서드 | 경로 | 설명 |
|---|---|---|
GET |
/sse |
SSE 스트림 연결 (세션 생성) |
POST |
/messages?sessionId=... |
JSON-RPC 메시지 전송 |
공통
| 메서드 | 경로 | 설명 |
|---|---|---|
GET |
/health |
서버 상태 확인 |
클라이언트 설정
Claude Desktop
claude_desktop_config.json:
{
"mcpServers": {
"wordpress": {
"command": "node",
"args": ["/절대경로/wordpress-mcp-server/dist/stdio.js"],
"env": {
"WORDPRESS_BASE_URL": "https://your-site.com",
"WORDPRESS_USERNAME": "admin",
"WORDPRESS_APP_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
}
}
}
}
Claude Code
claude mcp add wordpress -- node /절대경로/wordpress-mcp-server/dist/stdio.js
또는 .mcp.json:
{
"mcpServers": {
"wordpress": {
"command": "node",
"args": ["/절대경로/wordpress-mcp-server/dist/stdio.js"],
"env": {
"WORDPRESS_BASE_URL": "https://your-site.com",
"WORDPRESS_USERNAME": "admin",
"WORDPRESS_APP_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx",
"WORDPRESS_TLS_REJECT_UNAUTHORIZED": "false"
}
}
}
}
SSE 모드 클라이언트 연결
SSE 서버를 실행한 후, MCP 클라이언트에서 접속:
# Streamable HTTP 지원 클라이언트 (최신)
http://localhost:3000/mcp
# Legacy SSE 지원 클라이언트 (구버전)
http://localhost:3000/sse
MCP Tools
listPosts
게시글 목록을 조회한다. 페이지네이션, 검색, 상태 필터를 지원한다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
page |
number | X | 페이지 번호 (기본값: 1) |
per_page |
number | X | 페이지당 게시글 수 (기본값: 10, 최대: 100) |
search |
string | X | 검색어 |
status |
enum | X | publish, draft, pending, private, trash |
orderby |
enum | X | date, id, title, slug, modified |
order |
enum | X | asc, desc |
getPost
게시글 하나를 ID로 조회한다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number | O | 게시글 ID |
createPost
새 게시글을 생성한다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
title |
string | O | 게시글 제목 |
content |
string | O | 게시글 내용 (HTML 가능) |
status |
enum | X | publish, draft, pending, private (기본값: draft) |
excerpt |
string | X | 게시글 요약 |
categories |
number[] | X | 카테고리 ID 배열 |
tags |
number[] | X | 태그 ID 배열 |
updatePost
기존 게시글을 수정한다. 전달된 필드만 변경된다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number | O | 수정할 게시글 ID |
title |
string | X | 변경할 제목 |
content |
string | X | 변경할 내용 (HTML 가능) |
status |
enum | X | publish, draft, pending, private |
excerpt |
string | X | 변경할 요약 |
categories |
number[] | X | 변경할 카테고리 ID 배열 |
tags |
number[] | X | 변경할 태그 ID 배열 |
deletePost
게시글을 삭제한다.
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
id |
number | O | 삭제할 게시글 ID |
force |
boolean | X | true이면 영구 삭제, false이면 휴지통 이동 (기본값: false) |
기술 스택
| 항목 | 사용 기술 |
|---|---|
| 런타임 | Node.js 18+ |
| 언어 | TypeScript (ESM) |
| MCP SDK | @modelcontextprotocol/sdk ^1.26.0 |
| HTTP 클라이언트 | Node.js 내장 fetch |
| 스키마 검증 | zod |
| SSE 서버 | Express + StreamableHTTPServerTransport + SSEServerTransport |
| WordPress API | /wp-json/wp/v2 (REST API v2) |
주요 설계 결정
- 공통 로직 분리:
server.ts의createServer(config)함수가 McpServer 인스턴스와 모든 Tool을 생성한다. STDIO와 SSE 진입점은 전송 방식만 다르다. - stderr 로깅: STDIO 모드에서 stdout은 JSON-RPC 프로토콜 메시지 전용이므로, 모든 로그는
console.error(stderr)로 출력한다. - 듀얼 전송 프로토콜: SSE 서버가 Streamable HTTP(
/mcp)와 레거시 SSE(/sse+/messages)를 동시에 제공한다. 최신 클라이언트와 구버전 클라이언트 모두 호환된다. - 세션 관리: 두 전송 방식 모두 클라이언트별 독립 세션을 생성한다. Streamable HTTP는
mcp-session-id헤더, 레거시 SSE는sessionId쿼리 파라미터로 세션을 식별한다. - 오류 처리: WordPress API 오류 응답(4xx, 5xx)을 파싱하여 MCP
isError: true결과로 반환한다. 에이전트가 오류 내용을 이해하고 대응할 수 있다.