Google Search Console + MCP: Claude에게 검색 데이터를 제공하는 3가지 방법 (그리고 제가 구축한 과정)
요약
본 글은 Search Console API를 활용하여 SEO 데이터를 추출하고, 이를 Claude와 같은 AI 에이전트가 분석할 수 있도록 연결하는 방법을 다룹니다. Google의 공식 MCP 서버 부재로 인해 직접 연결(wire up)해야 하며, 구체적인 API 사용법과 데이터 처리 시 주의사항을 안내합니다.
핵심 포인트
- Search Console은 유용한 SEO 데이터를 제공하지만 접근성이 문제입니다.
- API를 통해 검색어 노출/클릭/순위 등 핵심 데이터를 추출할 수 있습니다.
- 데이터 분석 시 속성 형식, 지연 시간, 순위 계산 방식 등에 주의해야 합니다.
- 호스팅형 커넥터는 편리하나 비용이 발생하고 다중 소스에 적합합니다.
Search Console은 대부분의 개발자들이 열어보지 않는 가장 유용한 SEO 데이터입니다. 이 도구는 어떤 검색어(query)가 페이지를 노출시키는지, 사람들이 얼마나 자주 클릭하는지, 그리고 어느 순위에 랭크되는지를 알려줍니다. 이를 '이번 주에 이 세 가지를 수정하세요'라는 구체적인 작업 목록으로 만드는 것은 지루한 표 작업이며, 이는 에이전트(agents)가 가장 잘 수행할 수 있는 영역입니다.
문제는 접근성(access)입니다. Google은 공식 Search Console MCP 서버를 제공하지 않기 때문에, 직접 연결(wire up)해야 합니다. 이 글에서는 다음 내용을 다룹니다:
- API가 제공하는 것 (그리고 그 특이점)
- 이를 MCP를 통해 노출시키는 세 가지 방법
- 제가 제품에 호스팅한 방법을 구축하고, 그 과정에서 발생했던 버그
- 데이터를 작업으로 전환하는 프롬프트(Prompts)
고지 사항: 아래의 Route C는 제 제품(Blogizi)입니다. Route A와 B에는 포함되어 있지 않습니다.
1. 2분 만에 이해하는 API
유용한 거의 모든 정보는 하나의 엔드포인트, searchanalytics.query에서 나옵니다:
import { google } from "googleapis";
const searchconsole = google.searchconsole({ version: "v1", auth: oauthClient });
...
에이전트에게 중요한 특이점(quirks)들은 다음과 같습니다:
- 두 가지 속성 형식. 도메인 속성은
sc-domain:example.com입니다. URL 접두사 속성은 뒤에 슬래시가 붙은https://example.com/형태입니다. 둘 다 정규화(Normalize)하지 않으면 인증 버그처럼 보이는 403 에러를 받게 됩니다. - 데이터 지연 시간은 약 2~3일입니다. 만약 에이전트가 이를 고려하지 않고 '지난 7일'을 비교한다면, 트래픽이 급격히 감소하고 있다고 잘못 알려줄 것입니다.
- 행(Rows)은 클릭 수로 정렬됩니다. 이 점을 염두에 두세요. 이는 섹션 3의 버그입니다.
- 순위(Position)는 노출수(impressions)를 가중치로 한 평균값입니다. 여러 행에 걸쳐 집계할 때는 평균값을 내지 말고, 노출수를 기준으로 가중치를 부여해야 합니다.
- 원하는 범위(scope)는
webmasters.readonly입니다. 데이터를 읽는 에이전트에게 속성에 대한 쓰기 권한을 가질 이유가 없습니다.
- Google Cloud 프로젝트를 생성합니다.
- Search Console API를 활성화합니다.
- OAuth 클라이언트 또는 서비스 계정을 만듭니다. 서비스 계정의 경우, 해당 이메일을 Search Console의 속성(property) 사용자로 추가해야 합니다.
- 서버가 자격 증명 JSON 파일(
credentials)을 가리키도록 설정하고 이를 클라이언트에 등록합니다:
claude mcp add gsc -- npx some-gsc-mcp-server --credentials ./service-account.json
장점: 무료이며, 전체 API 접근(URL 검사, 모든 차원, 다수 사이트)이 가능하고 데이터가 로컬 머신에 보관됩니다.
단점: Cloud Console 설정에 약 20분이 소요됩니다. 로컬 프로세스로 실행되므로, 프로세스 생성이 불가능한 호스팅 에이전트에서는 작동하지 않습니다.
B. 호스팅형 데이터 커넥터 (Hosted data connectors)
여러 마케팅 데이터 플랫폼에서 Google OAuth를 이미 처리하는 호스팅형 MCP 엔드포인트를 제공합니다. 이들은 종종 GA4 및 광고 데이터와 함께 번들로 제공됩니다. 유료이며 다중 소스(multi-source)이기 때문에 에이전시에 적합합니다.
C. 발행 플랫폼에 내장 (Built into the publishing platform)
이것은 제가 직접 구축한 방식입니다. 그 이유는 다음과 같습니다: SEO 에이전트의 루프는 성능 읽기 → 변경할 내용 결정 → 게시물 수정 순서로 진행됩니다. 만약 읽기와 쓰기가 서로 다른 MCP 서버에서 이루어진다면, 에이전트는 신원(identity)을 연결해야 합니다 (어떤 GSC 페이지가 어떤 게시물인가?). 하지만 같은 서버에 있다면, get_search_performance와 update_post가 프로젝트와 URL 공간을 공유할 수 있습니다.
claude mcp add --transport http blogizi https://blogizi.com/api/mcp \
--header "Authorization: Bearer $BLOGIZI_API_KEY"
대시보드에서 'Google 연결'을 한 번 클릭하고 속성을 선택하기만 하면 됩니다. Cloud 프로젝트가 필요 없습니다. 다음은 작동 방식입니다.
3. 호스팅 버전 구축하기 (Building the hosted version)
OAuth, 사용자당 한 번만 진행
const GSC_SCOPES = [
"https://www.googleapis.com/auth/webmasters.readonly",
"openid",
...
리프레시 토큰(refresh token)은 저장 시 암호화됩니다. 만약 Google이 리프레시 토큰을 반환하지 않는 경우 (사용자가 이전에 동의한 경우), 콜백 메시지를 통해 사용자에게 앱을 Google 계정 권한에서 제거하고 다시 시도하도록 안내해야 합니다. 사용자들이 이 상황에 직면할 것이므로, 오류 메시지에는 정확히 그렇게 명시되어야 합니다.
캐싱(Cache)을 사용하고 프록시(Proxy)는 사용하지 않습니다.
MCP 도구는 Google 라이브(live)를 호출하지 않습니다. 매일 크론(cron) 동기화가 바인딩된 각 속성(bound property)을 스냅샷으로 저장하며, 이 도구는 그 스냅샷을 읽어옵니다:
{ "crons": [{ "path": "/api/cron/gsc-sync", "schedule": "0 6 * * *" }] }
이 동기화 과정은 7일, 28일, 그리고 90일 기간에 걸쳐 date, query, page 차원(dimension)을 병렬로 실행합니다. 수동 새로고침에는 5분간의 대기 시간이 필요합니다.
캐싱이 필요한 이유:
- 에이전트가 도구를 많이 호출하기 때문입니다. "내 SEO 분석" 세션 하나만 해도 다양한 기간으로
get_search_performance를 5~10번 호출할 수 있습니다. 이것이 30개의 Google API 호출로 이루어져서는 안 됩니다. - 지연 시간(Latency) 문제: 스냅샷 읽기는 밀리초 단위이지만, 라이브 API는 그렇지 않습니다.
- 어차피 데이터가 2일 이상 오래되었습니다. 실시간 구매는 아무 의미가 없습니다.
도구 자체
server.registerTool(
"get_search_performance",
{
...
설계 노트:
days는 숫자가 아닌 리터럴 유니온(literal union)입니다. 에이전트는 30일이나 45일을 요청하는 데 아무 문제가 없습니다. 리터럴 유니온을 사용하면 스키마가 어떤 기간이 정확히 존재하는지 명시하므로, 모델은 오류를 발생시키는 대신 그중 하나를 선택하게 됩니다.range와lastSyncedAt을 반환하세요. 그러면 에이전트는 "10월 8일까지의 데이터"라고 말할 수 있으며, 이것이 실시간이라는 것을 암시하지 않습니다.- 행(row)은 1,000개가 아닌 25개입니다. 도구 출력은 컨텍스트 창에 들어갑니다. 쿼리 25개와 페이지 25개만으로도 모델을 압도하지 않으면서 근접한 성공 사례를 찾기에 충분합니다.
제가 배포했던 버그
기사 스크린샷을 찍는 동안, 저는 제 대시보드의 상위 쿼리 목록이 알파벳순이라는 것을 발견했습니다: "astro app", "nanoclaw", "surfer seo" 등입니다. 제 노출(impression)의 4분의 1을 담당하는 핵심 쿼리가 그 목록에 없었습니다.
동기화 과정은 rowLimit: 50을 요청했고, 행들을 API 순서로 저장했습니다. 하지만 이 API는 클릭 수(clicks)를 기준으로 정렬합니다. 신규 사이트의 경우 거의 모든 쿼리가 클릭 수가 0이므로, 모든 것이 동률 처리되고 저는 알파벳순으로 정렬된 결과를 받았습니다. 상위 50개(그리고 나중에는 25개)로 자르면서 가장 많이 노출된 쿼리 대신 알파벳 순서가 빠른 쿼리들이 유지되었습니다. 더 심각한 것은, 이것이 MCP 도구가 반환하는 것이었기 때문에 에이전트들은 알파벳순의 샘플을 분석하고 있었다는 점입니다.
해결책은 광범위하게 데이터를 가져와 실제로 중요한 것에 대해 정렬하는 것입니다:
const rows = mapApiRows(res.data.rows) // rowLimit: 1000으로 요청됨
.sort((a, b) => b.clicks - a.clicks || b.impressions - a.impressions)
.slice(0, 50);
MCP 도구에 API를 래핑하는 모든 사람을 위한 일반적인 교훈: 자르기(truncation)는 제품 결정입니다. 당신이 잘라낸 것은 모델에게 보이지 않으며, 모델은 그것을 요청해야 한다는 것을 알지 못합니다.
4. 가치가 있는 프롬프트들
이들은 세 가지 경로 모두에서 작동합니다.
클릭을 얻지 못하는 제목들
지난 28일간의 검색 성과를 알려주세요. 노출(impressions)은 200개 이상이지만, 비슷한 위치에 있는 페이지들에 비해 클릭률(CTR)이 현저히 낮은 페이지는 무엇인가요? 각 페이지별로 상위 검색어(top query)를 기반으로 새로운 제목과 메타 설명을 제안해 주세요.
페이지 1 근접한 것들
제가 8~20위에 순위가 높은 검색어는 무엇인가요? 각각에 대해: 어떤 페이지가 순위를 차지하는지, 검색자가 원하는 것과 비교했을 때 무엇이 부족한지, 그리고 제 다른 포스트 중 어느 것이 이 페이지로 링크해야 하는지 알려주세요.
제공하지 못하고 있는 수요
순위가 높은 페이지가 제 홈페이지나 느슨하게 관련된 포스트인 검색어 목록을 작성해 주세요. 의도(intent)별로 그룹화하고 새로운 포스트나 섹션을 제안해 주세요.
쇠퇴하는 포스트들
지난 7일간의 일별 클릭수를 28일 및 90일 비율과 비교해 주세요. 보고 지연 때문에 지난 3일은 무시해주세요. 어떤 페이지들이 하락세이며, 그 안에 있는 무엇이 오래되었을 가능성이 높은가요?
배포하기(Ship it)
상위 세 가지 변경 사항을 적용하고
update_post로 초안 저장해 주세요.
한 습관: 모든 추천에 대해 그 뒤의 숫자를 보여달라고 요청하세요. 모델은 때때로
- 다수의 사이트, 심층 감사(deep audits), URL 검사: 자체 호스팅 오픈 소스 서버.
- GA4, 광고 및 GSC를 함께 사용하는 에이전시: 호스팅형 다중 출처 커넥터.
- 하나의 제품 블로그가 있고, 발견한 것을 에이전트가 수정하길 원할 때: 계속 읽고 동일한 서버에 게시하세요. 이것이 경로 C이며, 위의 패턴으로 직접 구축할 수 있습니다.
더 긴 비교 내용은 여기에서 확인하실 수 있습니다. 만약 여러분이 GSC MCP 서버를 직접 구축했다면, 행 제한(row-limit)/정렬 문제를 어떻게 처리했는지 듣고 싶습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기