Velog について
Velogは、ClaudeなどのMCPクライアントからVelogの記事を扱うMCPサーバーです。記事の閲覧、執筆、バックアップ、分析、図の生成に対応し、公開投稿は明示的に有効化するまで使えません。
主な機能
- 01記事の閲覧・検索・分析
- 02下書き作成と記事管理
- 03YAMLメタデータ付きMarkdownの出力
- 04図・シーケンス図・カバーの生成
- 05公開投稿には明示的な許可が必要
活用シーン
- 01ブログ内の過去記事を探す
- 02記事をバックアップして指標を確認する
- 03下書きを作成して既存シリーズに追加する
- 04記事用の図やカバーを作成する
MCP 対応
stdio方式のMCPサーバーとして、ローカルのMCPクライアントにVelogの記事閲覧、投稿、バックアップ、分析、画像生成のツールを提供します。環境変数で公開投稿の利用可否を制御します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y @milcho0604/velog-mcpVELOG_ACCESS_TOKENシークレット벨로그 access token. 둘 중 아무거나 있으면 쓰기가 열린다. 이쪽이 먼저 만료된다.VELOG_REFRESH_TOKENシークレット벨로그 refresh token. 둘 중 아무거나 있으면 쓰기가 열린다. 이쪽은 30일 간다.VELOG_ALLOW_PUBLIC1 이면 공개 발행이 열린다. 기본은 꺼짐이고, 모델은 이 값을 못 바꾼다.VELOG_ALLOW_PROFILE1 이면 프로필 수정이 열린다. 프로필 읽기는 언제나 된다.VELOG_CHROME_PATH로컬 크롬 실행 파일 경로. 다이어그램, 시퀀스, 표지 렌더링에 쓴다.ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
23掲載時のツール一覧 · 1 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| id | string | いいえ | 글 UUID. 이걸 주면 username/url_slug 는 불필요 |
| url_slug | string | いいえ | URL の最後のセグメント |
| username | string | いいえ | @ は付けません。例:"velopert" |
詳細
velog-mcp
벨로그をClaudeなどのMCPクライアントから操作するサーバーです。 記事の閲覧、下書きの作成、公開、丸ごとバックアップができます。

