MCP Adapter 开发文档

迁移指南:版本 0.3.0

Estimated reading: 13 minutes 1 views 贡献人员

迁移指南:版本 0.3.0

版本 0.3.0 对可观测性系统进行了重大改进,并通过统一的 HTTP 传输实现简化了传输层。

变更内容

可观测性系统重构

可观测性系统已完全重构为使用基于元数据的架构,具有一致的事件命名和状态标签。

重大变更

1. 带有状态标签的统一事件名称(重大变更)

所有事件现在使用一致的基础名称和 status 标签,而不是为成功/失败使用单独的事件名称。

之前(v0.2.x):

// 成功和失败使用不同的事件名称
$handler->record_event('mcp.request.success', ['method' => 'tools/call']);
$handler->record_event('mcp.request.error', ['method' => 'tools/call']);

$handler->record_event('mcp.tool.execution_success', ['tool_name' => 'my-tool']);
$handler->record_event('mcp.tool.execution_failed', ['tool_name' => 'my-tool']);

$handler->record_event('mcp.component.registered', ['component_type' => 'tool']);
$handler->record_event('mcp.component.registration_failed', ['component_type' => 'tool']);

之后(v0.3.0):

// 单一事件名称与状态标签
$handler->record_event('mcp.request', ['status' => 'success', 'method' => 'tools/call']);
$handler->record_event('mcp.request', ['status' => 'error', 'method' => 'tools/call']);

// 工具事件合并到带有元数据的请求事件中
$handler->record_event('mcp.request', [
    'status' => 'success',
    'method' => 'tools/call',
    'component_type' => 'tool',
    'tool_name' => 'my-tool',
    'ability_name' => 'my_ability'
]);

$handler->record_event('mcp.component.registration', ['status' => 'success', 'component_type' => 'tool']);
$handler->record_event('mcp.component.registration', ['status' => 'failed', 'component_type' => 'tool']);

优势:

  • 更容易过滤:使用一个事件名称查询所有请求,按状态过滤
  • 更好的分组:轻松计算成功率
  • 一致的 API:各处模式相同
  • 更丰富的上下文:自动包含工具/提示词/资源元数据

监控系统的迁移:

如果您正在使用查询事件名称的外部监控系统:

-- 之前:查询成功事件
SELECT * FROM events WHERE event_name = 'mcp.request.success'

-- 之后:使用状态过滤器查询
SELECT * FROM events WHERE event_name = 'mcp.request' AND tags->>'status' = 'success'

2. 基于元数据的可观测性

可观测性事件现在在传输层(RequestRouter)集中记录,而不是在各个处理程序中。处理程序将 _metadata 附加到响应,然后流向传输层。

影响: 如果您创建了自定义 MCP 处理程序(工具、提示词、资源),无需迁移 – 系统是向后兼容的。但是,如果您在自定义代码中手动调用 observabilityhandler->recordevent(),请更新为返回 _metadata 代替。

之前(v0.2.x):

class CustomToolsHandler {
    public function call_tool(array $params): array {
        // 手动调用可观测性
        $this->observability_handler->record_event(
            'mcp.tool.execution_success',
            ['tool_name' => $params['name']]
        );
        
        return ['result' => 'success'];
    }
}

之后(v0.3.0):

class CustomToolsHandler {
    public function call_tool(array $params): array {
        // 返回元数据代替
        return [
            'result' => 'success',
            '_metadata' => [
                'component_type' => 'tool',
                'tool_name' => $params['name'],
            ]
        ];
    }
}

RequestRouter 自动:

  • 从响应中提取 _metadata
  • 与请求上下文(方法、传输、server_id)合并
  • 记录带持续时间计时的事件
  • 在返回给客户端之前剥离 _metadata

3. 已移除的辅助方法

已移除: McpObservabilityHelperTrait::recorderrorevent()

此辅助方法在事件名称后附加 _failed 后缀,与新的状态标签模式冲突。

之前(v0.2.x):

$this->record_error_event('mcp.tool.execution', $exception, ['tool_name' => 'my-tool']);
// 创建事件:mcp.tool.execution_failed

之后(v0.3.0):

// 使用标准的 record_event 并包含状态和错误分类
$this->record_event('mcp.request', [
    'status' => 'error',
    'tool_name' => 'my-tool',
    'error_type' => get_class($exception),
    'error_category' => self::categorize_error($exception),
]);

