diff --git a/docs/source/platypush/events/chat.slack.rst b/docs/source/platypush/events/chat.slack.rst
index eb8e8dba9..2ec92aef0 100644
--- a/docs/source/platypush/events/chat.slack.rst
+++ b/docs/source/platypush/events/chat.slack.rst
@@ -1,5 +1,5 @@
-``platypush.message.event.chat.slack``
-======================================
+``chat.slack``
+==============
 
 .. automodule:: platypush.message.event.chat.slack
     :members:
diff --git a/docs/source/platypush/events/dbus.rst b/docs/source/platypush/events/dbus.rst
index c053f4021..c44aec397 100644
--- a/docs/source/platypush/events/dbus.rst
+++ b/docs/source/platypush/events/dbus.rst
@@ -1,5 +1,5 @@
-``platypush.message.event.dbus``
-================================
+``dbus``
+========
 
 .. automodule:: platypush.message.event.dbus
     :members:
diff --git a/docs/source/platypush/events/gotify.rst b/docs/source/platypush/events/gotify.rst
index 82b661bd4..afe674ab9 100644
--- a/docs/source/platypush/events/gotify.rst
+++ b/docs/source/platypush/events/gotify.rst
@@ -1,5 +1,5 @@
-``platypush.message.event.gotify``
-==================================
+``gotify``
+==========
 
 .. automodule:: platypush.message.event.gotify
     :members:
diff --git a/docs/source/platypush/events/irc.rst b/docs/source/platypush/events/irc.rst
index 7eab9d025..c6ba0c308 100644
--- a/docs/source/platypush/events/irc.rst
+++ b/docs/source/platypush/events/irc.rst
@@ -1,5 +1,5 @@
-``platypush.message.event.irc``
-===============================
+``irc``
+=======
 
 .. automodule:: platypush.message.event.irc
     :members:
diff --git a/docs/source/platypush/events/ngrok.rst b/docs/source/platypush/events/ngrok.rst
index 3585933f7..f2108cf58 100644
--- a/docs/source/platypush/events/ngrok.rst
+++ b/docs/source/platypush/events/ngrok.rst
@@ -1,5 +1,5 @@
-``platypush.message.event.ngrok``
-=================================
+``ngrok``
+=========
 
 .. automodule:: platypush.message.event.ngrok
     :members:
diff --git a/docs/source/platypush/events/rss.rst b/docs/source/platypush/events/rss.rst
index cbd31237d..b699bdacf 100644
--- a/docs/source/platypush/events/rss.rst
+++ b/docs/source/platypush/events/rss.rst
@@ -1,5 +1,5 @@
-``platypush.message.event.rss``
-===============================
+``rss``
+=======
 
 .. automodule:: platypush.message.event.rss
     :members:
diff --git a/docs/source/platypush/events/sun.rst b/docs/source/platypush/events/sun.rst
index 135e60d25..a58ea0629 100644
--- a/docs/source/platypush/events/sun.rst
+++ b/docs/source/platypush/events/sun.rst
@@ -1,5 +1,5 @@
-``platypush.message.event.sun``
-===============================
+``sun``
+=======
 
 .. automodule:: platypush.message.event.sun
     :members:
diff --git a/docs/source/platypush/plugins/media.jellyfin.rst b/docs/source/platypush/plugins/media.jellyfin.rst
index 7a9eacc6d..74b8eed95 100644
--- a/docs/source/platypush/plugins/media.jellyfin.rst
+++ b/docs/source/platypush/plugins/media.jellyfin.rst
@@ -1,5 +1,5 @@
 ``media.jellyfin``
-================================
+==================
 
 .. automodule:: platypush.plugins.media.jellyfin
 	:members:
diff --git a/generate_missing_docs.py b/generate_missing_docs.py
index bce44186a..9c80d93d6 100644
--- a/generate_missing_docs.py
+++ b/generate_missing_docs.py
@@ -1,3 +1,4 @@
+import inspect
 import os
 
 from platypush.backend import Backend
@@ -6,11 +7,17 @@ from platypush.plugins import Plugin
 from platypush.utils.manifest import get_manifests
 
 
+def _get_inspect_plugin():
+    p = get_plugin('inspect')
+    assert p, 'Could not load the `inspect` plugin'
+    return p
+
+
 def get_all_plugins():
     manifests = {mf.component_name for mf in get_manifests(Plugin)}
     return {
         plugin_name: plugin_info
-        for plugin_name, plugin_info in get_plugin('inspect').get_all_plugins().output.items()
+        for plugin_name, plugin_info in _get_inspect_plugin().get_all_plugins().output.items()
         if plugin_name in manifests
     }
 
