起きたこと
ChatGPTからXへ投稿するMCPを実運用したところ、X側では投稿されていないのにMCPが posted:true を返すケースがあった。
CreateTweetのHTTPレスポンス自体は200。ただしGraphQLの errors にはエラーコード186が入り、Tweet IDも返っていなかった。
{
"code": 186,
"message": "Authorization: Tweet needs to be a bit shorter. (186)"
}
HTTP 200だけを見て成功扱いすると、この状態を取りこぼす。
成功条件をTweet ID基準に変更
修正後は、Tweet IDが取得できた場合だけ成功扱いするようにした。
Tweet IDがない場合は posted:false として、GraphQL側のエラーも返す。これでHTTPレベルでは成功していても、実際の投稿作成に失敗したケースを区別できる。
文字数判定はtwitter-textに任せる
もう1つハマったのがXの文字数制限だった。
Xは単純な280文字ではなく重み付きで数える。日本語中心なら実質約140文字、ASCII中心なら最大280文字になる。
この判定を自前で持つより、twitter-text@3.1.0 の parseTweet() を使う形に変更した。
const tweetAnalysis = twitterText.parseTweet(text);
if (!tweetAnalysis.valid) {
// Xへ送る前にエラーとして返す
}
投稿前にここで弾けば、Xへリクエストしてから186で落ちるケースも減らせる。
HumanizerとX MCPで責務を分けた
文章生成側のHumanizerは、Xの上限ギリギリを狙わず安全側の長さに整える。
そのうえでX MCP側は twitter-text で最終判定する。
Humanizerは読みやすさと長さの調整、X MCPは投稿可能かどうかの決定的な検証。この2段構えにした。
最後に実投稿まで行い、Tweet IDと weightedLength が返ることを確認した。