article
MCP 経由で記事を書く
ampless の MCP HTTP トランスポート、トークンと認可境界、利用できるツール、curl で叩く例をまとめました。この記事自体も MCP 経由で更新しています。
ampless には MCP (Model Context Protocol) サーバーが同梱されています。管理 UI、公開サイト、MCP は同じ AppSync スキーマを使いますが、MCP Lambda だけは IAM (SigV4) で接続します。AI エージェントに記事作成や更新を任せたいときは、この経路を使います。
トランスポート
MCP のトランスポートは HTTP に集約しています。Lambda Function URL に Bearer トークンを付けて POST する形です。stdio は廃止しました。
ワイヤフォーマットは JSON-RPC 2.0 です。initialize / tools/list / tools/call の三つだけを自前で扱う、かなり小さな実装にしています。
MCP クライアント
↓ HTTPS POST + Authorization: Bearer amk_...
Lambda Function URL
↓ SHA-256 ハッシュ → McpToken テーブルを GetItem(admin 専用モデル)
↓ 一致 + 失効/期限切れでなければ通過
ツールディスパッチ(@ampless/mcp-server/tools)
├── AppSync を SigV4 (IAM) で叩く
└── S3 を Lambda 実行ロールで叩く
トークンの仕組み
トークンは、amk_ プレフィックスに base64url のランダム値を足した文字列です。
- 発行は管理画面
/admin/mcp-tokensから行う(McpToken は admin 専用モデル) - 保管するのは SHA-256 ハッシュのみ。平文は発行時に 1 回だけ表示
- 認証パスは McpToken テーブルへの
GetItem1 回で終わり、途中で AppSync は通らない
トークン自体にはロールを載せていません。実際の認可境界は MCP Lambda の IAM ロールです。スキーマ側の allow.resource(mcpHandler).to(['query', 'mutate']) によって、Post / Page / PostTag / Media へ admin 相当でアクセスできます。
つまり、トークンを持っていること = admin 相当の CMS アクセス権を持っていることに近いです。発行できるのは admin だけですが、配布先を選ぶときも、admin 権限を渡すのと同じ重さで考える必要があります。
ペイロードと制約
- Function URL の呼び出しサイズ上限は、base64 展開後でおよそ 6 MB
- 大きな静的バンドルは、差分系ツール(
upload_static_file/commit_static_post)に分けて投入する create_post/update_postは、format: 'static'を意図的に弾く。manifest と S3 のズレを避けるため、static は専用ツールに一本化している
ツール一覧
いま登録されているツールは 11 個です。
| ツール | 説明 |
|---|---|
list_posts |
ステータスフィルタとページネーション付きで、投稿一覧を返す |
get_post |
slug / postId で 1 件取得 |
create_post |
投稿を新規作成(format ∈ tiptap / markdown / html、static は拒否) |
update_post |
投稿を更新 |
delete_post |
投稿を削除し、PostTag 行も合わせてクリーンアップ |
upload_media |
base64 のバイト列を public/media/YYYY/MM/ にアップロードして Media レコードを作成 |
get_schema |
CMS のコンテンツスキーマ(static 投稿の注記つき)を返す |
upload_static_bundle |
zip 1 発で送るバンドルアップロード。展開・検証・S3 プレフィックス置換・manifest 上書きを atomic に |
upload_static_file |
public/static/<slug>/ 配下に、1 ファイルずつ差分アップロード |
delete_static_file |
public/static/<slug>/ 配下のファイルを、差分削除 |
commit_static_post |
S3 プレフィックスを再スキャンして、Post の manifest を再構築(差分編集後の "save" にあたる操作) |
ロール別の制御はまだありません。MCP トークンが発行された時点で、全ツールへアクセスできます。
curl で素朴に叩く
中身は JSON-RPC over HTTP なので、シェルから直接叩けます。投稿一覧を 5 件だけ取得する例です。
curl -sS -X POST "$MCP_URL" \
-H "Authorization: Bearer $MCP_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_posts",
"arguments": { "limit": 5 }
}
}'
この紹介サイトのスクリーンショットも、同じ流れで upload_media を叩き、戻り値の src を Markdown の画像リンクに差し込みました。
エージェントから記事を書くフロー
Claude Code や Claude Desktop のような MCP 対応エージェントから書く場合、作業はだいたい次の順番になります。
get_schemaでスキーマを確認し、list_postsで既存記事を見るupload_mediaで図版・スクリーンショットをアップロードし、戻り値の URL を本文に埋め込むcreate_post(format: markdown / tiptap / html)で投稿する- ブラウザで
/<slug>を開き、表示を目で確認する
この記事だけでなく、ホームから辿れるほかの紹介記事もこの流れで入れました。書き手として AI エージェントを使いつつ、構成や判断はサイト運用者側に残す、という分担です。
editor の信頼モデル
ampless では、Cognito グループの editor を信頼済みプリンシパルとして扱います。本文が tiptap / markdown / html のどれであっても、サニタイズせずそのまま保存・配信します。WordPress の unfiltered_html capability に近い考え方です。
MCP トークンは、前述のとおり実質 admin 相当です。通常の editor より信頼境界をもう一段厳しく見てください。トークンを渡す相手は、admin と同じくらい信頼できる人物か、同等の制約を置いた運用ルールの中に閉じるのが安全です。
サニタイズが必要な運用に向けては、opt-in のサニタイズプラグイン(DOMPurify ベース)を予定しています。
関連記事
- ampless の全体像 → what-is-ampless
- 投稿フォーマット → post-formats
- サーバレス構成 → serverless-stack