注意: categorize_error() 方法在辅助特质中仍然可用。

4. 增强的事件标签

所有事件现在自动包含更丰富的上下文:

请求事件(mcp.request):

  • statussuccess | error
  • method:MCP 方法名称
  • transport:传输类型
  • server_id:服务器 ID
  • component_type:工具/资源/提示词(适用时)
  • toolnameabilitynamepromptnameresourceuri:组件详情
  • failurereason:特定失败原因(notfound、permissiondenied、executionfailed 等)
  • errorcodeerrortypeerror_category:错误详情

组件注册事件(mcp.component.registration):

  • statussuccess | failed
  • component_type:工具/资源/提示词类型
  • component_name:组件名称
  • server_id:服务器 ID
  • error_type:异常类型(失败时)

会话和请求跟踪:

  • request_id:用于请求关联的 JSON-RPC 请求 ID
  • session_id:MCP 会话 ID(对于 CLI 等非会话传输为 null)
  • newsessionid:新创建的会话 ID(仅在初始化时)
  • params:已清理的请求参数(工具名称、URI、参数计数)

权限错误详情:

当 WordPress 能力从 haspermission() 返回 WPError 时,特定的错误消息和代码现在会自动提取并使用:

// 示例:能力返回带有验证详细信息的 WP_Error
$wp_error = new WP_Error(
    'ability_invalid_input',
    '能力 "wpcom-mcp/user-notifications" 输入无效。原因:input[action] 不是 list、get_settings、get_devices 和 test_delivery 之一。'
);

// 旧行为:
//   - 错误消息:通用 "Access denied for tool: X"
//   - failure_reason:总是 "permission_denied"

// 新行为:
//   - 错误消息:包含详细信息的完整 WP_Error 消息
//   - failure_reason:WP_Error 代码("ability_invalid_input")

