무색
기술블로그
에세이
연구
프로덕트
소개

무색

소프트웨어로 비즈니스의 가능성을 만듭니다. 웹·앱 개발, 음성 AI, 자동화 콘텐츠 제작까지 — 기술이 필요한 곳에 무색이 있습니다.

연락처

[email protected]

사업자 정보

상호: 무색

대표: 배성재

사업자등록번호: 577-58-00836

인천광역시 연수구 인천타워대로 323, 에이동 8층 801-802호 AB-132 (송도동, 송도 센트로드)

© 2026 무색. All rights reserved.
개인정보처리방침·이용약관
INCHEON, KR
MCP로 AI 에이전트가 CMS를 직접 조작하게 만든 이야기 — pencil-sketch key visual
museck 만들기
2026. 1. 10.

MCP로 AI 에이전트가 CMS를 직접 조작하게 만든 이야기

PayloadCMSMCPn8nAI Agent자동화

블로그 글 하나 쓰려면 할 일이 꽤 많다. 글을 쓰고, 코드 블록을 정리하고, 이미지를 만들어서 올리고, CMS에 들어가서 필드를 채우고 저장한다. 이걸 매번 손으로 하다 보니 글 쓰는 것보다 CMS 작업이 더 귀찮아졌다.

그래서 AI 에이전트한테 이 과정을 통째로 맡기기로 했다. 글감만 던져주면 글 작성부터 이미지 생성, CMS 저장까지 알아서 처리하는 파이프라인이다. 핵심은 MCP(Model Context Protocol) 플러그인으로 PayloadCMS를 AI 에이전트에게 열어주는 부분이었다.

전체 구조

파이프라인은 크게 세 덩어리로 나뉜다.

blog-writer 서브에이전트가 글감 파일을 읽어서 Lexical JSON으로 본문을 작성한다. ComfyUI로 대표 이미지와 다이어그램을 생성하고, MCP 프로토콜을 통해 PayloadCMS에 draft로 저장한다. 글이 발행되면 afterChange 훅이 n8n 웹훅을 호출해서 후속 자동화(SNS 공유 등)를 트리거한다.

MCP 플러그인으로 CMS 열어주기

AI 에이전트가 CMS를 조작하려면 API가 필요하다. REST API를 직접 호출해도 되지만 MCP를 쓰면 에이전트가 스키마를 자동으로 파악하고 타입 안전하게 CRUD를 수행할 수 있다. PayloadCMS는 공식 MCP 플러그인을 제공해서 설정이 간단했다.

plugins: [
  mcpPlugin({
    collections: {
      posts: {
        enabled: true,
        description: '기술 블로그 게시글. Lexical richText...',
      },
      media: {
        enabled: { find: true, create: true, update: false, delete: false },
        description: '블로그 이미지. alt 텍스트 필수.',
      },
    },
  }),
]

posts는 전체 CRUD를 열어줬지만 media는 find와 create만 허용했다. 에이전트가 실수로 기존 이미지를 덮어쓰거나 삭제하는 걸 원천 차단하려는 안전장치다. 이렇게 컬렉션별로 권한을 세밀하게 제어할 수 있는 게 MCP 플러그인의 장점이다.

n8n 웹훅으로 발행 알림 자동화

글이 draft에서 published로 바뀌는 순간 n8n에 알림을 보내고 싶었다. PayloadCMS의 afterChange 훅을 활용했다.

export const notifyN8nOnPublish: CollectionAfterChangeHook = async ({
  doc, previousDoc, operation,
}) => {
  if (!N8N_WEBHOOK_URL) return doc

  const isPublishing =
    doc._status === 'published' &&
    (operation === 'create' || previousDoc?._status !== 'published')

  if (!isPublishing) return doc

  await fetch(N8N_WEBHOOK_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ id: doc.id, title: doc.title, slug: doc.slug }),
  })

  return doc
}

핵심 로직은 단순하다. 현재 문서의 상태가 published이고 이전 상태가 published가 아닐 때만 웹훅을 쏜다. 새 글을 바로 published로 만드는 경우(operation === 'create')도 잡아준다.

한 가지 마음에 드는 패턴은 if (!N8N_WEBHOOK_URL) return doc 부분이다. n8n 웹훅 URL을 환경변수로 관리하면서 값이 없으면 조용히 넘어간다. 개발 환경에서는 n8n이 안 돌고 있을 텐데 그때도 에러 없이 동작하니까 편하다.

blog-writer 서브에이전트

이제 진짜 재밌는 부분이다. Claude Code의 서브에이전트로 블로그 글 작성 전체를 자동화했다. 에이전트 하나가 처리하는 워크플로우는 이렇다.

  1. 글감 파일(마크다운)을 읽어서 컨텍스트, 코드, 아키텍처 등을 파악한다
  2. Lexical richText JSON 형식으로 본문을 작성한다. 이미지가 들어갈 자리는 태그로 표시해둔다
  3. ComfyUI로 대표 이미지를 생성하고 Mermaid로 다이어그램을 렌더링한다
  4. 생성된 이미지를 PayloadCMS media에 업로드하고 본문의 태그를 upload 노드로 교체한다
  5. MCP를 통해 posts 컬렉션에 draft 상태로 저장한다

