자동화

  • 클로드 코드 플러그인 korean-skills로 한글 AI 패턴 6개 찾은 후기

    클로드 코드 플러그인 korean-skills로 한글 AI 패턴 6개 찾은 후기

    클로드 코드 플러그인 korean-skills를 설치하고 실제 글에 돌려봤다. 줄표 14개를 5개로 줄였다. 자문형 표현 9곳을 전부 평서문으로 바꿨다. 괄호 용어 풀이 규칙을 코드에 박아 넣었다. 숫자가 먼저다. 어떻게 여기까지 왔는지는 아래에 있다.

    애드센스 2차 거절에서 발견한 서식 균일성 문제

    직접 진단해봤던 ujinify.com 애드센스 거절 건이다. ‘가치가 별로 없는 콘텐츠’로 두 번 거절당했다. 2026년 9월 30일, 그리고 10월 16일. 두 번째 진단에서 이상한 걸 발견했다. 35개 글 전부가 같은 서사 틀로 찍혀 나왔다.

    훅 도입, 피크엔드 결론. 매 글 똑같은 구조였다. 그래서 agents/style-variants.ts를 만들어 오프닝·클로징·분량을 글마다 다르게 뽑도록 고쳤다. 근데 그건 글 전체 구조 수준의 얘기였다. 더 미세한 문장·서식 수준에서 AI가 쓴 것처럼 보이는 패턴이 남아 있는지 확인할 도구가 없었다.

    영어용 AI 탐지기인 ai-checker(Byakugan)는 이미 써봤다. 별로였다. 한글 글에 돌렸더니 전부 ‘human’ 판정이 나왔다. 가장 비중 큰 판정 신호가 영어 상투어 사전 매칭이라서 한글에는 처음부터 안 맞는 구조였다. 한글 전용 도구를 따로 찾아야 했다.

    korean-skills 클로드 코드 플러그인, 명령어 2줄이면 끝

    GitHub에서 daleseo/korean-skills(⭐228)를 찾았다. 클로드 코드(Claude Code, AI 코딩 보조 도구) 플러그인(plugin, 기능을 추가하는 확장 모듈) 형태로 humanizer, grammar-checker(한글 맞춤법검사기 기능), style-guide 세 가지 스킬을 묶어서 제공한다.

    설치는 명령어 두 줄이다.

    claude plugin marketplace add daleseo/korean-skills
    claude plugin install korean-skills@korean-skills

    둘 다 성공 메시지가 떴다. claude plugin list로 확인하니 Version 1.0.0, Status: enabled.

    claude plugin marketplace add와 claude plugin install 명령어 실행 결과, korean-skills가 enabled 상태로 잡힌 화면

    실제 설치 직후 터미널 출력이다. marketplace 등록, 플러그인 설치, 상태 확인까지 전부 성공으로 떴다.

    설치 직후 바로 안 되는 이유, 새 세션이 필요하다

    클로드 코드 플러그인을 설치하고 바로 korean-skills:humanizer를 불렀다. ‘Unknown skill’ 에러가 났다. 이건 좀 웃겼다. 성공 메시지까지 다 떴는데 못 찾는다고 한다.

    새로 설치한 플러그인은 설치한 바로 그 세션(session, 현재 열려 있는 대화 창)에는 안 잡힌다. 새 세션을 열어야 쓸 수 있다. 전에 ai-checker MCP 플러그인 설치했을 때도 똑같은 패턴이었다. 매번 새 세션을 열어야 한다는 건 단점이다. 명확히 불편하다.

    새 세션에서 korean-skills:humanizer 스킬을 다시 호출해 정상적으로 로드된 화면, 분석할 텍스트 선택지 세 가지 제시

    새 세션을 열고 다시 호출하니 이번엔 정상 작동했다. 어떤 텍스트를 분석할지 선택지 세 개를 먼저 물어봤다.

    실제 글 4개를 분석해서 나온 6가지 반복 패턴

    ujinify.com에 올라간 실제 글들을 humanizer에 넣었다. 먼저 #297 도입부를 테스트했더니 ‘자연도 A등급, 교정 불필요’가 나왔다. 그래도 약한 패턴 다섯 개를 짚어줬다.

    ujinify.com 포스트 297번 도입부를 humanizer로 분석한 결과, 자연도 A등급과 패턴 5개, 고친 버전, 의미 보존 검증 결과

    #297 분석 결과 화면이다. A등급이 나왔는데도 괄호 용어 풀이 반복 같은 패턴 5개를 꼼꼼하게 짚어줬다.

    이어서 #360, #213, #16까지 4개 글을 비교 분석했다. 사이트 전체에서 반복되는 패턴이 따로 뽑혔다.

    ujinify.com 글 4개(297, 360, 213, 16)의 쉼표·줄표·주요 패턴·자연도 등급을 표로 비교한 결과 화면

    4개 글을 표로 비교한 화면이다. 개별 글에서는 안 보이던 사이트 전체 패턴이 숫자로 드러났다.

    • 괄호 용어 풀이가 4개 글 모두 반복됐다. 개별 글만 보면 약한 신호지만 사이트 전체로 보면 균일하다
    • 최근 33개 제목 중 8개에 줄표 사용
    • #360 본문에만 줄표 11번
    • #213·#16에 ‘결론부터 말하면’류 전환 공식이 똑같이 반복
    • 소제목에 ‘~란?’, ‘~했을까’ 자문형 반복
    • #16이 이 패턴들을 가장 많이 갖고 있었다. 초기 프롬프트가 지금보다 더 고정적이었다는 뜻이다

    코드와 라이브 글을 직접 고친 뒤 확인한 것

    style-variants.ts가 못 잡은 부분이라서 바로 코드에 규칙을 추가했다.

    content-writer.ts 프롬프트에 추가한 규칙: 괄호 용어 풀이는 처음 등장할 때 한 번만, 글 전체에서 최대 4개까지. 본문 줄표는 최대 1회. ‘결론부터 말하면’류 전환 공식 금지. outline-writer.ts에도 추가했다. 소제목에 줄표 금지, 질문형 소제목은 4~6개 중 최대 1개로 제한. npm test 7개 파일 전부 통과했다.

    라이브 글 두 개도 직접 고쳤다. #360은 줄표 14개에서 5개로 줄었다. 남은 5개는 인용된 제목이나 이미지 alt 텍스트처럼 바꾸면 안 되는 자리뿐이다. #16은 자문형 표현 9곳을 전부 평서문으로 바꾸고 줄표 1곳도 정리했다. wp.data로 수정하고 LiteSpeed 캐시 퍼지한 뒤 라이브 페이지에서 직접 확인했다.

    숫자로 증명할 수 있다는 점이 생각보다 유용했다

    이 클로드 코드 플러그인 없이 사람이 35개 글을 일일이 비교하면서 패턴을 찾기는 현실적으로 어렵다. 한 글만 봐서는 눈치 못 채는 게 사이트 전체로 펼쳐 보면 숫자로 나온다. 그게 이 도구의 실제 쓸모였다.

    한계는 분명하다. 새 세션에서만 쓸 수 있어서 매번 세션을 새로 열어야 한다. 수정 제안은 사람이 직접 라이브 글에 반영해야 한다. 자동 적용은 안 된다. 앞으로 ujinify.com 글쓰기 파이프라인에 이 클로드 코드 플러그인을 정기적으로 돌릴 생각이다.

    처음엔 글 전체 구조만 다양하게 바꾸면 충분할 거라 봤다. 틀렸다. 문장 수준의 서식 패턴이 따로 쌓이고 있었다. 글 하나만 보면 절대 못 잡는 패턴이었다. 비교해야만 보였다.

  • 랭크매스 포커스 키워드, wp.data로 직접 넣는 법

    랭크매스 포커스 키워드, wp.data로 직접 넣는 법

    ujinify.com 업로드 스크립트가 REST API(Application Programming Interface, 외부에서 워드프레스 데이터를 주고받는 통로)로 랭크매스 포커스 키워드를 보내고 있었다. 응답도 200이 왔다. 에러도 없었다. 그런데 글을 열어보면 포커스 키워드 칸이 비어 있다.

    조용히 무시당한 거다. 한동안 이걸 몰랐고, 그동안은 글마다 에디터를 열어서 손으로 키워드를 입력했다. 글이 늘수록 이게 제일 귀찮은 수작업이었다.

    이 글은 그 문제를 해결한 방법을 정리한다. wp.data라는 워드프레스 내부 저장소(앱 안에서 데이터를 관리하는 공간)를 직접 건드리는 방식이다.

    REST API가 랭크매스 포커스 키워드를 무시하는 이유

    REST API로 글을 저장할 때 meta 필드에 rank_math_focus_keyword를 넣으면 된다고 생각했다. 실제로 그렇게 했다. 그리고 저장은 됐다. 응답 코드도 200이었다.

    랭크매스가 이 값을 받아도 포커스 키워드로 반영하지 않는다. 에러를 주지도 않는다. 그냥 없는 것처럼 동작한다.

    정확한 내부 원인까지는 확인하지 못했다. 확인한 건 하나다. 랭크매스의 점수 계산 엔진(SEO 점수를 계산하는 프로그램)이 브라우저 자바스크립트(JavaScript, 웹 브라우저에서 실행되는 프로그래밍 언어)로 돌아가서, 에디터 화면을 열었을 때만 점수가 계산된다. 키워드도 그 화면 안에서 넣으면 들어갔다.

    스크립트가 이걸 감지해서 경고는 띄워주게 됐지만, 근본 해결은 아니었다. 에디터를 열고 직접 넣는 수밖에 없었다. 그러다 자동화할 방법을 찾기 시작했다.

    wp.data 저장소에서 랭크매스 액션 찾기

    wp-admin(워드프레스 관리자 화면) 글 에디터를 열어둔 상태에서 시작했다.

    이 글의 코드는 브라우저 개발자 도구 콘솔(Console, 코드를 직접 실행할 수 있는 창)에 그대로 붙여 넣어도 돌아가는 코드다. 나는 같은 코드를 Playwright(브라우저 자동 조종 도구)로 실행했다. 워드프레스 블록 에디터는 wp.data라는 내부 저장소 시스템을 쓴다. 워드프레스 공식 문서에도 나오는 방식이다. 플러그인도 여기에 자기 저장소를 등록할 수 있다. 랭크매스도 그렇게 했다.

    콘솔에 이렇게 입력하면 랭크매스 저장소에 접근할 수 있다.

    wp.data.select('rank-math')

    그리고 액션(Action, 저장소에 변경을 가하는 명령)을 확인하려면 이렇게 입력한다.

    wp.data.dispatch('rank-math')

    여기서 액션이 87개나 나왔다. 이름을 하나씩 보다가 바로 눈에 띄는 게 있었다. updateKeywords, updateDescription, updateSerpDescription, updateTitle. 이름만 봐도 뭘 하는지 명확했다.

    아래 스크린샷은 이 방식으로 값을 넣은 글의 에디터 화면이다. 오른쪽 랭크매스 패널에 포커스 키워드와 점수(78/100)가 들어가 있다.

    랭크매스 포커스 키워드가 REST로 안 들어갈 때, wp.data로 직접 넣는 법 스크린샷 1

    액션 이름은 랭크매스 버전에 따라 바뀔 수 있다. 지금 여기서 나열하는 이름들은 현재 ujinify.com에 설치된 랭크매스에서 직접 확인한 것들이다. 버전이 다르면 이름이 달라질 수 있으니 반드시 직접 확인해야 한다.

    updateKeywords로 포커스 키워드 직접 입력하기

    확인했으니 바로 써봤다. 콘솔에서 이렇게 입력했다.

    wp.data.dispatch('rank-math').updateKeywords('세션 ID')

    포커스 키워드 칸에 바로 들어갔다. 4초쯤 기다렸더니 랭크매스 점수가 22점에서 71점으로 뛰었다.

    이게 맞는 방법이었다. REST API를 우회해서 에디터가 직접 받아서 처리하는 경로로 넣는 거다.

    저장까지 마치려면 core/editor(워드프레스 에디터의 핵심 저장소)의 savePost()를 써야 한다. 비동기 함수라서 await를 붙여서 호출했다.

    await wp.data.dispatch('core/editor').savePost()

    내가 쓴 순서는 이렇다. updateKeywords를 먼저 호출하고, 점수 갱신을 잠깐 기다린 뒤, savePost()로 저장했다.

    updateDescription, updateTitle로 다른 메타데이터 채우기

    포커스 키워드만 넣었는데 점수가 71점이었다. 메타 설명(검색 결과에 표시되는 글 요약문)이 비어 있었다.

    updateDescription으로 메타 설명을 넣었더니 73점이 됐다.

    wp.data.dispatch('rank-math').updateDescription('여기에 메타 설명 텍스트를 넣는다')

    같은 방식으로 SEO 제목도 바꿀 수 있다.

    wp.data.dispatch('rank-math').updateTitle('여기에 SEO 제목을 넣는다')

    updateSerpDescription도 있었는데, SERP에 표시되는 설명을 따로 관리하는 액션이다. 저장소에 이름이 있으니 확인해두면 된다.

    이후 본문 첫 10% 안에 키워드가 없다는 항목이 걸려 있어서 첫 문단에 문장을 하나 추가했다. 긴 문단을 쪼개고, 제목이 키워드로 시작하게 순서를 바꿨다. 첫 번째 글은 최종 76점까지 올라갔다. 두 번째 글은 70점에서 시작해서 본문에 실제 캡처 이미지 2장을 추가했더니 78점이 됐다.

    아래 스크린샷은 랭크매스 패널의 항목 목록이다. 통과 항목은 초록, 감점 항목은 빨강이다. URL 항목이 빨간색으로 남아 있다.

    랭크매스 포커스 키워드가 REST로 안 들어갈 때, wp.data로 직접 넣는 법 스크린샷 2

    점수 갱신이 늦거나 예전 값이 나올 때 확인법

    헷갈리는 지점이 있었다. window.rankMathEditor.resultManager.getResults()로 테스트 통과 여부를 읽었는데, 키워드가 제목에도 본문에도 분명히 있는데 전부 false로 나왔다.

    화면 항목 목록에는 ‘제목에 포커스 키워드를 사용하고 있습니다’가 통과로 표시돼 있었다. 이 값은 갱신이 늦거나 예전 스냅샷(특정 시점의 데이터 복사본)을 돌려주는 거였다. 그래서 getResults() 반환값은 신뢰하지 않기로 했다. 화면에 보이는 항목 목록을 기준으로 삼는다.

    또 하나. 통과(has: true)로 표시돼도 점수가 다 들어오지 않는 항목이 있다. 이미지 항목은 1/6점, 본문 길이는 2/8점처럼 부분 점수로 처리되는 경우가 있었다. 점수가 기대보다 낮게 나오면 이걸 먼저 확인해야 한다. 통과 여부만 보고 끝내면 안 된다.

    화면에 뜬 점수와 데이터베이스에 저장된 점수가 다를 수도 있다. 저장 후에는 REST API로 get-post-seo-meta를 조회해서 DB에 실제로 반영된 점수를 따로 확인해야 한다. 이 단계를 빼면 안 된다. 화면 숫자만 믿다가 나중에 데이터가 다른 걸 발견하면 그때는 더 번거롭다.

    이 방법의 한계와 실제 적용 시 주의점

    이 방법에는 명확한 한계가 있다. 숨기지 않겠다.

    • 브라우저 에디터를 열어야 한다. REST API나 MCP(Model Context Protocol, AI 도구가 외부 서비스에 명령을 보내는 통신 방식)만으로는 동작하지 않는다. 점수 계산 엔진이 브라우저 자바스크립트라서, 에디터 화면이 열려 있어야 실행된다.
    • 액션 이름이 버전마다 다를 수 있다. updateKeywords, updateDescription 같은 이름은 현재 내 사이트 랭크매스에서 직접 확인한 것들이다. 업데이트 후에 이름이 바뀌면 동작하지 않는다. 사용 전에 반드시 wp.data.dispatch('rank-math')를 콘솔에서 직접 실행해서 목록을 확인해라.
    • 저장 후 DB 값을 반드시 확인해야 한다. 화면 점수와 실제 DB에 저장된 점수가 다를 수 있다. REST API로 get-post-seo-meta를 조회하는 단계를 절대 생략하지 마라.
    • 올릴 수 없는 점수가 존재한다. URL에 한국어 키워드가 없는 항목(5점), 유료 Content AI 항목(5점)은 구조적으로 올리기 어렵거나 올리지 않을 항목이다. 이 점수를 제외하면 실제 달성 가능한 최대치는 처음부터 그만큼 낮다.

    수작업으로 키워드를 하나씩 입력하는 것보다는 낫다. 하지만 완전 자동화는 아니다. 에디터 화면을 열고 콘솔에서 코드를 실행하는 단계는 여전히 남는다.

    지금은 이 정도로 쓰고 있다.

    랭크매스 점수가 왜 에디터를 열어야 계산되는지는 랭크매스 SEO 16점→76점 글에, 같은 결의 버그 다섯 개는 워드프레스 SEO 버그 5개 총정리에 정리해뒀다.

    같은 랭크매스 주제로 이어서 읽으면 좋은 글: 랭크매스 무료 기능으로 고아 포스트 2개 찾아낸 이야기, 메타 설명 오류 — 색인됐는데 검색 안 되던 이유.

  • 세션 ID 문제, Claude Code에서 MCP가 안 보이는 이유

    세션 ID 문제, Claude Code에서 MCP가 안 보이는 이유

    ujinify.com 워드프레스에 MCP Adapter가 코어에 내장돼 있다는 걸 알게 됐다. 나중에 밝혀졌지만, 이 이야기의 결론은 결국 세션 ID 하나였다.

    거기에 랭크매스(워드프레스 SEO 플러그인)가 ability(어빌리티, 서버가 외부에 제공하는 기능 단위)를 25개나 등록해뒀다. get-seo-scores로 여러 글 점수를 한 번에 조회하거나, audit-site-seo/fix-site-seo로 사이트 전체를 진단하고 자동 수정하거나, set-homepage-seo로 설정까지 바꿀 수 있는 것들이었다.

    그전까지는 SEO 점수 하나 확인하려면 Playwright(플레이라이트, 브라우저를 자동으로 조종하는 도구)로 wp-admin 에디터를 직접 열어야 했다. 이걸 Claude Code에 MCP 서버로 등록하면 API 호출 하나로 끝낼 수 있겠다 싶었다. 그래서 등록했다. 그리고 아무것도 안 됐다.

    문제: MCP가 ‘연결됨’인데 tool이 하나도 안 보여요

    등록 자체는 간단했다.

    claude mcp add --transport http ujinify-wp <MCP 서버 URL> --header "Authorization: Basic ..."

    claude mcp list를 돌리면 “✔ Connected”가 떴다. 연결됐다는 뜻이다. 그런데 ToolSearch(툴서치, Claude Code에서 사용 가능한 도구를 찾는 기능)로 아무리 찾아봐도 랭크매스 tool(툴, 도구)이 하나도 잡히지 않았다. 매번 “No matching deferred tools found”였다. 세션을 새로 시작해봤다. 재시작도 해봤다. 결과는 똑같았다.

    서버는 연결됐다는데, 실제로 쓸 수 있는 tool은 하나도 없는 상태. 이건 좀 웃겼다.

    curl로 직접 테스트해보니 세션 ID가 필요했다

    Claude Code를 믿지 않기로 했다. curl(컬, 터미널에서 HTTP 요청을 직접 보내는 도구)로 MCP 서버에 직접 말을 걸어보기로 했다.

    먼저 initialize(초기화 요청, MCP 서버와 처음 악수하는 단계)를 호출했다. 서버는 정상 응답했다. 그런데 응답 헤더(header, 서버가 응답과 함께 보내는 부가 정보)를 보니 mcp-session-id라는 값이 딸려 내려왔다. 이 서버는 Streamable HTTP(스트리머블 HTTP, 요청마다 세션 ID를 주고받는 MCP 통신 방식)를 쓰는 타입이었다.

    그 상태에서 세션 ID 없이 바로 tools/list를 호출했다. 결과는 “Missing Mcp-Session-Id header” 에러였다. 반대로, initialize에서 받은 세션 ID를 Mcp-Session-Id 헤더에 실어서 tools/list를 다시 호출했더니 — 랭크매스가 등록한 tool 3개의 스키마(schema, 도구의 구조와 사용법을 정의한 명세)가 정상으로 내려왔다.

    서버는 100% 정상이었다. 문제는 Claude Code 쪽이었다.

    왜 Claude Code는 세션 ID를 못 챙겼을까

    MCP 통신은 핸드셰이크(handshake, 통신 시작 전에 서로 규칙을 맞추는 절차)가 필요하다. MCP 공식 스펙 문서에도 명시돼 있는 내용인데, 순서는 이렇다.

    • initialize 요청을 보낸다.
    • 서버가 응답 헤더로 세션 ID를 내려준다.
    • 이후 모든 요청에 그 세션 ID를 Mcp-Session-Id 헤더에 실어서 보낸다.

    Claude Code의 HTTP MCP 클라이언트가 이 두 번째와 세 번째 단계를 처리하지 못하고 있었다. initialize는 성공했지만, 거기서 받은 세션 ID를 이후 요청에 다시 실어 보내지 않는 것이다.

    claude mcp list의 “Connected” 표시는 initialize 성공만 확인한다. 그러니 이 핸드셰이크 실패를 잡아내지 못하고, 겉으로는 정상처럼 보인다. 연결은 됐지만 실제로 아무것도 못 쓰는 상태가 “Connected”로 표시되는 것이다. 별로였다.

    해결책: 직접 만든 함수로 세션 핸드셰이크 처리하기

    MCP tool 등록에 기대는 걸 포기했다. 대신 이 핸드셰이크 절차를 그대로 코드로 옮겼다.

    scripts/rankmath-mcp.ts에 callRankMathAbility 함수를 만들었다. 이 함수는 호출될 때마다 아래 순서를 자동으로 처리한다.

    • initialize 요청을 보내서 세션 ID를 받는다.
    • 받은 세션 ID를 헤더에 실어서 tools/call을 호출한다.
    • 결과를 반환한다.

    CLI(커맨드 라인 인터페이스, 터미널에서 명령어로 프로그램을 실행하는 방식)에서 바로 쓸 수 있게 npm run rankmath -- <ability-name> '<json-params>' 형태로도 만들었다. 기존 upload.ts의 getWpConfig()를 그대로 재사용해서 인증 정보를 따로 관리할 필요도 없게 했다.

    Claude Code가 못 하는 걸 직접 구현한 것이다. 우아하진 않지만 동작한다.

    실제로 점수를 가져왔을 때 검증 결과

    get-seo-scores ability(어빌리티, 여기서는 랭크매스가 MCP를 통해 제공하는 기능)를 호출해서 여러 글의 점수를 한 번에 받아봤다. 이전에 Playwright로 wp-admin 에디터를 직접 열어서 확인했던 점수와 정확히 일치했다. 132번 글 81점, 109번 글 83점, 42번 글 79점. 숫자가 맞았다.

    그다음엔 실제로 사이트 전체를 점검했다. seo_filter를 bad(50점 이하), empty-fk(포커스 키워드 없음), unscored(채점 안 됨)로 각각 돌렸다. 결과는 깔끔했다. 문제되는 글은 하나도 없었다. 포커스 키워드가 없는 건 애초에 필요 없는 고정 페이지 3개뿐이었다.

    브라우저를 한 번도 열지 않았다. 몇 초 만에 끝났다.

    이 방법의 한계, 읽기만 되고 쓰기는 안 된다

    명확히 해둬야 할 게 있다.

    get-seo-scores는 데이터베이스에 이미 저장된 점수를 ‘읽기’만 한다. 랭크매스의 점수 계산 엔진 자체는 여전히 브라우저, 구체적으로는 wp-admin 에디터의 자바스크립트에서만 돌아간다. 새 글을 올리거나 콘텐츠를 수정한 직후에 점수를 새로 계산하려면 여전히 에디터를 열어야 한다. REST나 MCP로는 재계산을 트리거할 방법이 없다.

    analyze-post-content라는 ability도 있다. 이건 점수를 주지 않는다. 원본 콘텐츠와 24개 테스트 목록, 채점 기준 문서를 던져주고 AI가 직접 채점하라는 방식이다. 손이 많이 가서 아직 시도하지 않았다.

    결국 이 방법으로 해결된 건 ‘이미 채점된 점수를 빠르게 읽는 것’이다. 채점 자체는 여전히 브라우저 의존이다. 한계를 알고 쓰면 된다. 모르고 쓰면 나중에 헷갈린다.

    다음에는 analyze-post-content를 실제로 써볼 생각이다. AI가 직접 채점한 결과가 랭크매스 공식 점수와 얼마나 차이 나는지 비교해보면 쓸만한지 아닌지 판단할 수 있을 것이다.

    “설정 화면에 값이 있다고 실제로 작동한다는 보장은 없다”는 패턴은 이번에도 반복됐다. 워드프레스 SEO 버그 5개 총정리 글에서 다룬 다섯 가지 사례와 정확히 같은 결이다. 이번엔 랭크매스 설정이 아니라 Claude Code의 MCP 연결 상태였다는 것만 다르다.

    세션 쪽에서 겪은 또 다른 문제는 Claude 5시간 한도 72% 찍힌 이유는 세션 길이였다에도 있다.

  • 워드프레스 SEO 버그 5개, curl로 찾은 공통 원인

    워드프레스 SEO 버그 5개, curl로 찾은 공통 원인

    블로그에 글이 15개쯤 쌓였을 때 돌아봤다. 그중 5개가 전부 워드프레스 SEO 설정을 자동화하거나 고치다가 만난 버그 이야기였다. 흩어져 있으니까 불편했다. 나중에 비슷한 문제를 다시 만났을 때 어느 글을 찾아야 할지 헷갈렸다. 그래서 한 페이지에 몰아서 정리하기로 했다.

    설정을 저장했는데도 작동하지 않은 이유

    다섯 개를 나란히 놓고 보니까 패턴이 보였다. 전부 같은 이야기였다.

    ‘설정 화면에 값이 있다고 해서 실제로 그게 적용되고 있다는 보장은 없다.’

    WPCode에서는 코드를 저장했는데 실제로는 깨진 채로 배포됐다. 랭크매스에서는 홈페이지 메타 설명을 입력해도 워드프레스 읽기 설정 때문에 그 값이 조용히 무시됐다. REST API(워드프레스에 데이터를 보내고 받는 통로)로 포커스 키워드를 보내도 저장이 안 되는 경우도 여러 번 있었다.

    관리자 화면의 저장 성공 메시지, REST API의 200 응답, 설정 페이지에 입력된 값. 이런 것들은 전부 ‘내가 뭔가를 입력했다’는 증거일 뿐이다. ‘그게 실제로 작동하고 있다’는 증거가 아니다.

    아래 다섯 개가 그 증거다.

    버그 1: 랭크매스 점수가 재계산되지 않는 이유 (16점→76점의 함정)

    랭크매스(워드프레스용 SEO 플러그인)가 매기는 SEO 점수가 16점이었다. 뭘 고쳐야 할지 몰랐다. 점수만 보면 아무것도 알 수 없었다.

    처음에는 REST API로 점수를 강제로 재계산시키려고 했다. 여기서 함정에 빠질 뻔했다. API 응답은 200으로 떴다. 성공처럼 보였다. 그런데 실제 점수는 그대로였다.

    원인은 단순했다. 랭크매스 SEO 점수는 wp-admin(워드프레스 관리자 에디터 화면)을 직접 열어야 제대로 계산된다. API로 우회하면 점수가 갱신되지 않는다. 에디터를 열고 나서야 점수가 76점으로 올라갔다.

    이 경험에서 배운 것은 하나다. API 응답이 성공이어도 실제 결과를 화면에서 직접 확인해야 한다. 200은 ‘요청이 도착했다’는 뜻이지 ‘원하는 대로 됐다’는 뜻이 아니다.

    → 전체 진단 과정: 랭크매스 SEO 16점→76점, API 함정 피하고 올린 과정

    버그 2: WPCode 보안 헤더가 깨지는 현상 (저장은 됐는데 적용 안 됨)

    WPCode(워드프레스에 코드 조각을 추가하는 플러그인)로 보안 헤더(Security Header, 브라우저에 보안 정책을 전달하는 HTTP 응답값)를 추가했다. PHP 코드 스니펫(snippet, 짧은 코드 조각)을 넣고 저장했다. 저장 성공 메시지가 떴다.

    그런데 실제로는 헤더가 적용되지 않고 있었다.

    curl(터미널에서 웹 페이지 응답을 직접 확인하는 명령어)로 라이브 페이지 응답 헤더를 확인하고 나서야 알았다. 보안 헤더가 없었다. 원인은 사소한 문법 오류였다. PHP 코드 안에 오타가 있었고, 그 오류 때문에 코드 전체가 실행되지 않았다.

    저장 성공 메시지만 보고 넘어갔으면 계속 몰랐을 거다. WPCode는 코드 내용의 오류를 검증하지 않는다. 저장 자체는 항상 성공한다. 그래서 더 위험하다.

    보안 설정을 추가한 뒤에는 반드시 curl로 응답 헤더를 직접 확인해야 한다. 저장 성공 메시지를 믿지 마라.

    curl -I https://내-사이트-주소.com

    위 명령어를 터미널에 입력하면 응답 헤더 목록이 나온다. 추가한 헤더 이름이 거기 있어야 진짜 적용된 거다.

    → 전체 진단 과정: WPCode로 보안 헤더 추가하다 코드가 깨진 이유

    버그 3~4: fire-your-seo-agency와 AI Link Genius로 만난 예상 밖의 문제들

    fire-your-seo-agency는 Claude Code에서 쓸 수 있는 스킬(skill, AI에게 특정 작업 방식을 지정하는 설정)이다. 이걸로 블로그 4개를 한꺼번에 SEO 점검했다.

    중간에 파일이 세 번 중복으로 받아지는 해프닝이 있었다. 이건 좀 웃겼다. 그래도 생각보다 빠르게 끝났다. 스킬 하나로 블로그 4개를 동시에 점검한다는 게 실제로 되는 일이라는 걸 이때 처음 확인했다.

    → 전체 진단 과정: fire-your-seo-agency 스킬로 4개 블로그 자동 SEO 최적화한 후기

    네 번째 버그는 AI Link Genius 이야기다. AI Link Genius는 랭크매스 안에 있는 내부 링크 분석 기능이다. 설치는 해놨는데 한 번도 안 써봤다. 어느 날 다시 살펴보다가 고아 포스트(Orphan Post, 다른 글에서 링크를 하나도 받지 못한 글)가 2개 있다는 걸 발견했다.

    그 글들은 검색 엔진이 찾아오기 어려운 상태였다. 내부 링크를 걸어주고 나서야 제대로 연결됐다.

    → 전체 진단 과정: 랭크매스 무료 기능으로 고아 포스트 2개 찾아낸 이야기

    이 두 버그에서 공통으로 배운 게 있다. 설치는 해놨지만 한 번도 안 써본 플러그인 기능이 있는지 주기적으로 점검해야 한다. 있는 기능을 모르고 있으면 없는 거나 마찬가지다.

    버그 5: 메타 설명이 검색엔진에 반영 안 되는 이유 (읽기 설정의 함정)

    홈페이지가 색인됐는데 메타 설명이 이상했다. 랭크매스에 분명히 입력해뒀는데, 검색 결과에 다른 문구가 나왔다.

    ‘색인 = 노출’이라고 착각하고 있었다. 아니었다. 색인됐어도 메타 설명이 틀리면 검색 결과가 이상하게 보인다.

    원인은 워드프레스 읽기 설정이었다.

    워드프레스 관리자 화면 → 설정 → 읽기 에서 홈페이지 표시가 ‘최신 글’로 설정되어 있으면, 랭크매스에 입력한 홈페이지 메타 설명이 무시된다. 대신 워드프레스 기본 태그라인이 메타 설명 자리에 들어간다.

    랭크매스 설정 화면에는 분명히 내가 쓴 문구가 있었다. 그런데 실제 HTML에는 태그라인이 들어가 있었다. curl로 확인하기 전까지 몰랐다.

    curl -s https://내-사이트-주소.com | grep -i "meta name=\"description\""

    위 명령어로 실제 HTML에 박힌 메타 설명을 확인할 수 있다. 설정 화면에 뭐가 적혀 있든 상관없다. 이 결과가 진짜다.

    홈페이지 메타 설명을 제대로 쓰려면 읽기 설정에서 ‘정적 페이지’를 선택하고 홈페이지를 지정해야 한다. 그래야 랭크매스가 입력한 값을 실제로 가져다 쓴다.

    → 전체 진단 과정: 메타 설명 오류 — 색인됐는데 검색 안 되던 이유

    다음 버그를 빨리 찾는 4가지 확인 순서 (curl 포함)

    다섯 번을 겪고 나서 확인 순서가 생겼다. 비슷한 문제를 만나면 이 순서로 본다.

    • 첫째, 설정을 저장한 뒤 바로 curl로 라이브 페이지를 확인한다. 저장 성공 메시지는 신뢰하지 않는다. curl -s 주소 | grep 확인할내용 으로 실제 HTML에 반영됐는지 바로 본다.
    • 둘째, REST API 응답이 200이어도 응답 바디를 다시 읽는다. 200은 요청이 도착했다는 뜻이다. 원하는 처리가 됐다는 뜻이 아니다. 응답 안에 실제로 뭐가 담겨 있는지 확인해야 한다.
    • 셋째, 설정 화면 말고 ‘진짜 소스’가 따로 있는지 의심한다. 워드프레스는 표면 설정 화면 뒤에 그 값을 실제로 가져다 쓰는 다른 설정이 있을 수 있다. 읽기 설정과 태그라인이 그 예다. 플러그인 설정만 보면 안 된다.
    • 넷째, 설치는 해놨지만 한 번도 안 써본 플러그인 기능을 주기적으로 점검한다. AI Link Genius처럼, 있는 기능인지 모르고 넘어간 것들이 반드시 있다.

    이 네 가지는 순서대로 해야 빠르다. 첫째를 건너뛰고 셋째부터 보다가 시간을 날린 적이 있다. 순서를 지켜라.

    지금은 5개지만, 앞으로 비슷한 버그를 만날 때마다 이 글에 추가할 생각이다. 워드프레스 SEO 설정을 직접 만지다가 막히는 사람에게 이 페이지가 첫 번째 참고 지점이 됐으면 한다. 경험이 쌓일수록 이 목록도 길어질 거다.

    같은 워드프레스 주제로 이어서 읽으면 좋은 글: 대표 이미지가 잘리는 이유 , 템플릿 비율 3:2→16:9 차이, 이미지가 삐져나가는 버그, 원인 찾고 자동화까지 한 후기, 워드프레스 SEO 플러그인 충돌 피하기 , 켜야 할 것, 꺼야 할 것.

  • 블로그 자동 크로스포스팅, 알아보고 완전 보류한 이유

    블로그 자동 크로스포스팅, 알아보고 완전 보류한 이유

    자동 크로스포스팅, 편하면 좋겠다고 생각한 게 시작이었다. ujinify.com 글이 올라갈 때마다 레딧과 X에도 같이 뿌려지면 손이 덜 갈 것 같았다.

    편하려던 것 하나로 시작했는데…

    ujinify.com에 글을 올릴 때마다 레딧이랑 X에도 자동으로 같이 올라가면 어떨까. 그런 생각이 들었다. 그래서 Claude Code(AI 코딩 도우미)한테 바로 물어봤다. 지금 블로그에 글을 업로드하면 레딧이나 X에도 자동 업로드되게 할 수 있냐고.

    Claude Code는 가능하다고 했다. 근데 “가능하다”는 말이 끝이 아니었다. 확인해야 할 게 줄줄이 나왔다.

    먼저 뭐부터 확인해야 할까? (API 키 체크)

    API 키(API key, 외부 서비스를 코드로 사용할 때 필요한 비밀번호 같은 값)부터 확인했다. 이미 가지고 있으면 바로 붙일 수 있으니까.

    내가 쓰는 프로젝트 폴더(project folder, 하나의 작업 단위로 묶인 파일 모음)가 11개다. 블로그, 숏츠, 릴스 관련 작업들이 각각 분리돼 있다. 각 폴더 안에 있는 .env, .env.local 파일(환경변수 파일, API 키 같은 민감한 값을 저장해두는 설정 파일)을 전부 뒤졌다. TWITTER, X_API, REDDIT 관련 키워드로 전부 검색했다.

    결과는 깔끔했다. 하나도 없었다.

    처음부터 앱을 새로 등록하고 키를 발급받아야 하는 상황이었다. 그 순간부터 “이게 정말 해볼 만한 건지”를 다시 따져보기 시작했다.

    프로젝트 폴더 11개의 .env 파일을 전부 검색해 레딧·X API 키가 없는 것을 확인한 터미널 화면

    위 화면이 실제로 11개 프로젝트 폴더를 뒤진 결과다. 관련 키가 하나도 없는 걸 직접 확인했다.

    X 크로스포스팅, 요금이 생각보다 깐깐했다

    X(구 트위터) API(Application Programming Interface, 외부 서비스 기능을 코드로 연결하는 통로) 공식 요금 페이지를 확인했다. 무료 티어(tier, 등급)가 있겠거니 했다. 없었다.

    구독제도 아니다. 완전 종량제(사용한 만큼만 요금을 내는 방식)다. 구조는 이렇다.

    트윗 유형 건당 요금
    일반 트윗 $0.015
    링크 포함 트윗 $0.200

    문제는 내 블로그 글에는 항상 링크가 들어간다는 거다. 크로스포스팅이라는 게 결국 블로그 링크를 X에 올리는 일이니까, 건당 $0.200이 적용된다.

    한 달에 8개 올린다고 치면 $1.6. 그렇게 보면 큰돈은 아니다. 근데 매번 돈이 나가는 구조라는 게 확인됐다. 자동화를 붙인다는 건 이 비용이 쌓인다는 뜻이다. 올리는 글이 늘어날수록 같이 늘어난다.

    레딧이 더 무섭다: 계정 정지의 위험성

    레딧 API는 개인용 소규모 스크립트라면 무료로 열려 있다고 한다. 돈 문제가 아니다.

    진짜 문제는 계정 정지다.

    레딧의 거의 모든 서브레딧은 자기 홍보 링크 비율을 엄격하게 제한한다. 흔히 말하는 10분의 1 법칙 같은 게 있다. 홍보 아닌 글 9개당 홍보 글 1개 정도만 허용된다는 기준이다.

    기계적으로 같은 도메인 링크를 반복 게시하면 스팸 필터에 걸린다. 계정이 아예 밴될 수 있다. 자동 크로스포스팅은 이 패턴을 정확하게 만들어낸다.

    ujinify.com 글 올릴 때 레딧·X에 자동 크로스포스팅 하고 싶었는데, 알아보고 나서 완전 보류로 정했다 스크린샷 2

    실제로 Claude Code와 이 리스크를 확인하는 과정에서 나온 내용이다. 기술적으로 가능하다는 것과, 해도 된다는 건 다른 문제였다.

    기존에 쌓아온 신뢰도가 한 번에 깎인다는 걸 알다

    이 부분이 가장 크게 와닿았다.

    지금까지 레딧이나 네이버 지식iN에 백링크 작업을 할 때는 직접 했다. 관련 질문 스레드를 직접 찾아서, 맥락에 맞게, 조심스럽게 답변을 달았다. 그렇게 쌓은 신뢰도가 있다.

    자동 크로스포스팅을 붙이면 그게 한 번에 깎인다. 방향이 완전히 반대다.

    신경 써서 만들어온 계정 신뢰도를 자동화 스크립트 하나가 스팸 계정으로 만들 수 있다. 그걸 알고 나니 선택지가 명확해졌다.

    최종 결정: 완전 보류로 정한 이유

    보류했다. 완전히.

    X는 기술적으로는 된다. 근데 건당 비용이 계속 나간다. 레딧은 API보다 계정 정지 위험이 훨씬 크다. 두 채널 다 지금 당장 붙일 이유가 없었다.

    지금 우선순위는 두 가지다. 애드센스 승인, 그리고 ujinify.com 자체 SEO(Search Engine Optimization, 검색엔진 최적화, 검색 결과 상위에 노출되게 만드는 작업) 노출이다. 여기에 자동 크로스포스팅을 얹는 건 도움보다 리스크가 크다.

    나중에 블로그가 어느 정도 자리를 잡으면 그때 다시 검토한다. 계정 신뢰도가 충분히 쌓이고, 수동으로도 어느 정도 커뮤니티 활동이 된 뒤에. 지금은 아니다.

    편하려고 시작한 건데, 알아볼수록 지금은 하지 않는 게 맞다는 결론이 나왔다. 그게 이번 조사의 결과다.

    기술적으로 되는 것과, 지금 해도 되는 것은 다른 질문이다. 이번에 자동 크로스포스팅을 알아보면서 그 차이를 제일 크게 배웠다. 앞으로도 새 자동화를 붙이기 전에는 비용과 리스크부터 먼저 따지기로 했다.

    크로스포스팅 대신 먼저 만든 예약 발행 기능은 예약 발행 기능을 직접 만들고 4개 글을 한 번에 올린 후기에 정리했다.

  • 이미지가 삐져나가는 버그, 원인 찾고 자동화까지 한 후기

    이미지가 삐져나가는 버그, 원인 찾고 자동화까지 한 후기

    이미지가 삐져나가는 버그, 처음엔 그냥 넘어갈 뻔했다. 블로그 글을 올리고 나서 멀쩡히 보이는지 확인하는 건 습관이다. 그날도 그냥 훑어보고 있었다.

    이미지가 삐져나가는 버그, 눈에 띄는 이상함: 스크린샷 하나가 삐져나가 보였던 이유

    본문을 읽다가 뭔가 이상했다. 스크린샷 하나가 오른쪽으로 쏠려 있었다. 다른 이미지들은 멀쩡한데 그것만.

    이유는 몰랐다. 그냥 딱 봐도 어색했다. 바로 Claude Code(AI 기반 코딩 보조 도구)에 말했다. “지금 본문에서 이 이미지만 오른쪽으로 쏠려있어. 사이즈 조절해서 중앙으로 보기 좋게 다시 작성해줘.” 원인 분석보다 고치는 게 먼저였다.

    아래가 당시 상태다. 텍스트 컬럼(column, 본문이 들어가는 세로 영역) 오른쪽으로 이미지가 넘쳐 있다.

    이미지가 삐져나가는 버그 — 텍스트 컬럼 밖으로 삐져나온 스크린샷

    이렇게 이미지가 본문 영역 밖으로 삐져나오면 레이아웃(layout, 화면 배치 구조) 전체가 깨진 것처럼 보인다. 작은 것 같지만 실제로 읽는 사람 입장에서는 바로 티가 난다.

    원인은 간단했다: 업로드 스크립트가 이미지를 줄이지 않고 있었네

    원인은 허무했다. 업로드 스크립트(script, 특정 작업을 자동으로 처리하는 코드 파일)가 이미지를 그대로 박아넣고 있었다. 리사이즈(resize, 이미지 크기를 줄이거나 늘리는 작업) 없이. 원본 그대로.

    원본 이미지의 가로 크기가 본문 컬럼 폭보다 훨씬 넓었다. 그러니 오른쪽으로 넘칠 수밖에 없다. 알고 나니 별거 아니었다. 근데 이게 지금까지 계속 이렇게 올라가고 있었다는 게 더 문제였다.

    이 버그(bug, 코드나 프로그램에서 발생하는 오류) 자체는 금방 고칠 수 있다. 문제는 따로 있다.

    버그 수정만으로는 부족한 이유: 같은 실수가 반복되면?

    지금 이 이미지만 고치고 끝내면 어떻게 될까. 다음에 글 올릴 때 또 같은 일이 생긴다. 스크립트가 그대로니까.

    버그를 발견했을 때 그 버그만 패치하고 넘어가는 건 임시방편이다. 원인이 코드 안에 남아 있으면 같은 실수는 반드시 다시 나온다. 타이밍만 다를 뿐이다.

    그래서 바로 한 마디 더 붙였다. “처음부터 작성할 때 이런 것 체크해서 최종 마무리해줘.” 재발 방지까지 해야 진짜 끝난 거라고 생각했다.

    자동화로 근본 해결하기: 스크립트에 리사이즈 기능 추가하기

    수정 방향은 하나였다. 업로드 스크립트 자체를 고치는 것.

    이미지를 올릴 때마다 수동으로 크기를 확인하는 건 지속 가능하지 않다. 귀찮으면 빠뜨리게 돼 있다. 그러니 스크립트가 알아서 처리하게 만드는 게 맞다.

    Claude Code에 요청해서 업로드 스크립트를 수정했다. 핵심은 두 가지다.

    • 새 글을 올릴 때 이미지가 자동으로 본문 폭에 맞게 리사이즈된다.
    • 리사이즈된 이미지는 중앙 정렬로 삽입된다.

    이제 이미지 크기를 신경 쓰지 않아도 된다. 스크립트가 처리한다. 이게 자동화(automation, 사람이 직접 하던 작업을 코드가 대신 처리하도록 만드는 것)의 의미다. 한 번 제대로 만들어두면 그 다음부터는 신경 끄면 된다.

    재발 방지까지: 업로드 후 최종 확인 프로세스 정하기

    스크립트를 고치는 것만으로는 완전하지 않다고 봤다. 코드가 제대로 동작하는지 눈으로 확인하는 단계가 없으면 또 다른 문제가 조용히 지나갈 수 있다.

    그래서 규칙을 명확히 정했다. Claude Code에 이렇게 못 박았다.

    • 이미지는 본문 폭 안에 딱 맞게, 중앙 정렬로 들어가야 한다.
    • 업로드 후에는 Claude Code가 직접 최종 확인을 하고, 그 결과를 나한테 컨펌받아야 한다.
    • 스크린샷으로 실제 화면을 직접 확인하는 것을 기본으로 한다.

    코드만 고치고 “됐겠지” 하고 넘어가지 않는다. 반드시 눈으로 확인한다. 이게 기준이다.

    이 사례에서 배울 점: 코드만 고치지 말고 프로세스도 함께

    이번 건 작은 버그였다. 이미지 하나가 삐져나간 것. 근데 거기서 멈추지 않은 게 핵심이다.

    버그를 고치는 건 시작이다. 왜 생겼는지 파악하고, 같은 일이 반복되지 않도록 구조를 바꾸고, 확인 단계까지 만드는 것이 진짜 마무리다.

    AI 도구를 쓸 때 “고쳐줘”만 하고 끝내는 사람이 많다. 그러면 똑같은 질문을 다음 달에 또 하게 된다. “왜 또 이러지?” 하면서.

    물어봐야 할 건 두 가지다.

    • 지금 이걸 어떻게 고치냐.
    • 앞으로 이게 안 생기려면 뭘 바꿔야 하냐.

    두 번째 질문을 안 하면 첫 번째 질문을 계속 반복한다.

    다음에는 업로드 스크립트 전체를 한 번 훑어볼 생각이다. 이미지 말고 다른 곳에서도 비슷한 게 조용히 지나가고 있을 수 있다. 결국 이미지가 삐져나가는 버그 하나가 전체 업로드 파이프라인을 점검하게 만든 셈이다.

    비슷한 패턴은 다른 데서도 반복됐다. WPCode로 보안 헤더 추가하다 코드가 깨진 사례도 결국 같은 교훈이었다 , 자동화 도구를 만들 땐 “일단 되는 것”과 “제대로 확인된 것”은 다르다.

    같은 워드프레스 주제로 이어서 읽으면 좋은 글: 대표 이미지가 잘리는 이유 , 템플릿 비율 3:2→16:9 차이, 워드프레스 SEO 버그 5개, curl로 찾은 공통 원인.

    좌표 값 하나를 잘못 잡아서 생긴 다른 버그는 자막이 카드 텍스트와 겹쳤다, y=h*0.8로 좌표 하나 바꿔 고친 이야기에도 정리했다.