优势:

  • 日志中更具体的失败原因(例如 abilityinvalidinput 与通用的 permission_denied
  • 更容易跟踪和警报特定的权限失败类型
  • 错误消息包含来自能力的完整验证上下文
  • 可以监控特定的错误模式(速率限制、配额超出等)

5. 基于实例的处理程序(不再是静态的)

可观测性处理程序现在使用实例方法而不是静态方法,与错误处理程序模式匹配。

之前(v0.2.x):

// 处理程序作为类名传递
$adapter->create_server(
    'my-server',
    'mcp/v1',
    '/mcp',
    'My Server',
    'Description',
    '1.0.0',
    [ HttpTransport::class ],
    ErrorLogMcpErrorHandler::class,
    NullMcpObservabilityHandler::class  // 类名
);

// 静态方法调用
MyObservabilityHandler::record_event('event.name', ['tag' => 'value']);
MyObservabilityHandler::record_timing('metric.name', 123.45, ['tag' => 'value']);

之后(v0.3.0):

// 处理程序仍然作为类名传递给 create_server
// (服务器在内部实例化它们)
$adapter->create_server(
    'my-server',
    'mcp/v1',
    '/mcp',
    'My Server',
    'Description',
    '1.0.0',
    [ HttpTransport::class ],
    ErrorLogMcpErrorHandler::class,
    NullMcpObservabilityHandler::class  // 仍然是类名,由服务器实例化
);

// 实例方法调用(实现自定义处理程序时)
class MyObservabilityHandler implements McpObservabilityHandlerInterface {
    public function record_event(string $event, array $tags = [], ?float $duration_ms = null): void {
        // 实现
    }
}

2. 统一事件/计时接口

recordtiming() 方法已被移除。使用 recordevent() 并带有可选的 $duration_ms 参数代替。

之前(v0.2.x):

// 事件和计时使用单独的方法
$handler::record_event('mcp.request.success', ['method' => 'tools/call']);
$handler::record_timing('mcp.request.duration', 45.23, ['method' => 'tools/call']);

// 这会创建 2 个单独的日志条目

之后(v0.3.0):

// 统一方法,带有可选的持续时间参数
$handler->record_event('mcp.request.success', ['method' => 'tools/call'], 45.23);

// 这会创建 1 个包含计时信息的日志条目
// 输出:[MCP Observability] EVENT mcp.request.success 45.23ms [method=tools/call,...]

3. 已移除的事件

以下事件已被移除以减少日志量:

  • mcp.request.count – 不再发射(与成功/错误事件冗余)

之前: 每个请求生成 3-4 个日志条目:

  • mcp.request.count
  • mcp.request.successmcp.request.error
  • mcp.request.duration

之后: 每个请求生成 1 个日志条目:

  • mcp.request.success(带持续时间)或 mcp.request.error(带持续时间)

自定义处理程序的迁移步骤

如果您有自定义的可观测性处理程序,请更新它们:

步骤 1:从静态方法转换为实例方法

// 之前
class MyHandler implements McpObservabilityHandlerInterface {
    public static function record_event(string $event, array $tags = []): void {
        // ...
    }
    
    public static function record_timing(string $metric, float $duration_ms, array $tags = []): void {
        // ...
    }
}

// 之后
class MyHandler implements McpObservabilityHandlerInterface {
    public function record_event(string $event, array $tags = [], ?float $duration_ms = null): void {
        // 在一个方法中处理事件和计时
        // 如果 $duration_ms 不为 null,请在您的跟踪中包含它
    }
}

步骤 2:移除 record_timing() 方法

recordtiming() 方法在接口中不再存在。将所有跟踪合并到 recordevent() 中。

步骤 3:更新辅助特质使用

如果使用 McpObservabilityHelperTrait::recorderrorevent(),现在是实例方法:

// 之前
static::record_error_event('operation', $exception, ['context' => 'value']);

// 之后
$this->record_error_event('operation', $exception, ['context' => 'value']);

传输层变更

已移除的传输

以下传输类已被移除:

统一 HTTP 传输

HttpTransport 现在是唯一的 HTTP 传输实现:

  • ✅ 完全符合 MCP 2025-06-18 规范
  • ✅ 支持 WordPress REST API 和 JSON-RPC 2.0 格式
  • ✅ 处理流式响应(SSE)和标准 JSON 响应
  • ✅ 内置会话管理和批量请求支持

使用 HttpTransport

所有 MCP 服务器默认使用 HttpTransport

use WPMCPCoreMcpAdapter;
use WPMCPTransportHttpTransport;

add_action('mcp_adapter_init', function($adapter) {
    $adapter->create_server(
        'my-server-id',
        'my-namespace',
        'mcp',
        '我的 MCP 服务器',
        '服务器描述',
        '1.0.0',
        [ HttpTransport::class ],  // 使用 HttpTransport
        ErrorLogMcpErrorHandler::class,
        ['my-plugin/my-ability']
    );
});

高级用法

自定义身份验证

使用传输权限回调进行自定义身份验证:

add_action('mcp_adapter_init', function($adapter) {
    $adapter->create_server(
        'secure-server',
        'secure',
        'mcp',
        '安全服务器',
        '自定义身份验证示例',
        '1.0.0',
        [ HttpTransport::class ],
        ErrorLogMcpErrorHandler::class,
        NullMcpObservabilityHandler::class,
        ['my-plugin/ability'],
        [],  // 资源
        [],  // 提示词
        function() {
            // 自定义权限逻辑
            $api_key = $_SERVER['HTTP_X_API_KEY'] ?? '';
            return validate_api_key($api_key);
        }
    );
});

有关更多身份验证模式,请参见 传输权限指南

自定义传输实现

对于特殊需求(消息队列、自定义协议等),创建自定义传输:

use WPMCPTransportContractsMcpRestTransportInterface;
use WPMCPTransportInfrastructureMcpTransportContext;
use WPMCPTransportInfrastructureMcpTransportHelperTrait;

class MyCustomTransport implements McpRestTransportInterface {
    use McpTransportHelperTrait;
    
    private McpTransportContext $context;
    
    public function __construct(McpTransportContext $context) {
        $this->context = $context;
        $this->register_routes();
    }
    
    public function register_routes(): void {
        // 注册您的自定义路由
    }
    
    public function check_permission(WP_REST_Request $request) {
        return is_user_logged_in();
    }
    
    public function handle_request(WP_REST_Request $request): WP_REST_Response {
        $body = $request->get_json_params();
        
        $result = $this->context->request_router->route_request(
            $body['method'],
            $body['params'] ?? [],
            $body['id'] ?? 0,
            $this->get_transport_name()
        );
        
        return rest_ensure_response($result);
    }
}

有关详细的实现说明,请参见 自定义传输指南

下一步

留下第一个评论