429 ) ); } $presented = self::extract_token( $request ); if ( '' === $presented ) { Mcp_Rate_Limiter::record_failure(); return self::unauthorized( 'Missing MCP token.' ); } $stored = Mcp_Pairing::site_token(); if ( '' === $stored ) { // Not connected — nothing to authenticate against. return self::unauthorized( 'This site is not connected to xSpeed MCP.' ); } if ( ! hash_equals( $stored, $presented ) ) { Mcp_Rate_Limiter::record_failure(); return self::unauthorized( 'Invalid MCP token.' ); } Mcp_Rate_Limiter::clear(); return true; } /** * Read the site token from the request header. Trimmed; empty string * when absent. * * @param \WP_REST_Request $request Incoming request. */ private static function extract_token( \WP_REST_Request $request ): string { $header = $request->get_header( self::TOKEN_HEADER ); if ( ! is_string( $header ) ) { return ''; } return trim( $header ); } /** * Build a 401 WP_Error with the REST status attached so the broker * (and any direct caller) sees a proper HTTP 401. * * @param string $message Human-readable reason. * @return \WP_Error */ private static function unauthorized( string $message ) { return new \WP_Error( 'xspeed_mcp_unauthorized', $message, array( 'status' => 401 ) ); } }