PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.3
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.3
3.4.3 3.4.2 3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 All 196 releases
convertkit / vendor / wordpress / mcp-adapter / includes / Transport / HttpTransport.php

HttpTransport.php in Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages 3.4.3, at vendor/wordpress/mcp-adapter/includes/Transport/HttpTransport.php

155 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MCP HTTP Transport for WordPress (MCP 2025-11-25 baseline)
4 *
5 * This transport implements the MCP HTTP transport surface used by this plugin.
6 * It can work both with and without the mcp-wordpress-remote proxy.
7 *
8 * Note: SSE (GET streaming) is not yet implemented; GET currently returns 405.
9 *
10 * @package McpAdapter
11 */
12
13 declare( strict_types=1 );
14
15 namespace WP\MCP\Transport;
16
17 use WP\MCP\Transport\Contracts\McpRestTransportInterface;
18 use WP\MCP\Transport\Infrastructure\HttpRequestContext;
19 use WP\MCP\Transport\Infrastructure\HttpRequestHandler;
20 use WP\MCP\Transport\Infrastructure\McpTransportContext;
21 use WP\MCP\Transport\Infrastructure\McpTransportHelperTrait;
22
23 // Exit if accessed directly.
24 defined( 'ABSPATH' ) || exit;
25
26 /**
27 * MCP HTTP Transport - Unified transport for both proxy and direct clients
28 *
29 * Implements the MCP 2025-11-25 HTTP transport shape used by this adapter (POST + sessions).
30 *
31 * Note: SSE (GET streaming) is not yet implemented; GET currently returns 405.
32 */
33 class HttpTransport implements McpRestTransportInterface {
34 use McpTransportHelperTrait;
35
36 /**
37 * The HTTP request handler.
38 *
39 * @var \WP\MCP\Transport\Infrastructure\HttpRequestHandler
40 */
41 protected HttpRequestHandler $request_handler;
42
43 /**
44 * Initialize the class and register routes
45 *
46 * @param \WP\MCP\Transport\Infrastructure\McpTransportContext $transport_context The transport context.
47 */
48 public function __construct( McpTransportContext $transport_context ) {
49 $this->request_handler = new HttpRequestHandler( $transport_context );
50 add_action( 'rest_api_init', array( $this, 'register_routes' ), 16 );
51 }
52
53 /**
54 * Register MCP HTTP routes
55 */
56 public function register_routes(): void {
57 // Get server info from request handler's transport context
58 $server = $this->request_handler->get_transport_context()->mcp_server;
59
60 // Single endpoint for MCP communication (POST, GET reserved for SSE, DELETE for session termination).
61 // Do not remove GET: it is part of the MCP HTTP transport shape and will be implemented (SSE) in a future iteration.
62 register_rest_route(
63 $server->get_server_route_namespace(),
64 $server->get_server_route(),
65 array(
66 'methods' => array( 'POST', 'GET', 'DELETE' ),
67 'callback' => array( $this, 'handle_request' ),
68 'permission_callback' => array( $this, 'check_permission' ),
69 )
70 );
71 }
72
73 /**
74 * Check if the user has permission to access the MCP API
75 *
76 * @param \WP_REST_Request<array<string, mixed>> $request The request object.
77 *
78 * @return bool True if the user has permission, false otherwise.
79 */
80 public function check_permission( \WP_REST_Request $request ) {
81 $context = new HttpRequestContext( $request );
82
83 // Check permission using callback or default
84 $transport_context = $this->request_handler->get_transport_context();
85
86 if ( null !== $transport_context->transport_permission_callback ) {
87 try {
88 $result = call_user_func( $transport_context->transport_permission_callback, $context->request );
89
90 // Handle WP_Error returns
91 if ( ! is_wp_error( $result ) ) {
92 // Cast to bool to match return type while preserving truthy/falsy semantics.
93 return (bool) $result;
94 }
95
96 // Log the error and deny access (fail-closed)
97 $this->request_handler->get_transport_context()->error_handler->log(
98 'Permission callback returned WP_Error: ' . $result->get_error_message(),
99 array( 'HttpTransport::check_permission' )
100 );
101
102 return false;
103 } catch ( \Throwable $e ) {
104 // Log the error and deny access (fail-closed)
105 $this->request_handler->get_transport_context()->error_handler->log( 'Error in transport permission callback: ' . $e->getMessage(), array( 'HttpTransport::check_permission' ) );
106
107 return false;
108 }
109 }
110
111 /**
112 * Filters the default user capability required for MCP transport access.
113 *
114 * This filter is only applied when no custom transport permission callback
115 * is provided. The capability is checked using current_user_can().
116 *
117 * @since 0.3.0
118 *
119 * @param string $capability The required capability. Default 'read'.
120 * @param \WP\MCP\Transport\Infrastructure\HttpRequestContext $context The HTTP request context.
121 */
122 $user_capability = apply_filters( 'mcp_adapter_default_transport_permission_user_capability', 'read', $context );
123
124 // Validate that the filtered capability is a non-empty string
125 if ( ! is_string( $user_capability ) || empty( $user_capability ) ) {
126 $user_capability = 'read';
127 }
128
129 $user_has_capability = current_user_can( $user_capability ); // phpcs:ignore WordPress.WP.Capabilities.Undetermined -- Capability is filtered and defaults to 'read'
130
131 if ( ! $user_has_capability ) {
132 $user_id = get_current_user_id();
133 $this->request_handler->get_transport_context()->error_handler->log(
134 sprintf( 'Permission denied for MCP API access. User ID %d does not have capability "%s"', $user_id, $user_capability ),
135 array( 'HttpTransport::check_permission' )
136 );
137 }
138
139 return $user_has_capability;
140 }
141
142 /**
143 * Handle HTTP requests according to MCP 2025-11-25 specification
144 *
145 * @param \WP_REST_Request<array<string, mixed>> $request The request object.
146 *
147 * @return \WP_REST_Response
148 */
149 public function handle_request( \WP_REST_Request $request ): \WP_REST_Response {
150 $context = new HttpRequestContext( $request );
151
152 return $this->request_handler->handle_request( $context );
153 }
154 }
155