diff --git a/doc/source/api.rst b/doc/source/api.rst
index b950f39..786640a 100644
--- a/doc/source/api.rst
+++ b/doc/source/api.rst
@@ -6,3 +6,8 @@ API reference
 .. automodule:: jenkins
     :members:
     :undoc-members:
+
+.. automodule:: jenkins.plugins
+    :members:
+    :noindex:
+    :undoc-members:
diff --git a/jenkins/__init__.py b/jenkins/__init__.py
index 45d1909..679f706 100644
--- a/jenkins/__init__.py
+++ b/jenkins/__init__.py
@@ -53,6 +53,7 @@ import socket
 import sys
 import warnings
 
+import multi_key_dict
 import six
 from six.moves.http_client import BadStatusLine
 from six.moves.urllib.error import HTTPError
@@ -60,6 +61,10 @@ from six.moves.urllib.error import URLError
 from six.moves.urllib.parse import quote, urlencode, urljoin, urlparse
 from six.moves.urllib.request import Request, urlopen
 
+from jenkins import plugins
+
+warnings.simplefilter("default", DeprecationWarning)
+
 if sys.version_info < (2, 7, 0):
     warnings.warn("Support for python 2.6 is deprecated and will be removed.")
 
@@ -495,7 +500,10 @@ class Jenkins(object):
         """Get all installed plugins information on this Master.
 
         This method retrieves information about each plugin that is installed
-        on master.
+        on master returning the raw plugin data in a JSON format.
+
+        .. deprecated:: 0.4.9
+           Use :func:`get_plugins` instead.
 
         :param depth: JSON depth, ``int``
         :returns: info on all plugins ``[dict]``
@@ -513,24 +521,24 @@ class Jenkins(object):
             u'gearman-plugin', u'bundled': False}, ..]
 
         """
-        try:
-            plugins_info = json.loads(self.jenkins_open(
-                Request(self._build_url(PLUGIN_INFO, locals()))
-            ))
-            return plugins_info['plugins']
-        except (HTTPError, BadStatusLine):
-            raise BadHTTPException("Error communicating with server[%s]"
-                                   % self.server)
-        except ValueError:
-            raise JenkinsException("Could not parse JSON info for server[%s]"
-                                   % self.server)
+        warnings.warn("get_plugins_info() is deprecated, use get_plugins()",
+                      DeprecationWarning)
+        return [plugin_data for plugin_data in self.get_plugins(depth).values()]
 
     def get_plugin_info(self, name, depth=2):
         """Get an installed plugin information on this Master.
 
-        This method retrieves information about a speicifc plugin.
+        This method retrieves information about a specific plugin and returns
+        the raw plugin data in a JSON format.
         The passed in plugin name (short or long) must be an exact match.
 
+        .. note:: Calling this method will query Jenkins fresh for the
+            information for all plugins on each call. If you need to retrieve
+            information for multiple plugins it's recommended to use
+            :func:`get_plugins` instead, which will return a multi key
+            dictionary that can be accessed via either the short or long name
+            of the plugin.
+
         :param name: Name (short or long) of plugin, ``str``
         :param depth: JSON depth, ``int``
         :returns: a specific plugin ``dict``
@@ -548,12 +556,45 @@ class Jenkins(object):
             u'gearman-plugin', u'bundled': False}
 
         """
+        plugins_info = self.get_plugins(depth)
         try:
