article
MCP 経由で記事を書く
ampless の MCP HTTP トランスポート、トークンと認可境界の考え方、いま並んでいる 14 個のツール、curl で素朴に叩く例。AI エージェントをコエンジニアとして参加させたいときの content side の入口です。
ampless には MCP (Model Context Protocol) サーバが最初から同梱されています。管理 UI、公開サイト、MCP — どれも同じ AppSync スキーマを叩いている構成で、MCP Lambda だけは IAM (SigV4) で接続するかたち。Claude / Cursor / Claude Code のような MCP 対応エージェントをサイトにコエンジニアとして同居させたい場面では、コンテンツ側の入口がこの経路になります(コード編集や npm、git のような作業側はエージェント自身のツールが受け持ちます)。
トランスポート
MCP のトランスポートは、HTTP 一本に集約しています(Lambda Function URL + Bearer トークン)。stdio は廃止しました。ワイヤフォーマットは JSON-RPC 2.0 で、initialize / tools/list / tools/call の三つだけを自前でハンドリングする最小構成になっています。
flowchart TD
Client["MCP クライアント"] -->|"HTTPS POST<br/>Authorization: Bearer amk_..."| Url["Lambda Function URL"]
Url --> Token["SHA-256 hash<br/>McpToken GetItem"]
Token -->|"一致 + 有効"| Dispatch["tool dispatcher<br/>@ampless/mcp-server/tools"]
Dispatch -->|"SigV4 / IAM"| AppSync["AppSync GraphQL"]
Dispatch -->|"Lambda execution role"| S3["S3"]
トークンの仕組み
トークンは 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 は専用ツールに一本化)
ツール一覧
いま登録されているのは 14 個です。
| ツール | 説明 |
|---|---|
list_posts |
軽量サマリーで投稿一覧を返す。検索 / ソート / status フィルタ + ページネーション対応 |
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 レコードを作成 |
list_media |
アップロード済みメディアの一覧 |
search_media |
メディアをファイル名や MIME タイプで検索 |
delete_media |
S3 オブジェクトと 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>を開いて、表示を目視で確認する
この記事に限らず、ホームから辿れるほかの紹介記事もすべて、この流れで入れました。
コエンジニアとしての参加範囲
MCP が担うのはあくまでも コンテンツ側(投稿、メディア、静的バンドル)です。それ以外 — テーマの React コンポーネントを編集する、cms.config.ts にプラグインを足す、copy-theme で themes/my-*/ を切り出す、npm run sandbox で動作確認する、git push で本番反映する — といった作業は、エージェント自身が持っているファイルシステム / シェル / npm / git のツール側でやることになります。
両方が同じプロジェクトディレクトリで動くと、エージェントは「投稿を書く」「テーマを書き換える」「プラグインを試す」を一連の作業として往復できるようになります。書き手だけでなく、サイト全体を一緒に育てるコエンジニアとして振る舞ってもらえる、というのが他の CMS と大きく違うところです。書く方向や判断はサイト運用者側に残しつつ、手を動かす部分はかなり広く渡せます。
editor の信頼モデル
ampless では、Cognito グループの editor を信頼済みプリンシパルとして扱う設計にしています。本文は tiptap / markdown / html のどれであっても、サニタイズせずそのまま保存・配信されます。WordPress の unfiltered_html capability に近い考え方です。
MCP トークンは前述のとおり実質 admin 相当なので、信頼境界はもう一段ぶん厳しく見る必要があります。トークンを渡す相手は、admin と同等に信頼できる人物か、それに見合った運用ルールの中に閉じる、という形で整理するのが安全です。サニタイズが要る運用に向けては、opt-in のサニタイズプラグイン(DOMPurify ベース)を予定しています。
関連記事
- ampless の全体像 → what-is-ampless
- 始めるのに用意するもの → getting-started
- 投稿フォーマット → post-formats
- サーバレス構成 → serverless-stack