📦build-mcpb
- プラグイン
- mcp-server-dev
- ソース
- GitHub で見る ↗
説明
次のような場合に使用: ユーザーが「MCPサーバーをパッケージ化したい」「MCPをバンドルしたい」「MCPBを作りたい」「ローカルのMCPサーバーを配布したい」「ローカルMCPを配布したい」と要求する場合、`.mcpb` ファイルについて言及する場合、NodeまたはPythonのランタイムをMCPサーバーに同梱することを検討している場合、あるいはローカルのファイルシステム・デスクトップアプリ・OSと連携するMCPサーバーを、ユーザーがNode/Pythonをセットアップしていない環境でもインストール可能な形で提供する必要がある場合。
原文を表示
This skill should be used when the user wants to "package an MCP server", "bundle an MCP", "make an MCPB", "ship a local MCP server", "distribute a local MCP", discusses ".mcpb files", mentions bundling a Node or Python runtime with their MCP server, or needs an MCP server that interacts with the local filesystem, desktop apps, or OS and must be installable without the user having Node/Python set up.
ユースケース
- ✓MCPサーバーをパッケージ化したい
- ✓.mcpbファイルについて相談される
- ✓MCPサーバーを配布・インストール可能にしたい
- ✓ランタイム環境を同梱する必要がある
本文(日本語訳)
MCPB(バンドル型ローカル MCP サーバー)の構築
MCPB は、ランタイムをパッケージに同梱したローカル MCP サーバーです。 ユーザーはファイルを1つインストールするだけで動作し、Node・Python・その他のツールチェーンをマシンにインストールする必要がありません。 ローカル MCP サーバーを配布する際の公式な方法です。
MCPB は第2の配布経路です。Anthropic はディレクトリ掲載にはリモート MCP サーバーを推奨しています。 詳細: https://claude.com/docs/connectors/building/what-to-build
次のような場合に使用: サーバーがユーザーのマシン上で動作しなければならない場合 — ローカルファイルの読み取り、デスクトップアプリの操作、localhost サービスとの通信、OS レベルの API へのアクセスなど。
サーバーがクラウド API を呼び出すだけであれば、ほぼ確実にリモート HTTP サーバーの方が適切です(build-mcp-server を参照)。
URL で済む処理のために MCPB のパッケージングコストを払う必要はありません。
MCPB バンドルの構成
my-server.mcpb (zip アーカイブ)
├── manifest.json ← 識別情報、エントリーポイント、設定スキーマ、互換性情報
├── server/ ← MCP サーバーコード
│ ├── index.js
│ └── node_modules/ ← バンドルされた依存パッケージ(またはベンダー管理)
└── icon.png
ホストは manifest.json を読み込み、server.mcp_config.command を stdio MCP サーバーとして起動し、メッセージをパイプします。
コードの観点からはローカルの stdio サーバーと完全に同一であり、異なるのはパッケージング方法のみです。
マニフェスト
{
"$schema": "https://raw.githubusercontent.com/anthropics/mcpb/main/schemas/mcpb-manifest-v0.4.schema.json",
"manifest_version": "0.4",
"name": "local-files",
"version": "0.1.0",
"description": "Read, search, and watch files on the local filesystem.",
"author": { "name": "Your Name" },
"server": {
"type": "node",
"entry_point": "server/index.js",
"mcp_config": {
"command": "node",
"args": ["${__dirname}/server/index.js"],
"env": {
"ROOT_DIR": "${user_config.rootDir}"
}
}
},
"user_config": {
"rootDir": {
"type": "directory",
"title": "Root directory",
"description": "Directory to expose. Defaults to ~/Documents.",
"default": "${HOME}/Documents",
"required": true
}
},
"compatibility": {
"claude_desktop": ">=1.0.0",
"platforms": ["darwin", "win32", "linux"]
}
}
server.type — node・python・binary のいずれか。情報提供目的の項目であり、実際の起動は mcp_config に基づきます。
server.mcp_config — プロセス起動に使用するコマンド・引数・環境変数を直接指定します。
バンドル相対パスには ${__dirname} を、インストール時の設定値の参照には ${user_config.<key>} を使用します。
自動プレフィックスは付与されません — サーバーが読み取る環境変数名は、env に記述した内容がそのまま使われます。
user_config — インストール時にホストの UI 上で表示される設定項目です。
type: "directory" はネイティブのフォルダーピッカーとして描画されます。
sensitive: true を指定すると OS のキーチェーンに保存されます。
全フィールドの詳細は references/manifest-schema.md を参照してください。
サーバーコード: 通常のローカル stdio と同じ
サーバー自体は標準的な stdio MCP サーバーです。 ツールのロジック内に MCPB 固有の記述は一切ありません。
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { readFile, readdir } from "node:fs/promises";
import { join } from "node:path";
import { homedir } from "node:os";
// ROOT_DIR はマニフェストの server.mcp_config.env に記述した内容から取得 — 自動プレフィックスなし
const ROOT = (process.env.ROOT_DIR ?? join(homedir(), "Documents"));
const server = new McpServer({ name: "local-files", version: "0.1.0" });
server.registerTool(
"list_files",
{
description: "List files in a directory under the configured root.",
inputSchema: { path: z.string().default(".") },
annotations: { readOnlyHint: true },
},
async ({ path }) => {
const entries = await readdir(join(ROOT, path), { withFileTypes: true });
const list = entries.map(e => ({ name: e.name, dir: e.isDirectory() }));
return { content: [{ type: "text", text: JSON.stringify(list, null, 2) }] };
},
);
server.registerTool(
"read_file",
{
description: "Read a file's contents. Path is relative to the configured root.",
inputSchema: { path: z.string() },
annotations: { readOnlyHint: true },
},
async ({ path }) => {
const text = await readFile(join(ROOT, path), "utf8");
return { content: [{ type: "text", text }] };
},
);
const transport = new StdioServerTransport();
await server.connect(transport);
サンドボックス化はすべて開発者の責任です。
マニフェストレベルのサンドボックス機能は存在せず、プロセスはユーザーの完全な権限で実行されます。
パスのバリデーション、ROOT からの逸脱の拒否、spawn のアクセス制限を必ず実装してください。
詳細は references/local-security.md を参照してください。
設定環境変数から ROOT をハードコードする前に、ホストが roots/list をサポートしているか確認してください。
これはユーザーが承認したディレクトリを取得するための仕様標準の方法です。
パターンの詳細は references/local-security.md を参照してください。
ビルドパイプライン
Node
npm install
npx esbuild src/index.ts --bundle --platform=node --outfile=server/index.js
# または: ネイティブ依存パッケージがバンドルに対応していない場合は node_modules をそのままコピー
npx @anthropic-ai/mcpb pack
mcpb pack はディレクトリを zip 圧縮し、manifest.json をスキーマに対して検証します。
Python
pip install -t server/vendor -r requirements.txt
npx @anthropic-ai/mcpb pack
依存パッケージをサブディレクトリにベンダー管理し、エントリースクリプトの先頭で sys.path に追加してください。
ネイティブ拡張(numpy 等)はターゲットプラットフォームごとにビルドが必要です — 可能な限りネイティブ依存は避けてください。
MCPB にサンドボックスはない — セキュリティは開発者の責任
モバイルアプリストアとは異なり、MCPB はパーミッションを強制しません。
マニフェストに permissions ブロックは存在せず、サーバーはユーザーの完全な権限で実行されます。
references/local-security.md は任意の参考資料ではなく、必須の読み物です。
プラットフォームレベルでは何も止めてくれないため、すべてのパスをバリデーションし、すべての spawn をアクセス制限する必要があります。
マニフェストによるファイルシステムやネットワークのスコープ制限を期待していた場合: そのような機能は存在しません。ツールハンドラー内で自前で実装してください。
サーバーの役割がクラウド API の呼び出しだけであれば、立ち止まって考えてください — それは MCPB に偽装したリモートサーバーです。 ユーザーはローカルで実行することから何も得られず、開発者だけが不必要なローカルセキュリティの負担を抱えることになります。
MCPB と UI ウィジェット
MCPB サーバーは、リモート MCP アプリと全く同様に UI リソースを提供できます。 ウィジェットの仕組みはトランスポートに依存しないため、実際のディスクをブラウズするローカルファイルピッカーや、ネイティブアプリを制御するダイアログなども実装可能です。
ウィジェットの作成方法は build-mcp-app スキルで説明しており、こちらでも同様に機能します。
唯一の違いはサーバーの実行場所です。
テスト
# マニフェストの対話的作成(初回)
npx @anthropic-ai/mcpb init
# stdio 経由でサーバーを直接起動し、インスペクターで動作確認
npx @modelcontextprotocol/inspector node server/index.js
# マニフェストをスキーマに対して検証してからパック
npx @anthropic-ai/mcpb validate
npx @anthropic-ai/mcpb pack
# 配布用に署名
npx @anthropic-ai/mcpb sign dist/local-files.mcpb
# インストール: .mcpb ファイルを Claude Desktop にドラッグ&ドロップ
リリース前に、開発ツールチェーンがインストールされていないマシンでテストしてください。 MCPB での「自分のマシンでは動く」問題は、ほぼ確実に実際にはバンドルされていなかった依存パッケージが原因です。
リファレンスファイル
references/manifest-schema.md—manifest.jsonの全フィールドリファレンスreferences/local-security.md— パストラバーサル、サンドボックス化、最小権限の原則
原文(English)を表示
Build an MCPB (Bundled Local MCP Server)
MCPB is a local MCP server packaged with its runtime. The user installs one file; it runs without needing Node, Python, or any toolchain on their machine. It's the sanctioned way to distribute local MCP servers.
MCPB is the secondary distribution path. Anthropic recommends remote MCP servers for directory listing — see https://claude.com/docs/connectors/building/what-to-build.
Use MCPB when the server must run on the user's machine — reading local files, driving a desktop app, talking to localhost services, OS-level APIs. If your server only hits cloud APIs, you almost certainly want a remote HTTP server instead (see build-mcp-server). Don't pay the MCPB packaging tax for something that could be a URL.
What an MCPB bundle contains
my-server.mcpb (zip archive)
├── manifest.json ← identity, entry point, config schema, compatibility
├── server/ ← your MCP server code
│ ├── index.js
│ └── node_modules/ ← bundled dependencies (or vendored)
└── icon.png
The host reads manifest.json, launches server.mcp_config.command as a stdio MCP server, and pipes messages. From your code's perspective it's identical to a local stdio server — the only difference is packaging.
Manifest
{
"$schema": "https://raw.githubusercontent.com/anthropics/mcpb/main/schemas/mcpb-manifest-v0.4.schema.json",
"manifest_version": "0.4",
"name": "local-files",
"version": "0.1.0",
"description": "Read, search, and watch files on the local filesystem.",
"author": { "name": "Your Name" },
"server": {
"type": "node",
"entry_point": "server/index.js",
"mcp_config": {
"command": "node",
"args": ["${__dirname}/server/index.js"],
"env": {
"ROOT_DIR": "${user_config.rootDir}"
}
}
},
"user_config": {
"rootDir": {
"type": "directory",
"title": "Root directory",
"description": "Directory to expose. Defaults to ~/Documents.",
"default": "${HOME}/Documents",
"required": true
}
},
"compatibility": {
"claude_desktop": ">=1.0.0",
"platforms": ["darwin", "win32", "linux"]
}
}
server.type — node, python, or binary. Informational; the actual launch comes from mcp_config.
server.mcp_config — the literal command/args/env to spawn. Use ${__dirname} for bundle-relative paths and ${user_config.<key>} to substitute install-time config. There's no auto-prefix — the env var names your server reads are exactly what you put in env.
user_config — install-time settings surfaced in the host's UI. type: "directory" renders a native folder picker. sensitive: true stores in OS keychain. See references/manifest-schema.md for all fields.
Server code: same as local stdio
The server itself is a standard stdio MCP server. Nothing MCPB-specific in the tool logic.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { readFile, readdir } from "node:fs/promises";
import { join } from "node:path";
import { homedir } from "node:os";
// ROOT_DIR comes from what you put in manifest's server.mcp_config.env — no auto-prefix
const ROOT = (process.env.ROOT_DIR ?? join(homedir(), "Documents"));
const server = new McpServer({ name: "local-files", version: "0.1.0" });
server.registerTool(
"list_files",
{
description: "List files in a directory under the configured root.",
inputSchema: { path: z.string().default(".") },
annotations: { readOnlyHint: true },
},
async ({ path }) => {
const entries = await readdir(join(ROOT, path), { withFileTypes: true });
const list = entries.map(e => ({ name: e.name, dir: e.isDirectory() }));
return { content: [{ type: "text", text: JSON.stringify(list, null, 2) }] };
},
);
server.registerTool(
"read_file",
{
description: "Read a file's contents. Path is relative to the configured root.",
inputSchema: { path: z.string() },
annotations: { readOnlyHint: true },
},
async ({ path }) => {
const text = await readFile(join(ROOT, path), "utf8");
return { content: [{ type: "text", text }] };
},
);
const transport = new StdioServerTransport();
await server.connect(transport);
Sandboxing is entirely your job. There is no manifest-level sandbox — the process runs with full user privileges. Validate paths, refuse to escape ROOT, allowlist spawns. See references/local-security.md.
Before hardcoding ROOT from a config env var, check if the host supports roots/list — the spec-native way to get user-approved directories. See references/local-security.md for the pattern.
Build pipeline
Node
npm install
npx esbuild src/index.ts --bundle --platform=node --outfile=server/index.js
# or: copy node_modules wholesale if native deps resist bundling
npx @anthropic-ai/mcpb pack
mcpb pack zips the directory and validates manifest.json against the schema.
Python
pip install -t server/vendor -r requirements.txt
npx @anthropic-ai/mcpb pack
Vendor dependencies into a subdirectory and prepend it to sys.path in your entry script. Native extensions (numpy, etc.) must be built for each target platform — avoid native deps if you can.
MCPB has no sandbox — security is on you
Unlike mobile app stores, MCPB does NOT enforce permissions. The manifest has no permissions block — the server runs with full user privileges. references/local-security.md is mandatory reading, not optional. Every path must be validated, every spawn must be allowlisted, because nothing stops you at the platform level.
If you came here expecting filesystem/network scoping from the manifest: it doesn't exist. Build it yourself in tool handlers.
If your server's only job is hitting a cloud API, stop — that's a remote server wearing an MCPB costume. The user gains nothing from running it locally, and you're taking on local-security burden for no reason.
MCPB + UI widgets
MCPB servers can serve UI resources exactly like remote MCP apps — the widget mechanism is transport-agnostic. A local file picker that browses the actual disk, a dialog that controls a native app, etc.
Widget authoring is covered in the build-mcp-app skill; it works the same here. The only difference is where the server runs.
Testing
# Interactive manifest creation (first time)
npx @anthropic-ai/mcpb init
# Run the server directly over stdio, poke it with the inspector
npx @modelcontextprotocol/inspector node server/index.js
# Validate manifest against schema, then pack
npx @anthropic-ai/mcpb validate
npx @anthropic-ai/mcpb pack
# Sign for distribution
npx @anthropic-ai/mcpb sign dist/local-files.mcpb
# Install: drag the .mcpb file onto Claude Desktop
Test on a machine without your dev toolchain before shipping. "Works on my machine" failures in MCPB almost always trace to a dependency that wasn't actually bundled.
Reference files
references/manifest-schema.md— fullmanifest.jsonfield referencereferences/local-security.md— path traversal, sandboxing, least privilege
原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。