-            plugins_info = json.loads(self.jenkins_open(
+            return plugins_info[name]
+        except KeyError:
+            pass
+
+    def get_plugins(self, depth=2):
+        """Return plugins info using helper class for version comparison
+
+        This method retrieves information about all the installed plugins and
+        uses a Plugin helper class to simplify version comparison. Also uses
+        a multi key dict to allow retrieval via either short or long names.
+
+        When printing/dumping the data, the version will transparently return
+        a unicode string, which is exactly what was previously returned by the
+        API.
+
+        :param depth: JSON depth, ``int``
+        :returns: info on all plugins ``[dict]``
+
+        Example::
+
+            >>> j = Jenkins()
+            >>> info = j.get_plugins()
+            >>> print(info)
+            {('gearman-plugin', 'Gearman Plugin'):
+              {u'backupVersion': None, u'version': u'0.0.4',
+               u'deleted': False, u'supportsDynamicLoad': u'MAYBE',
+               u'hasUpdate': True, u'enabled': True, u'pinned': False,
+               u'downgradable': False, u'dependencies': [], u'url':
+               u'http://wiki.jenkins-ci.org/display/JENKINS/Gearman+Plugin',
+               u'longName': u'Gearman Plugin', u'active': True, u'shortName':
+               u'gearman-plugin', u'bundled': False}, ...}
+
+        """
+
+        try:
+            plugins_info_json = json.loads(self.jenkins_open(
                 Request(self._build_url(PLUGIN_INFO, locals()))))
-            for plugin in plugins_info['plugins']:
-                if plugin['longName'] == name or plugin['shortName'] == name:
-                    return plugin
         except (HTTPError, BadStatusLine):
             raise BadHTTPException("Error communicating with server[%s]"
                                    % self.server)
@@ -561,6 +602,13 @@ class Jenkins(object):
             raise JenkinsException("Could not parse JSON info for server[%s]"
                                    % self.server)
 
+        plugins_data = multi_key_dict.multi_key_dict()
+        for plugin_data in plugins_info_json['plugins']:
+            keys = (str(plugin_data['shortName']), str(plugin_data['longName']))
+            plugins_data[keys] = plugins.Plugin(**plugin_data)
+
+        return plugins_data
+
     def get_jobs(self, folder_depth=0):
         """Get list of jobs.
 
diff --git a/jenkins/plugins.py b/jenkins/plugins.py
new file mode 100644
index 0000000..d16e1d5
--- /dev/null
+++ b/jenkins/plugins.py
@@ -0,0 +1,111 @@
+# Software License Agreement (BSD License)
+#
+# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following
+#    disclaimer in the documentation and/or other materials provided
+#    with the distribution.
+#  * Neither the name of Willow Garage, Inc. nor the names of its
+#    contributors may be used to endorse or promote products derived
+#    from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors:
+# Darragh Bailey <dbailey@hp.com>
+
+'''
+.. module:: jenkins.plugins
+    :platform: Unix, Windows
+    :synopsis: Class for interacting with plugins
+'''
+
+import operator
+import re
+
+import pkg_resources
+
+
+class Plugin(dict):
+    '''Dictionary object containing plugin metadata.'''
+
+    def __init__(self, *args, **kwargs):
+        '''Populates dictionary using json object input.
+
+        accepts same arguments as python `dict` class.
+        '''
+        version = kwargs.pop('version', None)
+
+        super(Plugin, self).__init__(*args, **kwargs)
+        self['version'] = version
+
+    def __setitem__(self, key, value):
+        '''Overrides default setter to ensure that the version key is always
+        a PluginVersion class to abstract and simplify version comparisons
+        '''
+        if key == 'version':
+            value = PluginVersion(value)
+        super(Plugin, self).__setitem__(key, value)
+
+
+class PluginVersion(object):
+    '''Class providing comparison capabilities for plugin versions.'''
+
+    _VERSION_RE = re.compile(r'(.*)-(?:SNAPSHOT|BETA)')
+
+    def __init__(self, version):
+        '''Parse plugin version and store it for comparison.'''
+
+        self._version = version
+        self.parsed_version = pkg_resources.parse_version(
+            self.__convert_version(version))
+
+    def __convert_version(self, version):
+        return self._VERSION_RE.sub(r'\g<1>.preview', str(version))
+
+    def __compare(self, op, version):
+        return op(self.parsed_version, pkg_resources.parse_version(
+            self.__convert_version(version)))
+
+    def __le__(self, version):
+        return self.__compare(operator.le, version)
+
+    def __lt__(self, version):
+        return self.__compare(operator.lt, version)
+
+    def __ge__(self, version):
+        return self.__compare(operator.ge, version)
+
+    def __gt__(self, version):
+        return self.__compare(operator.gt, version)
+
+    def __eq__(self, version):
+        return self.__compare(operator.eq, version)
+
+    def __ne__(self, version):
+        return self.__compare(operator.ne, version)
+
+    def __str__(self):
+        return str(self._version)
+
+    def __repr__(self):
+        return str(self._version)
diff --git a/requirements.txt b/requirements.txt
index 1b08df6..4e3e8db 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
 six>=1.3.0
 pbr>=0.8.2,<2.0
+multi_key_dict
diff --git a/test-requirements.txt b/test-requirements.txt
index 0d2aa87..956f12a 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -6,4 +6,5 @@ unittest2
 python-subunit
 sphinx>=1.2,<1.3.0
 testrepository
+testscenarios
 testtools
diff --git a/tests/test_plugins.py b/tests/test_plugins.py
index 04eae34..698a7a6 100644
--- a/tests/test_plugins.py
+++ b/tests/test_plugins.py
@@ -1,7 +1,42 @@
+# Software License Agreement (BSD License)
+#
+# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#  * Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+#  * Redistributions in binary form must reproduce the above
+#    copyright notice, this list of conditions and the following
+#    disclaimer in the documentation and/or other materials provided
+#    with the distribution.
+#  * Neither the name of Willow Garage, Inc. nor the names of its
+#    contributors may be used to endorse or promote products derived
+#    from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+
 import json
 from mock import patch
+from testscenarios.testcase import TestWithScenarios
 
 import jenkins
+from jenkins import plugins
 from tests.base import JenkinsTestBase
 
 
@@ -29,6 +64,14 @@ class JenkinsPluginsBase(JenkinsTestBase):
         ]
     }
 
+    updated_plugin_info_json = {
+        u"plugins":
+        [
+            dict(plugin_info_json[u"plugins"][0],
+                 **{u"version": u"1.6"})
+        ]
+    }
+
 
 class JenkinsPluginsInfoTest(JenkinsPluginsBase):
 
@@ -129,6 +172,28 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
         self.assertEqual(plugin_info, self.plugin_info_json['plugins'][0])
         self._check_requests(jenkins_mock.call_args_list)
 
+    @patch.object(jenkins.Jenkins, 'jenkins_open')
+    def test_get_plugin_info_updated(self, jenkins_mock):
+
+        jenkins_mock.side_effect = [
+            json.dumps(self.plugin_info_json),
+            json.dumps(self.updated_plugin_info_json)
+        ]
+        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+
+        plugins_info = j.get_plugins()
+        self.assertEqual(plugins_info["mailer"]["version"],
+                         self.plugin_info_json['plugins'][0]["version"])
+
+        self.assertNotEqual(
+            plugins_info["mailer"]["version"],
+            self.updated_plugin_info_json['plugins'][0]["version"])
+
+        plugins_info = j.get_plugins()
+        self.assertEqual(
+            plugins_info["mailer"]["version"],
+            self.updated_plugin_info_json['plugins'][0]["version"])
+
     @patch.object(jenkins.Jenkins, 'jenkins_open')
     def test_return_none(self, jenkins_mock):
         jenkins_mock.return_value = json.dumps(self.plugin_info_json)
@@ -191,3 +256,87 @@ class JenkinsPluginInfoTest(JenkinsPluginsBase):
             str(context_manager.exception),
             'Error communicating with server[http://example.com/]')
         self._check_requests(jenkins_mock.call_args_list)
+
+
+class PluginsTestScenarios(TestWithScenarios, JenkinsPluginsBase):
+    scenarios = [
+        ('s1', dict(v1='1.0.0', op='__gt__', v2='0.8.0')),
+        ('s2', dict(v1='1.0.1alpha', op='__gt__', v2='1.0.0')),
+        ('s3', dict(v1='1.0', op='__eq__', v2='1.0.0')),
+        ('s4', dict(v1='1.0', op='__eq__', v2='1.0')),
+        ('s5', dict(v1='1.0', op='__lt__', v2='1.8.0')),
+        ('s6', dict(v1='1.0.1alpha', op='__lt__', v2='1.0.1')),
+        ('s7', dict(v1='1.0alpha', op='__lt__', v2='1.0.0')),
+        ('s8', dict(v1='1.0-alpha', op='__lt__', v2='1.0.0')),
+        ('s9', dict(v1='1.1-alpha', op='__gt__', v2='1.0')),
+        ('s10', dict(v1='1.0-SNAPSHOT', op='__lt__', v2='1.0')),
+        ('s11', dict(v1='1.0.preview', op='__lt__', v2='1.0')),
+        ('s12', dict(v1='1.1-SNAPSHOT', op='__gt__', v2='1.0')),
+        ('s13', dict(v1='1.0a-SNAPSHOT', op='__lt__', v2='1.0a')),
+    ]
+
+    def setUp(self):
+        super(PluginsTestScenarios, self).setUp()
+
+        plugin_info_json = dict(self.plugin_info_json)
+        plugin_info_json[u"plugins"][0][u"version"] = self.v1
+
+        patcher = patch.object(jenkins.Jenkins, 'jenkins_open')
+        self.jenkins_mock = patcher.start()
+        self.addCleanup(patcher.stop)
+        self.jenkins_mock.return_value = json.dumps(plugin_info_json)
+
+    def test_plugin_version_comparison(self):
+        """Verify that valid versions are ordinally correct.
+
+        That is, for each given scenario, v1.op(v2)==True where 'op' is the
+        equality operator defined for the scenario.
+        """
+        plugin_name = "Jenkins Mailer Plugin"
+        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        plugin_info = j.get_plugins()[plugin_name]
+        v1 = plugin_info.get("version")
+
+        op = getattr(v1, self.op)
+
+        self.assertTrue(op(self.v2),
+                        msg="Unexpectedly found {0} {2} {1} == False "
+                            "when comparing versions!"
+                            .format(v1, self.v2, self.op))
+
+    def test_plugin_version_object_comparison(self):
+        """Verify use of PluginVersion for comparison
+
+        Verify that converting the version to be compared to the same object
+        type of PluginVersion before comparing provides the same result.
+        """
+        plugin_name = "Jenkins Mailer Plugin"
+        j = jenkins.Jenkins('http://example.com/', 'test', 'test')
+        plugin_info = j.get_plugins()[plugin_name]
+        v1 = plugin_info.get("version")
+
+        op = getattr(v1, self.op)
+        v2 = plugins.PluginVersion(self.v2)
+
+        self.assertTrue(op(v2),
+                        msg="Unexpectedly found {0} {2} {1} == False "
+                            "when comparing versions!"
+                            .format(v1, v2, self.op))
+
+
+class PluginsTest(JenkinsPluginsBase):
+
+    def test_plugin_equal(self):
+
+        p1 = plugins.Plugin(self.plugin_info_json)
+        p2 = plugins.Plugin(self.plugin_info_json)
+
+        self.assertEqual(p1, p2)
+
+    def test_plugin_not_equal(self):
+
+        p1 = plugins.Plugin(self.plugin_info_json)
+        p2 = plugins.Plugin(self.plugin_info_json)
+        p2[u'version'] = u"1.6"
+
+        self.assertNotEqual(p1, p2)