第 49 章

Plugin vs Skill:本质区别 / 能力边界 / 十大 Plugin 专属能力

第四十九章:Plugin 架构详解:MCP Server、Hooks、LSP 与监控的四层模型

49.1 Plugin 与 Skill 的根本区别

在开始深入技术细节之前,必须先厘清 Claude 生态中两个极易混淆的概念:PluginSkill。许多初学者将它们当作同义词,这会在后续开发中造成严重的认知偏差。

Skill 是最小的可复用能力单元。一个 Skill 就是一个 Markdown 文件,文件头部有 YAML frontmatter 声明元数据,文件正文用自然语言描述这个能力的使用场景、输入输出规范和行为约束。Skill 本身不包含可执行代码——它是一份"行为说明书",Claude 读取这份说明书后知道如何执行某类任务。

Plugin 则是一个完整的软件包。一个 Plugin 可以包含:

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 非常适合实现:

内置 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。

本章评分
4.7  / 5  (3 评分)

💬 留言讨论