@@ -19,17 +26,17 @@ def get_all_backends():
     manifests = {mf.component_name for mf in get_manifests(Backend)}
     return {
         backend_name: backend_info
-        for backend_name, backend_info in get_plugin('inspect').get_all_backends().output.items()
+        for backend_name, backend_info in _get_inspect_plugin().get_all_backends().output.items()
         if backend_name in manifests
     }
 
 
 def get_all_events():
-    return get_plugin('inspect').get_all_events().output
+    return _get_inspect_plugin().get_all_events().output
 
 
 def get_all_responses():
-    return get_plugin('inspect').get_all_responses().output
+    return _get_inspect_plugin().get_all_responses().output
 
 
 # noinspection DuplicatedCode
@@ -100,16 +107,17 @@ Backends
 
 # noinspection DuplicatedCode
 def generate_events_doc():
+    from platypush.message import event as event_module
     events_index = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'events.rst')
     events_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'platypush', 'events')
-    all_events = sorted(event for event in get_all_events().keys())
+    all_events = sorted(event for event in get_all_events().keys() if event)
 
     for event in all_events:
-        event_file = os.path.join(events_dir, event[len('platypush.message.event.'):] + '.rst')
+        event_file = os.path.join(events_dir, event + '.rst')
         if not os.path.exists(event_file):
             header = '``{}``'.format(event)
             divider = '=' * len(header)
-            body = '\n.. automodule:: {}\n    :members:\n'.format(event)
+            body = '\n.. automodule:: {}.{}\n    :members:\n'.format(event_module.__name__, event)
             out = '\n'.join([header, divider, body])
 
             with open(event_file, 'w') as f:
@@ -127,21 +135,22 @@ Events
 ''')
 
         for event in all_events:
-            f.write('    platypush/events/' + event[len('platypush.message.event.'):] + '.rst\n')
+            f.write('    platypush/events/' + event + '.rst\n')
 
 
 # noinspection DuplicatedCode
 def generate_responses_doc():
+    from platypush.message import response as response_module
     responses_index = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'responses.rst')
     responses_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'docs', 'source', 'platypush', 'responses')
-    all_responses = sorted(response for response in get_all_responses().keys())
+    all_responses = sorted(response for response in get_all_responses().keys() if response)
 
     for response in all_responses:
-        response_file = os.path.join(responses_dir, response[len('platypush.message.response.'):] + '.rst')
+        response_file = os.path.join(responses_dir, response + '.rst')
         if not os.path.exists(response_file):
             header = '``{}``'.format(response)
             divider = '=' * len(header)
-            body = '\n.. automodule:: {}\n    :members:\n'.format(response)
+            body = '\n.. automodule:: {}.{}\n    :members:\n'.format(response_module.__name__, response)
             out = '\n'.join([header, divider, body])
 
             with open(response_file, 'w') as f:
@@ -159,7 +168,7 @@ Responses
 ''')
 
         for response in all_responses:
-            f.write('    platypush/responses/' + response[len('platypush.message.response.'):] + '.rst\n')
+            f.write('    platypush/responses/' + response + '.rst\n')
 
 
 generate_plugins_doc()
diff --git a/platypush/message/__init__.py b/platypush/message/__init__.py
index c79bee4b1..c32f65b0d 100644
--- a/platypush/message/__init__.py
+++ b/platypush/message/__init__.py
@@ -71,7 +71,7 @@ class Message(object):
                 logger.warning('Could not serialize object type {}: {}: {}'.format(
                     type(obj), str(e), obj))
 
-    def __init__(self, timestamp=None, *args, **kwargs):
+    def __init__(self, timestamp=None, *_, **__):
         self.timestamp = timestamp or time.time()
 
     def __str__(self):
@@ -98,9 +98,9 @@ class Message(object):
     def parse(cls, msg):
         """
         Parse a generic message into a key-value dictionary
-        Params:
-            msg -- Original message - can be a dictionary, a Message,
-                   or a string/bytearray, as long as it's valid UTF-8 JSON
+
+        :param msg: Original message. It can be a dictionary, a Message,
+           or a string/bytearray, as long as it's valid UTF-8 JSON
         """
 
         if isinstance(msg, cls):
@@ -124,8 +124,8 @@ class Message(object):
     def build(cls, msg):
         """
         Builds a Message object from a dictionary.
-        Params:
-            msg -- The message as a key-value dictionary, Message object or JSON string
+
+        :param msg: The message as a key-value dictionary, Message object or JSON string
         """
         from platypush.utils import get_message_class_by_type
 
diff --git a/platypush/plugins/inspect/__init__.py b/platypush/plugins/inspect/__init__.py
index 5271e82f6..5a9c1761b 100644
--- a/platypush/plugins/inspect/__init__.py
+++ b/platypush/plugins/inspect/__init__.py
@@ -4,6 +4,7 @@ import json
 import pkgutil
 import re
 import threading