なぜまた作ったのか
ベル로그のMCPサーバーはすでに2つあります。この実装には3つの違いがあります。
1. 公開はデフォルトではなく、権限です。 インストール直後から、下書きの作成と非公開での公開ができます。公開での公開は環境変数を設定しないと有効になりません。このスイッチはモデルから操作できません。MCP設定ファイルを開く人だけが変更できます。
2. ベル로그の動作を推測せず、実測しました。 ベル로그のGraphQLは非公式で、ドキュメントがありません。このレポジトリでは、velog-io/velogのソースと実際の呼び出しを使って、実際の動作を確認し、記録しています。サーバー側の落とし穴6つがdocs/api-reference.mdに記載されています。エラーなしで空の結果が返る場合や、公開済みの記事が非公開になる場合などです。
3. ランタイム依存関係は2つです。 @modelcontextprotocol/sdk と zod のみです。
HTTP、テストランナー、TypeScriptの実行には、すべてNodeの組み込み機能を使います。
インストール
Node.js 22.18以上が必要です。実行されるのはコンパイル済みのdist/index.jsですが、開発と検証では.tsを直接実行しており、フラグなしで実行できるようになった最初のバージョンが22.18です。CIは22.18、24、26で実行します。
Claude Codeプラグインとして(推奨)
/plugin marketplace add milcho0604/velog-mcp
/plugin install velog@milcho
インストール時に4つの値を尋ねます。何も入力しなくてもインストールされ、読み取り専用で動作します。
| 尋ねる項目 | 入力しない場合 |
|---|---|
| Velog refresh token | 読み取り専用(閲覧・検索・統計はそのまま利用可能) |
| 公開での公開を許可 | 下書きと非公開での公開のみ |
| プロフィールの編集を許可 | プロフィールツールが無効 |
| Chromeのパス | 標準の場所から自動的に検出 |
**トークンはmacOSキーチェーンに保存されます。**設定ファイルに平文で残ることはありません。
sensitive: trueと宣言された値だけがキーチェーンに保存されることを、テストで検証しています(P7)。
値を後から変更するには、/plugin manageを実行します。
MCPサーバーとして使う
npmに公開済みなので、クローンせずにMCPクライアントからnpxで起動できます。設定ブロックとクライアントの対応範囲は設定を参照してください。
claude mcp add velog -e VELOG_REFRESH_TOKEN=여기에_토큰 \
-- npx -y @milcho0604/[email protected]
この方法では、トークンがクライアントの設定ファイルに残ります。上記のプラグイン方式ではキーチェーンに保存されます。
直接ビルドする
git clone https://github.com/milcho0604/velog-mcp.git
cd velog-mcp
npm install && npm run build
設定
MCPクライアントの設定ファイル(claude_desktop_config.json、.mcp.jsonなど)に追加します。
{
"mcpServers": {
"velog": {
"command": "npx",
"args": ["-y", "@milcho0604/[email protected]"],
"env": {
"VELOG_REFRESH_TOKEN": "여기에 토큰"
}
}
}
}
Claude Code CLIの場合:
claude mcp add velog -e VELOG_REFRESH_TOKEN=여기에_토큰 \
-- npx -y @milcho0604/[email protected]
ローカルのチェックアウトから実行するには、commandを
node /絶対パス/velog-mcp/dist/index.jsに変更します。
**どのクライアントで使えますか?**これはstdioサーバーです。クライアントがローカルプロセスとして起動します。 Claude Code・Claude Desktop・Cursorのように、MCPサーバーをローカルで実行するクライアントで利用できます。 claude.aiとChatGPTのウェブアプリでは利用できません。どちらもHTTPでアクセスできるリモートMCPサーバーのみを受け付けます。接続が自分のマシンではなく、相手側のサーバーから開始されるためです。ウェブで使うには、サーバーを公開ホスティングし、ベル로그のトークンをそのデプロイ先に渡す必要がありますが、そうするとトークンを自分のマシンだけに置いておく理由がなくなります。
トークンの取得方法
ベル로그には公開書き込みAPIがないため、ブラウザーのセッションクッキーで認証します。
- velog.ioにログイン
- 開発者ツール(
F12)→ Application → Cookies →https://velog.io - **
refresh_token**の値をコピー
VELOG_REFRESH_TOKENだけ設定すれば十分です。ベル로그のサーバーが有効期間の短い
access_tokenを自動で再発行し(authPlugin.mts)、このサーバーは応答に含まれる更新クッキーを受け取って使います。一度設定すれば30日間使えます。
VELOG_ACCESS_TOKENも受け付けますが、単独では1時間で期限切れになります。
トークンは環境変数からのみ読み取ります。ディスクには書き込まず、ブラウザーのクッキーデータベースやOSのキーチェーンにもアクセスしません。ただし、MCP設定ファイルに記述した値はそのファイルに平文で残ります。そのファイルの管理はユーザーの責任です。
**トークンがなくてもサーバーは起動します。**読み取り専用で動作し、公開記事の閲覧・検索・トレンド・ブログ統計は認証なしで利用できます。
権限
| 環境変数 | できること |
|---|---|
| (設定なし) | 全件読み取り・下書きの作成・非公開での公開・画像の生成とアップロード・スキーマのチェック — ツール23個 |
VELOG_ALLOW_PUBLIC=1 | …公開での公開を追加(is_privateパラメーターが追加されます) |
VELOG_ALLOW_PROFILE=1 | …プロフィールの編集を追加(ツール5個) |
2つのスイッチは独立しています。片方だけでも両方でも有効にできます。
"env": {
"VELOG_REFRESH_TOKEN": "...",
"VELOG_ALLOW_PUBLIC": "1",
"VELOG_ALLOW_PROFILE": "1"
}
有効と見なされる値は1、true、yes、onのみです。それ以外はすべて無効です。入力ミスで意図せず有効になることはありません。
公開での公開が無効の場合、どのツールにもis_privateパラメーターは存在しません。
モデルが公開を要求する方法自体がありません。有効にするとパラメーターが追加されますが、デフォルト値は引き続きtrue(非公開)です。
なぜ非公開がデフォルトなのか
慎重になりすぎているのではなく、実測に基づいています。ベル로그の公開制限は、is_private: falseの記事のみを数えます。
// apps/server/src/services/PostApiService/index.mts
count({ where: { fk_user_id, is_private: false, released_at: { gt: 5분전 } } })
if (count >= 10) {
updateMany({ where: { fk_user_id, released_at: { gt: 5분전 } },
data: { is_private: true } }) // 최근 글을 '전부' 비공개로
}
非公開記事はこのカウントを増やしません。ただし、isPostLimitReached()は公開かどうかを確認する前に必ず実行されるため、直近5分間に公開記事がすでに10件あると、非公開の下書きリクエストでも破壊的な動作を引き起こすことがあります。「増やさない」ことと「引き起こさない」ことは別です。そのため、書き込み時の再試行なしと独自の上限設定を維持しています。
公開記事はカウントを増やします。また、一度公開されるとRSS・検索インデックス・購読メールにすでに配信されているため、削除しても取り消せません。明示的なオプトインが必要なのは、こうした非対称性があるためです。
詳細はdocs/security.mdを参照してください。
ツール
23個あります。そのうち、ベル로그の状態を変更するのは10個だけです。
읽기 — 인증 불필요
| 도구 | 하는 일 |
|---|---|
velog_get_post | 글 하나를 본문까지 |
velog_list_posts | 사용자의 글 목록, 태그로 좁힐 수 있음 |
velog_search_posts | 키워드 검색. username 을 주면 그 블로그 안에서만 |
velog_trending_posts | 트렌딩 (day/week/month/year) |
velog_recent_posts | 벨로그 전체 최신 글 |
velog_get_user | 프로필·팔로워 수·소개 |
velog_list_series | 시리즈 목록 (글 수와 id 포함) |
velog_user_tags | 사용자가 쓰는 태그와 글 수 |
읽기 — 인증 필요
| 도구 | 하는 일 |
|---|---|
velog_whoami | 토큰이 어느 계정인지 (토큰 생존 확인용으로도) |
velog_list_drafts | 내 초안 목록과 id |
파생 — 벨로그에 없는 기능
| 도구 | 하는 일 |
|---|---|
velog_blog_stats | 조회수·좋아요·댓글 집계, 상위 글, 연도별·태그별 분포 |
velog_export_posts | 글을 YAML 프론트매터 붙은 마크다운으로 저장 |
velog_diagnose | 지금 벨로그 스키마가 이 서버의 기준선과 같은지 대조 |
쓰기
| 도구 | 효과 |
|---|---|
velog_create_draft | 초안 저장. 어떤 설정에서도 발행하지 않는다 |
velog_update_draft | 초안 전체 교체 — 생략한 필드는 초기화된다 |
velog_publish_post | 새 글 발행 |
velog_publish_draft | 기존 초안을 발행 (저장된 본문을 그대로 씀) |
velog_unpublish_post | 발행글을 초안으로 되돌림 |
velog_update_post | 발행글 수정 — 생략한 필드는 유지된다 |
velog_update_draft는 생략하면 초기화하고,velog_update_post는 유지한다. 의도한 비대칭이고 이유는 docs/tools.md 에 있다.
썸네일 자동 채움
thumbnail 을 생략하면 본문 첫 이미지를 썸네일로 쓴다. 목록·공유 카드가 글자만
나오는 걸 막기 위해서다. 무엇을 넣었는지는 결과에 항상 표시하고, 후보가 여럿이면
나머지도 함께 보여준다.
thumbnail 값 | 동작 |
|---|---|
| 생략 | 본문 첫 이미지로 자동 설정 |
| URL | 그대로 사용 |
null | 자동 채움 끄기 — 일부러 비워 두는 경우 |
코드블록·인라인코드 안의 이미지는 후보에서 제외한다(예제로 적어둔 마크다운이
썸네일이 되면 안 되므로). velog_update_post 는 기존 썸네일이 있으면 덮지 않는다 —
제목만 고쳤는데 목록 카드가 바뀌는 일이 없도록 한 것이고, 이때 null 은 "채우지 마라"이지
"지워라"가 아니다.
시리즈 — 이름으로 한 번에
series_name 에 이름을 주면 저장 전에 내 시리즈에서 찾아 같은 요청에 실어 보낸다.
글쓰기와 시리즈 등록이 한 번의 호출로 끝난다. id 는 사람도 AI 도 모르기 때문에 이름을 받는다.
series_name: "PostgreSQL" ← 대소문자·앞뒤 공백은 무시하고 찾는다
series_id: "e53810ca-..." ← id 를 알면 이쪽이 우선
⚠️ 못 찾으면 글을 저장하지 않는다. 조용히 시리즈 없이 저장하면 들어간 줄 알기 때문이다. 이때 있는 시리즈 목록을 함께 알려준다.
series_name·series_id 를 둘 다 생략하면 저장 뒤 결과에 내 시리즈 목록을 붙여준다.
이 조회가 실패해도 글은 이미 저장된 뒤이므로 저장을 실패시키지 않는다(취소도 삼킨다 —
여기서 실패로 보고하면 재시도 때 글이 두 번 생긴다).
⚠️ 벨로그 API 로는 시리즈를 만들 수 없다. 뮤테이션에 시리즈 관련이 하나도 없고
WritePostInput도series_id만 받는다. 새 시리즈는 벨로그 웹에서 한 번 만들면 그 뒤부터 이 도구로 붙일 수 있다.
username 을 받는 도구 중 velog_list_drafts·velog_blog_stats·velog_export_posts
는 생략하면 내 계정을 쓴다. velog_search_posts 는 생략하면 벨로그 전체를 검색한다.
그림 — 다이어그램·표지
| 도구 | 효과 |
|---|---|
velog_render_diagram | 구성도·흐름도를 그려 올린다 |
velog_render_sequence | 참가자와 순서 있는 메시지로 시퀀스 다이어그램을 그린다 |
velog_render_cover | 글 표지 카드(1200×630)를 만든다 |
velog_upload_image | 로컬 이미지를 올리고 마크다운을 돌려준다 |
넘기는 건 무엇이 있고 무엇이 어디로 흐르는지뿐이다. 색·여백·글자 실측·모서리 라운딩·캔버스 크기는 렌더러가 쥔다. 매번 처음부터 그리면 매번 다르게 생기기 때문이다.
수치는 전부 실측이다. 노드 폭과 줄바꿈은 브라우저 getBBox() 로 잰다 — 글자수로
추정하면 한글·영문이 섞인 라벨에서 반드시 틀린다. 캔버스는 다 그린 뒤에 내용
bbox 로 정하므로 그림이 잘릴 수가 없다.
그리고 스스로 감사해서 여섯 가지를 보고한다:
카드 밖으로 삐져나온 글자 · 억지로 맞추려 눌린 자간
노드를 관통하거나 노드 뒤에 숨은 선 · 그룹 이름표를 가린 선
선끼리 겹침 · 노드끼리 겹침 · 라벨이 카드나 그룹 이름표에 얹히거나 그룹 테두리에 걸침
감사에 하나라도 걸리면 올리지 않는다. 그리고 그걸 끄는 스위치는 없다.
벨로그에는 이미지 삭제 API 가 없고 업로드 한도도 깎이니, 어설픈 그림은 올리는 것보다
고쳐 그리는 게 낫다. 모델이 스스로 켤 수 있는 우회는 방어가 아니다 —
공개 발행 스위치와 같은 이유다(ADR 0004).
감사에 떨어진 PNG 는 이 서버로 올릴 길이 없다. upload:false 로 그려도 그 산출물은
거부 목록에 오르고, 경로를 velog_upload_image 에 줘도 막힌다 — 그 두 단계 우회를
막으려고 만든 장치다. 고쳐서 다시 그리는 것이 유일한 경로다.
(감사를 통과한 PNG 는 upload:false 로 그린 뒤 경로를 넘겨 올릴 수 있다.)
아이콘은 내장 28종(server·database·cloud·clock·alert …)이고 전부 도형
조합이다. 밖에서 받아오는 게 하나도 없다 — 렌더러는 DNS 를 막은 채로 돈다.
크롬이 필요하다 (크로미움 계열이면 된다: Edge·Brave·Chromium). macOS·리눅스·
윈도우에서 알아서 찾고, 다른 데 있으면 VELOG_CHROME_PATH 로 지정한다.
이 중 브라우저를 쓰는 건 velog_render_diagram, velog_render_sequence, velog_render_cover 셋뿐이고,
velog_upload_image 를 포함한 나머지 19개는 크롬 없이 동작한다.
비용은 실측해서 밝혀 둔다. 그림 한 장에 크롬 911개·최대 약 1GB 를 34초 쓰고
0 으로 돌아온다. 이건 크롬의 바닥이지 우리 그림 탓이 아니다.
좌표·글자·개수에는 전부 상한이 있고, 캔버스 상한(6000px/900만px)은 페이지 안에서
걸린다 — 브라우저는 크기를 받는 순간 표면을 준비하므로 바깥에서 막으면 늦다.
렌더는 줄을 세운다 — MCP 클라이언트가 도구를 병렬로 부르기 때문에, 안 그러면
그림 다섯 장 요청에 크롬 45개·6GB 가 된다. 줄을 세우면 동시 4회도 한 장 분량으로
고정된다. 10회 연속에서 누적이 없는 것도 확인했다.
프로필 수정 — VELOG_ALLOW_PROFILE=1
도구 5개가 추가된다: velog_update_profile(이름·한줄소개), velog_update_about,
velog_update_blog_title, velog_update_social_links, velog_update_profile_image.
설정이 없으면 등록조차 되지 않는다.
게이트를 둔 건 위험해서가 아니다 — 전부 되돌릴 수 있고 본인 계정에만 영향이며
어디로도 배포되지 않는다. 이유는 혼동이다: 프로필의 short_bio 와 글의
short_description 은 이름이 비슷하다. "소개 좀 고쳐줘" 가 어느 쪽인지 모호할 때,
스위치가 꺼져 있으면 잘못 짚어도 프로필에 손이 닿지 않는다.
velog_update_profile 은 생략한 항목을 유지한다. 벨로그의 UpdateProfileInput
은 display_name 과 short_bio 를 둘 다 필수로 받아서 한쪽만 보내면 다른 쪽이
빈 문자열로 덮인다 — 그래서 현재 값을 읽어 채워 보낸다.
사용법
설정이 끝나면 MCP 클라이언트에 그냥 말하면 된다.
"오늘 고친 버그로 벨로그 초안 잡아줘"
→ 마크다운을 쓰고 초안으로 저장, 편집 URL 을 준다
"작년에 HTTP/2 로 뭐 썼더라"
→ 내 글 안에서 검색
"내 글 조회수 상위 10개랑 어떤 태그가 제일 많이 읽혔는지"
→ 블로그 전체를 훑어 집계
"내 글 전부 ~/blog-backup 에 백업해"
→ 프론트매터 붙은 .md 로 저장
"그 초안 발행해줘"
→ 기본은 비공개. 공개는 VELOG_ALLOW_PUBLIC=1 이 있어야 한다
"요청이 LB 에서 워커 거쳐 레디스까지 어떻게 흐르는지 그려줘"
→ 그림을 그리고 자가감사한 뒤 올리고, 본문에 붙일 마크다운을 준다
"이 글 표지 이미지 만들어줘"
→ 1200×630 카드. 주소를 velog_update_post 의 thumbnail 에 넣으면 표지가 된다
되돌릴 수 없는 도구에는 destructiveHint 가 붙어 있다. 다만 annotation 은
«힌트» 이지 차단이 아니다 — 호출 전에 승인을 물을지는 MCP 클라이언트 설정에 달렸다.
서버가 막는 것은 따로다: 공개 발행은 VELOG_ALLOW_PUBLIC=1 없이는 경로 자체가 없고,
쓰기는 재시도하지 않으며, 공개 발행은 이 서버 인스턴스 안에서 5분에 5건으로
스스로 제한한다(비공개 발행·초안에는 이 제한이 걸리지 않는다).
백업 파일 형식
---
title: "글 제목"
date: 2022-12-31T18:32:39.790Z
slug: "url-slug"
url: "https://velog.io/@username/url-slug"
tags: ["태그1", "태그2"]
likes: 260
views: 16323
---
마크다운 본문…
개발
npm test # node:test 로 .ts 직접 실행 — jest·ts-node 없음
npm run typecheck # 테스트 포함 — 종전엔 제외돼 실제 오류가 숨어 있었다
npm run lint # typescript-eslint (타입 기반)
npm run build # tsconfig.build.json (dist 에 테스트 미포함)
npm run schema:dump # 현재 벨로그 GraphQL 스키마 덤프
npm run schema:baseline # schema/baseline.json 을 실측으로 다시 만든다 (velog_diagnose 의 기준선)
npm run schema:baseline -- --check # 쓰지 않고 «지금 기준선이 맞는지» 만 본다
테스트 684건(0.9.6 기준). safety.test.ts 가 보안 불변식(A1A13)을,
R23, D1)과 시퀀스 불변식(S1render.test.ts 가 구성도 불변식(R1S12)을,
P28)을 고정한다.
깨지면 우회하지 말고 왜 깨졌는지부터 볼 것.plugin.test.ts 가 포장 불변식(P1
여기 있는 방어는 전부 일부러 망가뜨려 확인했다. 소스 변이 54종 + 발행 관문
자체를 겨눈 변이 12종(scripts/gate-mutation.sh), 각각이 검사를 정확히 1건씩
실패시켜야 한다. 방어를 지웠는데도 통과하는 테스트는 테스트가 아니다.
이 저장소에도 그런 게 여럿 있었고, 그렇게 해서 고쳤다.
문서
| 문서 | 내용 |
|---|---|
| docs/PRD.md | 기획서 — 목표·비목표·성공 기준 |
| docs/architecture.md | 구조, Node 타입 스트리핑이 허용하는 TS 부분집합 |
| docs/api-reference.md | 벨로그 GraphQL 스키마 실측 + 서버 함정 |
| docs/security.md | 토큰 취급, 권한 모델, 의도적으로 뺀 기능 |
| docs/tools.md | 도구 카탈로그와 주의사항 |
| docs/decisions/ | 설계 결정 기록 (ADR) |
| CHANGELOG.md | 버전별로 무엇이 깨져 있었고 무엇이 고쳐졌나 |
참고
벨로그 내부 GraphQL API 를 쓴다. 비공식이라 예고 없이 바뀔 수 있다.
뭔가 깨지면 npm run schema:dump 를 돌려 docs/api-reference.md 와 diff 하는 게
가장 빠르다.
벨로그 이용약관에는 자동화 접근을 제한하는 조항이 없다. 본인 토큰으로 본인 글을 다루는 것은 권한 내 행위이고, 게시물 저작권은 회원에게 귀속된다(제5조).
라이선스
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。