チュートリアル

Agent Plugins は AI コーディングエージェントにどう新しい能力を足すか:Plugin Manifest、Skills、MCP、インストール後の JSON

プラグインを入れてもモデルは賢くならない。クライアントが決まった場所から JSON を数個読むだけだ。

前の二本は 箱の形と 箱にしない判断だった。今日は Plugin を出すと決めた前提で書く。読者が本当に聞きたいのは、Cursor や Claude Code、Antigravity がそのディレクトリを入れたあと、モデルが急に請求書を引き、週報を書ける理由だ。重みの更新でも、システムプロンプトの書き換えでもない。Agent Plugins 1.0.0 ははっきりしている。根の plugin.json を先に読み、固定位置の skills/ と mcp.json を見つける。Google Cloud Developer Plugin も同じ歩き方だ。インストール後の JSON hop を最後まで見て、MCP と JSON Schema の検証につなぐ。

五段の流れ。「学習した」ではない

「エージェントが自動で能力を得た」と聞くと、モデルが技能を覚えたように聞こえる。実装は五段で、一段も飛ばせない。一段目:クライアントがディレクトリをプラグイン根に置く。解決後のパスが根の外へ出たら拒否する。根の外を指すシンボリックリンクも同じ。二段目:plugin.json を読み、閉集合 Schema を通し、name と仕様バージョンを取る。ここで落ちたらパッケージ全体を拒否し、三段目以降は走らない。三段目:skills/ があれば、直下の子ディレクトリだけを見て、ちょうど SKILL.md という通常ファイルがあるものを取り、name と description を文脈へ入れる。四段目:mcp.json があれば、各エントリの type でつなぎ、ハンドシェイクのあと tools/list。五段目:モデルが説明かツール名に当たってから、Skill 本文を読むか tools/call を出す。

仕様はインストールボタンの見た目をわざと定義しない。Google Developers Blog も、インストール、権限、サンドボックス、確認 UX は各クライアントの義務だと書いている。Agents CLI と Cursor と Claude Code のダイアログが違ってよい。持ち運べるのはディレクトリと、閉じた JSON 二枚だ。レビューで聞くべきは「ユーザーはどこをクリックするか」ではなく、「入れたあとメモリに何が増えたか」だ。Manifest が無ければ後続は走らない。Manifest は通ったが mcp.json の $schema が plugin.json と食い違うなら、MCP だけ止めてスキルは残す。一本の SKILL.md が Agent Skills に合わなければ、その一つだけ飛ばす。

横方向の委譲はこの流れの外だ。別チームの請求書エージェントをどう見つけるかは Agent Card で、A2A の記事に書いた。今日見るのは、このコーディングエージェントがスキルとツールの一式をどう足すかだけだ。「新しい能力」を発見の結果と呼んでから、各 hop の JSON を見る。

この hop クライアントが今持っている JSON モデルが今できること
plugin.json を読む身元:name / version / $schemaまだ何もできない。箱が合法なだけ
skills/ を歩くスキルメタデータの配列(本文はまだ無い)説明書は選べる。本文は必要になってから
MCP につなぎ tools/listツール名と inputSchemaSchema に沿って引数は書ける。実行はまだ

先に Manifest:plugin.json は身元契約

クライアントはコンポーネントを見つける前に、根の plugin.json を読まなければならない。ファイル名は変えられない。スキルも MCP も Manifest に埋め込んではならない。Schema は閉集合で、許されるトップレベルキーは $schema、name、version、description、author、homepage、repository、license、keywords、extensions だけだ。余分なトップレベルキーは報告して無視する。それで拒否してはならない。致命なのは必須欠け、型違い、name 違反だ。その場合はパッケージ全体を拒否し、コンポーネントを一つも見つけない。1.0.0 の $schema は https://agent-plugins.org/schemas/1.0.0/plugin.schema.json でなければならない。クライアントはそれでローカル規則を選び、読み込み中に Schema を取りに行ってはならない。

name は識別子で、店頭の表示名ではない。長さ 1–64。使えるのは小文字、数字、ハイフン、ドットだけ。先頭と末尾は英数字。-- と .. は禁止。My-Plugin も -start もパッケージ全体が落ちる。version は SemVer を勧めるが、「SemVer に見えない」だけでは拒否できない。author オブジェクトに入れてよいのは name / email / url だけ。クライアント固有の値は extensions.com.example.client か、根の逆ドメインディレクトリへ。hooks 用の五番目のトップレベルキーを作るな。plugin.json のトップレベルに hooks を書けば、仕様は無視しろと言う。今の IDE が偶然読めても、次のクライアントでは消える。

