記事を書くだけでは自動化にならなかった。Publishing MCPを作った

連載「ChatGPTと育てる、自分専用AI基盤」第5回。ChatGPTからPublishing MCPを介してWordPress、X、Bluesky、Instagramへ発信し、n8nは無人処理側に分けた構成を描くシンプルな水彩画調サムネイル。 AI

※「ChatGPTと育てる、自分専用AI基盤」第5回です。

前回は、ChatGPTがコードを変更できるようになっても、その変更をそのままmainへ入れず、GitHub Pull Requestを「正式に採用する境界」にした話を書きました。

第4回:ChatGPTからPRを作り、安全にマージできるようにした

ここまでで、記憶、開発、強い実行、GitHubでの確定まで、かなりの作業をChatGPTから進められるようになりました。

すると次に気になったのは、ブログとSNSです。

ChatGPTに記事を書いてもらうこと自体は、かなり前からできていました。

でも、記事を書いてもらっただけでは公開されません。

WordPressを開く。タイトルを入れる。本文を貼る。抜粋を入れる。slugを決める。カテゴリーとタグを付ける。SEO titleとdescriptionを入れる。画像をアップロードしてアイキャッチを設定する。

さらに、X、Bluesky、Instagram用の文章を作って、それぞれ投稿する。

文章を書くところだけAIになっても、その後ろには人間の作業がかなり残っていました。

そこで作ったのがPublishing MCPです。

最初はn8nに全部つなぐつもりだった

当時、サーバーにはすでにn8nを入れていました。

WordPress、SNS、Webhook、定期処理をつなぐなら、最初はかなり自然に、

ChatGPT
  ↓
n8n
  ↓
WordPress / SNS

という構成を考えました。

n8nは、決められた処理を繰り返すのには向いています。

毎朝同じ時間に処理する。Webhookを受けたら決まった順番で動く。データをAからBへ運ぶ。監視結果を通知する。

そういう仕事なら、今でもn8nはかなり便利です。

ただ、記事制作を実際にやってみると少し違いました。

タイトルを途中で変える。

「この段落はいらない」と削る。

サムネイルを作り直す。

Xだけ短くする。

Blueskyはスレッドにする。

InstagramはURLを本文へ入れず、プロフィールへ誘導する。

最後になって「今日は公開せず下書きまで」と判断することもあります。

記事は、完成する直前まで形が変わり続けます。

これを最初から固定workflowへ押し込むと、ChatGPTとの会話より、n8nへ渡すJSONや分岐条件を整える方が面倒になってきました。

ここで、「自動化基盤だから全部n8nへ寄せる」という考えをやめました。

対話する仕事と、無人で回る仕事を分けた

そこで役割を分けました。

対話しながら変わる仕事
ChatGPT → Publishing MCP → WordPress / Buffer

決まった形で無人実行する仕事
n8n → 定期処理 / Webhook / 監視

n8nを捨てたわけではありません。

むしろ、n8nを得意な仕事へ戻した形です。

Publishing MCPは、ChatGPTとの会話の途中で変わり続ける記事、SNS文、画像、公開条件を受け止めるための専用工具にしました。

第1回から何度も出てきた考え方ですが、ここでも「便利だから一つへまとめる」のではなく、仕事の性質が違うなら分けています。

最初のPublishing MCPは、投稿すらできなかった

Publishing MCPを作ると決めても、最初からWordPressへ投稿できるようにはしませんでした。

2026年8月1日に実装した最初のP0では、外部サービスへ書き込む機能を持たせていません。

まず作ったのは、Publicationという投稿パッケージを保存する仕組みでした。

Publicationには、たとえば次の情報をまとめます。

  • どのサイトの記事か
  • WordPress本文
  • title / slug / excerpt
  • SEO title / meta description
  • X用文章
  • Bluesky用文章
  • Instagram用文章
  • 使用する画像
  • 公開予定時刻

つまり、いきなり投稿ボタンを作るのではなく、

「何を、どこへ、どの内容で出そうとしているのか」

を一つのデータとして固定するところから始めました。

最初のP0はPublicationの保存、validation、revision管理だけです。

この時点ではWordPressにもBufferにも何も出ません。

かなり地味ですが、後から考えるとこれが重要でした。

会話中に内容が変わるので、revisionを持たせた