+from abc import ABC, abstractmethod
 from typing import Optional
 
 import platypush.backend   # lgtm [py/import-and-import-from]
@@ -19,8 +20,7 @@ from platypush.message.response import Response
 from platypush.utils import get_decorators
 
 
-# noinspection PyTypeChecker
-class Model:
+class Model(ABC):
     def __str__(self):
         return json.dumps(dict(self), indent=2, sort_keys=True)
 
@@ -37,6 +37,10 @@ class Model:
 
         return docutils.core.publish_parts(doc, writer_name='html')['html_body']
 
+    @abstractmethod
+    def __iter__(self):
+        raise NotImplementedError()
+
 
 class ProcedureEncoder(json.JSONEncoder):
     def default(self, o):
@@ -49,7 +53,7 @@ class ProcedureEncoder(json.JSONEncoder):
 
 
 class BackendModel(Model):
-    def __init__(self, backend, prefix='', html_doc: bool = False):
+    def __init__(self, backend, prefix='', html_doc: Optional[bool] = False):
         self.name = backend.__module__[len(prefix):]
         self.html_doc = html_doc
         self.doc = self.to_html(backend.__doc__) if html_doc and backend.__doc__ else backend.__doc__
@@ -60,11 +64,11 @@ class BackendModel(Model):
 
 
 class PluginModel(Model):
-    def __init__(self, plugin, prefix='', html_doc: bool = False):
+    def __init__(self, plugin, prefix='', html_doc: Optional[bool] = False):
         self.name = plugin.__module__[len(prefix):]
         self.html_doc = html_doc
         self.doc = self.to_html(plugin.__doc__) if html_doc and plugin.__doc__ else plugin.__doc__
-        self.actions = {action_name: ActionModel(getattr(plugin, action_name), html_doc=html_doc)
+        self.actions = {action_name: ActionModel(getattr(plugin, action_name), html_doc=html_doc or False)
                         for action_name in get_decorators(plugin, climb_class_hierarchy=True).get('action', [])}
 
     def __iter__(self):
@@ -77,8 +81,8 @@ class PluginModel(Model):
 
 
 class EventModel(Model):
-    def __init__(self, event, html_doc: bool = False):
-        self.package = event.__module__
+    def __init__(self, event, prefix='', html_doc: Optional[bool] = False):
+        self.package = event.__module__[len(prefix):]
         self.name = event.__name__
         self.html_doc = html_doc
         self.doc = self.to_html(event.__doc__) if html_doc and event.__doc__ else event.__doc__
@@ -89,8 +93,8 @@ class EventModel(Model):
 
 
 class ResponseModel(Model):
-    def __init__(self, response, html_doc: bool = False):
-        self.package = response.__module__
+    def __init__(self, response, prefix='', html_doc: Optional[bool] = False):
+        self.package = response.__module__[len(prefix):]
         self.name = response.__name__
         self.html_doc = html_doc
         self.doc = self.to_html(response.__doc__) if html_doc and response.__doc__ else response.__doc__
@@ -187,7 +191,7 @@ class InspectPlugin(Plugin):
 
         for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
                                                    prefix=prefix,
-                                                   onerror=lambda x: None):
+                                                   onerror=lambda _: None):
             try:
                 module = importlib.import_module(modname)
             except Exception as e:
@@ -207,7 +211,7 @@ class InspectPlugin(Plugin):
 
         for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
                                                    prefix=prefix,
-                                                   onerror=lambda x: None):
+                                                   onerror=lambda _: None):
             try:
                 module = importlib.import_module(modname)
             except Exception as e:
@@ -226,7 +230,7 @@ class InspectPlugin(Plugin):
 
         for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
                                                    prefix=prefix,
-                                                   onerror=lambda x: None):
+                                                   onerror=lambda _: None):
             try:
                 module = importlib.import_module(modname)
             except Exception as e:
@@ -238,7 +242,7 @@ class InspectPlugin(Plugin):
                     continue
 
                 if inspect.isclass(obj) and issubclass(obj, Event) and obj != Event:
-                    event = EventModel(event=obj, html_doc=self._html_doc)
+                    event = EventModel(event=obj, html_doc=self._html_doc, prefix=prefix)
                     if event.package not in self._events:
                         self._events[event.package] = {event.name: event}
                     else:
@@ -250,7 +254,7 @@ class InspectPlugin(Plugin):
 
         for _, modname, _ in pkgutil.walk_packages(path=package.__path__,
                                                    prefix=prefix,
-                                                   onerror=lambda x: None):
+                                                   onerror=lambda _: None):
             try:
                 module = importlib.import_module(modname)
             except Exception as e:
