Plugin vs Skill:本质区别 / 能力边界 / 十大 Plugin 专属能力
第四十九章:Plugin 架构详解:MCP Server、Hooks、LSP 与监控的四层模型
49.1 Plugin 与 Skill 的根本区别
在开始深入技术细节之前,必须先厘清 Claude 生态中两个极易混淆的概念:Plugin 和 Skill。许多初学者将它们当作同义词,这会在后续开发中造成严重的认知偏差。
Skill 是最小的可复用能力单元。一个 Skill 就是一个 Markdown 文件,文件头部有 YAML frontmatter 声明元数据,文件正文用自然语言描述这个能力的使用场景、输入输出规范和行为约束。Skill 本身不包含可执行代码——它是一份"行为说明书",Claude 读取这份说明书后知道如何执行某类任务。
Plugin 则是一个完整的软件包。一个 Plugin 可以包含:
- 一个或多个 MCP Server(提供工具调用能力)
- 一组 Hooks(在 Claude 工作流的关键节点注入逻辑)
- 一个 LSP 实现(让 Claude Code 理解特定语言或领域)
- 一组监控模块(追踪 Claude 的决策过程)
Plugin 是容器,Skill 是内容。一个 Plugin 可以声明它提供哪些 Skill,也可以不提供任何 Skill,纯粹只是扩展 Claude 的工具或感知能力。
Plugin(软件包)
├── plugin.json ← 清单文件
├── mcp/ ← MCP Server 实现
│ ├── server.ts
│ └── tools/
├── hooks/ ← Hook 注入点
│ ├── pre-tool.ts
│ └── post-response.ts
├── lsp/ ← Language Server Protocol
│ └── server.ts
├── monitor/ ← 监控与可观测性
│ └── collector.ts
└── skills/ ← 可选:附带的 Skill 文件
├── skill-a.md
└── skill-b.md
Skill(单个 .md 文件)
└── my-skill.md ← 独立存在,无需依附 Plugin
这种设计的哲学根源在于关注点分离:Skill 服务于"告诉 Claude 做什么",Plugin 服务于"让 Claude 有能力做什么"。
49.2 四层模型总览
Claude Plugin 架构由四个层次组成,每一层都有明确的职责边界和扩展接口。
┌─────────────────────────────────────────────┐
│ Layer 4: 监控层 (Monitor Layer) │
│ 追踪决策、记录成本、审计日志 │
├─────────────────────────────────────────────┤
│ Layer 3: LSP 层 (Language Server Layer) │
│ 领域语言理解、代码补全、诊断 │
├─────────────────────────────────────────────┤
│ Layer 2: Hooks 层 (Lifecycle Hooks Layer) │
│ 生命周期注入、前后处理、权限检查 │
├─────────────────────────────────────────────┤
│ Layer 1: MCP 层 (Model Context Protocol) │
│ 工具定义、资源暴露、外部服务连接 │
└─────────────────────────────────────────────┘
每一层都是可选的。一个最简单的 Plugin 可能只有 MCP 层;一个安全审计 Plugin 可能只有 Hooks 层和监控层;一个语言支持 Plugin 可能只有 LSP 层。
49.3 Layer 1:MCP Server 层
MCP 协议基础
Model Context Protocol(MCP)是 Anthropic 定义的开放协议,规定了 Claude 与外部工具之间的通信格式。MCP Server 是实现这个协议的服务端程序,它向 Claude 暴露三类资源:
Tools(工具):Claude 可以主动调用的函数。工具有明确的 JSON Schema 定义输入参数和返回格式。Claude 在推理过程中决定是否调用某个工具、传入什么参数。
Resources(资源):Claude 可以读取的数据源。与工具不同,资源不需要 Claude 显式调用——Claude 可以在任何时候请求读取某个资源 URI 的内容。资源适合暴露文档、配置文件、数据库视图等"被动读取"的内容。
Prompts(提示模板):预定义的提示模板,用户可以在对话中引用这些模板触发特定工作流。
MCP Server 的传输模式
MCP Server 支持两种传输模式:
STDIO 模式(本地插件):
Claude Code 进程 → stdin/stdout → MCP Server 进程
适用场景:本地工具、命令行集成、无需网络的处理
HTTP/SSE 模式(远程插件):
Claude Code 进程 → HTTP/SSE → 远程 MCP Server
适用场景:云端服务、跨机器调用、需要持久连接
MCP Server 的 Plugin 集成
在 Plugin 中定义 MCP Server 时,plugin.json 需要声明 MCP Server 的启动方式:
{
"name": "my-database-plugin",
"version": "1.0.0",
"mcp": {
"servers": [
{
"id": "db-server",
"transport": "stdio",
"command": "node",
"args": ["./mcp/server.js"],
"env": {
"DB_URL": "${config.databaseUrl}"
}
}
]
}
}
MCP Server 启动后,它通过标准 MCP 握手协议向 Claude 宣告自己提供哪些工具和资源。Claude 将这些工具加入到当前会话的可用工具列表中。
工具定义示例
下面是一个数据库查询工具的完整定义(TypeScript):
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "database-plugin",
version: "1.0.0",
});
server.tool(
"query_database",
"Execute a read-only SQL query against the connected database",
{
sql: z.string().describe("The SQL query to execute (SELECT only)"),
limit: z.number().optional().default(100).describe("Maximum rows to return"),
},
async ({ sql, limit }) => {
// 安全检查:只允许 SELECT 语句
if (!sql.trim().toUpperCase().startsWith("SELECT")) {
throw new Error("Only SELECT queries are allowed");
}
const results = await db.query(sql, { limit });
return {
content: [
{
type: "text",
text: JSON.stringify(results, null, 2),
},
],
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
49.4 Layer 2:Hooks 层
Hooks 的设计理念
Hooks 是 Plugin 对 Claude 工作流生命周期的注入点。与 MCP 工具的"被动等待调用"不同,Hooks 是主动的——它们在 Claude 的每一步操作中自动触发,无需 Claude 显式调用。
这种设计使得 Hooks 非常适合实现:
- 前置检查:在 Claude 执行工具调用前验证权限
- 后置处理:在 Claude 生成回复后进行内容过滤
- 行为审计:记录 Claude 的每一次决策
- 成本控制:在 token 消耗超过阈值时中断对话
内置 Hook 点
Claude 的工作流暴露了以下 Hook 点:
PreToolCall ← 工具调用前(可修改参数、可中止调用)
PostToolCall ← 工具调用后(可修改结果)
PreResponse ← 生成回复前(可修改 system prompt)
PostResponse ← 生成回复后(可修改输出文本)
SessionStart ← 会话开始时
SessionEnd ← 会话结束时
TokenBudgetWarning ← token 使用量达到警告阈值
Hook 实现示例
// hooks/pre-tool.ts
import type { PreToolCallHook, HookContext } from "@claude/plugin-sdk";
export const preToolCall: PreToolCallHook = async (
toolName: string,
toolInput: Record<string, unknown>,
context: HookContext
) => {
// 权限检查:敏感工具需要额外确认
const sensitiveTools = ["execute_bash", "write_file", "delete_file"];
if (sensitiveTools.includes(toolName)) {
const userId = context.session.userId;
const hasPermission = await checkUserPermission(userId, toolName);
if (!hasPermission) {
// 返回 block 信号,中止工具调用
return {
action: "block",
reason: `User ${userId} does not have permission to use ${toolName}`,
};
}
}
// 参数修改示例:自动注入审计字段
if (toolName === "write_file") {
return {
action: "modify",
modifiedInput: {
...toolInput,
metadata: {
...(toolInput.metadata as object),
modifiedBy: context.session.userId,
modifiedAt: new Date().toISOString(),
},
},
};
}
// 允许继续执行
return { action: "allow" };
};
Hook 注册配置
在 plugin.json 中注册 Hook 实现:
{
"hooks": {
"preToolCall": "./hooks/pre-tool.js",
"postResponse": "./hooks/post-response.js",
"sessionStart": "./hooks/session-init.js"
}
}
49.5 Layer 3:LSP 层
Language Server Protocol(LSP)最初由 Microsoft 为 VS Code 设计,用于在编辑器与语言服务之间建立标准化通信。Claude Code 将 LSP 概念引入 Plugin 系统,让 Plugin 能够向 Claude 提供关于特定语言或领域的深度理解能力。
LSP 在 Claude Plugin 中的角色
当用户要求 Claude Code 分析某种专有语言(如企业内部 DSL)或特定框架的代码时,Claude 默认的语言理解能力可能不够精确。LSP Plugin 可以提供:
- 代码诊断:识别领域特定的错误和警告
- 符号定义:跳转到自定义语言的符号定义
- 代码补全:基于领域规则的智能补全建议
- 文档悬停:在光标处显示领域文档
LSP 的 Plugin 集成方式
{
"lsp": {
"languages": ["solidity", "my-dsl"],
"server": {
"command": "node",
"args": ["./lsp/server.js"]
},
"documentSelector": [
{ "language": "solidity", "pattern": "**/*.sol" },
{ "language": "my-dsl", "pattern": "**/*.mydsl" }
]
}
}
Claude Code 在读取匹配文件时会自动启动 LSP Server,并将 LSP 提供的诊断信息、符号信息注入到 Claude 的上下文中。
49.6 Layer 4:监控层
监控层是四层中最容易被忽视但在生产环境中最重要的一层。它负责收集 Claude 工作过程中的遥测数据,为调试、优化和审计提供基础。
监控层的数据维度
决策链路:每一步推理过程的 thinking 摘要
工具调用:工具名称、参数、返回值、延迟
Token 消耗:prompt tokens、completion tokens、成本估算
错误记录:工具调用失败、MCP 超时、解析错误
会话元数据:用户 ID、会话 ID、开始/结束时间
监控层与 Hooks 的关系
监控层通常通过 Hooks 实现,但 Claude Plugin SDK 提供了更高层次的监控抽象,简化了遥测数据的收集和上报:
// monitor/collector.ts
import type { MonitorCollector } from "@claude/plugin-sdk";
export const collector: MonitorCollector = {
onDecision(event) {
metrics.record("claude.decision", {
sessionId: event.sessionId,
model: event.model,
inputTokens: event.usage.inputTokens,
outputTokens: event.usage.outputTokens,
latencyMs: event.latencyMs,
});
},
onToolCall(event) {
metrics.record("claude.tool_call", {
tool: event.toolName,
success: event.success,
latencyMs: event.latencyMs,
sessionId: event.sessionId,
});
},
};
49.7 plugin.json 完整规范
plugin.json 是 Plugin 的清单文件,定义了 Plugin 的全部元数据和配置。以下是完整的字段说明:
{
"name": "my-awesome-plugin",
"version": "1.2.3",
"description": "一句话描述这个 Plugin 做什么",
"author": "Your Name <[email protected]>",
"license": "MIT",
"keywords": ["database", "sql", "analytics"],
"homepage": "https://github.com/yourname/my-awesome-plugin",
"engines": {
"claude-code": ">=1.0.0"
},
"config": {
"schema": {
"databaseUrl": {
"type": "string",
"description": "PostgreSQL connection string",
"required": true,
"secret": true
},
"maxQueryRows": {
"type": "number",
"description": "Maximum rows per query",
"default": 1000
}
}
},
"mcp": {
"servers": [
{
"id": "main",
"transport": "stdio",
"command": "node",
"args": ["./mcp/server.js"]
}
]
},
"hooks": {
"preToolCall": "./hooks/pre-tool.js",
"postResponse": "./hooks/post-response.js"
},
"lsp": {
"languages": ["sql"],
"server": {
"command": "node",
"args": ["./lsp/server.js"]
}
},
"monitor": {
"collector": "./monitor/collector.js",
"sampling": 1.0
},
"skills": [
"./skills/query-builder.md",
"./skills/schema-explorer.md"
],
"permissions": [
"read:files",
"network:outbound"
]
}
字段详解
engines:声明 Plugin 所需的最低 Claude Code 版本,防止在不兼容版本上安装。
config.schema:定义用户安装 Plugin 时需要提供的配置项。secret: true 字段会让 Claude Code 以加密方式存储该值,不在日志中明文输出。
permissions:声明 Plugin 需要的系统权限。Claude Code 在安装时会向用户展示权限列表并要求确认。未声明的权限在运行时将被拒绝。
49.8 Plugin 的隔离模型
安全是 Plugin 系统设计的首要考量。Claude Plugin 采用多层隔离机制:
进程隔离
每个 MCP Server 和 LSP Server 都在独立的子进程中运行,通过 STDIO 或 HTTP 与主进程通信。子进程崩溃不会影响 Claude Code 主进程。
权限隔离
Plugin 声明的 permissions 字段决定了 Plugin 能访问哪些系统资源。Claude Code 在沙箱层面强制执行这些限制,即使 Plugin 代码尝试访问未授权资源也会被操作系统级别的限制拦截。
配置隔离
Plugin 的配置(包括 secrets)与其他 Plugin 的配置完全隔离。每个 Plugin 只能访问自己的配置命名空间。
49.9 从零理解四层协作
以一个"代码安全审计 Plugin"为例,理解四层如何协同工作:
用户请求:"帮我审计这个 Solidity 合约的安全漏洞"
1. LSP 层介入:
- LSP Server 读取 .sol 文件
- 提供 Solidity 语法解析和已知漏洞模式匹配
- 将诊断结果注入 Claude 的上下文
2. MCP 层介入:
- Claude 决定调用 "fetch_vulnerability_database" 工具
- MCP Server 连接到漏洞数据库 API
- 返回最新的 CVE 和漏洞模式
3. Hooks 层介入:
- PreToolCall Hook 检查是否有权限访问外部 API
- PostResponse Hook 验证输出中不包含误导性内容
4. 监控层介入:
- 记录本次审计的完整决策链路
- 统计工具调用次数和延迟
- 上报到监控系统供后续分析
四层各司其职,共同为用户提供一个可靠、可审计、可扩展的 Plugin 能力。
小结
Claude Plugin 的四层架构(MCP → Hooks → LSP → Monitor)提供了一套清晰的关注点分离体系:MCP 负责连接外部世界,Hooks 负责控制工作流,LSP 负责深化语言理解,Monitor 负责全程可观测性。Plugin 与 Skill 的区别在于 Plugin 是软件包容器,Skill 是行为说明书。掌握 plugin.json 清单格式是开发任何 Plugin 的起点。下一章我们将从零开始实际开发一个完整的 Plugin。