記事をChatGPTと作っていると、内容は何度も変わります。

本文を直したあとで、古い状態の投稿処理が残っていたら危険です。

たとえば、

  1. 記事Aを作る
  2. 下書き用Publicationを作る
  3. その後、本文を大きく修正する
  4. 古いPublicationのまま公開処理を実行する

となれば、確認した内容と違う記事を公開する可能性があります。

そこでPublicationにはrevisionを持たせ、更新するたびに版を進めました。

外部へ書き込む操作では、

「今から実行するのは、このrevisionで間違いないか」

を確認します。

古いrevisionを基準にした操作は拒否する。

Knowledge MCPで文書更新前にSHA-256を確認し、Gitでexpected HEADを確認したのと同じ考え方です。

対象は違っても、またここで、

「見た状態と、実際に変更する状態が同じ時だけ進める」

という原則が出てきました。

次に、WordPressの「下書きだけ」を作れるようにした

P0の次に追加したのがWordPress下書きです。

ここでも、最初から公開はさせませんでした。

Publicationを作る
  ↓
previewする
  ↓
WordPressへdraftを作る
  ↓
内容を確認する

という低リスクなところから始めています。

実際に下書きを作れるようになると、すぐに次の問題が見つかりました。

APIが「成功」と返しても、正しく投稿できているとは限らない。

タイトルは合っているか。

本文は途中で欠けていないか。

slugは合っているか。

カテゴリー・タグは意図どおりか。

CocoonのSEO欄へ正しく入ったか。

アイキャッチは本当に設定されたか。

そこで、投稿したあとにWordPressからもう一度読み戻すようにしました。

「送った」ではなく「届いた」を確認する

WordPress下書き作成後は、実際のWordPressから次を読み戻して照合します。

  • title
  • 本文のhash
  • excerpt
  • slug
  • category / tag
  • draft status
  • Cocoon SEO
  • featured image

ここはPublishing MCPを作った中でも、かなり重要な設計変更だったと思います。

APIへ命令を送って200 OKが返ることと、目的の状態になっていることは別だからです。

これはブログ投稿に限りません。

外部サービスをAIに操作させるなら、

命令する
↓
成功responseを受ける

だけではなく、

命令する
↓
外部サービスから読み戻す
↓
本当に意図した状態か照合する

まで必要でした。

後にこの考え方は、reconciliationとしてさらに強くなっていきます。

SNSも「3媒体へ同じ文章を送る」ではなかった

WordPressの次にBuffer連携を追加しました。

ここでも、単純に同じ文章を3SNSへ送る形にはしませんでした。

XにはX向けの文章があります。

Blueskyはスレッドにしたいことがあります。

Instagramはクリックできる記事URLを本文へ置くより、プロフィールへの導線にした方が自然です。

画像枚数や縦横比も媒体ごとに違います。

そのためPublicationの中で、媒体ごとの文章と画像を別々に持たせました。

一つの記事
  ├─ WordPress本文
  ├─ X用
  ├─ Bluesky用
  └─ Instagram用

同じ内容をコピペするのではなく、一つの発信物から媒体別の完成形を持つようにしたわけです。

現在この連載でも、XとBlueskyはスレッド、Instagramは画像付き要約という形で使っています。

Bufferでも、実運用しないと分からない失敗が出た

もちろん、SNS側も最初からきれいには動きませんでした。

分かりやすかったのが、Bufferのdraftをそのまま即時送信へ変える処理です。

投稿作成時に使う入力と、既存投稿を編集するときに使う入力が微妙に違いました。

その違いを十分に扱えておらず、

送信へ切り替えたつもりなのにdraftのまま残る

可能性がありました。

修正では、作成時だけ必要な値をedit時には送らないようにし、draftを解除する条件を明示し、状態遷移そのものを回帰テストへ入れました。

ここでも学んだのは、

APIは「投稿」という物体だけ見ても足りない。draft → sending → sentのような状態遷移までテストする必要がある

ということでした。

公開ボタンは、最後まで別にした

Publishing MCPで下書きもSNS準備もできるようになると、当然「そのまま公開までやってほしい」となります。

でも、第4回のGitHub PRと同じで、作れることと確定してよいことは別です。

そこで公開系は、

prepare
  ↓
preview
  ↓
人が確認
  ↓
confirmed execution
  ↓
