kuroco-mng-api-browser

📁 diverta/kuroco-skills 📅 5 days ago
4
总安装量
4
周安装量
#49285
全站排名
安装命令
npx skills add https://github.com/diverta/kuroco-skills --skill kuroco-mng-api-browser

Agent 安装分布

opencode 4
gemini-cli 4
claude-code 4
github-copilot 4
codex 4
kimi-cli 4

Skill 文档

Kuroco mng_api Browser Skill

概要

Kurocoの管理API(mng_api)をclaude-in-chrome MCPツール経由で操作するスキル。

mng_apiの5つのモード:

  • whoami: セッション情報の取得(GET) — member_id, name, group_ids, expiresAt を返す
  • discover: 利用可能なモジュール・コントローラの探索(GET)
  • schema: コントローラ/サービスのリクエスト・レスポンススキーマ取得(GET)
  • advise: 自然言語でやりたいことを伝えると、呼ぶべきAPIと手順をAIが回答(POST)
  • execute: APIの実行(GET/POST) — columnsパラメータでレスポンスカラム選択可能

認証方式: ブラウザのセッションCookie(__Host-rcms_api_access_token、HttpOnly)を利用。javascript_toolでfetch()を実行すれば、Cookieが自動送信されるためトークンの抽出は不要。

前提条件:

  • claude-in-chrome MCPが利用可能(未設定の場合は下記「操作フロー」Step 0 で案内)
  • ユーザーがKuroco管理画面(https://*.*.kuroco-mng.app)にログイン済み
  • 対象サイトが不明な場合は、サイトキーまたは管理画面URLをユーザーに確認して特定する
  • すべての操作はログイン中ユーザーの権限で実行される

最小操作フロー(読み取り: 4-5回、書き込み: 5-6回の tool call):

  1. javascript_tool: 認証チェック(MODE=whoami)
  2. navigate + get_page_text: /llms.txt でモジュール/コントローラ特定
  3. navigate + get_page_text: /direct/rcms_api/llms/?mt={module} でフィールド名・パラメータ仕様を取得
  4. (書き込み時) javascript_tool: MODE=schema でフィールド型・必須項目・ブロックエディタ構造を取得
  5. javascript_tool: API実行(mt/ct形式)

Step 3 は必須。 /llms.txt(概要)にはモジュール一覧しかなく、ext_colのフィールド名は含まれない。フィールド名の把握にはモジュール詳細が必要。 Step 4 は書き込み操作で必須。 スキーマは data.request.properties にJSON Schema形式でフィールド定義を返す。topics_group_id を指定することでext_col/ブロックエディタの必須フィールドが判明する。 discoverモードは通常不要。llms.txtの2段階(概要→詳細)で十分な情報が得られる。


操作フロー

すべてのAPI操作はこのフローに従うこと。

操作開始前の判断: ユーザーから「〜を確認して」「〜を検索して」「〜のデータを見て」等のリクエストを受けた場合、まずそれが**データ取得(API)**で解決できるか判断する。管理画面のUIが目の前にあっても、反射的にクリック操作に入らないこと。APIで取得できるデータはAPIで取得する。UIブラウザ操作はAPIでは不可能な操作(ファイルアップロード、プレビュー、GUI固有の設定変更等)にのみ使用する。

Step 0: claude-in-chrome MCP の確認

このスキルは mcp__claude-in-chrome__* ツール群に依存する。操作開始前に、これらのツールが利用可能か確認する。

確認方法: mcp__claude-in-chrome__tabs_context_mcp を呼び出す。

  • 成功した場合 → Step 1 へ進む
  • ツールが見つからない / 接続エラーの場合 → ユーザーにセットアップを案内する:
ブラウザ操作に必要な claude-in-chrome MCP が利用できません。
以下の手順でセットアップしてください。

【必要なもの】
1. Google Chrome または Microsoft Edge
2. Claude in Chrome 拡張機能(v1.0.36以上)
   → Chrome Web Store からインストール:
   https://chromewebstore.google.com/detail/claude/fcoeoabgfenejglbffodgkkbkcdhcgfn
3. Claude Code v2.0.73 以上

【有効化の手順】
- Claude Code セッション内で `/chrome` を実行
- または `claude --chrome` で起動

セットアップ完了後、もう一度お試しください。

注意: Chrome連携は Anthropic の直接プラン(Pro, Max, Teams, Enterprise)が必要です。サードパーティプロバイダ(Amazon Bedrock, Google Cloud Vertex AI 等)経由では利用できません。

Step 1: 対象サイトの特定

mcp__claude-in-chrome__tabs_context_mcpを呼び出し、URLパターン *.*.kuroco-mng.app に一致するタブを探す。

  • タブが1つ見つかった場合 → そのタブのURLからベースURL(https://{site_key}.{env}.kuroco-mng.app)を取得し、以降の操作で使用
  • 複数のKurocoタブが見つかった場合 → どのサイトを操作するかユーザーに確認
  • タブが見つからない場合 → AskUserQuestion ツールでサイトキーまたは管理画面URLを確認:
{
  "questions": [{
    "question": "操作対象のKuroco管理画面を特定できませんでした。サイトキーまたは管理画面URLを教えてください(例: demo / https://demo.g.kuroco-mng.app/management/ / https://demo.stg.kuroco-mng.app/management/)",
    "header": "対象サイト",
    "options": [
      { "label": "URLを入力する", "description": "管理画面のURL(https://***.*.kuroco-mng.app/management/)を入力" },
      { "label": "サイトキーを入力する", "description": "サイトキー(例: demo)を入力。環境はタブのURLまたはユーザーに確認" }
    ],
    "multiSelect": false
  }]
}

ユーザーの回答からベースURLを特定し、mcp__claude-in-chrome__tabs_create_mcp で管理画面を開く:

  • URLが提供された場合 → URLからホスト部分を抽出(例: https://demo.g.kuroco-mng.app)
  • サイトキーが提供された場合 → https://{site_key}.{env}.kuroco-mng.app を構築(envはユーザーに確認、デフォルトは g)

注意: すべての操作はブラウザでログイン中のユーザーの権限で実行されます。そのユーザーがアクセス権を持たないモデルやメソッドは操作できません。

Step 2: 認証チェック(軽量リクエスト)

mcp__claude-in-chrome__javascript_toolで以下を実行:

(async () => {
  const r = await fetch('/direct/rcms_api/mng_api/?MODE=whoami', {credentials:'include'});
  const d = await r.json();
  return JSON.stringify({status: r.status, ok: r.ok, member_id: d.member_id, name: (d.name2 || '') + ' ' + (d.name1 || ''), group_ids: d.group_ids});
})()

重要: javascript_tool ではトップレベル await は使えない。 ページコンテキストでの評価となるため、await を使う場合は必ず (async () => { ... })() でラップすること。トップレベルで await を書くと SyntaxError: await is only valid in async functions になる。

MODE=whoami はセッション情報(member_id, name1, name2, group_ids, expiresAt)を返す軽量エンドポイント。認証確認と同時にログインユーザーの権限情報が取得できる。

Step 3: llms.txt でサイト構造把握(必須)

navigate + get_page_text で llms.txt を読む。1回のリクエストで以下が得られる:

  • 全モジュール・コントローラ一覧
  • コンテンツ定義・API・フォーム等のサイトマップ
  • mng_api の使い方・パラメータ仕様
  • ワークフロー例
navigate → /llms.txt
get_page_text → サイト全体の構造を取得

注意:

  • 管理画面ページ巡回の前に必ずllms.txtを確認。大半の構造情報はここで得られる(discoverモード通常不要)
  • llms.txt はKurocoがログインユーザーの権限に基づいて動的に生成する。ユーザーの権限外のAPIは表示されない
  • /llms.txt(概要)にはモジュール一覧のみ。ext_colフィールド名は次の Step 3.5 で取得

Step 3.5: モジュール詳細でフィールド名を把握(必須)

操作対象のモジュールが特定できたら、必ずモジュール詳細を読んでフィールド名を把握する。

navigate → /direct/rcms_api/llms/?mt={module}
get_page_text → ext_colのフィールド名、Available Columns、パラメータ仕様を取得

このステップを省略してはならない。 ext_col_01〜20のフィールド名(例: ext_col_03 = to, ext_col_04 = cc)はモジュール詳細にしか記載されていない。管理画面のDOMを巡回したり、APIレスポンスの中身を推測するのは非効率でエラーの原因になる。

Step 4: スキーマ取得(書き込み操作では必須)

書き込み操作(INSERT/UPDATE)を行う場合は、必ずスキーマを取得してフィールド構造を確認すること。 特にブロックエディタや拡張項目(ext_col)を持つコンテンツ定義では、必須フィールド名や型がスキーマでしか把握できない。

重要: スキーマレスポンスはJSON Schema形式。 data.request 直下にはフィールド情報はない。data.request.properties にフィールド定義が、data.request.required に必須フィールドが格納されている。

コンテンツ定義固有のフィールドを取得するには topics_group_id を指定する:

// javascript_tool — topics_group_id指定でext_col含むフィールド一覧を取得
(async () => {
  const r = await fetch('/direct/rcms_api/mng_api/?MODE=schema&mt=topics&ct=topics_edit&topics_group_id=99', {credentials:'include'});
  const data = await r.json();
  const props = data.request?.properties || {};
  const required = Array.isArray(data.request?.required) ? data.request.required : Object.keys(data.request?.required || {});
  const fields = {};
  Object.entries(props).forEach(([k, v]) => {
    fields[k] = {type: v.type, description: v.description, kurocoType: v['x-kuroco-type'], required: required.includes(k)};
  });
  return JSON.stringify(fields, null, 2);
})();

注意:

  • topics_group_id を省略すると汎用フィールドのみ返る(ext_col が含まれない)
  • topics_group_id を指定するとブロックエディタ・拡張項目のフィールド名(ext_1, ext_14 等)、型、必須フラグが取得できる
  • list系コントローラ(topics_list等)はスキーマが空を返すため、書き込み用コントローラ(topics_edit)を指定すること
  • レスポンスの x-kuroco-type でフィールドの種類(wysiwyg, json, checkbox, file 等)がわかる

Step 5: API実行

認証確認・構造把握が完了したら、API実行パターンに従ってAPIを実行する。

Step 6: 認証失敗・セッション切れ対応

401または403が返った場合:

  1. ユーザーにログインが必要な旨を伝える
  2. ログインURL: {base_url}/management/login/login/(base_urlはタブのURLから取得)
  3. ユーザーがログインするまで待機
  4. ログイン後に再度認証チェック

複数ステップの操作中に401/403が発生した場合:

  1. 即座に操作を停止
  2. どこまで成功したかをユーザーに報告
  3. 再認証を案内
  4. 再認証後、未完了の操作から再開

手段選択の判断基準(最重要)

原則: データの取得・検索・フィルタリングが目的なら、UIではなくAPIを使う。

ブラウザで管理画面が開いていても、UI要素をクリックして情報を探すのは人間の操作方法であり、AIエージェントの操作方法ではない。ブラウザのセッションCookieは javascript_tool の fetch() でも自動送信されるため、UIナビゲーションとAPI呼び出しの認証コストは同じ。

目的 手段 理由
データ一覧の取得・検索・フィルタリング API(mng_api) 構造化JSON、プログラム的に処理可能
特定コンテンツの詳細確認 API(mng_api) columns指定で必要項目だけ取得可能
サイト構造・API仕様の把握 llms.txt 1回で全体把握可能
ファイルアップロード・プレビュー・GUI固有の設定変更 UIブラウザ操作 APIでは不可能な操作のみ

アンチパターン

やりがち 問題 推奨
管理画面のUI要素をクリックしてデータを検索・閲覧する 人間の操作を模倣しているだけ。遅く、結果がHTMLで構造化されていない。改善・自動化に繋がらない mng_apiのfetch()でJSON取得。同じセッションCookieが使えるのでUIを経由する理由がない
columnsを指定せずにGETリクエスト レスポンスが巨大でブロックされる 常にcolumns=必要カラムを指定(効かない場合は.map()で抽出)
fetch() でHTMLを取得→DOMParserでパース Vue.jsレンダリング部分が空になる mng_api でJSON取得
document.querySelector('main').textContent で全文取得 Cookieブロックのリスク 必要なデータのみ抽出
トップレベル await を使う SyntaxError になる 必ず (async () => { ... })() でラップ
メールアドレスを含むフィールド値をそのまま返す [BLOCKED] になる .includes() で判定結果のみ返す
Object.keys(data.request) でスキーマのフィールドを探す JSON Schema形式なので type,properties,required しか返らない data.request.properties でフィールド一覧を取得する
スキーマ取得時に topics_group_id を省略する 汎用フィールドのみでext_colが含まれない &topics_group_id={id} を指定してコンテンツ定義固有のフィールドを取得

API実行パターン

パラメータ形式

mng_apiでは mt(モジュール)と ct(コントローラ)の形式を使用する。

パラメータ 説明 例
mt モジュール名(小文字) topics, member, inquiry
ct コントローラ名 topics_list, topics_edit, member_list

注意: model=Topics&method=list 形式は使用しないこと。HTMLが返却される場合がある。必ず mt/ct 形式を使用する。

GETリクエスト(一覧取得・検索)

// javascript_tool — columns + cnt で必要最小限のレスポンスを取得
(async () => {
  const r = await fetch('/direct/rcms_api/mng_api/?mt=topics&ct=topics_list&topics_group_id[]=1&cnt=10&columns=topics_id,subject,ymd', {credentials:'include'});
  const data = await r.json();
  return JSON.stringify(data, null, 2);
  // → columns対応エンドポイントではサーバー側フィルタ(各アイテム {topics_id, subject, ymd} のみ)
  // → 非対応の場合は .map() でクライアント側抽出:
  //   data.topics_list?.map(t => ({id: t.topics_id, subject: t.subject}))
})()

columns原則: GETリクエストでは常に columns を指定。対応エンドポイントではサーバー側フィルタリング、非対応でも無視されるだけなので常に指定して問題ない。効かなかった場合はクライアント側 .map() で抽出。columnsはexecuteモード専用(discoverモードには適用されない)。

POSTリクエスト(作成・更新・削除)

// javascript_tool — MODE=INSERTで新規作成
(async () => {
  const r = await fetch('/direct/rcms_api/mng_api/?mt=topics&ct=topics_edit_api&MODE=INSERT', {
    method: 'POST',
    credentials: 'include',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
      subject: 'タイトル',
      contents: '本文',
      topics_group_id: 1
    })
  });
  const data = await r.json();
  return JSON.stringify(data, null, 2);
})()

重要なルール

ルール 説明
credentials 全リクエストに credentials: 'include' 必須
パラメータ形式 必ず mt/ct 形式を使用(model/method 形式は不可)
GET配列パラメータ [] suffix必須(例: topics_group_id[]=1)
POST配列パラメータ ネイティブJSON配列(例: {"topics_group_id": [1]})
件数制限 レスポンスが大きい場合は cnt パラメータで制限
columns指定 columns=col1,col2 でレスポンスカラムを最小限にする。対応エンドポイントでは必ず指定すること(javascript_toolの出力制限対策・レスポンス効率化)。効かないエンドポイントもあるため、その場合はクライアント側で抽出
変更操作の確認 insert/update/deleteは実行前にユーザーに確認すること
レスポンス切り詰め javascript_toolの出力制限があるため、大きなレスポンスは必要部分のみ抽出

レスポンス構造が不明な場合

.map() する前に Object.keys() で構造を確認。プロパティ名を推測して複数回試行せず、1回で構造を把握する:

(async () => {
  const r = await fetch(url, {credentials:'include'});
  const data = await r.json();
  const keys = Object.keys(data);
  const firstArrayKey = keys.find(k => Array.isArray(data[k]));
  const firstItem = firstArrayKey ? data[firstArrayKey][0] : null;
  return JSON.stringify({
    topLevelKeys: keys, firstArrayKey,
    firstItemKeys: firstItem ? Object.keys(firstItem) : null
  }, null, 2);
})();

詳細は references/error-handling.md を参照


API探索

adviseモード(AI支援、推奨)

やりたいことを自然言語で伝えると、どのAPIをどの順序で呼べばよいかAIが回答する。レスポンスの endpoint, api_spec はシステムが自動生成(ハルシネーションなし)。summary, description, body_example, note はAIが生成。

// javascript_tool — やりたいことからAPI手順を取得
(async () => {
  const r = await fetch('/direct/rcms_api/mng_api/?MODE=advise', {
    method: 'POST',
    credentials: 'include',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({request: '記事を新しく作成したい'})
  });
  const data = await r.json();
  return JSON.stringify(data.advice?.steps?.map(s => ({
    step: s.step, description: s.description, mt: s.mt, ct: s.ct,
    http_method: s.http_method, mode: s.mode, endpoint: s.endpoint
  })), null, 2);
})()

discoverモード(構造化JSON、通常不要)

// javascript_tool — モジュール一覧取得(特定モジュールは &mt=topics を追加)
(async () => {
  const r = await fetch('/direct/rcms_api/mng_api/?MODE=discover', {credentials:'include'});
  const data = await r.json();
  return JSON.stringify(data.modules.map(m => ({mt: m.mt, controllers: m.controllers.map(c => c.ct)})), null, 2);
})()

使い分け

方法 用途
llms.txt概要(推奨) サイト全体のAPI構造を把握(最初に使う)
llms.txt詳細 特定モジュールのパラメータ仕様を確認
advise やりたいことからAPI手順をAIが提案(mt/ctが不明な場合に有用)
discover プログラム的にモジュール/コントローラを列挙(通常不要)

詳細は references/api-discovery.md を参照


管理画面ブラウザ操作

API呼び出しだけでは不十分な場合(ファイルアップロード、プレビュー、GUI設定変更等)に使用。

操作手順

  1. mcp__claude-in-chrome__navigate で管理画面ページへ移動
  2. mcp__claude-in-chrome__read_page でアクセシビリティツリー取得
  3. mcp__claude-in-chrome__find / mcp__claude-in-chrome__form_input / mcp__claude-in-chrome__computer でフォーム操作
  4. mcp__claude-in-chrome__get_page_text でページ内容取得

主要URL

ページ URL
コンテンツ新規作成 /management/topics/topics_edit/?topics_group_id={id}
コンテンツ編集 /management/topics/topics_edit/?topics_id={id}
コンテンツ一覧 /management/topics/topics_list/?topics_group_id={id}

URLパターンは /management/{module}/{action}/。全URL一覧は references/admin-ui-patterns.md を参照


エラーハンドリング

コード 原因 対処
401/403 セッション切れ/権限不足 ログインURL案内、再認証後リトライ
400 不正パラメータ llms.txt詳細で仕様確認、パラメータ修正
404 モジュール/コントローラ不在 discoverで存在確認
500 サーバーエラー リクエスト内容を確認、再試行
Network Error タブが別ドメイン Kurocoドメインのタブで実行しているか確認

詳細は references/error-handling.md を参照


セキュリティ注意事項

  • Cookie値を表示・ログ出力しないこと — セッション情報の漏洩防止
  • document.cookieでのトークン抽出は禁止 — HttpOnlyで取得不可かつ不要
  • 変更操作は必ずユーザー確認後に実行 — insert/update/deleteは取り消しが困難
  • APIレスポンスのファイル保存はユーザー同意必須 — 個人情報を含む可能性
  • 認証情報をjavascript_toolの出力に含めない — ヘッダーやCookieの内容を返さない

javascript_tool の安全な使い方

ブロックの仕組み

javascript_tool の返却値は chrome拡張のセキュリティフィルタを通過する。以下が検出されると [BLOCKED] に置き換えられる:

  • セッションCookie値、email/login_id 等のセンシティブなクエリパラメータ
  • メールアドレスを含むフィールド値(ext_colに格納されている場合も対象)
  • 個人情報を含む大量テキスト

回避ルールと推奨パターン

ルール 理由
返却値は必要最小限に絞る ID・件数・名前のみ等、必要なフィールドだけ抽出
fetch() の生レスポンスをそのまま返さない Cookie関連データが混入する可能性
DOM全体のtextContentを返さない hidden inputやURL文字列にセンシティブ情報が含まれる
URLパラメータが多いページでは注意 URL自体にセンシティブなパラメータ名が含まれるとブロック対象
// ✅ 安全 — mng_apiからcolumns指定+必要フィールドのみ抽出
(async () => {
  const r = await fetch('/direct/rcms_api/mng_api/?mt=topics&ct=topics_group_list&columns=topics_group_id,group_nm', {credentials:'include'});
  const data = await r.json();
  return JSON.stringify(data.topics_group_list?.map(g => ({id: g.topics_group_id, name: g.group_nm})));
})();

// ✅ 安全 — メールアドレスは値を返さず判定結果だけ返す
(async () => {
  const target = 'user@example.com';
  const r = await fetch('/direct/rcms_api/mng_api/?mt=topics&ct=topics_list&topics_group_id[]=1&cnt=30&columns=topics_id,subject,ext_col_03&keyword=' + encodeURIComponent(target), {credentials:'include'});
  const data = await r.json();
  return JSON.stringify(data.topics_list?.filter(t => {
    return (t.ext_col_03 || []).some(v => v && v.includes(target));
  }).map(t => ({id: t.topics_id, subject: t.subject})));
})();

ツール別の安全度

ツール ブロックリスク 用途
get_page_text 低 (拡張がフィルタ済みテキストを返す) ページ全文の読み取り
read_page 低 (アクセシビリティツリー、Cookie含まない) DOM構造の把握
javascript_tool + mng_api JSON 低 (必要フィールドのみ抽出すれば安全) データ操作・API実行
javascript_tool + fetch() → 生テキスト 高 避ける
javascript_tool + DOM全文取得 中〜高 (ページ内容による) 特定要素のみ抽出に限定

他スキルとの連携

スキル 用途 使い分け
/kuroco-api-content フロントエンドAPI設計・認証パターン、コンテンツCRUDパターン エンドユーザー向けAPI
/kuroco-frontend-integration Nuxt.js/Next.js統合、AI自動デプロイ フロントエンド実装
/kuroco-docs Kurocoドキュメント参照 公式ドキュメント検索

本スキルはブラウザ経由のmng_api実行と管理画面操作に特化。 フロントエンドAPI(*.g.kuroco.app)の操作には上記の関連スキルを使用すること。