diff --git a/doc/source/server.rst b/doc/source/server.rst
index 933829f3a..b7ac48650 100644
--- a/doc/source/server.rst
+++ b/doc/source/server.rst
@@ -16,3 +16,5 @@ Server
 .. autofunction:: expected_exceptions
 
 .. autoexception:: ExpectedException
+
+.. autofunction:: get_local_context
diff --git a/oslo/messaging/__init__.py b/oslo/messaging/__init__.py
index 83529c5b4..453a73ea2 100644
--- a/oslo/messaging/__init__.py
+++ b/oslo/messaging/__init__.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from .exceptions import *
+from .localcontext import *
 from .notify import *
 from .rpc import *
 from .serializer import *
diff --git a/oslo/messaging/_drivers/amqpdriver.py b/oslo/messaging/_drivers/amqpdriver.py
index b20a61cf0..bece4cc25 100644
--- a/oslo/messaging/_drivers/amqpdriver.py
+++ b/oslo/messaging/_drivers/amqpdriver.py
@@ -73,8 +73,6 @@ class AMQPListener(base.Listener):
         self.incoming = []
 
     def __call__(self, message):
-        # FIXME(markmc): del local.store.context
-
         # FIXME(markmc): logging isn't driver specific
         rpc_common._safe_log(LOG.debug, 'received %s', message)
 
diff --git a/oslo/messaging/localcontext.py b/oslo/messaging/localcontext.py
new file mode 100644
index 000000000..f7da49f63
--- /dev/null
+++ b/oslo/messaging/localcontext.py
@@ -0,0 +1,55 @@
+
+# Copyright 2013 Red Hat, Inc.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+__all__ = [
+    'get_local_context',
+    'set_local_context',
+    'clear_local_context',
+]
+
+import threading
+import uuid
+
+_KEY = '_%s_%s' % (__name__.replace('.', '_'), uuid.uuid4().hex)
+_STORE = threading.local()
+
+
+def get_local_context(ctxt):
+    """Retrieve the RPC endpoint request context for the current thread.
+
+    This method allows any code running in the context of a dispatched RPC
+    endpoint method to retrieve the context for this request.
+
+    This is commonly used for logging so that, for example, you can include the
+    request ID, user and tenant in every message logged from a RPC endpoint
+    method.
+
+    :returns: the context for the retuest dispatched in the current thread
+    """
+    return getattr(_STORE, _KEY, None)
+
+
+def set_local_context(ctxt):
+    """Set the request context for the current thread.
+
+    :param ctxt: a deserialized request context
+    :type ctxt: dict
+    """
+    setattr(_STORE, _KEY, ctxt)
+
+
+def clear_local_context():
+    """Clear the request context for the current thread."""
+    delattr(_STORE, _KEY)
diff --git a/oslo/messaging/rpc/dispatcher.py b/oslo/messaging/rpc/dispatcher.py
index 183b7ca58..93d230088 100644
--- a/oslo/messaging/rpc/dispatcher.py
+++ b/oslo/messaging/rpc/dispatcher.py
@@ -26,6 +26,7 @@ __all__ = [
 import logging
 
 from oslo.messaging import _utils as utils
+from oslo.messaging import localcontext
 from oslo.messaging import serializer as msg_serializer
 from oslo.messaging import server as msg_server
 from oslo.messaging import target
@@ -118,7 +119,11 @@ class RPCDispatcher(object):
                 continue
 
             if hasattr(endpoint, method):
-                return self._dispatch(endpoint, method, ctxt, args)
+                localcontext.set_local_context(ctxt)
+                try:
+                    return self._dispatch(endpoint, method, ctxt, args)
+                finally:
+                    localcontext.clear_local_context()
 
             found_compatible = True