下はリポジトリに置けるフル Manifest だ。最小の二フィールドより、人向けのメタデータが多い。インストールボタンの話をする前に、parse できて公式 Schema を通すこと。keywords はカタログ検索用。description は人が入れるか決める用で、モデルがツールを選ぶ助けにはならない。スキルは SKILL.md の description で選び、ツールは tools/list で選ぶ。Manifest の説明をツール解説にしても、発見面は空のままだ。

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
  "name": "invoice-ops",
  "version": "1.2.0",
  "description": "Invoice query MCP plus the weekly-summary skill, shipped as one directory",
  "author": {
    "name": "Finance Platform",
    "url": "https://docs.example.com/invoice-ops"
  },
  "homepage": "https://docs.example.com/invoice-ops",
  "repository": "https://github.com/example/invoice-ops",
  "license": "MIT",
  "keywords": ["invoices", "weekly-summary", "mcp"]
}

入れたあと:クライアントが持つ能力スナップショット

仕様は「インストール済み能力」ファイルの出力を要求しない。レビューはそれでも、入れたあとメモリにあるものを見たい。五段の結果を一つのスナップショット JSON にまとめる。plugin の身元、見つかったスキル(メタデータだけ)、MCP の接続状態、tools/list が返したツール契約。このスナップショットは plugin.schema.json のインスタンスではない。包装 Schema で検証するな。CI の fixture だ。スキル数、ツール名、inputSchema の必須を断言する。インストールは成功したのにスナップショットが合わないなら、発見かハンドシェイクが壊れている。「モデルがまだ覚えていない」ではない。

「自動で得た」はこのオブジェクトで見える。skills[].loaded は metadata であり body ではない。起動時はおおよそ百トークン、本文は必要になってから。tools[] はハンドシェイク後の tools/list から来る。plugin.json に手で書いた一覧ではない。mcpServers[].status は実行時であり、包装契約ではない。スナップショットの tools が空で MCP が connected なら、握手は通ってサーバがツールを出していない。Manifest を直すな、サーバを見ろ。逆に Manifest は合法なのにスキルがゼロなら、SKILL.md を一段深く埋めていないか見る。

Google Cloud Developer Plugin を入れたあとも、クライアント側の形は同じだ。箱の身元、gcloud ガードレールスキルのメタデータ、Developer Knowledge MCP のツール一覧。利用者は「Cloud ドキュメントを調べられるようになった」と言う。データ上は tools が数件増えただけだ。スナップショットとリポジトリの plugin.json / mcp.json を並べて diff すると、実行時状態を包装ファイルへ書き戻した人がすぐ分かる。それは drift であり、仕様のフィールドではない。

{
  "plugin": {
    "name": "invoice-ops",
    "version": "1.2.0",
    "spec": "1.0.0"
  },
  "skills": [
    {
      "name": "write-weekly-summary",
      "description": "Turn invoice query results into the weekly summary finance reads. Use when the user asks for a week-end report.",
      "path": "skills/write-weekly-summary/SKILL.md",
      "loaded": "metadata"
    }
  ],
  "mcpServers": [
    {
      "id": "invoice-tools",
      "type": "streamable-http",
      "status": "connected"
    }
  ],
  "tools": [
    {
      "name": "query_invoices",
      "server": "invoice-tools",
      "inputSchema": {
        "type": "object",
        "required": ["week"],
        "properties": {
          "week": { "type": "string", "pattern": "^[0-9]{4}-W[0-9]{2}$" },
          "status": { "type": "string", "enum": ["open", "paid", "overdue"] }
        }
      }
    }
  ]
}

スキル段:frontmatter が発見面になる

Agent Plugins は SKILL.md を書き直さない。発見規則は一つだけ。skills/ の直下の子ディレクトリに、名前がちょうど SKILL.md の通常ファイルがあること。skills/deploy/extra/SKILL.md に隠しても見えない。Agent Skills に合わないその一つは飛ばし、他のスキルと MCP は読み続ける。文脈に入るのは frontmatter の name と description、それに本文や scripts/、references/ を後で読むためのパスだ。

description には「何をするか」と「いつ使うか」の両方を書く。invoice-ops-skill-v2 や一人称のスローガンだと発見面はゼロになる。箱は入ったのにモデルが選ばず、利用者はプラグインが壊れたと思う。壊れているのは説明書だ。scripts/ は今まで通り「持っているシェルでこれを走れ」であり、引数は argv だ。tools/list の一等ツールではない。スナップショットの tools[] にスクリプト名を出すな。出ていたら、Skill の添付を MCP と取り違えている。

本文を必要になってから読むのは、窓を守るためだ。スナップショットを loaded: metadata のままにするのは、ランブック全文をシステムプロンプトへ流し込む回帰を捕まえるためだ。説明書で窓が膨らむのは Plugin 形式のせいではなく、クライアントの読み込み方針のせいだ。仕様が保証するのはスキルが見つかることだけ。モデルと利用者への出し方はクライアントが決める。

MCP 段:つないでから tools/list

