Claude Code から Substack に直接記事を投稿する — Substack MCP の作り方・仕組み・使い方
結論を先に置きます
Substack には公開された投稿用 API がありません。なので私が作っちゃいました。
X や note にあるような、サードパーティが投稿を作成・公開できる公式エンドポイントは存在しません。すべての記事公開は、基本的に Substack の Web エディタ経由でしかできません。
これは、執筆ワークフローを Claude Code に任せたい人にとって、地味に大きな壁です。
そこで、`python-substack` という非公式ライブラリの上に薄い MCP レイヤーを被せて、Claude Code から会話的に Substack を操作できるようにしたのが本稿で扱う `substack-mcp` です。
認証は Chrome の Cookie を借りる方式。Substack 側からは「自動化」が一切見えない。
入出力は MCP プロトコル。Claude Code から普通の会話として呼べる。
さらに `substack-article` スキルを `npx skills add` で入れると、企画→執筆→サムネ→公開を一気通貫で頼める。
リポジトリはここです:<https://github.com/nanameru/substack-mcp>
また、これからもsubstack-Skillsのアップデート(ポッドキャスト自動生成)や、活用術(リプライの自動送信や、チャットを自動作成も実はできます。)を発信していく予定なので、ぜひTaiyo | サブスタ自動化ツール公開中をサブスクしてください!
---
1. なぜこれが必要だったのか
Substack の API ドキュメントは、読み取り系(RSS、購読者リストの一部)しか公開されていません。
「投稿を作る」「カバー画像を設定する」「予約公開する」みたいな書き込み系は、ドキュメントがそもそも存在しない。Web エディタの裏側で動いている内部 API だけが実装で、その仕様は外に出ていません。
つまり、自動化したいなら 3 つの選択肢 しかありません。
1. Web エディタを Playwright で操作する → 重い、遅い、ボット検知に弾かれる
2. 内部 API を読み解いて叩く → 不安定、Substack 仕様変更で死ぬ可能性
3. 諦めて手で投稿する → 自動化の意味がない
このうち 2 番 を選んだのが `python-substack` というライブラリで、`substack-mcp` はその上に乗っています。
Claude Code から呼びたかった
執筆を Claude にやらせたいケースは、結構あります。
過去の note 記事を Substack 用に書き直して投げる
ローカル Markdown を一発で公開する
スケジュール記事を CLI 経由で仕込む
複数アカウントの Publication を運用する
これら全部、「Claude Code に会話で頼んだら裏でやっておいてくれる」が理想形です。MCP(Model Context Protocol)は、まさにそのためのプロトコル。
書き込み API がない → 自動化しにくい → でも MCP の表面さえ整えれば AI に任せられる。この発想で作ったのが `subsack-mcp` です。
---
2. 設計の中心:Chrome の Cookie をそのまま借りる
ここが `substack-mcp` の 一番の設計判断 です。
Playwright を選ばなかった理由
最初の素朴なアイデアは「Playwright でブラウザを起動して、ID/PW を流し込む」でした。
実装も書きました。リポジトリには `browser_setup.py` という Playwright 経由のフォールバックが残っています。
ただ、デフォルトでは使いません。理由は単純で、Substack のボット検知に頻繁に弾かれるからです。
具体的には:
Cloudflare のチャレンジが入る
ログイン後にセッションが正常に発行されない
User-Agent やフィンガープリントで「自動化ブラウザ」と判定される
体感で半分以上が失敗。運用に乗せられる信頼性ではありませんでした。
ログイン**ではなく**、セッション**を借りる**
代わりに採用したのが、`pycookiecheat` で Chrome の暗号化 Cookie DB から `substack.sid` を直接読み出す 方式です。
ポイントは、Substack 側からは「自動化」が一切見えないこと。
ユーザーが普段ブラウザで使っているそのままのセッション Cookie を、ローカルから読んでいるだけ。
新しいログインは発生しない
新しい User-Agent も飛ばない
Substack のサーバーには「いつもの本人」しか見えない
これで Cloudflare のチャレンジも、ボット検知も、すべてバイパスできます。
サポートしているブラウザは Chrome / Brave / Edge / Chromium / Vivaldi / Opera。
Publication URL は覚えなくていい
Cookie を取れたあと、`chrome_setup.py` は `https://substack.com/api/v1/user/profile/self` を叩いて、ユーザーの primary publication を検出します。
`custom_domain` があればそちらを優先
なければ `<subdomain>.substack.com` を採用
ユーザーは自分の Publication URL を入力しません。入力させるのではなく、検出する。地味だけど大事な体験設計です。
---
3. macOS Keychain との 1 回だけのやりとり
Chrome は Cookie を Keychain で暗号化しているため、初回だけ macOS が 2 回連続で Keychain アクセスを聞いてきます。
1 枚目:機密情報を「使用」しようとしている
「`Chrome Safe Storage` に保存されている機密情報を使用しようとしています」 と出ます。
ここでキーチェーン「ログイン」のパスワードを入力して、「常に許可」を選びます。
2 枚目:キーへの「アクセス」をしようとしている
その直後にもう一回、「キーチェーンに含まれるキー `Chrome Safe Storage` へアクセスしようとしています」 が出ます。
これも同じく「常に許可」。
1 度許可すれば次回以降は無音
両方を「常に許可」しておけば、`python3.x` がそのキーチェーンに対する永続的なアクセス権を持ちます。
次から `substack-mcp-setup` を走らせても、プロンプトは出ません。
プロンプトを出し直したい場合
テスト用、スクショ用、別アカウントへの切り替え用などで再度プロンプトを表示させたいときは:
1. Keychain Access アプリを開く
2. 検索欄に `Chrome Safe Storage` を入力
3. 出てきた項目をダブルクリック
4. 「アクセス制御」タブを開く
5. リストから `python3.x` を選択して「−」で削除
6. 「変更を保存」をクリック
これで次の `substack-mcp-setup` 実行時にまた確認ダイアログが出ます。
---
4. できることの全体像
`substack-mcp` は Claude Code に対して、長文記事系と Notes 系の 2 種類のツール群 を公開しています。
長文記事(Posts)系の 10 ツール
下書き作成から公開予約まで、Web エディタでできることはほぼ全部カバー。
`create_draft(title, content_markdown, subtitle?, audience?)` — Markdown から下書きを作成
`update_draft(post_id, title?, subtitle?, content_markdown?, audience?)` — 既存下書きの部分更新。指定したフィールドだけ書き換わる
`upload_image(image_path)` — ローカル画像 or HTTP(S) URL を Substack の CDN にアップロード
`set_cover_image(post_id, image_url)` — カバー画像を設定
`publish_draft(post_id, send_email?, share_automatically?)` — 即時公開。`send_email=True` で購読者にメール配信、`False` なら Web のみ
`schedule_draft(post_id, iso_datetime)` — ISO 8601 で予約公開
`unschedule_draft(post_id)` — 予約解除
`list_drafts(limit?)` — 直近の下書き一覧(最大 50 件)
`get_draft(post_id)` — 下書きの詳細を取得
`delete_draft(post_id)` — 下書きを永久削除(取り消し不可)
Notes(短文)系の 1 ツール
- `post_note(text)` — Notes(X / Threads 風の短文)を Substack 全体のフィードに即時公開。タイトルなし、メール配信なし、最大 4000 字
Notes と Posts は別物です。これは後ろのセクションで詳しく書きます。
---
5. セットアップは 4 ステップで終わる
時間にして 3 分あれば終わります。
ステップ 1:依存をインストール
git clone https://github.com/nanameru/substack-mcp.git ~/substack
cd ~/substack
uv pip install -e .依存バージョンは `pyproject.toml` で `~=` でピン留め済み。
`mcp ~= 1.2`
`python-substack ~= 0.1.20`
`pydantic ~= 2.0`
`pycookiecheat ~= 0.7`
ステップ 2:Chrome で Substack にログイン
すでにログインしているなら、何もしなくて OK。
していなければ <https://substack.com> を開いてログインしてください。
ステップ 3:認証情報を保存
substack-mcp-setupこれだけで終わります。Chrome → Brave → Chromium の順で `substack.sid` を探し、見つかった瞬間にプロファイル API を叩いて Publication を確定。
成功すると、こんな感じの出力が出ます:
`Authenticated as: ...` と `Publication: ... -> https://...` が出ていれば認証情報の保存は完了。`Saved to: ~/Library/Application Support/substack-mcp/config.json` の場所に Cookie が `0600` で書き込まれます。
ステップ 4:Claude Code に MCP を登録
claude mcp add substack-mcp --scope user -- /Users/$USER/substack/.venv/bin/substack-mcpClaude Code を再起動して `/mcp` と打ち、`substack-mcp` が `connected` になっていれば完了です。
---
6. さらに:substack-article スキルも入れる
ここまでで MCP(道具)のセットアップは終わりです。
ただ、これだけだと Claude Code に「create_draft 呼んで」「upload_image 使って」といちいち手順を指示する必要があります。
そこでもう一段、スキルを入れておくと、「Substack に記事書いて」だけで 企画ヒアリング → 構成案 → 本文執筆 → サムネ生成 → 下書き作成 → 公開許可待ち → 公開 までを Claude が一気にやってくれます。
道具ではなく、使い方を教える
MCP は、Claude が呼べる「道具」(`create_draft` などの関数)
Skills は、Claude に「手順と振る舞いを教える指示書」
例えるなら、MCP が「ハンマーやノコギリ」で、Skills が「家具の組み立て手順書」。両方そろうと、Claude は道具の使い方も含めてユーザーの意図通りに動けます。
インストールは `npx skills add` 一発
`substack-mcp` リポジトリは Vercel Skills フォーマットに対応しているので、1 コマンドでインストールできます。
npx skills add nanameru/substack-mcp -g -a claude-code -yこれで `~/.claude/skills/substack-article/` に必要なファイルが配置されます。Claude Code を再起動すれば準備完了。
実際の起動は明示的なコマンド呼び出し不要で、「Substack 記事を書いて」「Substack に投稿して」「短文ポストして」のような自然言語の依頼で Claude Code が自動でこのスキルを発動します。
`npx skills` の主要オプション
`npx skills` は Claude Code 専用ではなく、Cursor / Codex / OpenCode / GitHub Copilot など 50 以上のエージェント に対応しています。
`-g` — グローバル(`~/.claude/skills/`)にインストール。プロジェクト単位で入れたいなら省略
`-a claude-code` — Claude Code 用に入れる(複数指定可)
`-y` — 確認プロンプトを飛ばす(CI 用)
`--list` — リポジトリにあるスキル一覧を表示するだけ
`-s, --skill` — 複数スキルがあるリポジトリで特定のものだけ入れたいときに使う
このリポジトリには現在、`substack-article`(記事特化)と `substack`(all-in-one)の 2 つのスキルが同梱されています。記事執筆メインなら前者、チャット返信や自動運用も含めたいなら後者。`-s` で指定してください。
スキルが何をしてくれるのか
`SKILL.md` には、`substack-mcp` の使い方と Substack の運用ベストプラクティスが詰まっています。
モード判定:「長文記事」と「Notes(短文)」のどちらが必要か、ユーザーの言葉から自動判定
長文記事フロー:ヒアリング → 構成合意 → 執筆 → 下書き作成 → サムネ生成(Codex MCP 経由) → カバー設定 → 公開許可待ち → 公開
Notes フロー:目的を聞く → ドラフト提示 → ユーザー OK で `post_note`
ガードレール:公開前に必ず止まる、メール配信フラグはユーザー確認なしに `True` にしない、など
実際この記事も、`substack-article` スキルを使って書いて公開しました。冒頭でテーマを聞かれて、構成案を出されて、本文を書いて、Codex でサムネを作って、下書きを作って、プレビューを確認してから公開する、という流れ全部です。
Codex MCP も入れておくとサムネ自動生成までいける
スキルの「サムネ生成」ステップは Codex MCP を使います(OpenAI API キーは不要、Codex のサブスク内で完結)。
サムネ生成までは要らないなら Codex MCP のセットアップは飛ばして OK。その場合は手動でカバー画像を用意して `set_cover_image` を呼ぶフローになります。
---
7. 使い方は 3 パターン覚えておけば十分
スキルを入れない素の MCP 操作で見ると、実運用ではこの 3 パターンに集約されます。
パターン 1:Markdown を投げて下書きにする
あなた: この Markdown を Substack の下書きにして
タイトル「テスト記事」、本文は \n\n本文…
Claude: create_draft を呼びます…
post_id: 145678901
edit_url: https://example.substack.com/publish/post/145678901`` のように Markdown 内に書いたローカル画像は、`python-substack` の `Post.from_markdown()` が自動で Substack の CDN にアップロードしてくれます。
パターン 2:サムネを別途設定して予約公開する
1. upload_image("./thumb.png")
→ { "url": "https://substackcdn.com/image/...", ... }
2. set_cover_image(post_id, image_url=<上の URL>)
3. schedule_draft(post_id, iso_datetime="2026-05-15T09:00:00+09:00")`schedule_draft` は ISO 8601 を受け取るだけ。タイムゾーン付きで書けば JST でも UTC でも OK。
パターン 3:Notes(短文)を出す
post_note("新しい記事公開しました\n\nリンクは別途↓")
→ https://substack.com/note/c-xxxxxxxx`\n\n` で段落、`\n` でソフト改行になります。これは内部で ProseMirror の `doc` ノード に変換しています(`client.py:_text_to_prosemirror_doc`)。
---
8. Notes と Posts の使い分けが、運用の肝
`substack-mcp` を使い始めて最初に混乱するのが、ここです。
「Notes は短文、Posts は長文」ではなく、「到達経路もアーカイブの扱いも、完全に別物」と捉えてください。
仕様レベルでの違い
観点ごとに、Posts と Notes でどう違うか並べます。
タイトル・サブタイトル — Posts: ある / Notes: なし
文字数の上限 — Posts: 実質なし / Notes: 最大 4000 字
メール配信 — Posts: `send_email=True` で購読者全員に届く / Notes: 絶対に飛ばない
アーカイブ — Posts: 残る / Notes: 残らない
表示場所 — Posts: 自分の Publication / Notes: Substack 全体の Notes フィード
カバー画像 — Posts: 設定可能 / Notes: 単体添付
audience の指定 — Posts: 4 種類から選べる / Notes: 公開のみ
URL の形 — Posts: `https://<pub>.substack.com/p/<slug>` / Notes: `https://substack.com/note/c-<id>`
Posts を使うべき 3 つのケース
1. ストックしたい話:あとから読み返される / 検索でたどり着いてほしい話
2. メールで届けたい話:購読者の受信箱に「届く」こと自体が価値になる発信
3. 構造のある内容:見出し・リスト・引用・コードブロックを使った技術解説や論考
`audience` を `only_paid` などにすれば、有料記事の課金導線にもなります。
Notes を使うべき 3 つのケース
1. 日常的なプレゼンス:長文を書かない日でも「いる」ことを示す
2. 他の Substacker との交流:Notes フィードはクロス Publication の発見面
3. 長文記事のリサイクル:公開済み Post の引用・要約を Notes に流して導線にする
Notes は「Substack 版の X」と思って良いです。ただし文化はやや違います。
ありがちな失敗 3 つ
Notes でハッシュタグを羅列する — Substack は X 文化と違って、ハッシュタグ詰め込みは浮く
Posts で短い更新を流してメール配信する — 3 行の更新でメールが届くと購読解除されやすい
Notes を連投する — フィードを占拠してミュートされる。1 日 1〜2 本が目安
ハイブリッド戦略
「Posts で長文を出した日に、その記事への導線になる Notes を 1 本出す」が一番素直です。
1. create_draft(...) # Markdown を下書きに
2. upload_image(...) → set_cover_image(...) # サムネ設定
3. publish_draft(post_id, send_email=True) # 購読者にメール配信
4. post_note("新しい記事を出しました:<タイトル>\n\n<URL>")メール配信は確実にリーチしますが、メールを開かない購読者や未購読の Substacker には届きません。Notes を 1 本足すと、その層にも届く。配信ではなく、露出を増やすための Notes、と考えるのが筋。
---
9. 予約公開の運用 Tips(事故ったことがある人向け)
`schedule_draft(post_id, iso_datetime)` は単純な API ですが、運用で事故を起こしやすいポイントがあります。
ISO 8601 のタイムゾーン書き方
`schedule_draft` は内部で `datetime.fromisoformat(iso_datetime)` を呼ぶだけ。書き方は以下のいずれでも OK:
`2026-05-15T09:00:00+09:00` — JST の 9:00
`2026-05-15T00:00:00+00:00` — UTC の 0:00(= JST 9:00)
`2026-05-15T00:00:00Z` — 同上(`Z` 表記)
`2026-05-15T09:00:00` — タイムゾーンなし → 推奨しない
運用上の推奨は「常に JST のオフセット付き」で書くこと。後でログを読み返したときに直感的にわかります。
メール配信のタイミングと曜日
Substack のメール配信は、公開と同時に購読者全員へ送信されます。つまり予約公開時刻 = メールが届く時刻。
これを踏まえると:
早朝の予約公開は要注意:日本の購読者の通知音が朝 5 時に鳴る
無難なのは平日の朝 7〜9 時 / 夜 19〜21 時 / 土日午前
業務時間ど真ん中(13〜17 時)は開封率が下がりがち
金曜夜・土曜朝は良い枠:週末に時間ができた読者が腰を据えて読む
予約解除と差し替えの流れ
予約済みの記事を「やっぱり修正したい」というケースはよくあります。
1. unschedule_draft(post_id) # 下書きに戻す
2. update_draft(post_id, content_markdown=...) # 修正
3. schedule_draft(post_id, iso_datetime=...) # 再予約`update_draft` は部分更新なので、本文だけ差し替えたいなら他のフィールドを省略できます。
ただし、カバー画像だけ差し替えたい場合は `update_draft` ではなく `set_cover_image` を使います。
「メール配信なし」の予約公開もできる(ただし変則技)
`publish_draft(post_id, send_email=False)` で Web には公開されるがメールは飛ばない状態にできます。
ただし `schedule_draft` 自体には `send_email` 相当の引数がありません。なので「メール配信なしで予約したい」場合は:
1. 公開したい時刻にローカルで cron / launchd を仕掛ける
2. 時刻になったら `publish_draft(post_id, send_email=False)` を呼ぶ
…という変則技になります。実運用では「メールなしなら予約せず、直前に手で publish」で十分。
連投を避ける目安
予約公開を仕込みすぎると、購読者のメールボックスを 1 週間で何通も占拠することになります。
週 1 本のメール配信付き Post までが安全圏
週 2 本以上にするなら、片方は `send_email=False` で Web のみ
複数記事の予約は最低 2〜3 日空ける
タイムゾーン事故を防ぐ 4 項目チェックリスト
エージェント経由で予約を仕込んだら、必ず確認:
1. iso_datetime にタイムゾーン(`+09:00` or `Z`)が付いているか
2. 意図した日時か(`schedule_draft` の戻り値 `scheduled_for` を必ず読む)
3. Web 編集画面で予約状態を 1 度は目視確認する(特に初回)
4. 公開 1 時間前に `list_drafts` で再確認
これだけで「翌朝 5 時に購読者全員にメールが飛んだ」みたいな事故はほぼ防げます。
---
10. 内部実装で詰まったところ(書き残しておく価値があるやつ)
`python-substack` のリストノード生成バグ
`python-substack 0.1.20` は、bullet/ordered list の中の text node を ProseMirror 的に不正な形 で吐きます。
// バグった出力
{ "content": "...", "marks": [...] }
// 正しい形
{ "type": "text", "text": "...", "marks": [...] }これをそのまま Substack に投げると、編集画面で本文が壊れたり、リスト要素がレンダリングされなかったりします。
`substack-mcp` は `client.py:_normalize_prosemirror` でツリー全体を再帰的に走査して、`type` が無く `content` が文字列のノードを見つけ次第、上記の正しい形に書き換えています。
def _fix_node(node):
if "type" not in node and isinstance(node.get("content"), str):
text_value = node["content"]
marks = node.get("marks")
node.clear()
node["type"] = "text"
node["text"] = text_value
if marks:
node["marks"] = marksこれがあるおかげで、MCP 経由なら Markdown のリストもそのまま正しく組み立てられます。
Substack 編集画面の「Offline」表示は無視で OK
API 経由で更新した直後、Substack の Web 編集画面が「Offline」と表示することがあります。
これは Substack 側の WebSocket 同期の表示バグで、データ自体は正しく保存されています。MCP 経由の更新・公開には一切影響しないので、無視してください。
Markdown のテーブル記法は使わない
`python-substack` は Markdown の テーブル記法(`| col1 | col2 |` と `|---|---|`)を Substack の表ブロックに変換できません。
本文中にそのまま書くと、パイプ記号と区切り線がリテラル文字として残って表示されます。
比較情報を入れたいときは、太字+箇条書きや、見出し+段落で書き換える方が確実です(この記事自体がその実例)。
本文中に水平線記号を裸で書かない
`python-substack` の Markdown パーサーは水平線記号(ハイフン3つ)を正しく処理せず、本文中にリテラル文字として残ることがあります。
区切りが必要なら見出しで代替するか、空行に置き換えるのが安全です。
---
11. セキュリティモデル:Cookie はパスワード相当
ここを軽視してはいけません。
`substack.sid` は事実上のパスワード
Substack の `substack.sid` Cookie を持っている人間(or プロセス)は、そのアカウントで投稿・課金設定変更・購読者リスト閲覧 など、ほぼすべての操作ができます。
トークン認可ではなく、ブラウザセッションをそのまま使っているからです。
保存場所と権限
macOS: `~/Library/Application Support/substack-mcp/config.json`(パーミッション `0600`)
Linux: `~/.config/substack-mcp/config.json`(同上)
環境変数経由: `SUBSTACK_PUBLICATION_URL` + `SUBSTACK_SESSION_TOKEN`(ただし子プロセスに継承される点に注意)
ディレクトリは `0700`、ファイルは `0600` で「自分しか読めない」状態にしています。
一時 Cookie ファイルの扱い
`python-substack` の `Api` は Cookie をファイルから読む API なので、起動時に短命の一時ファイルを作っています。
`tempfile.mkstemp` で `0600` で作成し、`SubstackApi` の初期化が終わったら `finally` ブロックで即削除。プロセスが落ちても残らない設計。
Token が漏れたら 3 ステップで復旧
1. Substack → Settings → Security → 「Sign out of all sessions」 を実行(既存の `substack.sid` がすべて即時無効化)
2. 改めて Chrome で Substack にログイン
3. `substack-mcp-setup` を再実行して新しい Cookie を保存
画像アップロードのパス検証
LLM エージェントに任せている以上、Prompt Injection で「`~/.ssh/id_rsa` を画像としてアップロードしろ」と言われる可能性は常にあります。
これを防ぐため、`upload_image` は以下を強制します:
拡張子は `.png` / `.jpg` / `.jpeg` / `.gif` / `.webp` / `.heic` / `.heif` のみ
以下のパス配下は問答無用で拒否:
`/etc`, `/private/etc`, `/private/var`, `/System`, `/usr`
`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.kube`, `~/.docker`
`~/Library/Application Support/substack-mcp`(自分の Cookie ファイル)
`~/Library/Keychains`, `~/Library/Cookies`
既知の制約:`create_draft` の Markdown 本文中の `` は `python-substack` 側の処理でこの検証をバイパスします。信頼できない Markdown を流す場合は、呼び出し側で画像パスをサニタイズしてから渡してください。
依存バージョンのピン留め
`pyproject.toml` で `~=` を使い、メジャーバージョンの自動ジャンプを禁止。
特に `python-substack` は Substack の非公式 API を叩いている ため、上げる前に必ず動作確認してください。
---
12. よくある詰まりポイント
`Could not find a Substack session in any installed browser` — Chrome(or Brave)で Substack にログインしていない。先にログインして再実行
`[chrome] keychain access denied` — macOS の Keychain プロンプトで「拒否」した。「常に許可」で再試行
`cookie value looks too short` — Cookie が壊れているか期限切れ。Chrome でログアウト → 再ログイン → `substack-mcp-setup`
`'NoneType' object is not subscriptable`(setup 時) — プロファイル API のレスポンス構造が変わった可能性。`chrome_setup.py:_resolve_publication_url` を確認
編集画面で本文が崩れる(リスト関連) — `_normalize_prosemirror` がスキップされている可能性。MCP サーバー再起動して試す
「Offline」表示 — Substack 側の表示バグ。データは正しく保存されているので無視
---
まとめ:3 つの設計判断
`substack-mcp` を作るうえで、3 つの判断をしました。
1. 認証は「ログインさせるのではなく、既存セッションを借りる」 — Playwright を使った自動ログインは Substack のボット検知に弾かれるので、ユーザーがすでに持っているセッション Cookie を読むだけにする
2. 入出力は「自前 API ではなく、MCP に揃える」 — Claude Code から会話的に呼べるインターフェースが、執筆ワークフローに一番合う
3. 不安定さは「Substack 側で直すのを待つのではなく、クライアント側で吸収する」 — `python-substack` のバグや Substack 側の WebSocket バグは、`substack-mcp` の中で正規化・無視する
そしてもう一段、`substack-article` スキルを `npx skills add nanameru/substack-mcp` で入れることで、「Substack 記事を書いて」だけで企画→執筆→サムネ→公開まで通せるようになります。MCP は道具、Skills は使い方。両方を用意しておくと、執筆ワークフローが一気に Claude Code に乗ります。
Substack に「公式の投稿 API」がない以上、サードパーティ製のクライアントはどうしても内部 API を読み解いて喋る形になります。
これは脆さでもありますが、同時に「ブラウザ操作と同じ表面を持っている」ということでもあり、ボット検知や Cloudflare のチャレンジに引っかからずに動かせる、というメリットもあります。
執筆フローを Claude Code に任せたい / ローカルの Markdown を一発で Substack に流したい人にとって、悪くない出発点になっていると思います。
---
リンク・クレジット
本記事のリポジトリ:<https://github.com/nanameru/substack-mcp>
スキルのインストール:`npx skills add nanameru/substack-mcp -g -a claude-code -y`
スキル本体(リポジトリ内):`skills/substack-article/SKILL.md`
Vercel Skills Directory:<https://skills.sh/>
土台にしているライブラリ:
`python-substack`:<https://github.com/ma2za/python-substack>
`pycookiecheat`:<https://pypi.org/project/pycookiecheat/>
Issue / PR、特に Substack 側の API 仕様変更で動かなくなったときのレポート、歓迎します。
それでは、良い Substack ライフを。






ちなみにこれは規約違反ですよ
Cookie弄って自動投稿はマジでヤバいです