Lexical JSON을 직접 생성하는 게 이 에이전트의 가장 까다로운 부분이었다. heading, paragraph, code, upload 등 모든 노드 타입의 JSON 구조를 에이전트 설정 파일에 상세히 문서화해야 했다. 특히 코드 블록은 각 줄이 별도의 code-highlight 노드이고 줄바꿈마다 linebreak 노드가 들어가야 하는데 이 구조를 처음 파악하는 데 시간이 좀 걸렸다.

MCP vs REST API

사실 REST API로도 같은 일을 할 수 있다. 그런데 MCP를 쓰면 에이전트 입장에서 몇 가지가 편해진다.

첫째, 스키마를 자동으로 이해한다. REST API는 에이전트에게 어떤 필드가 있고 타입이 뭔지 알려줘야 하는데 MCP는 프로토콜 자체에 스키마 정보가 포함된다. 둘째, 타입 안전한 CRUD가 가능하다. 잘못된 필드명이나 타입을 보내면 프로토콜 레벨에서 거부된다. 셋째, 권한 제어가 세밀하다. 앞에서 본 것처럼 media 컬렉션은 find/create만 허용하는 식으로 에이전트의 행동 범위를 제한할 수 있다.

삽질 기록

media 권한을 열어뒀다가 낭패 본 이야기

처음에는 media도 전체 CRUD를 열어놨었다. 테스트하다가 에이전트가 기존 이미지의 alt 텍스트를 "수정"하려고 update를 날린 적이 있다. 의도는 좋았는데 원본 메타데이터가 날아갔다. 그 뒤로 media는 find/create만 허용하는 걸로 바꿨다. AI 에이전트한테 너무 많은 권한을 주면 선의의 실수가 발생한다는 걸 배웠다.

Lexical JSON 구조 파악

PayloadCMS의 Lexical 에디터가 생성하는 JSON 구조는 문서화가 잘 안 돼 있다. 결국 관리자 패널에서 직접 글을 써보고 API로 조회해서 JSON 구조를 역추적했다. heading 노드의 tag 필드가 "h2" 형태로 이미 접두사를 포함하고 있다는 것도 이렇게 알아냈다. (이건 다음 글에서 다룰 Live Preview 삽질에서도 중요한 포인트다.)

환경변수 옵셔널 패턴

n8n 웹훅 URL을 환경변수로 관리한 건 단순해 보이지만 쓸모가 크다. 로컬 개발에서는 n8n 없이도 돌아가고 staging에서는 테스트 웹훅을 넣고 프로덕션에서는 진짜 웹훅을 쓸 수 있다. 환경 의존적 기능을 옵셔널로 만드는 이 패턴은 다른 훅에도 그대로 적용할 수 있다.

정리하면

Headless CMS에 MCP를 붙이면 AI 에이전트에게 콘텐츠 관리를 안전하게 위임할 수 있다. 핵심은 세 가지였다.

  • MCP 플러그인으로 에이전트에게 CMS 스키마를 노출하되 권한은 최소한으로
  • afterChange 훅 + 웹훅으로 발행 이벤트를 외부 자동화 도구에 연결
  • 서브에이전트 패턴으로 글 작성/이미지 생성/CMS 저장 파이프라인을 하나의 단위로 묶기

이 글 자체가 이 파이프라인으로 작성됐다. 글감 파일을 읽고 본문을 쓰고 이미지를 만들어서 PayloadCMS에 넣는 과정 전부를 blog-writer 에이전트가 처리했다. 아직 draft 상태니까 발행 버튼은 내가 직접 누르겠지만 그 뒤의 n8n 알림은 자동이다.

자주 묻는 질문

PayloadCMS MCP 플러그인으로 AI 에이전트에 CMS 권한을 어떻게 제어하나요?
mcpPlugin 설정에서 컬렉션별로 CRUD 권한을 개별 지정할 수 있습니다. 예를 들어 media는 find/create만 허용하고 update/delete를 차단하면 에이전트의 실수로 기존 데이터가 손상되는 것을 방지할 수 있습니다.
Claude Code 서브에이전트로 블로그 글 작성을 자동화하려면 무엇이 필요한가요?
Lexical richText JSON 구조를 에이전트 설정에 상세히 문서화해야 합니다. heading, paragraph, code, upload 등 각 노드 타입의 JSON 스키마를 정의하고, MCP를 통해 PayloadCMS에 draft로 저장하는 흐름을 구성합니다.
PayloadCMS afterChange 훅으로 발행 알림을 자동화하는 방법은?
afterChange 훅에서 doc._status가 published이고 이전 상태가 published가 아닐 때만 웹훅을 호출합니다. 환경변수로 웹훅 URL을 관리하면 개발 환경에서는 알림 없이, 프로덕션에서만 동작하도록 할 수 있습니다.
museck 만들기(7/10)
Prev

Tailwind 토큰 바꿨을 뿐인데 홈페이지가 브루탈리즘이 됐다

Next

PayloadCMS Lexical 에디터에 코드 블록 넣기: 4개 레이어 삽질기