EmDash は /_emdash/api/mcp に組み込みの Model Context Protocol(MCP)サーバーを公開しています。MCP クライアントは、コンテンツ、バイライン、スキーマ、メディア、タクソノミ、メニュー、リビジョン、設定の読み取りと管理、およびサイト全体のエクスポート/インポートに使用します。
認証
MCP エンドポイントには Bearer トークンが必要です。EmDash は次のトークンフローをサポートします。
| 方式 | 用途 |
|---|---|
| OAuth 2.1 Authorization Code with Proof Key for Code Exchange (PKCE) | 対話型 MCP クライアント。ユーザーがブラウザで要求されたスコープを承認します。 |
| Personal access token | クライアントまたは自動化向けの長期アクセス。トークンは ec_pat_ プレフィックスを持ち、管理画面で作成します。 |
| OAuth 2.0 Device Authorization Grant | ユーザーにブラウザでコード承認を求める CLI クライアント。emdash login がこのフローを使用します。 |
セッション Cookie は MCP エンドポイントの認証には使えません。
Scopes
OAuth およびパーソナルアクセストークンは、クライアントが呼び出せるツールを制限します。ユーザーのロールは別途チェックされるため、スコープがユーザーにない権限を付与することはありません。
| Scope | アクセス |
|---|---|
content:read | コンテンツ、バイライン、タクソノミ、用語、メニュー、リビジョンの読み取りと検索。下書き相当のコンテンツには、ユーザーの content:read_drafts 権限も必要です。 |
content:write | コンテンツ、バイライン、リビジョンの作成と変更。既存トークンとの互換のため taxonomies:manage と menus:manage も付与します。 |
media:read | メディアレコードの読み取り。 |
media:write | メディアのアップロード、登録、更新、削除。 |
schema:read | コレクションとフィールドの読み取り。 |
schema:write | コレクションとフィールドの作成、更新、削除。 |
taxonomies:manage | タクソノミ定義と用語の作成、更新、削除。 |
menus:manage | メニューとメニュー項目の作成、更新、削除。 |
settings:read | サイト設定の読み取り。 |
settings:manage | サイト設定の更新。 |
mcp:tools | 有効な任意のプラグインが公開する MCP ツールの呼び出し。 |
mcp:tools:<pluginId> | 有効な 1 つのプラグインが公開する MCP ツールの呼び出し。 |
transfer:export | サイト全体を サイト パッケージとしてエクスポートしてダウンロード。 |
transfer:analyze | サイト パッケージをアップロードし、インポート向けに分析。 |
transfer:execute | サイト インポートの開始、進行、キャンセル、放棄。 |
admin | サイト転送ツールを含むすべてのコア ツールの呼び出し。プラグイン ツールは引き続き mcp:tools またはプラグイン固有のスコープが必要です。 |
admin スコープには transfer:export、transfer:analyze、transfer:execute が含まれます。各転送スコープは自身のアクションのみを付与し、管理者ロールが必要です。エージェントなどがエクスポート/インポートなしでサイト パッケージを分析できるようにするには、admin の代わりに transfer:analyze を付与します。
認可コードの同意ページでは、ユーザーが要求されたスコープを外せます。EmDash は要求をクライアントの登録スコープとユーザーのロールとの交差に制限し、空の付与を拒否します。
ロール要件
次の表は、広い能力ごとの最小ロールです。他ユーザーのコンテンツを操作する場合、所有権チェックでより高いロールが必要になることがあります。
| 能力 | 最小ロール |
|---|---|
| 公開コンテンツ、メディア、タクソノミ、用語、メニューの読み取り | Subscriber |
| 下書き、予約コンテンツ、ゴミ箱、比較、リビジョンの読み取り | Contributor |
| コンテンツ作成またはメディア アップロード | Contributor |
| 自身のコンテンツの編集・公開、メディア登録 | Author |
| バイライン、タクソノミ、メニュー、全ユーザーのコンテンツ管理 | Editor |
| スキーマまたは設定の読み取り | Editor |
| スキーマ・設定の変更、コンテンツの完全削除、メディア使用の修復 | Admin |
| サイト全体のエクスポートまたはインポート | Admin |
完全なロール定義は ユーザーロール を参照してください。
トランスポート
サーバーはステートレスな Streamable HTTP を使用します。各リクエストは独立で、MCP セッションや Server-Sent Events 接続は保持しません。
| メソッド | エンドポイント | 動作 |
|---|---|---|
POST | /_emdash/api/mcp | JSON-RPC の初期化、ツール一覧、ツール呼び出しを受け付けます。 |
GET | /_emdash/api/mcp | 405 Method Not Allowed を返します。 |
DELETE | /_emdash/api/mcp | 405 Method Not Allowed を返します。 |
応答は JSON-RPC 2.0 です。ツール リクエストを組み立てる前に tools/list を呼び、現在の入力スキーマと MCP アノテーションを取得してください。
ツール一覧
次の一覧は tools/list が返す静的ツールと一致します。クライアントがツール名の代わりに表示する場合があるため、登録タイトルも含めています。
コンテンツ ツール
| Tool | Registered title | Required scope |
|---|---|---|
content_list | List Content | content:read |
content_get | Get Content | content:read |
content_create | Create Content | content:write |
content_update | Update Content | content:write |
content_delete | Delete Content (Trash) | content:write |
content_restore | Restore Content | content:write |
content_permanent_delete | Permanently Delete Content | content:write |
content_publish | Publish Content | content:write |
content_unpublish | Unpublish Content | content:write |
content_schedule | Schedule Content | content:write |
content_unschedule | Cancel Scheduled Publication | content:write |
content_compare | Compare Live vs Draft | content:read |
content_discard_draft | Discard Draft | content:write |
content_list_trashed | List Trashed Content | content:read |
content_duplicate | Duplicate Content | content:write |
content_translations | Get Content Translations | content:read |
バイライン ツール
| Tool | Registered title | Required scope |
|---|---|---|
byline_list | List Bylines | content:read |
byline_get | Get Byline | content:read |
byline_create | Create Byline | content:write |
byline_update | Update Byline | content:write |
byline_delete | Delete Byline | content:write |
byline_translations | List Byline Translations | content:read |
スキーマ ツール
| Tool | Registered title | Required scope |
|---|---|---|
schema_list_collections | List Collections | schema:read |
schema_get_collection | Get Collection Schema | schema:read |
schema_list_block_types | List Block Types | schema:read |
schema_get_block_type | Get Block Type | schema:read |
schema_create_block_type | Create Block Type | schema:write |
schema_update_block_type | Update Block Type | schema:write |
schema_activate_block_type_version | Activate Block Type Version | schema:write |
schema_create_collection | Create Collection | schema:write |
schema_delete_collection | Delete Collection | schema:write |
schema_update_collection | Update Collection | schema:write |
schema_create_field | Add Field to Collection | schema:write |
schema_delete_field | Remove Field from Collection | schema:write |
schema_update_field | Update Field | schema:write |
メディア ツール
| Tool | Registered title | Required scope |
|---|---|---|
media_list | List Media | media:read |
media_create | Confirm Signed Media Upload | media:write |
media_upload | Upload Media | media:write |
media_get | Get Media Item | media:read |
media_update | Update Media Metadata | media:write |
media_delete | Delete Media | media:write |
media_usage_repair | Repair Media Usage Index | admin |
検索ツール
| Tool | Registered title | Required scope |
|---|---|---|
search | Search Content | content:read |
タクソノミ ツール
| Tool | Registered title | Required scope |
|---|---|---|
taxonomy_list | List Taxonomies | content:read |
taxonomy_get | Get Taxonomy Definition | content:read |
taxonomy_create | Create Taxonomy Definition | taxonomies:manage |
taxonomy_update | Update Taxonomy Definition | taxonomies:manage |
taxonomy_delete | Delete Taxonomy Definition | taxonomies:manage |
taxonomy_list_terms | List Taxonomy Terms | content:read |
taxonomy_create_term | Create Taxonomy Term | taxonomies:manage |
taxonomy_update_term | Update Taxonomy Term | taxonomies:manage |
taxonomy_delete_term | Delete Taxonomy Term | taxonomies:manage |
taxonomy_term_translations | List Term Translations | content:read |
メニュー ツール
| Tool | Registered title | Required scope |
|---|---|---|
menu_list | List Menus | content:read |
menu_get | Get Menu with Items | content:read |
menu_translations | List Menu Translations | content:read |
menu_create | Create Menu | menus:manage |
menu_update | Update Menu | menus:manage |
menu_delete | Delete Menu | menus:manage |
menu_set_items | Set Menu Items | menus:manage |
リビジョン ツール
| Tool | Registered title | Required scope |
|---|---|---|
revision_list | List Revisions | content:read |
revision_restore | Restore Revision | content:write |
設定ツール
| Tool | Registered title | Required scope |
|---|---|---|
settings_get | Get Site Settings | settings:read |
settings_update | Update Site Settings | settings:manage |
サイト転送ツール
transfer:* は transfer:export、transfer:analyze、transfer:execute のいずれかを意味します。admin スコープはこの表のすべての要件を満たします。
| Tool | Registered title | Required scope |
|---|---|---|
site_transfer_capabilities | Get Site Transfer Capabilities | transfer:* |
site_export_start | Start Site Export | transfer:export |
site_export_status | Get Site Export Status | transfer:export |
site_import_analyze | Analyze Site Import | transfer:analyze |
site_import_start | Start Site Import | transfer:execute |
site_import_status | Get Site Import Status | transfer:* |
site_import_resume | Resume Site Import | transfer:execute |
site_import_receipt | Get Site Import Receipt | transfer:* |
管理者がリクエストを承認した場合、site_export_start と site_import_start はスコープなしのトークンも受け付けます。承認されたリクエストが開始する操作については、site_export_status、site_import_status、site_import_resume、site_import_receipt も同じトークンをスコープなしで受け付けます。
ツール スキーマの利用
tools/list は各ツールの説明、JSON 入力スキーマ、アノテーションを返します。インストール済み EmDash バージョンがサポートするフィールド、許可値、制限を使うため、呼び出し前にメタデータを確認してください。
例: 記事を更新するクライアントはまず content_get を呼び、返された _rev を保持します。その後、次の JSON-RPC リクエストを送信できます。
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "content_update",
"arguments": {
"collection": "articles",
"id": "01JARTICLE0000000000000000",
"data": { "title": "Updated title" },
"_rev": "opaque-revision-token"
}
}
}
結果は最初のコンテンツ ブロック内の JSON テキストとして返されます。出力スキーマのあるツールは、同じ値を structuredContent にも返す場合があります。
コンテンツ ライフサイクルとバイライン
コンテンツ ライフサイクル リファレンス は、MCP、REST、CLI、管理パネルで共有する状態、リビジョン、 権限、競合、フックの動作を定義します。
content_get は不透明な _rev を返します。content_update、content_publish、content_unpublish、content_schedule、content_discard_draft に渡してください。古い値は競合を返すため、再試行前に項目を再読み込みしてください。
content_update は部分更新です。省略したフィールドは現在値を維持します。公開済み項目の更新は下書きをステージングし、ライブ版は変わりません。content_compare でライブと下書きを確認し、content_publish で下書きを公開するか content_discard_draft で破棄します。content_delete はゴミ箱へ移動します。完全削除は content_permanent_delete のみです。
バイラインは再利用可能な著者/寄稿クレジットです。byline_create はゲスト クレジットを作成するか、CMS ユーザーにリンクできます。返されたバイライン ID を content_create と content_update が受け付ける bylines 入力に渡します。バイライン削除はコンテンツからそのクレジットを外し、プライマリ バイラインもクリアします。
MCP の書き込みは管理画面の エントリ編集ロック に参加しません。_rev チェックはそれを受け付ける操作を保護しますが、編集者が開いている間に他の書き込みツールでエントリが変わる可能性があります。
翻訳
コンテンツ、バイライン、タクソノミ用語、メニューの翻訳ツールは、該当翻訳グループの各ロケール変種を返します。スキーマに translationOf がある場合は作成ツールの入力を使用してください。必須フィールドは tools/list が正とします。
content_translations はコレクションとコンテンツ ID またはスラッグを受け付けます。バイライン、用語、メニューの翻訳ツールは 1 レコードの ID または共有翻訳グループ ID を受け付けます。下書きアクセスのないユーザーは公開コンテンツの翻訳のみ見えます。
スキーマ、メディア、タクソノミ、メニュー
スキーマ ツールはデータベース構造を変更します。コンテンツ作成やフィールド変更の前に schema_get_collection を使い、利用可能なフィールド名、型、制約、検証ルールを取得してください。コレクションとフィールドの削除は保存コンテンツやフィールド値を失い、元に戻せません。
media_upload で base64 エンコードされたバイトを送ります。アップロードは設定されたサイズと MIME 制限の対象です。同一バイトは deduplicated: true で既存メディアを返す場合があります。
media_create は POST /_emdash/api/media/upload-url で作成した保留アップロードを確認します。返された署名 URL でファイルをアップロードし、同じユーザー アカウントから返された storageKey で media_create を呼びます。ツールは、メディア ライブラリで利用可能にする前に、保存ファイルの存在とアップロード URL 要求時のサイズ一致を確認します。
タクソノミ定義は分類と適用コレクションを記述します。用語はコンテンツに割り当てる個別の値です。階層用語は parentId を使えますが、親は同じタクソノミに属し、循環を作れません。非階層タクソノミで parentId 付きの用語を作成・更新すると VALIDATION_ERROR です。子がある用語は削除前に子を削除または移動する必要があります。
menu_set_items はメニューの項目リスト全体を 1 回の原子操作で置き換えます。配列順がメニュー順になります。ネスト項目の parentIndex は同じ配列内の前の項目を指すため、親は子より前に置いてください。
media_usage_repair は 1 コレクションまたは全コレクションを処理でき、大規模サイトでは長時間かかることがあります。complete、partial、failed、stale は成功したツール応答です。isError ではなく返されたステータスと件数を確認してください。認証、検証、予期しない実行失敗は isError: true です。
サイト転送
site_* ツールはサイト全体を サイト パッケージとしてエクスポートし、空のサイトにパッケージをインポートします。操作を開始・進行させ、上限付きサマリーを返します。パッケージ バイト、メディア、レコード内容、プリンシパルのメール、ダウンロード URL は運びません。エクスポートのダウンロードとインポート用パッケージのアップロードは CLI または REST API で行い、操作 ID で参照してください。
すべての転送ツールに Admin ロールが必要です。ロールはスコープより先にチェックされ、非管理者は INSUFFICIENT_PERMISSIONS で承認リクエストは作成されません。
エクスポート
site_export_start は comments(既定 true)を受け付け、新しい操作を返します。site_export_status は呼び出しごとに 1 つの上限付きエクスポート ステップを実行し、操作と nextRequestInMs を報告します。nextRequestInMs が null になるまでその遅延後に再呼び出ししてください。advance: false でステップを実行せず状態だけ読めます。エクスポート完了後、結果に totals(種別ごとのレコード数、メディア数とバイト、パッケージ ファイル数とバイト)も含まれます。
インポート
先にパッケージをアップロードします。CLI の emdash site import <file> --analyze がアップロード・分析し、操作 ID を表示します。
site_import_analyze は呼び出しごとに 1 つの上限付き分析ステップを実行します。nextRequestInMs が null になるまで繰り返すと、packageDigest、planDigest、executable、件数、サイズ、プリンシパル、決定、変換、警告、ブロッカーを含むプラン サマリーが得られます。各変換は code、レコードの kind(あれば)、count として列挙され、適用先 ID や値は含みません。プリンシパル、警告、ブロッカーは各最大 50 件、total に全体件数。プリンシパルはメールなしで、提案および現在マップされたターゲット ユーザー ID を列挙します。decisions でプリンシパルをターゲット ユーザー ID(または null)にマップし、パッケージまたはターゲットのタイトルとタグラインを選べます。変更ごとに新しい planDigest が生成されます。
site_import_start は操作 ID と最新プランの packageDigest と planDigest を取ります。プランにブロッカーがあってはいけません。ツールは destructiveHint: true です。開始後、インポートはサイトに書き込み、完了または管理者が放棄するまで他の書き込みをブロックします。呼び出し前にプランをユーザーに示し確認を得てください。
site_import_resume は 1 つの上限付きインポート ステップを実行し、操作と nextRequestInMs を報告します。nextRequestInMs が null になるまで呼び出します。切断後の再試行は安全です。site_import_status はインポートを進めず操作とアップロード済みファイル数を報告します。site_import_receipt はインポート完了後、receiptDigest を含む完全なレシートを返します。
インポート実行中、および失敗・キャンセル後から放棄まで、書き込み可能な他のすべてのツールは TRANSFER_IMPORT_IN_PROGRESS で失敗します(プラグイン ツール含む)。readOnlyHint: true のツールと 8 つの site_* ツールは動作し、initialize と tools/list はブロックされません。メディア使用アクティベーション中は書き込みツールが同様に MEDIA_USAGE_ACTIVATION_IN_PROGRESS で失敗します。
操作サマリーには id、kind、state、stage、progress、packageDigest、planDigest、error({ code } または null)、タイムスタンプが含まれます。progress は { done, total } ステップに加え、エクスポートが書き込んだ records、および判明次第 bytesDone と bytesTotal です。MCP ツールはインポートのキャンセルや放棄はできません。REST API を使用してください。
承認
admin または必要な転送スコープのあるトークンは承認を求めません。どちらもないトークン(transfer:analyze のみのエージェントなど)では、管理者が承認すると site_export_start と site_import_start が実行されます。
- スコープなしの最初の呼び出しは保留承認リクエストを作成し
TRANSFER_APPROVAL_REQUIREDで失敗します。メッセージと_meta.detailsにapprovalIdとexpiresAtがあります。同じ引数でapprovalIdなしに再呼び出すと同じ未処理リクエストが返ります。 - 管理者は 設定 → Transfer の Approval requests、または REST API のセッション専用承認エンドポイントで承認します。API トークンは承認できません。
- クライアントは同じ引数と
approvalIdで再呼び出します。承認はその呼び出しが操作を開始した時点で消費されます。開始に失敗した場合、期限まで同じapprovalIdで再試行できます。
リクエストはユーザー、トークン、操作、正確な引数(エクスポートオプション、またはインポート操作 ID と両 digest)に bound されます。保留は作成から 15 分、承認後も 15 分で期限切れです。引数やトークンが異なる、または拒否・期限切れ・使用済みの承認では TRANSFER_APPROVAL_INVALID です。
site_import_start はリクエスト作成前に digest、操作状態、プラン ブロッカーを確認するため、管理者は実行可能なインポートのみ承認されます。承認にはトークン ID が必要で、ない呼び出し元は INSUFFICIENT_SCOPE です。
承認済み呼び出しで操作開始後、同じユーザーとトークンはその操作についてスコープなしで site_export_status、または site_import_status、site_import_resume、site_import_receipt を呼べます。
プラグイン ツール
管理者は各プラグインの MCP サーフェスを有効にする必要があります。有効なツールは tools/list に <pluginId>__<localName> として現れ、トークン認証呼び出しには mcp:tools または mcp:tools:<pluginId> が必要です。EmDash はプラグイン ルートが宣言する権限も確認し、監査ログにプラグイン、ツール、ルート、実行者を記録します。
プラグイン ツールはインストール依存のため、上記の静的一覧には含まれません。
OAuth ディスカバリ
MCP クライアントは保護リソース メタデータから認可サーバーを発見します。
GET /.well-known/oauth-protected-resource
応答は /_emdash/api/mcp を保護リソースとして示し、認可サーバーへリンクします。クライアントは次でメタデータを読みます。
GET /.well-known/oauth-authorization-server/_emdash
このドキュメントは現在の認可、トークン、登録、デバイス認可エンドポイント、サポート スコープ、grant タイプ、PKCE メソッド S256 を提供します。OAuth プロトコル ルートをハードコードせず、発見した値を使ってください。
未認証の MCP リクエストはディスカバリ URL 付きで 401 を返します。
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://example.com/.well-known/oauth-protected-resource"
エラー
ツール失敗は isError: true です。最初のテキスト ブロックは安定したコードで始まり、_meta.code が構造化メタデータを読むクライアント向けに繰り返します。
{
"content": [{ "type": "text", "text": "[NOT_FOUND] Collection 'articles' not found" }],
"isError": true,
"_meta": { "code": "NOT_FOUND" }
}
認証失敗は INSUFFICIENT_SCOPE、INSUFFICIENT_PERMISSIONS などのコードを使います。トランスポート失敗は JSON-RPC 内部エラー -32603 を使い、根底の例外は公開しません。