Kuroco Admin MCP Skill
概要
Kuroco Admin MCP は、Kuroco 管理画面の操作(admin_api と同等の管理操作)を MCP (Model Context Protocol) サーバーとして公開する機能。JSON-RPC 2.0 ベースで、 Claude Code / Claude Desktop / ChatGPT などの MCP クライアントから接続できる。
AI エージェントから Kuroco の管理操作を行う際の推奨機能。 標準の MCP プロトコルと OAuth 2.0 に準拠しており、追加ツールのインストール不要で主要な MCP クライアントから そのまま利用できる。
最大の特徴: ツールは DB に登録するのではなく、管理画面のコントローラーと サービスモデルが実行時に動的に MCP ツール化される。管理画面でできる操作は 原則そのまま MCP ツールとして利用できる。
公式リファレンス: MCP クライアント設定リファレンス 仕様は活発に更新されているため、接続手順の最終確認は公式ドキュメントを参照すること。 同梱の kuroco-docs スキルからも参照できる:
../kuroco-docs/docs/reference-mcp-ai.md内のmcp-server(MCP サーバ)/mcp-client-configuration(クライアント設定)の各ページ
類似機能との区別(混同注意):
| 機能 | 対象 | ツールの実体 |
|---|---|---|
| Admin MCP(本スキル) | 管理操作全般 | 管理コントローラー/サービスを動的ツール化 |
| フロント API MCP | 特定の API (/rcms-api/{id}/...) |
管理画面で登録した MCP ツール |
| KurocoEdge の MCP アクション | Edge ルールから MCP を呼ぶクライアント側 | 外部/自サイトの MCP ツール |
エンドポイント
POST https://<site_key>.g.kuroco.app/direct/rcms_api/admin_mcp/x/<module>[,<module>][/readonly]
| URL | 意味 |
|---|---|
.../admin_mcp/x/all |
全モジュールの全ツール |
.../admin_mcp/x/all/readonly |
全モジュール・読み取り専用 |
.../admin_mcp/x/topics_group_5 |
特定コンテンツ定義のレコード操作のみ |
.../admin_mcp/x/topics_group |
グループ定義(TopicsGroup)のCRUD |
.../admin_mcp/x/member,topics_group_5 |
複数モジュール(カンマ区切り) |
.../admin_mcp/?MODE=tools |
利用可能モジュール一覧(REST, GET) |
重要なルール:
- エンドポイントのドメインは API ドメイン(
<site_key>.g.kuroco.app)。 管理ドメイン (.g.kuroco-mng.app)は管理画面・Issuer URL 用であり、MCP エンドポイントには使わない。 URL は手で組み立てず、Admin MCP 情報ページに 表示される値をそのまま使うこと。 /x/<スコープ>は必須。 bare の/direct/rcms_api/admin_mcp/は 400 を返す (旧仕様の「スコープ省略=全ツール」は廃止済み。全ツールは必ず/x/all)。- ベースパスは末尾スラッシュ必須。 ディスパッチャURL(デフォルト audience)は
/direct/rcms_api/admin_mcp/(スラッシュ込み)で、/direct/rcms_api/admin_mcp(スラッシュなし)は解決されない。スコープ付き URL(/x/all等)は例示どおり 末尾スラッシュなしで書く。 OAuth の audience はトークン発行時の URL 表記と 厳密一致するため、登録後に URL 表記を変えない。 - モジュール識別子は小文字英数字とアンダースコアのみ(
^[a-z][a-z0-9_]*$)。 カンマ区切りの順序に機能上の意味はないが、URL 表記は audience として扱われるため 一度登録した表記を固定すること。 - topics まわりは3つの識別子を使い分ける:
topics_group_<N>— グループNにスコープしたコンテンツ(レコード)の実操作topics_group— グループ定義(TopicsGroup)自体のCRUD(topics_group-create/-list/-update/-delete)topics単独指定 — discovery専用(グループ制約なしの同等表現)。ツールの呼び出しは拒否されるため、 実操作には使えない。レコード操作はtopics_group_<N>、グループ定義の操作はtopics_groupを指定する
認証
3 方式ある。Bearer トークンが提示された場合はセッションにフォールバックしない (RFC 6750 準拠。無効トークンは 401)。
方式1: OAuth 2.0 認可コードフロー(推奨)
管理画面に Admin MCP 用の OAuth 認可サーバー(Authorization Server) が
自動作成される(初回に Admin MCP (default) がシードされる)。
- Issuer URL:
https://<管理ドメイン>/direct/login/oauth_idp/<idp_id>- 管理画面 [Admin MCP 情報ページ] または OAuth Authorization Server 編集画面に表示される
- CIMD(クライアント ID メタデータドキュメント / URL クライアント ID) を有効化すると、 クライアント側での client_id / secret の手動設定が不要になる
- Dynamic Client Registration (RFC 7591) は非対応。 CIMD を使わない場合、 クライアントは管理画面で手動登録する
- Protected Resource Metadata (RFC 9728) は認証不要で公開:
GET /.well-known/oauth-protected-resource/direct/rcms_api/admin_mcp/ - CI/無人エージェントは
client_credentialsグラントを使う。CIMD クライアントでは 利用できないため手動登録が必要(認可サーバー・クライアント双方の「対応するグラントタイプ」にclient_credentialsを含め、クライアントのトークンエンドポイント認証方式はclient_secret_basic/client_secret_post)。トークン要求時はresourceパラメータ (RFC 8707)にスコープ付き URL を指定する。リフレッシュトークンは発行されないため、 対話的クライアントの常用には向かない(対話利用はauthorization_codeを使う)
方式2: 特権静的トークン
OAuth 導入前からの管理ツール向け方式。Authorization: Bearer <特権静的トークン> で接続。
スコープ制限はなく全権限(mcp:admin 相当)になるため、取り扱いに注意。
方式3: 管理セッション
管理画面内の UI(AI エージェント支援、ツールチェッカー等)からの呼び出し専用。 外部クライアントからは使用しない。
IP アドレスによるアクセス制限
Admin MCP エンドポイントは管理画面の IP アドレス制限の対象外(送信元 IP が一定しない クラウド型 MCP クライアントに対応するため)。接続元を限定する場合は、専用の許可 IP リストを **[環境設定]→[管理画面] の「Admin MCPのアクセス制限(IPアドレス)」**で有効化する。
- 判定は認証より前。許可外 IP からはトークンの正否にかかわらず
403(Access from this IP address is not allowed.)が返る - 対象: Admin MCP エンドポイント(
?MODE=tools含む)とファイルアップロード (/direct/rcms_api/mcp_upload/)。Bearer・管理セッションの両経路に適用され、 管理画面内の AI エージェント機能にも適用される - 対象外:
?MODE=protected_resource_metadata(RFC 9728 メタデータ配信) client_credentialsによるトークン取得と発行済みトークンでの呼び出しは 「管理画面のアクセス制限(IPアドレス)」の対象外(効くのは Admin MCP 専用リストのみ)
OAuth スコープ(権限レベル)
Admin MCP 用認可サーバーの権限は個別スコープ選択ではなく単一レベル選択(4段階)。
レベルはスコープ文字列で識別すること(管理画面の日本語ラベルは似た語が並び紛らわしいため)。
whoami の permissions.connection.scope が返すのもこのスコープ文字列:
| スコープ(弱い順) | 書き込みの上限 |
|---|---|
mcp:tools.read |
書き込み不可(全モジュールの select のみ) |
mcp:tools.write |
topics / csvtable / tag / comment 等の insert・update のみ。delete はどのモジュールでも不可。rcms_api member group batch は含まれない |
mcp:tools.all |
全モジュール・全操作。ただし下記の例外あり |
mcp:admin |
上限なし |
mcp:tools.writeは単独では選べず、mcp:tools.readとセットで付与される(読み取りは全モジュールに効く)auth.scopesには上表以外の値も混じる。 ツール一覧の取得に使われるmcp:tools.listが併せて付与されるため、whoamiは例えば["mcp:admin", "mcp:tools.list"]を返す。これは権限レベルではない。実効的な権限レベルの判定にはauth.scopesではなくpermissions.connection.scopeを見るmcp:tools.allの例外 — グループ(権限)と汎用Smartyバッチの作成・変更・削除/メンバーへのスーパーユーザーグループ付与/特権付き静的トークンの発行はできない(遅延実行や特権付き静的トークンには上限を安全に引き継げないため)mcp:adminはスーパーユーザーしか承認できない。それ以外のメンバーには同意画面で承認可能な最大レベルが提示され、そのレベルで発行される。スコープとして直接要求した場合は「mcp:tools.allを要求せよ」というメッセージで拒否される
管理画面のラベルで確認できるのは mcp:tools.all = 「全操作(委譲先メンバーの権限の範囲)」。
スコープは「上限(ceiling)」であって権限の付与ではない。 実効権限は メンバー自身の権限 ∩ スコープの上限。上限に含まれないモジュールは全操作が拒否される。 逆に、上限が広くてもメンバーに権限がなければ何もできない。
構築作業に必要なスコープ
サイト構築で必要なスコープは、どのモジュールに書き込むかで決まる:
| 作業 | 権限モジュール | 必要なスコープ |
|---|---|---|
| コンテンツ定義(TopicsGroup)の作成・更新 | topics |
mcp:tools.write |
| コンテンツの投入・更新 | topics |
mcp:tools.write |
| API定義・エンドポイントの作成 | rcms_api |
mcp:tools.all |
| 静的アクセストークンの発行 | rcms_api |
mcp:tools.all |
| レコードの削除全般 | — | mcp:tools.all |
| 会員グループ・汎用Smartyバッチの作成・変更・削除 | group / batch |
mcp:admin |
| メンバーへのスーパーユーザーグループ付与 | member |
mcp:admin |
特権付き静的トークンの発行、kuroco_front-generate_deploy_token |
— | mcp:admin |
API エンドポイントを作る時点で mcp:tools.write では足りない(rcms_api が
mcp:tools.write の上限に含まれないため、全操作が拒否される)。コンテンツ定義の作成までは
mcp:tools.write で進めるので、エンドポイント作成の手前で初めて失敗する。着手前に確認すること。
一連の構築を通しで行うなら mcp:tools.all、上表の mcp:admin 行に該当する作業を
含めるなら mcp:admin が必要。
リソース単位のスコープも存在する:
mcp:module.<mt>— 特定モジュール(例:mcp:module.member)、mcp:module.*で全モジュールmcp:topics_group.<N>— 特定コンテンツ定義、mcp:topics_group.*で全定義
enforce-if-present 方式: スコープは OAuth トークンにスコープが付与されている場合のみ 強制される。スコープなしのトークン(旧来の管理エージェントトークン・特権静的トークン)は 制限されない。「スコープを設定しない=制限なし」である点をユーザーに必ず伝えること。
特権メタツール:
kuroco_front-generate_deploy_tokenはmcp:adminスコープ必須rcms_api-generate_tokenはrcms_api/update権限が必要(=mcp:tools.all以上)。 さらにtoken_type: "privileged_static"は厳密なmcp:adminが必須で、mcp:tools.allでも発行できない(発行されるトークンが接続側の上限を持たない 常設の資格情報になるため)。token_type: "static"にはこの追加制約はない
設定箇所: 権限レベル・リソーススコープは OAuth Authorization Server 編集画面
(/management/external/memberregist_sso_oauth_idp_edit/)で設定する。設定値と Issuer URL は
Admin MCP 情報ページでも確認できる。
クライアント接続
接続手順の正本は kuroco-docs
クライアント別の対応状況(CIMD / 手動クライアント登録 / ヘッダー認証)と設定手順は
../kuroco-docs/docs/reference-mcp-ai.md の mcp-client-configuration ページが正本。
Claude Code / Claude(Web・Desktop・Mobile)/ ChatGPT(Developer mode)/ Codex CLI /
Cursor / Slackbot / GitHub Copilot / カスタム実装 の対応表と手順が揃っている。
このスキルは接続手順を複製しない。 docs は /sync-docs で公式サイトから再生成されるため、
複製すると再同期のたびに片方だけ更新されて乖離する。ここに置くのは、docs に無い
「Admin MCP 固有の URL の組み立て方」と「エージェントとしての振る舞い」だけ。
Admin MCP 固有: URL がスコープであり、リソース識別子
docs の手順の URL 部分を、Admin MCP のスコープ付き URL に置き換えて使う。
https://<site_key>.g.kuroco.app/direct/rcms_api/admin_mcp/x/all
https://<site_key>.g.kuroco.app/direct/rcms_api/admin_mcp/x/topics_group_5
https://<site_key>.g.kuroco.app/direct/rcms_api/admin_mcp/x/topics_group_1,member/readonly
共通の前提:
- OAuth 認可フローは Kuroco 管理画面のログイン・同意を経由するため、接続者には 対象サイトの管理メンバーアカウントが必要
- URL(スコープ)を変更した場合は再認可が必須(audience が URL 表記と厳密一致するため)。 クライアント UI で URL を編集できない場合は、コネクタを削除して新規追加する
- チーム利用や権限分離が必要な場合は、既定の
Admin MCP (default)を変更せず 用途ごとに専用の認可サーバーを作成する運用を推奨
CLI での例(OAuth の登録方式そのものは docs に従う):
# Claude Code
claude mcp add --transport http kuroco https://<site_key>.g.kuroco.app/direct/rcms_api/admin_mcp/x/all
claude mcp login kuroco
# Codex CLI
codex mcp add kuroco --url https://<site_key>.g.kuroco.app/direct/rcms_api/admin_mcp/x/all
codex mcp login kuroco
接続ごとに区別できるサーバー名を付ける(kuroco-blog など)。画面から設定するクライアント
(Claude Web・Desktop・Mobile、ChatGPT)は、MCP URL の入力欄に上記の URL を入れる。
特権静的トークンを使う場合(OAuth を経由しない。全権限になるため取り扱い注意 → 方式2: 特権静的トークン):
claude mcp add --transport http kuroco \
https://<site_key>.g.kuroco.app/direct/rcms_api/admin_mcp/x/all \
--header "Authorization: Bearer <特権静的トークン>"
Admin MCP のヘッダー認証は Authorization: Bearer。コンテンツ API MCP の
X-RCMS-API-ACCESS-TOKEN とは別なので、docs のヘッダー認証手順をそのまま流用しない。
接続時の振る舞い
- 利用クライアントを識別してから手順を選ぶ。 全クライアントで使える自動判定があると 仮定しない。システムから示された情報かユーザーの説明で判断し、それが無く手順の選択に 影響する場合だけ一度確認する
- 異なるクライアントの手順を混在させない。 CLI 利用者に画面操作を求めたり、 デスクトップ利用者に理由なく CLI コマンドを求めたりしない
- 手動クライアント登録は管理画面の永続的な設定変更。 実行前にユーザーの承認を得る。 CIMD が使えるかどうかは docs の対応表で確認し、 「エラーが出た」以外の理由で手動登録へ倒さない
- Kuroco は RFC 7591 の DCR を実装していない。 DCR しか持たないクライアント (Cursor 等)は手動クライアント登録が唯一の経路
- サイト全体に影響する設定変更はエージェントが確定しない。 認可サーバーの設定変更や CIMD の有効化が必要な場合は、必要性を説明してユーザー自身に操作してもらう
- 接続後は新しいタスクを開始して
whoamiを実行し、接続先ホスト・実効スコープ・ 読み書き権限・サイト固有の上限を確認してから作業に入る(whoami による事前確認) - 作業に必要な最小スコープの URL を選ぶ(構築作業に必要なスコープ)
担当者の責務で決める:
担当者の責務 スコープ 構築担当 mcp:admin改修担当 必要に応じて mcp:adminも許可保守・運用担当 最小権限 その他 最小権限
ツールの命名規則と使い方
tools/list が返すツール名は動的に生成される。コントローラー名の語尾と MODE が
動詞に畳み込まれた {resource}-{verb} 形式(1 コントローラーアクション = 1 ツール):
ハイフンは resource と verb を区切る1つだけ。 {resource} はコントローラー名から
_api と末尾1語(_list / _edit / _upload)を除いたもので、モジュールディレクトリ名ではない
(topics_group_edit_api → topics_group)。リソース名に含まれるアンダースコアは
ハイフンに置き換わらない。
| パターン | 例 | 意味 |
|---|---|---|
{resource}-{verb} |
topics-list, topics-create, topics-update, topics-delete |
コントローラー操作(INSERT→create 等、MODE ごとに別ツール) |
{resource}-{verb}(複合リソース) |
topics_group-list, topics_group-create |
サブエンティティ(グループ定義等)。ハイフンは1つで、リソース名側のアンダースコアはそのまま残る |
| 一括指定(別ツールではない) | topics-update / topics-delete の ids / filter / set / rows |
複数件は同じ update / delete ツールの引数で指定する。dry_run で件数を確認し expected_cnt でガード、200 件超は async: true |
{mt}-get |
topics-get |
単一レコードの ID 指定取得 |
{service}-{method} |
email-send |
サービスモデル |
| メタツール | whoami, topics-describe |
実効権限の確認/topics のフィールド定義確認 |
| ステージング | files-create_temp_upload_url |
ファイルアップロード(一時ストレージへの presigned PUT。topics バンドルにも公開される) |
正確なツール名と入力スキーマは必ず tools/list で確認する(名前を推測して呼ばない)。
topics_group_<N>スコープで接続した場合も、ツール名は汎用のtopics-{verb}のまま変わらない。 許可グループは各ツールのtopics_group_id引数の enum として制約され、許可外グループの指定は拒否される- スコープ由来の拒否は実行時に判定される。
topics_group_idの enum に載っていない ID を 指定して拒否された場合は、スコープ不足なのか ID が存在しないのかを読み取りツールで切り分ける
代表的な引数(正確な仕様は各ツールの inputSchema が正):
- list 系(
{mt}-list):filter(Kuroco DSL)・order_query(ソート)・cnt/pageID(ページング)・columns(カラム絞り込み)。topics はさらにtopics_keyword/vector_query(検索)が使える。 単一レコードを ID で取るときは{mt}-getを優先する - update / delete(単一レコード系): ID(
topics_id等)が必須。topics 系ツールは動詞によらずtopics_group_idを渡す
利用フロー:
whoamiで実効権限を確認する(下記)。特に構築作業の着手前と、破壊的操作の前tools/listで利用可能ツールを確認(または REST の?MODE=toolsでモジュール一覧)- 読み取りツールで現状確認(親子関係: Topics には
topics_group_id、Member にはgroup_idが必要。 親の ID はtopics_group-list等で先に解決する)- list 系ツールはデフォルトで全カラムを返す。
columns引数で必要なカラムだけに絞る
- list 系ツールはデフォルトで全カラムを返す。
- 書き込みツールの inputSchema を確認してから実行
topics の拡張項目(ext_col)は inputSchema に列挙されない。
topics-describeで 対象グループのフィールド定義を確認する:// tool: topics-describe(topics_group_id は必須) { "topics_group_id": 5 }update 系ツールは部分更新: 送信しなかったフィールドは変更されず既存値が保持される。 一部のフィールドだけ変えたい場合は、ID と変更するフィールドのみを送る(既存値の再送は不要)。 大きなテキストカラムは行単位でも部分更新できる(下記「部分更新」)
- INSERT / UPDATE / DELETE は実行前にユーザーに確認すること
- 複数レコードの書き込みは並列せず 1 件ずつ実行する。 各書き込みはサーバー側で
検索インデックス再構築・キャッシュ削除・トリガー処理を伴い、並列書き込みは
レート制限(HTTP 429)の対象になる。複数件は同じ update / delete ツールの
ids/filter(+set)で 1 回の呼び出しにまとめる(dry_run→expected_cntの順で安全に) - 成功レスポンスにも
errors配列が含まれることがある。 常に確認する
lightweight_mode の注意: topics の create/update で
lightweight_mode: trueを渡すと 書き込みが大幅に軽くなるが、後追いバッチで反映されるのは検索インデックスと ベクトル埋め込みのみ。トリガー・外部通知(FCM/メール)・タグ集計はスキップされ 恒久的に実行されない。既定動作を変えるため、使用はユーザー確認のうえで。
ツールが見えない場合のチェックリスト:
- 対象テーブルが 0 件のモジュールは読み取りツールが除外される(空モジュールは INSERT のみ表示)
- URL スコープ(
/x/<module>)にそのモジュールが含まれているか readonly付き URL では書き込みツールが出ない- OAuth スコープ(
mcp:module.*/mcp:topics_group.*)で絞られていないか - コンテンツ操作は
topicsではなくtopics_group_<N>を指定しているか
部分更新
Admin MCP の update 系ツールは 2 段階の部分更新に対応する。どちらも「変えない部分を 送らなくて済む」ための仕組みで、送受信量とコンテキスト消費を抑えられる。
フィールド単位(すべての update 系ツール)
送信しなかったフィールドは既存値が保持される。ID と変更するフィールドだけを送る。 既存値を読み直して再送する必要はない。
行単位(patch.<カラム>)
CSS・JS・Smarty テンプレートのように長くなるカラムは、行範囲を指定して一部だけを
書き換えられる。カラム全体を送る代わりに、同じ update ツールへ patch.<カラム名> を渡す。
patch. は部分更新の予約プレフィックス。対応カラムが増えても専用ツールは追加されず、
そのリソースの -update に引数が 1 つ増えるだけなので、ツール一覧は膨らまない。
対応カラム(tools/list の inputSchema が正本):
| リソース | カラム |
|---|---|
custom_function(カスタム処理) |
contents |
topics_group(コンテンツ定義) |
custom_css / custom_js / wysiwyg_custom_css / search_template_keyword / search_template_vector |
手順:
- 読み取りツール(
custom_function-get/topics_group-get)で対象カラムの<カラム名>_hashを取得する(保存内容の SHA-256) - その値を
base_hashに渡して update を呼ぶ
// tool: topics_group-update
{
"topics_group_id": 5,
"patch.custom_css": {
"base_hash": "<topics_group-get が返した custom_css_hash>",
"start_line": 2, // 1始まり
"delete_line_count": 1, // 0 なら挿入(replacement は空にできない)
"replacement": "/* 差し替え */" // 空文字なら該当行を削除
}
}
base_hashは楽観ロック。読み取り後に他の誰かがそのカラムを変更していれば 「changed since it was read」で拒否される。取り直して再試行する- 更新レスポンスにも保存後の
<カラム名>_hashが入る。続けてパッチする場合は 読み直さずその値を使う - カラム名そのものと
patch.<カラム名>は併用不可(同時指定はエラー)。 カラム名を送れば従来どおり全文置換になる - 改行コードは元の内容(内容に改行が無ければ
replacement)に合わせて正規化される - 1 回の呼び出しで複数カラムを同時にパッチできる(それぞれに
base_hashが必要)
ハッシュは保存内容から算出される。 サーバー側で保存時に値を正規化するカラムがあり (例:
search_template_*は空だと既定テンプレート全文に置換、custom_css/custom_jsは エディタのプレースホルダと一致すると空で保存)、送った値と保存された値は一致しないことがある。 だからbase_hashは必ず読み取りツールの<カラム名>_hashを使い、自分で ハッシュを計算しない。
whoami による事前確認
whoami はすべてのスコープ付きエンドポイントに常設されるメタツール(readonly バンドルにも出る)。
引数なしで呼べ、接続の実効コンテキストを返す。
| 返却フィールド | 内容 |
|---|---|
member |
接続しているメンバーと所属グループ |
auth.method / auth.scopes / auth.expires_at |
認証方式・付与スコープ・トークン失効時刻 |
permissions.granted / denied |
アカウント自身のモジュール権限 |
permissions.approval_required |
書き込みが承認ワークフローに回るモジュール(直接反映されない) |
permissions.connection.scope |
この接続で有効な実効スコープ(mcp:tools.write / mcp:tools.all / mcp:admin 等) |
permissions.connection.available_scopes |
再認可すれば取得できるスコープの一覧(強い順) |
permissions.connection.readonly / modules |
readonly バンドルか/エンドポイントのモジュール制限 |
request.client_ip |
接続元 IP(IP 制限の切り分けに使う) |
site |
接続先サイトの識別情報(サイトの取り違え検出)。topics_ext_key_format でこのサイトの拡張項目のキー命名、limits でコンテンツ構造の上限が分かる(下記) |
security.ip_restrictions |
IP 制限の状態(設定内容はサイト設定を更新できる接続のみ) |
実際に呼べるのは permissions.granted ∩ permissions.connection。 片方だけを見て判断しない。
拡張項目のキー命名(site.topics_ext_key_format)
topics の拡張項目のキー名はサイト設定によって2通りに分かれる。whoami はそのまま使える命名文字列を返す:
site.topics_ext_key_format |
意味 |
|---|---|
ext_<n> |
連番形式(例: ext_1)。拡張項目を JSONB で保持するサイト |
ext_col_<nn> |
ゼロ埋め2桁形式(例: ext_col_01)。レガシー形式のサイト |
- キー名を推測しない。 命名はサイト単位で決まるので、topics の読み書きの前に
whoamiで確認する - 返却値は定数名ではなく命名そのものなので、
<n>/<nn>を項目番号に置き換えてそのまま使える - グループ単位の正は
topics-describe。 実際のフィールド定義(どの番号がどの項目か、ext_slugが設定されているか)はこちらで確認する。topics_ext_key_formatはサイト全体の命名規則を先に知るためのもの ext_slugが設定されている項目は、フロントAPIではスラッグがキーになるためこの分岐の影響を受けない- 古いサイトでは
topics_ext_key_formatが返らないことがある。 その場合はtopics-describeの結果を正として扱う
コンテンツ構造の上限(site.limits)
site.limits は、コンテンツ構造に関わる4つの上限を {current, max} の形で返す。current はこのサイトの現在の設定値、max はシステム上引き上げられる上限。 どちらも推測しない——設計・作成の前に必ずここで確認する。
| キー | 内容 | max |
|---|---|---|
topics_max_extension |
TopicsGroupあたりの拡張項目数 | サイトが拡張項目をJSONB形式で持つ場合は999、レガシー形式の場合は99 |
topics_ext_group_loop |
フィールドグループ(繰り返し項目)の繰り返し回数 | 99 |
topics_contents_type_cnt |
TopicsGroupあたりのカテゴリ(contents_type)数 |
99 |
member_max_extension |
メンバーの拡張項目数 | 999 |
currentがmax未満なら、admin_setting-updateツールで引き上げられる(tools/listに存在するか確認してから使う。まだ見えない場合は未対応のサーバーなので、管理画面での引き上げ手順を案内する)。「拡張項目が99個までしか作れない」といった相談を受けたら、まずこのlimitsを見て、レガシー形式(max=99)なのかJSONB形式(max=999)なのか、現在値が上限に達しているだけなのかを切り分ける。
呼ぶべきタイミング:
- セッション開始時 — 接続先サイトが意図したものか、どのメンバーとして操作するかを確認
- 構築作業の着手前 —
connection.scopeがmcp:tools.allまたはmcp:adminかを確認する。 「読み書き」で始めるとコンテンツ定義までは成功し、エンドポイント作成で初めて失敗するため、 途中まで作られた状態が残る。不足していればavailable_scopesを提示して再認可を依頼する - コンテンツ構造の設計前 —
site.limits(上記)で拡張項目・フィールドグループ・カテゴリ・会員拡張項目の上限を確認する。/kuroco-content-structureはこの値をもとに分割・圧縮を判断する - 破壊的操作の前 — 対象サイトと権限を再確認
スコープが不足している場合、推測でツールを呼んで失敗を確かめない。
available_scopesを添えて、必要なレベルでの再認可をユーザーに依頼する。
ファイルアップロード
バイナリを直接 MCP に送らず、ステージング → 参照渡しの 2 段階方式:
files-create_temp_upload_urlツールを呼ぶと、file_idと S3 プリサインド PUT のpresigned_url(およびpresigned_short_url)が発行される。file_size(バイト数)とext(拡張子)の宣言が必須:// tool: files-create_temp_upload_url { "file_size": 1048576, "ext": "pdf" }発行された URL にファイル本体(生バイト)を PUT する(
presigned_short_urlが 307 を返す場合は GET でLocationを解決してから、その URL に PUT する)topics-create/topics-updateのファイル/画像型フィールドの値としてfile_idを渡して消費する。 値の形は文字列"files/temp/..."、またはキャプション付きの{"file_id": "files/temp/...", "desc": "キャプション"}
ファイルマネージャーへのアップロード(file_manager-upload)
topics の項目ではなくファイルマネージャーのツリー(files/user/・files/ltd/・クラウドストレージ)に置く場合は file_manager-upload を使う。
// 16MB まで: data URI をそのまま渡す
{ "storage": "kurocofiles_public", "directory": "docs/2026", "file": "data:application/pdf;base64,...", "file_name": "report.pdf" }
// それ以上: files-create_temp_upload_url で PUT した file_id を渡す
{ "storage": "cloud_public", "directory": "videos", "file": "files/temp/kuroco/<site>/<uuid>.mp4", "file_name": "intro.mp4" }
file_nameが保存名と拡張子を決める。拡張子はサイトのアップロード許可リストにあるもの(php 等の実行系は不可)で、内容と一致していること(HTML/SVG/JS の中身を画像拡張子で置くなど、偽装は拒否される)。フォルダごとの拡張子制限も適用されるdirectoryはfile_manager-listが返すpathと同じ相対パスで、途中のフォルダは自動作成される(フォルダ作成ツールは無い)- 同名ファイルは上書き(ツールは destructive 扱い)。
allow_overwrite: falseで拒否させられる - クラウドストレージ(
cloud_public/cloud_private)宛てのfile_idはストレージ側でコピーされ、Kuroco のサーバーを経由しない。files-create_temp_upload_urlにstorage: "S3"を付けて発行したfile_idならサイズ上限なし - ローカルストレージ(
kurocofiles_*)宛てのfile_idは 80MB まで。超える場合はクラウドストレージに置く - 応答の
pathはfile_manager-list/file_manager-deleteに渡す値、content_field_valueは「ファイル(ファイルマネージャーから)」型の項目に書き込む値
承認ゲートとの順序: 書き込み前のユーザー承認を得てから URL を発行し、 「発行 → PUT → 消費」を一続きで行うこと(承認待ちの間に発行すると期限切れのリスク)。
制約:
- プリサインド URL の有効期限は 10 分。「発行 → アップロード → 消費」を 10 分以内に完了させる
- サイズ上限は
file_sizeの宣言値で検査され、消費時にも再検査される(既定 100MB) storage: "S3"を付けるとサイトの S3 バケットのfiles/temp/に直接置かれる(GCS サイトでは不可)- 小さいファイル(16MB まで)はインライン data URI でも受理される
管理画面: Admin MCP 情報ページ
/management/rcms_api/admin_mcp_info/ に Admin MCP の設定情報が集約されている:
- エンドポイント URL 一覧(
x/all、x/all/readonly、モジュール指定の例) - OAuth 認可サーバー一覧と Issuer URL
- 接続クライアント一覧(client_id のみ表示。secret は表示されない)
- Admin MCP を利用する AI エージェント一覧(公開モジュール / 読み取り専用設定)
- ツールチェッカー(利用可能ツールの確認 UI)
ユーザーに Issuer URL やエンドポイントを案内するときは、まずこのページを参照させる。
トラブルシューティング
| 症状 | 原因と対処 |
|---|---|
| 400 Bad Request | URL に /x/<スコープ> がない。/x/all 等を付ける |
401 + WWW-Authenticate |
トークン無効/期限切れ。resource_metadata の URL から再認証。Bearer 提示時はセッションにフォールバックしないことに注意 |
403 Access from this IP address is not allowed. |
Admin MCP の IP アドレス制限。[環境設定]→[管理画面]の「Admin MCPのアクセス制限(IPアドレス)」に接続元 IP を追加 |
| 接続はできるがツールが空/少ない | 上記「ツールが見えない場合のチェックリスト」を確認 |
| エンドポイント作成だけ権限エラー | rcms_api は mcp:tools.write の上限外。whoami で connection.scope を確認し、mcp:tools.all 以上で再認可する。whoami が既に mcp:tools.all / mcp:admin を返した場合はこの行は原因ではない — 下の「権限エラーの切り分け」へ進む |
privileged_static トークンが発行できない |
厳密な mcp:admin が必要(mcp:tools.all では不可)。スーパーユーザーでの再認可が要る |
| 書き込みは成功するが反映されない | whoami の permissions.approval_required に該当モジュールがないか確認。承認ワークフロー待ちの可能性 |
| audience 不一致でトークン拒否 | エンドポイント URL の末尾スラッシュ・パス表記がトークン発行時と厳密一致しているか確認 |
rcms_api-generate_token が権限エラー |
rcms_api/update が要るため mcp:tools.all 以上。privileged_static はさらに mcp:admin が必要 |
files/temp/... の file_id が解決できない |
プリサインド URL の期限切れ(10 分)、PUT 前に消費した、または別サイトで発行した file_id。URL を再発行して PUT からやり直す |
| 認可サーバーが情報ページに出ない | 管理者が削除した認可サーバーは自動再作成されない。手動で再作成する |
| OAuth のクライアント登録が通らない | 認可サーバーで CIMD(クライアント ID メタデータドキュメント)が有効か確認する。CIMD 非対応クライアントは手動クライアント登録が必要(Kuroco は DCR を実装していない)。クライアント別の対応は ../kuroco-docs/docs/reference-mcp-ai.md の mcp-client-configuration を参照 |
| Codex から接続できない | ① 認可サーバーで CIMD が有効か ② スコープ付き URL(/x/...)を指定しているか ③ ~/.codex/config.toml の [mcp_servers.<name>.oauth] に client_id が残っていないか(設定済みの client_id が優先され CIMD が使われない)。CIMD を使わない場合は手動クライアント登録が必要(Kuroco は DCR を実装していない) |
権限エラーの切り分け
上表の症状マッチだけで原因を確定しない。 「書き込みが権限エラーになった」という報告は、 スコープ不足以外の原因でも同じように見える。ユーザーが「スコープ不足だと思う」と 自己診断していても、まず事実を確認する。
- HTTPステータスを確認する。
401は認証(トークン無効・失効)、403は認可 (スコープ・権限・IP制限)。ここを取り違えると以降の切り分けが全部ずれる whoamiを呼ぶ(推測でツールを呼んで失敗を再現しない)- 返ってきた事実で分岐する:
whoami の結果 |
判定 |
|---|---|
connection.scope が mcp:tools.write 以下、かつ対象が rcms_api 等の上限外モジュール |
スコープ不足。available_scopes を添えて再認可を依頼 |
permissions.denied に対象モジュールがある |
メンバー自身の権限不足。スコープを上げても解決しない。管理画面で権限を付与する |
permissions.approval_required に対象モジュールがある |
権限エラーではなく承認ワークフロー待ち(書き込みは成功して反映されない) |
connection.readonly が true、または connection.modules に対象モジュールが無い |
エンドポイントURL側の制限。スコープではなく接続URLを変える(再認可が必要) |
security.ip_restrictions.admin_mcp.current_ip_allowed が false |
IP制限(403、認証より前に判定される) |
auth.expires_at が失敗時刻より前 |
トークン失効(401)。再認証 |
| 上記すべてに該当せず、スコープも権限も足りている | スコープ問題ではない。 入力値のバリデーションエラー(URI重複・命名規則違反等)、別の接続/別サイトでの操作、といった候補に移る。エラーメッセージ全文・使用した接続名・失敗時刻を確認する |
whoami が十分な権限を示したのに「再認可してください」と案内してはいけない。
確認した事実と矛盾する対処を提示すると、ユーザーは解決しない作業に時間を使う。
セキュリティ注意事項
- 公開エンドポイント(セキュリティ=なし)での運用は非推奨。 特に書き込みを 認証なしで公開しない
- 特権静的トークンはスコープ制限が効かない(全権限)。可能な限り OAuth + 適切な権限レベルを使う
- 読み取り用途には
x/all/readonlyや「読み取り専用」権限レベルで最小権限にする - client_secret・トークン値をログや会話に出力しない
- Admin MCP のリクエストは管理ログに記録され、Admin API 同様リクエスト単位で課金対象
他スキルとの連携
| スキル | 使い分け |
|---|---|
/kuroco-security-audit |
Admin MCP の読み取り系ツールでセキュリティ設定を点検・診断する(読み取り専用) |
/kuroco-content-structure |
コンテンツ定義(TopicsGroup)の設計判断と、MCP ツールで作成する場合のフィールド定義リファレンス |
/kuroco-api-content |
エンドユーザー向けフロント API の設計・認証 |
/kuroco-docs |
公式ドキュメントの横断検索 |
使い分けの目安: AI エージェントからの管理操作は Admin MCP(本スキル)が推奨。 Claude Desktop / claude.ai / ChatGPT / Claude Code いずれからも標準の MCP 接続で利用できる。