read-back / reconciliation

にしました。

WordPress公開、予約公開、SNS即時送信は、下書き作成より強い操作として分けています。

「記事を作って」と言っただけで勝手に公開しない。

「この内容で公開して」と確定した時だけ、外部サービスへ出す。

この境界は、GitHubでPRをmergeする時とかなり似ています。

生成と確定を分ける。

コードでも記事でも、同じ原則が使えました。

失敗した媒体だけ、やり直せるようにした

SNSを複数媒体へ出すと、全部が同時に成功するとは限りません。

Xは成功した。

Blueskyも成功した。

Instagramだけ失敗した。

この時、もう一度全部送るとXとBlueskyへ重複投稿してしまいます。

そこで各媒体を別targetとして記録し、成功済みの媒体は再送しないようにしました。

一部だけ失敗したら、その媒体だけ再試行する。

さらに、外部サービス側で送信が完了したあとも、内部DBに古いSending状態が残ることがあります。

そこで後からWordPressやBufferの実状態を読み直し、内部記録と照合するreconcileも追加しました。

単発の自動投稿ではなく、失敗しても続きから直せる運用へ変わっていきました。

画像も、ChatGPTから直接送れるようになった

Publishing MCPを使っていると、画像の受け渡しも面倒になりました。

ChatGPTへ貼った画像を、別の場所へ一度アップロードしてURLを作る。

あるいはBase64へ変換する。

どちらも記事を書くたびにやりたくありません。

そこで、ChatGPTへ添付した画像をPublishing MCPへ直接渡し、対象サイトのWordPressメディアライブラリへ保存する経路を作りました。

ChatGPT添付画像
  ↓
Publishing MCP
  ↓
WordPress media library
  ↓
記事・SNSで再利用

これで、

「この画像をサムネイルにして」

という会話から、そのままWordPressのfeatured imageまでつながるようになりました。

この連載のサムネイルも、今まさにその経路を使っています。

振り返ると、Publishing MCPは「投稿ツール」ではなかった

最初は、WordPressとSNSへ投稿するためのMCPを作っている感覚でした。

でも実際に必要だったのは、単なる投稿APIではありませんでした。

  • 何を出すかを一つのPublicationへまとめる
  • revisionで内容を固定する
  • previewする
  • 下書きと公開を分ける
  • API成功後に読み戻す
  • 媒体ごとの完成形を持つ
  • 一部失敗だけ再試行する
  • 外部の現実と内部状態を照合する

つまり作っていたのは、

AIが発信物を安全に外へ届けるための境界

だったのだと思います。

Knowledge MCPは記憶の境界。

Development MCPは開発操作の境界。

Development Runnerは強い実行権限の境界。

GitHub PRは変更を確定する境界。

Publishing MCPは公開の境界。

こうして、ChatGPTから「覚える」「作る」「動かす」「確定する」「発信する」能力が一通りそろってきました。

その後、複数Chat・workspace・Workerを並列に動かせるところまで能力を伸ばした結果、別Chatが所有するPublishing MCPのworkspaceまで主開発Chatが進めそうになるという別種のIncidentも起きました。公開境界やfile scopeだけでは足りず、「誰がその仕事を担当してよいか」というownership境界まで必要になった話です。

AIが別のChatの仕事まで進めそうになった話――能力向上で生まれた新しい失敗モード

それでも、AIは自分から次の仕事を始めなかった

ここまで来ると、かなり自動化されたように見えます。

実際、ChatGPTから記事を作り、画像を設定し、WordPressへ公開し、SNSまで送れるようになりました。

でも、一つ大きなことは変わっていませんでした。

次に何をするかを決めているのは、まだ毎回自分です。

「この記事を書いて」

「この機能を直して」

「SNSへ投稿して」

と指示すれば動く。

でも、指示しなければ何も始まりません。

Knowledge MCP、Development MCP、Runner、Publishing MCPと、できることを増やしても、それだけではAIは自律化しませんでした。

そこで次に考えることになります。

「能力は揃った。では、次の仕事を決める仕組みを上に置けないか?」

ここからLoop Engineが始まります。この続きは第6回にまとめました。

第6回:MCPをいくつ作っても、AIは自律化しなかった。そこでLoop Engineを作った

連載ナビ

関連記事

コメント

タイトルとURLをコピーしました