@@ -262,14 +266,14 @@ class InspectPlugin(Plugin):
                     continue
 
                 if inspect.isclass(obj) and issubclass(obj, Response) and obj != Response:
-                    response = ResponseModel(response=obj, html_doc=self._html_doc)
+                    response = ResponseModel(response=obj, html_doc=self._html_doc, prefix=prefix)
                     if response.package not in self._responses:
                         self._responses[response.package] = {response.name: response}
                     else:
                         self._responses[response.package][response.name] = response
 
     @action
-    def get_all_plugins(self, html_doc: bool = None):
+    def get_all_plugins(self, html_doc: Optional[bool] = None):
         """
         :param html_doc: If True then the docstring will be parsed into HTML (default: False)
         """
@@ -284,7 +288,7 @@ class InspectPlugin(Plugin):
             })
 
     @action
-    def get_all_backends(self, html_doc: bool = None):
+    def get_all_backends(self, html_doc: Optional[bool] = None):
         """
         :param html_doc: If True then the docstring will be parsed into HTML (default: False)
         """
@@ -299,7 +303,7 @@ class InspectPlugin(Plugin):
             })
 
     @action
-    def get_all_events(self, html_doc: bool = None):
+    def get_all_events(self, html_doc: Optional[bool] = None):
         """
         :param html_doc: If True then the docstring will be parsed into HTML (default: False)
         """
@@ -311,13 +315,13 @@ class InspectPlugin(Plugin):
             return json.dumps({
                 package: {
                     name: dict(event)
-                    for name, event in self._events[package].items()
+                    for name, event in events.items()
                 }
                 for package, events in self._events.items()
             })
 
     @action
-    def get_all_responses(self, html_doc: bool = None):
+    def get_all_responses(self, html_doc: Optional[bool] = None):
         """
         :param html_doc: If True then the docstring will be parsed into HTML (default: False)
         """
@@ -329,9 +333,9 @@ class InspectPlugin(Plugin):
             return json.dumps({
                 package: {
                     name: dict(event)
-                    for name, event in self._responses[package].items()
+                    for name, event in responses.items()
                 }
-                for package, events in self._responses.items()
+                for package, responses in self._responses.items()
             })
 
     @action
@@ -342,7 +346,7 @@ class InspectPlugin(Plugin):
         return json.loads(json.dumps(Config.get_procedures(), cls=ProcedureEncoder))
 
     @action
-    def get_config(self, entry: Optional[str] = None) -> dict:
+    def get_config(self, entry: Optional[str] = None) -> Optional[dict]:
         """
         Return the configuration of the application or of a section.
 
diff --git a/platypush/plugins/media/jellyfin/__init__.py b/platypush/plugins/media/jellyfin/__init__.py
index 97f5259f5..69cf856a7 100644
--- a/platypush/plugins/media/jellyfin/__init__.py
+++ b/platypush/plugins/media/jellyfin/__init__.py
@@ -182,7 +182,7 @@ class MediaJellyfinPlugin(Plugin):
         :param genres: Filter results by (a list of) genres.
         :param tags: Filter results by (a list of) tags.
         :param years: Filter results by (a list of) years.
-        :return: .. schema:: jellyfin.JellyfinArtistSchema(many=True)
+        :return: .. schema:: media.jellyfin.JellyfinArtistSchema(many=True)
         """
         return self._query(
             '/Artists', schema_class=JellyfinArtistSchema,
@@ -196,7 +196,7 @@ class MediaJellyfinPlugin(Plugin):
         """
         Get the list of collections associated to the user on the server (Movies, Series, Channels etc.)
 
-        :return: .. schema:: jellyfin.JellyfinCollectionSchema(many=True)
+        :return: .. schema:: media.jellyfin.JellyfinCollectionSchema(many=True)
         """
         return self._query(
             f'/Users/{self._user_id}/Items',
@@ -242,6 +242,20 @@ class MediaJellyfinPlugin(Plugin):
         :param genres: Filter results by (a list of) genres.
         :param tags: Filter results by (a list of) tags.
         :param years: Filter results by (a list of) years.
+        :return: The list of matching results.
+
+        Schema for artists:
+            .. schema:: media.jellyfin.JellyfinArtistSchema
+
+        Schema for collections:
+            .. schema:: media.jellyfin.JellyfinCollectionSchema
+
+        Schema for movies:
+            .. schema:: media.jellyfin.JellyfinMovieSchema
+
+        Schema for episodes:
+            .. schema:: media.jellyfin.JellyfinEpisodeSchema
+
         """
         if collection:
             collections = self.get_collections().output   # type: ignore