mcp.json は根に置かなければならない。plugin.json へ埋め込んではならず、別のコアパスへ移してもならない。トップレベルは $schema と mcpServers だけ。$schema は https://agent-plugins.org/schemas/1.0.0/mcp.schema.json に固定し、Manifest が宣言した仕様バージョンと一致しなければならない。食い違えば、そのプラグインの MCP だけ止める。各サーバは type を明示する。stdio、streamable-http、任意のレガシー sse。オブジェクトの形から輸送を推測してはならない。streamable-http の url は絶対 http/https。ループバック以外は https。headers は見える包装データであり、秘密の置き場ではない。

つないだあとの発見面が tools/list だ。包装ファイルは「どこへつなぐか」に答える。ツール契約は「この hop の arguments が合法か」に答える。inputSchema を plugin.json へ写すな。name や version を inputSchema へ写すな。認証失敗はそのサーバの接続失敗であり、プラグイン設定の違法ではない。仕様は持ち運べる OAuth フィールドを定義しない。鍵はクライアント実行時に残す。線の詳細は MCP とは何か。

下は遠隔 MCP の持ち運び断片だ。リポジトリの fixture に API Key を書くな。つないだら tools/list の結果をスナップショットの tools[] へ入れる。ハンドシェイク失敗はその一台だけ飛ばし、他のサーバとスキルは続ける。この失敗境界は仕様に書いてある。製品の宣伝文句ではない。

{
  "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
  "mcpServers": {
    "invoice-tools": {
      "type": "streamable-http",
      "url": "https://billing.example.com/mcp"
    }
  }
}
失敗 死ぬもの 残るもの
plugin.json の name に大文字パッケージ全体。コンポーネントは見つからないなし
mcp.json の $schema が Manifest と不一致そのプラグインの MCP 全部スキルは読み続ける
一本の SKILL.md の frontmatter が壊れているその一つスキル他のスキル + MCP

独立した失敗、JSONVue に残す fixture

レビュー fixture は少なくとも四枚。上の合法 plugin.json、能力スナップショット、持ち運び mcp.json、query_invoices の arguments 一回。一枚目は公式 plugin.schema.json を通す。二枚目は自分たちのスナップショット Schema、または構造アサート。包装 Schema を被せるな。三枚目は mcp.schema.json。四枚目はツールの inputSchema。四枚とも JSON だが、仕事は違う。身元、在庫、接続、呼び出し。

負例を二枚足す。name を Invoice-Ops にする。mcp.json の一条から type を消す。前者はパッケージ全体を拒否しなければならない。後者はそのサーバだけ飛ばす。未知のトップレベルフィールドを CI が致命にするなら、クライアントより厳しい。仕様は報告して無視し、読み続けろと言う。リポジトリに入れる fixture に秘密を書くな。

ブラウザで足りる。JSON 整形で Manifest、スナップショット、mcp.json が parse できるか見る。JSON Schema 検証で $schema、name、mcpServers、inputSchema を見る。JSON Diffでスナップショットと包装ファイルを比べ、実行時を書き戻した drift を捕まえる。データはマシンから出ない。続きはMCP と JSON Schema、Plugins 概要、箱にする判断。

関連:Google Agent Plugins 2026、Skills vs MCP vs Plugins、MCP と JSON Schema、MCP とは何か。

よくある質問

Plugin を入れるとモデルは微調整されるのか

されない。重みは変わらない。クライアントが増やすのは身元オブジェクト、スキルメタデータ、tools/list が返したツール契約だ。できるように見えるのは発見面が変わったからで、モデルが請求業務を覚えたからではない。

ツール一覧を plugin.json に書いて mcp.json を省けるか

省けない。Manifest はコンポーネントを埋め込めず、発見パスも変えられない。ツール一覧はハンドシェイク後の tools/list から来る。plugin.json のトップレベルに書けば無視される。extensions に書けばそのクライアントだけ意味があり、次のクライアントでは消える。

能力スナップショットを公式 plugin.schema.json で検証できるか

できない。公式 Schema が描くのは箱の身元だけだ。スナップショットはクライアントが組み立てた在庫で、実行時の status とツールの inputSchema が入る。スナップショット用 Schema を別途書くか、CI で必要フィールドだけ断言する。

インストール UX がクライアントごとに違うなら、Plugin は持ち運べるのか

包装は持ち運べる。インストールは持ち運ばなくてよい。仕様はインストール、権限、サンドボックスを意図して外している。クライアントを替えても、ディレクトリと閉じた JSON 二枚は分岐しない。確認ダイアログと企業ポリシーは違ってよい。

まとめと次の一手

2026 年に「Plugin がコーディングエージェントへ自動で能力を足す」と言うなら、一行で足りる。新しい能力は発見の結果であり、重みではない。五段が終わると、メモリにあるのは身元、スキルメタデータ、ツール契約だ。一段欠けると、利用者は「入れたのに使えない」と報告する。

出す順はこうだ。先に plugin.json を公式 Schema に通す。skills/ と mcp.json を歩く。結果をスナップショット fixture に固める。最初の tools/call は inputSchema で arguments を見る。四つの契約は JSONVue に残す。箱の形は Plugins 記事、箱にするかは判断記事、線の協議は MCP 記事。