mcpField
B
build-mcpb

build-mcpb

github.com/anthropics开发45.1k6.4k 次安装1 天前更新
代码仓库

关于 build-mcpb

面向开发者的技能,用于将本地 MCP 服务及其运行时打包为 MCPB。内容涵盖清单、依赖打包、验证和安全注意事项,适用于需访问本地文件、桌面应用或 localhost 服务的服务。

主要功能

  1. 01定义 MCPB 清单与配置
  2. 02打包服务端代码及依赖
  3. 03打包并验证 MCPB 文件
  4. 04配置安装时的用户设置
  5. 05检查本地服务的安全风险

适用场景

  1. 01分发读取本地文件的服务
  2. 02打包控制桌面应用的服务
  3. 03打包使用 localhost 服务的服务

MCP 相关

MCPB 包含标准的 stdio MCP 服务。宿主根据清单配置启动该服务,并通过 stdio 传递 MCP 消息。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/anthropics/claude-plugins-official --skill build-mcpb

安装后在 Claude Code 中输入/build-mcpb确认已加载。

附带文件references/local-security.mdreferences/manifest-schema.md

详细介绍

构建 MCPB(打包的本地 MCP 服务)

MCPB 是一种与其运行时一起打包的本地 MCP 服务。用户安装单个文件即可运行,无需在其机器上安装 Node、Python 或任何工具链。这是分发本地 MCP 服务的官方认可方式。

MCPB 是次要分发路径。Anthropic 推荐使用远程 MCP 服务进行目录收录——参见 https://claude.com/docs/connectors/building/what-to-build。

当服务必须在用户机器上运行时使用 MCPB——读取本地文件、驱动桌面应用、与 localhost 服务通信、调用操作系统级 API。如果你的服务只访问云端 API,那几乎肯定应该改用远程 HTTP 服务(参见 build-mcp-server)。不要为了一件本可以做成 URL 的事情去支付 MCPB 的打包税。


MCPB 包包含什么

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

宿主读取 manifest.json,以 stdio MCP 服务的方式启动 server.mcp_config.command,并转发消息。从你的代码角度看,这与本地 stdio 服务完全相同——唯一区别在于打包方式。


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 或 binary。仅供参考;实际启动方式来自 mcp_config。

server.mcp_config——用于启动的字面命令/参数/环境变量。使用 ${__dirname} 表示包内相对路径,使用 ${user_config.<key>} 替换安装时配置。没有自动前缀——你的服务读取的环境变量名就是你在 env 中填写的名称。

user_config——在宿主 UI 中呈现的安装时设置。type: "directory" 会渲染原生文件夹选择器。sensitive: true 会存储到操作系统钥匙串。所有字段参见 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 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);

沙箱完全由你负责。 Manifest 层面没有沙箱——进程以完整的用户权限运行。验证路径、拒绝逃逸出 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
# or: copy node_modules wholesale if native deps resist bundling
npx @anthropic-ai/mcpb pack

mcpb pack 会打包该目录,并根据 schema 验证 manifest.json。

Python
pip install -t server/vendor -r requirements.txt
npx @anthropic-ai/mcpb pack

将依赖项放入子目录,并在你的入口脚本中将其前置到 sys.path。原生扩展(numpy 等)必须为每个目标平台分别构建——尽可能避免使用原生依赖。


MCPB 没有沙箱——安全由你负责

与移动应用商店不同,MCPB 不强制实施权限。Manifest 中没有 permissions 块——服务以完整的用户权限运行。references/local-security.md 是必读内容,而非可选。每个路径都必须验证,每次 spawn 都必须列入白名单,因为在平台层面没有任何机制能阻止你。

如果你来到这里时期望从 manifest 获得文件系统/网络范围限制:它并不存在。请在工具处理程序中自行实现。

如果你的服务唯一的工作就是访问某个云端 API,那就停下——那是一个穿着 MCPB 外衣的远程服务。用户在本地运行它得不到任何好处,而你却毫无理由地承担了本地安全负担。


MCPB + UI 组件

MCPB 服务可以像远程 MCP 应用一样提供 UI 资源——组件机制与传输方式无关。比如一个浏览真实磁盘的本地文件选择器、一个控制原生应用的对话框等。

组件编写在 build-mcp-app 技能中介绍;在这里同样适用。唯一区别是服务运行的位置。


测试

# 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

在发布前,在一台没有你的开发工具链的机器上测试。MCPB 中“在我机器上能跑”的失败几乎总是源于某个依赖实际上并未被打包进去。


参考文件

  • references/manifest-schema.md — 完整的 manifest.json 字段参考
  • references/local-security.md — 路径遍历、沙箱、最小权限

评论

支持 Markdown