diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2017-2018, The TokTok Team
+Copyright (c) 2009-2010, Hideyuki Tanaka
+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 the Hideyuki Tanaka 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 Hideyuki Tanaka ''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 <copyright holder> 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.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/msgpack-rpc-conduit.cabal b/msgpack-rpc-conduit.cabal
new file mode 100644
--- /dev/null
+++ b/msgpack-rpc-conduit.cabal
@@ -0,0 +1,83 @@
+name:                 msgpack-rpc-conduit
+version:              0.0.6
+synopsis:             A MessagePack-RPC Implementation
+homepage:             http://msgpack.org/
+license:              BSD3
+license-file:         LICENSE
+author:               Hideyuki Tanaka
+maintainer:           Iphigenia Df <iphydf@gmail.com>
+copyright:            Copyright (c) 2009-2016, Hideyuki Tanaka
+category:             Data
+stability:            Experimental
+cabal-version:        >= 1.10
+build-type:           Simple
+description:
+  A MessagePack-RPC Implementation <http://msgpack.org/>
+  .
+  This is a fork of msgpack-haskell <https://github.com/msgpack/msgpack-haskell>,
+  since the original author is unreachable. This fork incorporates a number of
+  bugfixes and is actively being developed.
+
+source-repository head
+  type:             git
+  location:         https://github.com/TokTok/hs-msgpack-rpc-conduit.git
+
+library
+  default-language: Haskell2010
+  ghc-options:
+      -Wall
+      -fno-warn-unused-imports
+  hs-source-dirs:
+      src
+  exposed-modules:
+      Network.MessagePack.Client
+      Network.MessagePack.Interface
+      Network.MessagePack.Rpc
+      Network.MessagePack.Server
+      Network.MessagePack.Types
+  other-modules:
+      Network.MessagePack.Capabilities
+      Network.MessagePack.Client.Basic
+      Network.MessagePack.Client.Internal
+      Network.MessagePack.Protocol
+      Network.MessagePack.Server.Basic
+      Network.MessagePack.Types.Client
+      Network.MessagePack.Types.Error
+      Network.MessagePack.Types.Result
+      Network.MessagePack.Types.Server
+      Network.MessagePack.Types.Spec
+  build-depends:
+      base < 5
+    , binary
+    , binary-conduit
+    , bytestring
+    , conduit
+    , conduit-extra
+    , data-default-class
+    , data-default-instances-base
+    , exceptions
+    , monad-control
+    , msgpack-binary                    >= 0.0.11
+    , msgpack-types                     >= 0.0.1
+    , mtl
+    , network                           < 3
+    , text
+    , unliftio-core
+
+test-suite testsuite
+  type: exitcode-stdio-1.0
+  default-language: Haskell2010
+  ghc-options:
+      -Wall
+  hs-source-dirs: test
+  main-is: testsuite.hs
+  other-modules:
+      Network.MessagePack.ServerSpec
+  build-depends:
+      base < 5
+    , async
+    , bytestring
+    , hspec
+    , msgpack-rpc-conduit
+    , mtl
+    , network                           < 3
diff --git a/src/Network/MessagePack/Capabilities.hs b/src/Network/MessagePack/Capabilities.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Capabilities.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE DeriveGeneric #-}
+module Network.MessagePack.Capabilities
+    ( ServerCapability (..)
+    , ClientCapability (..)
+    ) where
+
+import           Data.MessagePack (MessagePack)
+import           GHC.Generics     (Generic)
+
+
+data ServerCapability
+    = SCapMethodList
+      -- ^ Server supports method lists and can handle more efficient method codes
+      -- instead of strings for names. It supports the "internal.methodList" call
+      -- to return an ordered list of method names. The client can send an index
+      -- in this list instead of the name itself when performing an RPC call.
+    deriving (Eq, Generic)
+
+instance MessagePack ServerCapability
+
+
+data ClientCapability
+    = CCapMethodList
+      -- ^ Client supports method lists and can send more efficient method codes
+      -- instead of strings for names.
+    deriving (Eq, Generic)
+
+instance MessagePack ClientCapability
diff --git a/src/Network/MessagePack/Client.hs b/src/Network/MessagePack/Client.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Client.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE Trustworthy         #-}
+module Network.MessagePack.Client (
+  -- * MessagePack Client type
+    Basic.Client
+  , Basic.ClientT
+  , Basic.execClient
+  , runClient
+
+  -- * Call RPC method
+  , Basic.call
+
+  -- * RPC error
+  , Basic.RpcError (..)
+  , Basic.RpcType
+  ) where
+
+import           Control.Applicative                 (Applicative, pure)
+import           Control.Monad                       (when)
+import           Control.Monad.Catch                 (catch)
+import qualified Data.ByteString                     as S
+import           Data.Default.Class                  (Default (..))
+import           Data.Default.Instances.Base         ()
+
+import           Network.MessagePack.Capabilities    (ClientCapability (..),
+                                                      ServerCapability (..))
+import qualified Network.MessagePack.Client.Basic    as Basic
+import qualified Network.MessagePack.Client.Internal as Internal
+import qualified Network.MessagePack.Protocol        as Protocol
+
+
+useDefault :: (Applicative m, Default a) => Basic.RpcError -> m a
+useDefault _ = pure def
+
+
+initClient :: Basic.Client ()
+initClient = do
+  caps <- Protocol.capabilitiesC [CCapMethodList] `catch` useDefault
+  when (SCapMethodList `elem` caps) $ do
+    mths <- Protocol.methodListC
+    Internal.setMethodList mths
+
+
+runClient :: S.ByteString -> Int -> Basic.Client a -> IO a
+runClient host port client =
+  Basic.execClient host port (initClient >> client)
diff --git a/src/Network/MessagePack/Client/Basic.hs b/src/Network/MessagePack/Client/Basic.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Client/Basic.hs
@@ -0,0 +1,66 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE Trustworthy         #-}
+
+-------------------------------------------------------------------
+-- |
+-- Module    : Network.MessagePackRpc.Client
+-- Copyright : (c) Hideyuki Tanaka, 2010-2015
+-- License   : BSD3
+--
+-- Maintainer:  Hideyuki Tanaka <tanaka.hideyuki@gmail.com>
+-- Stability :  experimental
+-- Portability: portable
+--
+-- This module is client library of MessagePack-RPC.
+-- The specification of MessagePack-RPC is at
+-- <http://redmine.msgpack.org/projects/msgpack/wiki/RPCProtocolSpec>.
+--
+-- A simple example:
+--
+-- > import Network.MessagePackRpc.Client
+-- >
+-- > add :: Int -> Int -> Client Int
+-- > add = call "add"
+-- >
+-- > main = execClient "localhost" 5000 $ do
+-- >   ret <- add 123 456
+-- >   liftIO $ print ret
+--
+--------------------------------------------------------------------
+
+module Network.MessagePack.Client.Basic (
+  -- * MessagePack Client type
+    Client
+  , ClientT
+  , execClient
+
+  -- * Call RPC method
+  , call
+
+  -- * RPC error
+  , RpcError (..)
+  , RpcType (..)
+  ) where
+
+import qualified Control.Monad.State.Strict          as CMS
+import qualified Data.ByteString                     as S
+import           Data.Conduit                        (($$+))
+import           Data.Conduit.Network                (appSink, appSource,
+                                                      clientSettings,
+                                                      runTCPClient)
+
+import           Network.MessagePack.Client.Internal
+import           Network.MessagePack.Types.Client
+import           Network.MessagePack.Types.Error
+
+
+execClient :: S.ByteString -> Int -> Client a -> IO a
+execClient host port client =
+  runTCPClient (clientSettings port host) $ \ad -> do
+    (rsrc, _) <- appSource ad $$+ return ()
+    CMS.evalStateT (runClientT client) Connection
+      { connSource = rsrc
+      , connSink   = appSink ad
+      , connMsgId  = 0
+      , connMths   = []
+      }
diff --git a/src/Network/MessagePack/Client/Internal.hs b/src/Network/MessagePack/Client/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Client/Internal.hs
@@ -0,0 +1,102 @@
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+module Network.MessagePack.Client.Internal where
+
+import           Control.Applicative               (Applicative)
+import           Control.Monad                     (when)
+import           Control.Monad.Catch               (MonadCatch, MonadThrow,
+                                                    throwM)
+import qualified Control.Monad.State.Strict        as CMS
+import qualified Data.Binary                       as Binary
+import qualified Data.ByteString                   as S
+import           Data.Conduit                      (ConduitT, SealedConduitT,
+                                                    Void, runConduit, ($$++),
+                                                    (.|))
+import qualified Data.Conduit.Binary               as CB
+import           Data.Conduit.Serialization.Binary (sinkGet)
+import           Data.MessagePack                  (MessagePack (fromObject),
+                                                    Object)
+import           Data.Monoid                       ((<>))
+import           Data.Text                         (Text)
+import qualified Data.Text                         as T
+import qualified Network.MessagePack.Types.Result  as R
+
+import           Network.MessagePack.Interface     (IsClientType (..), Returns,
+                                                    ReturnsM)
+import           Network.MessagePack.Types.Client
+import           Network.MessagePack.Types.Error
+import           Network.MessagePack.Types.Spec
+
+
+-- | RPC connection type
+data Connection m = Connection
+  { connSource :: !(SealedConduitT () S.ByteString m ())
+  , connSink   :: !(ConduitT S.ByteString Void m ())
+  , connMsgId  :: !Int
+  , connMths   :: ![Text]
+  }
+
+
+newtype ClientT m a
+  = ClientT { runClientT :: CMS.StateT (Connection m) m a }
+  deriving (Functor, Applicative, Monad, CMS.MonadIO, MonadThrow, MonadCatch)
+
+type Client a = ClientT IO a
+
+instance IsClientType m (Returns r) where
+  type ClientType m (Returns r) = ClientT m r
+
+instance IsClientType m (ReturnsM io r) where
+  type ClientType m (ReturnsM io r) = ClientT m r
+
+
+instance (CMS.MonadIO m, MonadThrow m, MessagePack o)
+    => RpcType (ClientT m o) where
+  rpcc name args = do
+    res <- rpcCall name (reverse args)
+    case fromObject res of
+      R.Success ok  ->
+        return ok
+      R.Failure msg ->
+        throwM $ ResultTypeError (T.pack msg) res
+
+
+rpcCall :: (MonadThrow m, CMS.MonadIO m) => Text -> [Object] -> ClientT m Object
+rpcCall methodName args = ClientT $ do
+  conn <- CMS.get
+  let msgid = connMsgId conn
+
+  (rsrc', res) <- CMS.lift $ do
+    let req = packRequest (connMths conn) (0, msgid, methodName, args)
+    runConduit $ CB.sourceLbs req .| connSink conn
+    connSource conn $$++ sinkGet Binary.get
+
+  CMS.put conn
+    { connSource = rsrc'
+    , connMsgId  = msgid + 1
+    }
+
+  case unpackResponse res of
+    Nothing -> throwM $ ProtocolError "invalid response data"
+    Just (rtype, rmsgid, rerror, rresult) -> do
+      when (rtype /= 1) $
+        throwM $ ProtocolError $
+          "invalid response type (expect 1, but got " <> T.pack (show rtype) <> "): " <> T.pack (show res)
+
+      when (rmsgid /= msgid) $
+        throwM $ ProtocolError $
+          "message id mismatch: expect " <> T.pack (show msgid) <> ", but got " <> T.pack (show rmsgid)
+
+      case fromObject rerror of
+        Nothing -> throwM $ RemoteError rerror
+        Just () -> return rresult
+
+
+setMethodList :: Monad m => [Text] -> ClientT m ()
+setMethodList mths = ClientT $ do
+  conn <- CMS.get
+  CMS.put conn { connMths = mths }
diff --git a/src/Network/MessagePack/Interface.hs b/src/Network/MessagePack/Interface.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Interface.hs
@@ -0,0 +1,161 @@
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE InstanceSigs          #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+{-# LANGUAGE Safe                  #-}
+{-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE StandaloneDeriving    #-}
+{-# LANGUAGE TypeFamilies          #-}
+module Network.MessagePack.Interface
+    ( Interface (..)
+    , InterfaceM (..)
+    , IsDocType (..)
+    , IsClientType (..)
+    , IsReturnType (..)
+    , Doc (..)
+    , Returns
+    , ReturnsM
+    , call
+    , concrete
+    , interface
+    , method
+    ) where
+
+import           Control.Monad.Catch              (MonadThrow)
+import           Control.Monad.Trans              (MonadIO)
+import           Data.Text                        (Text)
+import qualified Data.Text                        as Text
+import           Data.Typeable                    (Typeable)
+import qualified Data.Typeable                    as Typeable
+
+import qualified Network.MessagePack.Types.Client as Client
+import           Network.MessagePack.Types.Server (Method, MethodDocs (..),
+                                                   MethodVal (..))
+import qualified Network.MessagePack.Types.Server as Server
+
+
+data Interface f = Interface
+  { name :: !Text
+  , docs :: !(Doc f)
+  }
+
+
+newtype InterfaceM (m :: * -> *) f = InterfaceM
+  { nameM :: Text
+  }
+
+
+interface :: Text -> Doc f -> Interface f
+interface = Interface
+
+
+concrete :: Interface f -> InterfaceM m f
+concrete = InterfaceM . name
+
+
+--------------------------------------------------------------------------------
+--
+-- :: Documentation
+--
+--------------------------------------------------------------------------------
+
+
+class IsDocType f where
+  data Doc f
+  flatDoc :: Doc f -> MethodDocs
+
+data Returns r
+
+instance Typeable r => IsDocType (Returns r) where
+  data Doc (Returns r) = Ret Text
+    deriving (Eq, Read, Show)
+  flatDoc (Ret retName) =
+    MethodDocs [] (MethodVal retName (typeName (undefined :: r)))
+
+data ReturnsM (m :: * -> *) r
+
+instance Typeable r => IsDocType (ReturnsM m r) where
+  data Doc (ReturnsM m r) = RetM Text
+    deriving (Eq, Read, Show)
+  flatDoc (RetM retName) =
+    MethodDocs [] (MethodVal retName (typeName (undefined :: r)))
+
+instance (Typeable o, IsDocType r) => IsDocType (o -> r) where
+  data Doc (o -> r) = Arg Text (Doc r)
+  flatDoc (Arg o r) =
+    let doc = flatDoc r in
+    let ty = typeName (undefined :: o) in
+    doc { methodArgs = MethodVal o ty : methodArgs doc }
+
+deriving instance Eq   (Doc r) => Eq   (Doc (o -> r))
+deriving instance Read (Doc r) => Read (Doc (o -> r))
+deriving instance Show (Doc r) => Show (Doc (o -> r))
+
+
+typeName :: Typeable a => a -> Text
+typeName = Text.replace "[Char]" "String" . Text.pack . show . Typeable.typeOf
+
+
+--------------------------------------------------------------------------------
+--
+-- :: Client
+--
+--------------------------------------------------------------------------------
+
+
+class IsClientType (m :: * -> *) f where
+  type ClientType m f
+
+instance IsClientType m r => IsClientType m (o -> r) where
+  type ClientType m (o -> r) = o -> ClientType m r
+
+
+call :: Client.RpcType (ClientType m f) => InterfaceM m f -> ClientType m f
+call = Client.call . nameM
+
+
+--------------------------------------------------------------------------------
+--
+-- :: Server
+--
+--------------------------------------------------------------------------------
+
+
+class IsReturnType (m :: * -> *) f where
+  type HaskellType f
+  type ServerType m f
+
+  implement :: InterfaceM m f -> HaskellType f -> ServerType m f
+
+
+instance IsReturnType m r => IsReturnType m (o -> r) where
+  type HaskellType (o -> r) = o -> HaskellType r
+  type ServerType m (o -> r) = o -> ServerType m r
+
+  implement i f a = next (coerce i) (f a)
+    where
+      next :: InterfaceM m r -> HaskellType r -> ServerType m r
+      next = implement
+
+      coerce :: InterfaceM m a -> InterfaceM m b
+      coerce = InterfaceM . nameM
+
+
+methodM
+  :: ( Server.MethodType m (ServerType m f)
+     , IsDocType f
+     , IsReturnType m f
+     , MonadThrow m
+     )
+  => InterfaceM m f -> Doc f -> HaskellType f -> Method m
+methodM i doc f = Server.method (nameM i) (flatDoc doc) (implement i f)
+
+
+method
+  :: ( MonadThrow m
+     , Server.MethodType m (ServerType m f)
+     , IsDocType f
+     , IsReturnType m f)
+  => Interface f -> HaskellType f -> Method m
+method i = methodM (concrete i) (docs i)
diff --git a/src/Network/MessagePack/Protocol.hs b/src/Network/MessagePack/Protocol.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Protocol.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings     #-}
+
+module Network.MessagePack.Protocol
+  ( capabilitiesN
+  , capabilitiesC
+  , capabilitiesS
+  , methodListN
+  , methodListC
+  , methodListS
+  , protocolMethods
+  ) where
+
+import           Control.Applicative              (Applicative, pure)
+import           Control.Monad.Catch              (MonadCatch)
+import           Control.Monad.Trans              (MonadIO)
+import           Control.Monad.Trans.Control      (MonadBaseControl)
+import           Data.Text                        (Text)
+
+import           Network.MessagePack.Capabilities
+import           Network.MessagePack.Client.Basic
+import           Network.MessagePack.Server.Basic
+
+
+capabilitiesN :: Text
+capabilitiesN = "rpc.capabilities"
+
+capabilitiesC :: [ClientCapability] -> Client [ServerCapability]
+capabilitiesC = call capabilitiesN
+
+capabilitiesS
+  :: Applicative m
+  => [Method m]
+  -> [ClientCapability]
+  -> ServerT m [ServerCapability]
+capabilitiesS _ _ = pure [SCapMethodList]
+
+
+methodListN :: Text
+methodListN = "rpc.methodList"
+
+methodListC :: Client [Text]
+methodListC = call methodListN
+
+methodListS
+  :: Applicative m
+  => [Method m]
+  -> ServerT m [Text]
+methodListS = pure . map methodName
+
+
+protocolMethods
+  :: (MonadBaseControl IO m, MonadIO m, MonadCatch m)
+  => [Method m]
+  -> [Method m]
+protocolMethods methods = methods ++
+  [ method capabilitiesN (MethodDocs [MethodVal "clientCaps" "ClientCapability"] (MethodVal "serverCaps" "ServerCapability"))
+      (capabilitiesS methods)
+  , method methodListN   (MethodDocs [] (MethodVal "names" "[String]"))
+      (methodListS   methods)
+  ]
diff --git a/src/Network/MessagePack/Rpc.hs b/src/Network/MessagePack/Rpc.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Rpc.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE Safe                  #-}
+{-# LANGUAGE TypeFamilies          #-}
+module Network.MessagePack.Rpc
+  ( I.Doc (..)
+  , I.Returns
+  , I.ReturnsM
+  , method
+  , rpc
+  , docs
+  , stubs, Rpc, RpcT (local)
+  ) where
+
+import           Control.Monad.Catch              (MonadThrow)
+import           Data.Text                        (Text)
+
+import qualified Network.MessagePack.Interface    as I
+import qualified Network.MessagePack.Types.Client as Client
+import qualified Network.MessagePack.Types.Server as Server
+
+-- Import orphan instances for RpcType and IsReturnType.
+-- TODO(SX91): Avoid orphan instances. See issue #7.
+import           Network.MessagePack.Client.Basic ()
+import           Network.MessagePack.Server.Basic ()
+
+
+class RpcService rpc where
+  type ClientMonad rpc :: * -> *
+  type ServerMonad rpc :: * -> *
+  type F rpc
+  rpc    :: rpc -> I.ClientType (ClientMonad rpc) (F rpc)
+  method :: rpc -> Server.Method (ServerMonad rpc)
+  docs   :: rpc -> (Text, I.Doc (F rpc))
+
+
+type Rpc f = RpcT IO IO f
+
+data RpcT mc ms f = RpcT
+  { rpcPure    :: !(I.ClientType mc f)
+  , local      :: !(I.HaskellType f)
+  , methodPure :: !(Server.Method ms)
+  , intfPure   :: !(I.Interface f)
+  }
+
+instance RpcService (RpcT mc ms f) where
+  type ClientMonad (RpcT mc ms f) = mc
+  type ServerMonad (RpcT mc ms f) = ms
+  type F (RpcT mc ms f) = f
+  rpc    = rpcPure
+  {-# INLINE rpc #-}
+  method = methodPure
+  {-# INLINE method #-}
+  docs r = (Server.methodName $ method r, I.docs $ intfPure r)
+  {-# INLINE docs #-}
+
+
+stubs
+  :: ( Client.RpcType (I.ClientType mc f)
+     , Server.MethodType ms (I.ServerType ms f)
+     , I.IsReturnType ms f
+     , I.IsDocType f
+     , MonadThrow ms
+     )
+  => Text -> I.Doc f -> I.HaskellType f -> RpcT mc ms f
+stubs n doc f = RpcT c f m i
+  where
+    c = Client.call n
+    m = I.method i f
+    i = I.interface n doc
diff --git a/src/Network/MessagePack/Server.hs b/src/Network/MessagePack/Server.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Server.hs
@@ -0,0 +1,38 @@
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+module Network.MessagePack.Server (
+  -- * RPC method types
+    Method
+  , MethodType (..)
+  , MethodDocs (..)
+  , MethodVal (..)
+  , ServerT (..)
+  , Server
+
+  -- * Build a method
+  , method
+  , methodName
+  , methodDocs
+
+  -- * Start RPC server
+  , serve
+  , runServer
+  ) where
+
+import           Control.Monad.Catch              (MonadCatch)
+import           Control.Monad.IO.Unlift          (MonadUnliftIO)
+import           Control.Monad.Trans              (MonadIO)
+import           Control.Monad.Trans.Control      (MonadBaseControl)
+
+import           Network.MessagePack.Protocol     (protocolMethods)
+import           Network.MessagePack.Server.Basic
+
+
+-- | Start RPC server with a set of RPC methods.
+runServer
+  :: (MonadBaseControl IO m, MonadIO m, MonadCatch m, MonadUnliftIO m)
+  => Int        -- ^ Port number
+  -> [Method m] -- ^ list of methods
+  -> m ()
+runServer port methods =
+  serve port (protocolMethods methods)
diff --git a/src/Network/MessagePack/Server/Basic.hs b/src/Network/MessagePack/Server/Basic.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Server/Basic.hs
@@ -0,0 +1,208 @@
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE Trustworthy                #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+-------------------------------------------------------------------
+-- |
+-- Module    : Network.MessagePackRpc.Server
+-- Copyright : (c) Hideyuki Tanaka, 2010-2015
+-- License   : BSD3
+--
+-- Maintainer:  tanaka.hideyuki@gmail.com
+-- Stability :  experimental
+-- Portability: portable
+--
+-- This module is server library of MessagePack-RPC.
+-- The specification of MessagePack-RPC is at
+-- <http://redmine.msgpack.org/projects/msgpack/wiki/RPCProtocolSpec>.
+--
+-- A simple example:
+--
+-- > import Network.MessagePackRpc.Server
+-- >
+-- > add :: Int -> Int -> Server Int
+-- > add x y = return $ x + y
+-- >
+-- > main = serve 1234 [ method "add" add ]
+--
+--------------------------------------------------------------------
+
+module Network.MessagePack.Server.Basic (
+  -- * RPC method types
+    Method
+  , MethodVal (..)
+  , MethodDocs (..)
+  , MethodType (..)
+  , ServerT (..)
+  , Server
+
+  -- * Build a method
+  , method
+
+  -- * Get the method name
+  , methodName
+  , methodDocs
+
+  -- * Start RPC server
+  , serve
+  ) where
+
+import           Control.Applicative               (Applicative, pure, (<$>),
+                                                    (<|>))
+import           Control.Monad.Catch               (MonadCatch, MonadThrow,
+                                                    catch, throwM)
+import           Control.Monad.IO.Unlift           (MonadUnliftIO)
+import           Control.Monad.Trans               (MonadIO, MonadTrans, lift,
+                                                    liftIO)
+import           Control.Monad.Trans.Control       (MonadBaseControl)
+import qualified Data.Binary                       as Binary
+import qualified Data.ByteString                   as S
+import           Data.Conduit                      (ConduitT, SealedConduitT,
+                                                    Void, runConduit, ($$+),
+                                                    ($$++), (.|))
+import qualified Data.Conduit.Binary               as CB
+import           Data.Conduit.Network              (appSink, appSource,
+                                                    runGeneralTCPServer,
+                                                    serverSettings,
+                                                    setAfterBind)
+import           Data.Conduit.Serialization.Binary (ParseError, sinkGet)
+import qualified Data.List                         as List
+import           Data.MessagePack                  (MessagePack, Object,
+                                                    fromObject, toObject)
+import           Data.Monoid                       ((<>))
+import qualified Data.Text                         as T
+import           Data.Traversable                  (sequenceA)
+import qualified Network.MessagePack.Types.Result  as R
+import           Network.Socket                    (SocketOption (ReuseAddr),
+                                                    setSocketOption)
+
+import           Network.MessagePack.Interface     (IsReturnType (..), Returns,
+                                                    ReturnsM)
+import           Network.MessagePack.Types
+
+
+newtype ServerT m a = ServerT { runServerT :: m a }
+  deriving (Functor, Applicative, Monad, MonadIO)
+
+
+instance MonadTrans ServerT where
+  lift = ServerT
+  {-# INLINE lift #-}
+
+
+type Server = ServerT IO
+
+
+instance (MonadThrow m, MessagePack o, MethodType m r) => MethodType m (o -> r) where
+  toBody n f (x : xs) =
+    case fromObject x of
+      Nothing -> throwM $ ServerError "argument type error"
+      Just r  -> toBody n (f r) xs
+  toBody _ _ [] = error "messagepack-rpc methodtype instance toBody failed"
+
+instance (Functor m, MonadThrow m, MessagePack o) => MethodType m (ServerT m o) where
+  toBody _ m [] = toObject <$> runServerT m
+  toBody n _ ls =
+    throwM $ ServerError $
+      "invalid arguments for method '" <> n <> "': " <> T.pack (show ls)
+
+-- Pure server
+instance Monad m => IsReturnType m (Returns r) where
+  type HaskellType (Returns r) = r
+  type ServerType m (Returns r) = ServerT m r
+
+  implement _ = return
+
+-- IO Server
+instance MonadIO m => IsReturnType m (ReturnsM IO r) where
+  type HaskellType (ReturnsM IO r) = IO r
+  type ServerType m (ReturnsM IO r) = ServerT m r
+
+  implement _ = liftIO
+
+
+processRequests
+  :: (Applicative m, MonadThrow m, MonadCatch m)
+  => [Method m]
+  -> SealedConduitT () S.ByteString m ()
+  -> ConduitT S.ByteString Void m t
+  -> m b
+processRequests methods rsrc sink = do
+  (rsrc', res) <-
+    rsrc $$++ do
+      obj <- sinkGet Binary.get
+      case unpackRequest obj of
+        Nothing ->
+          throwM $ ServerError "invalid request"
+        Just req@(_, msgid, _, _) ->
+          lift $ getResponse methods req `catch` \(ServerError err) ->
+            return (1, msgid, toObject err, toObject ())
+
+  _ <- runConduit $ CB.sourceLbs (packResponse res) .| sink
+  processRequests methods rsrc' sink
+
+
+getResponse
+  :: Applicative m
+  => [Method m]
+  -> Request Object
+  -> m Response
+getResponse methods (0, msgid, mth, args) =
+  process <$> callMethod methods mth args
+  where
+    process (R.Failure err) = (1, msgid, toObject err, toObject ())
+    process (R.Success ok ) = (1, msgid, toObject (), ok)
+
+getResponse _ (rtype, msgid, _, _) =
+  pure (1, msgid, toObject ["request type is not 0, got " <> T.pack (show rtype)], toObject ())
+
+
+callMethod
+  :: (Applicative m)
+  => [Method m]
+  -> Object
+  -> [Object]
+  -> m (R.Result Object)
+callMethod methods mth args = sequenceA $
+  (stringCall =<< fromObject mth)
+  <|>
+  (intCall =<< fromObject mth)
+
+  where
+    stringCall name =
+      case List.find ((== name) . methodName) methods of
+        Nothing -> R.Failure $ "method '" <> T.unpack name <> "' not found"
+        Just m  -> R.Success $ methodBody m args
+
+    intCall ix =
+      case drop ix methods of
+        []  -> R.Failure $ "method #" <> show ix <> " not found"
+        m:_ -> R.Success $ methodBody m args
+
+
+ignoreParseError :: Applicative m => ParseError -> m ()
+ignoreParseError _ = pure ()
+
+
+-- | Start RPC server with a set of RPC methods.
+serve
+  :: (MonadBaseControl IO m, MonadIO m, MonadCatch m, MonadUnliftIO m)
+  => Int        -- ^ Port number
+  -> [Method m] -- ^ list of methods
+  -> m ()
+serve port methods =
+  runGeneralTCPServer settings $ \ad -> do
+    (rsrc, _) <- appSource ad $$+ return ()
+    processRequests methods rsrc (appSink ad) `catch` ignoreParseError
+
+  where
+    settings =
+      setAfterBind
+        (\s -> setSocketOption s ReuseAddr 1)
+        (serverSettings port "*")
diff --git a/src/Network/MessagePack/Types.hs b/src/Network/MessagePack/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Types.hs
@@ -0,0 +1,8 @@
+module Network.MessagePack.Types
+  ( module X
+  ) where
+
+import           Network.MessagePack.Types.Client as X
+import           Network.MessagePack.Types.Error  as X
+import           Network.MessagePack.Types.Server as X
+import           Network.MessagePack.Types.Spec   as X
diff --git a/src/Network/MessagePack/Types/Client.hs b/src/Network/MessagePack/Types/Client.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Types/Client.hs
@@ -0,0 +1,22 @@
+module Network.MessagePack.Types.Client
+  ( RpcType (..)
+  , call
+  ) where
+
+import           Data.MessagePack (MessagePack (toObject), Object)
+import           Data.Text        (Text)
+
+
+class RpcType r where
+  rpcc :: Text -> [Object] -> r
+
+
+instance (MessagePack o, RpcType r) => RpcType (o -> r) where
+  rpcc name args arg = rpcc name (toObject arg : args)
+  {-# INLINE rpcc #-}
+
+
+-- | Call an RPC Method
+call :: RpcType a => Text -> a
+call name = rpcc name []
+{-# INLINE call #-}
diff --git a/src/Network/MessagePack/Types/Error.hs b/src/Network/MessagePack/Types/Error.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Types/Error.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+module Network.MessagePack.Types.Error
+  ( RpcError (..)
+  , ServerError (..)
+  ) where
+
+import           Control.Exception (Exception)
+import           Data.MessagePack  (Object)
+import           Data.Text         (Text)
+import           Data.Typeable     (Typeable)
+
+
+-- | RPC error type
+data RpcError
+  = RemoteError !Object           -- ^ Server error
+  | ResultTypeError !Text !Object -- ^ Result type mismatch
+  | ProtocolError !Text           -- ^ Protocol error
+  deriving (Show, Eq, Ord, Typeable)
+
+instance Exception RpcError
+
+
+newtype ServerError = ServerError Text
+  deriving (Show, Typeable)
+
+instance Exception ServerError
diff --git a/src/Network/MessagePack/Types/Result.hs b/src/Network/MessagePack/Types/Result.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Types/Result.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE CPP               #-}
+{-# LANGUAGE DeriveFoldable    #-}
+{-# LANGUAGE DeriveFunctor     #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE Safe              #-}
+module Network.MessagePack.Types.Result
+    ( Result (..)
+    ) where
+
+import           Control.Applicative (Alternative (..), Applicative (..), (<$>),
+                                      (<*>))
+import           Data.Foldable       (Foldable)
+import           Data.Traversable    (Traversable)
+
+data Result a
+    = Success a
+    | Failure String
+    deriving (Read, Show, Eq, Functor, Foldable, Traversable)
+
+instance Applicative Result where
+    pure = Success
+
+    Success f   <*> x = fmap f x
+    Failure msg <*> _ = Failure msg
+
+instance Alternative Result where
+    empty = Failure "empty alternative"
+
+    s@Success {} <|> _ = s
+    _            <|> r = r
+
+instance Monad Result where
+    return = Success
+    fail = Failure
+
+    Success x   >>= f = f x
+    Failure msg >>= _ = Failure msg
+
+#if (MIN_VERSION_base(4,13,0))
+instance MonadFail Result where
+    fail = Failure
+#endif
diff --git a/src/Network/MessagePack/Types/Server.hs b/src/Network/MessagePack/Types/Server.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Types/Server.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE Safe                  #-}
+module Network.MessagePack.Types.Server
+  ( MethodVal (..)
+  , MethodDocs (..)
+  , MethodType (..)
+  , Method (..)
+  , method
+  ) where
+
+import           Control.Monad    (Monad)
+import           Data.MessagePack (Object)
+import           Data.Text        (Text)
+
+
+data MethodVal = MethodVal
+  { valName :: !Text
+  , valType :: !Text
+  }
+  deriving (Show, Read, Eq)
+
+data MethodDocs = MethodDocs
+  { methodArgs :: ![MethodVal]
+  , methodRetv :: !MethodVal
+  }
+  deriving (Show, Read, Eq)
+
+-- ^ MessagePack RPC method
+data Method m = Method
+  { methodName :: !Text
+  , methodDocs :: !MethodDocs
+  , methodBody :: [Object] -> m Object
+  }
+
+
+class Monad m => MethodType m f where
+  -- | Create a RPC method from a Haskell function
+  toBody :: Text -> f -> [Object] -> m Object
+
+
+-- | Build a method
+method
+  :: MethodType m f
+  => Text     -- ^ Method name
+  -> MethodDocs
+  -> f        -- ^ Method body
+  -> Method m
+method name docs body = Method name docs $ toBody name body
diff --git a/src/Network/MessagePack/Types/Spec.hs b/src/Network/MessagePack/Types/Spec.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/MessagePack/Types/Spec.hs
@@ -0,0 +1,32 @@
+module Network.MessagePack.Types.Spec
+  ( Request
+  , Response
+  , packRequest
+  , packResponse
+  , unpackRequest
+  , unpackResponse
+  ) where
+
+import qualified Data.ByteString.Lazy as L
+import qualified Data.List            as List
+import           Data.MessagePack     (MessagePack, Object, fromObject, pack)
+
+type Request ix = (Int, Int, ix, [Object])
+type Response   = (Int, Int, Object, Object)
+
+packRequest :: (Eq mth, MessagePack mth) => [mth] -> Request mth -> L.ByteString
+packRequest [] req = pack req
+packRequest mths req@(rtype, msgid, mth, obj) =
+  case List.elemIndex mth mths of
+    Nothing -> pack req
+    Just ix -> pack (rtype, msgid, ix, obj)
+
+
+packResponse :: Response -> L.ByteString
+packResponse = pack
+
+unpackResponse :: Object -> Maybe Response
+unpackResponse = fromObject
+
+unpackRequest :: MessagePack ix => Object -> Maybe (Request ix)
+unpackRequest = fromObject
diff --git a/test/Network/MessagePack/ServerSpec.hs b/test/Network/MessagePack/ServerSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Network/MessagePack/ServerSpec.hs
@@ -0,0 +1,156 @@
+{-# LANGUAGE FlexibleContexts  #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Network.MessagePack.ServerSpec (spec) where
+
+import           Test.Hspec
+
+import           Control.Concurrent            (threadDelay)
+import           Control.Concurrent.Async      (race_)
+import           Control.Monad.Trans           (liftIO)
+import qualified Data.ByteString               as S
+import           Network.Socket                (withSocketsDo)
+
+import           Network.MessagePack.Client    (Client)
+import qualified Network.MessagePack.Client    as Client
+import           Network.MessagePack.Interface (Doc (..), Interface, Returns,
+                                                ReturnsM, call, concrete,
+                                                interface, method)
+import qualified Network.MessagePack.Rpc       as Rpc
+import           Network.MessagePack.Server    (MethodDocs (..), MethodVal (..))
+import qualified Network.MessagePack.Server    as Server
+
+
+add :: Int -> Int -> Int
+add = (+)
+
+addI :: Interface (Int -> Int -> Returns Int)
+addC :: Int -> Int -> Client Int
+(addI, addC) = (interface "add" (Arg "a" $ Arg "b" $ Ret "sum"), call . concrete $ addI)
+
+addR :: Rpc.Rpc (Int -> Int -> Returns Int)
+addR = Rpc.stubs "add" (Arg "a" $ Arg "b" $ Ret "sum")
+  add
+
+
+echo :: String -> IO String
+echo s = return $ "***" ++ s ++ "***"
+
+echoI :: Interface (String -> ReturnsM IO String)
+echoC :: String -> Client String
+(echoI, echoC) = (interface "echo" (Arg "input" $ RetM "output"), call . concrete $ echoI)
+
+
+helloR :: Rpc.Rpc (String -> Returns String)
+helloR = Rpc.stubs "hello" (Arg "name" $ Ret "hello")
+  ("Hello, " ++)
+
+
+helloIOR :: Rpc.Rpc (Int -> String -> ReturnsM IO String)
+helloIOR = Rpc.stubs "helloIO" (Arg "num" $ Arg "name" $ RetM "hello") $
+  \num name -> return $ "Hello, " ++ name ++ " " ++ show num
+
+
+port :: Int
+port = 5000
+
+
+runTest
+  :: (S.ByteString -> Int -> Client (Int, String) -> IO (Int, String))
+  -> (Int -> [Server.Method IO] -> IO ())
+  -> IO ()
+runTest runC runS = withSocketsDo $
+  server runS `race_` do
+    threadDelay 1000
+    res <- client runC
+    res `shouldBe` (333, "***hello***")
+
+
+spec :: Spec
+spec = do
+  describe "simple client" $ do
+    it "can communicate with simple server" $
+      runTest Client.execClient Server.serve
+
+    it "can communicate with advanced server" $
+      runTest Client.execClient Server.runServer
+
+  describe "advanced client" $ do
+    it "can communicate with simple server" $
+      runTest Client.runClient Server.serve
+
+    it "can communicate with advanced server" $
+      runTest Client.runClient Server.runServer
+
+  describe "documentation" $ do
+    it "is type-safe" $
+      Rpc.docs helloR `shouldBe` ("hello", Arg "name" $ Ret "hello")
+
+    it "works for IO and non-IO" $ do
+      Rpc.docs helloR   `shouldBe` ("hello"  , Arg "name" $ Ret "hello")
+      Rpc.docs helloIOR `shouldBe` ("helloIO", Arg "num" $ Arg "name" $ RetM "hello")
+
+    it "has working read/show implementations" $ do
+      let docs = Rpc.docs addR
+      read (show docs) `shouldBe` docs
+      show docs `shouldBe` "(\"add\",Arg \"a\" (Arg \"b\" (Ret \"sum\")))"
+
+    it "has type information" $ do
+      let meth = Rpc.method helloIOR
+      let docs = Server.methodDocs meth
+      read (show docs) `shouldBe` docs
+      docs `shouldBe` MethodDocs
+        { methodArgs =
+            [ MethodVal {valName = "num", valType = "Int"}
+            , MethodVal {valName = "name", valType = "String"}
+            ]
+        , methodRetv = MethodVal {valName = "hello", valType = "String"}
+        }
+      Server.methodName meth `shouldBe` "helloIO"
+
+    it "can be retrieved from type-erased methods" $ do
+      let docs = map Server.methodDocs methods
+      length docs `shouldNotBe` 0
+      mapM_ (\mdoc -> do
+          let args = Server.methodArgs mdoc
+          let retv = Server.methodRetv mdoc
+          length args `shouldNotBe` 0
+          mapM_ (\arg -> do
+              Server.valName arg `shouldNotBe` ""
+              Server.valType arg `shouldNotBe` ""
+            ) args
+          Server.valName retv `shouldNotBe` ""
+          Server.valType retv `shouldNotBe` ""
+        ) docs
+
+  describe "methods" $
+    it "can be executed locally" $
+      Rpc.local helloR "world" `shouldBe` "Hello, world"
+
+
+methods :: [Server.Method IO]
+methods =
+  [ method addI add
+  , method echoI echo
+  , Rpc.method helloR
+  , Rpc.method helloIOR
+  ]
+
+
+server :: (Int -> [Server.Method IO] -> IO ()) -> IO ()
+server run = run port methods
+
+
+client
+  :: (S.ByteString -> Int -> Client (Int, String) -> IO (Int, String))
+  -> IO (Int, String)
+client run =
+  run "127.0.0.1" port $ do
+    r1 <- addC 111 222
+    liftIO $ r1 `shouldBe` 333
+    r2 <- echoC "hello"
+    liftIO $ r2 `shouldBe` "***hello***"
+    r3 <- Rpc.rpc helloR "iphy"
+    liftIO $ r3 `shouldBe` "Hello, iphy"
+    r4 <- Rpc.rpc helloIOR 911 "iphy"
+    liftIO $ r4 `shouldBe` "Hello, iphy 911"
+    return (r1, r2)
diff --git a/test/testsuite.hs b/test/testsuite.hs
new file mode 100644
--- /dev/null
+++ b/test/testsuite.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
