diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Kwang Yul Seo (c) 2016
+
+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 Kwang Yul Seo nor the names of other
+      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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# tagsoup-megaparsec
+
+[![Build Status](https://travis-ci.org/kseo/tagsoup-megaparsec.svg?branch=master)](https://travis-ci.org/kseo/tagsoup-megaparsec)
+
+A Tag token parser and Tag specific parsing combinators
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Text/Megaparsec/TagSoup.hs b/src/Text/Megaparsec/TagSoup.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Megaparsec/TagSoup.hs
@@ -0,0 +1,113 @@
+{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
+-- |
+-- Module      :  Text.Megaparsec.TagSoup
+-- Copyright   :  © 2016 Kwang Yul Seo
+-- License     :  BSD
+--
+-- Maintainer  :  Kwang Yul Seo <kwangyul.seo@gmail.com>
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Make Tags an instance of 'Stream' with 'Tag str' token type.
+module Text.Megaparsec.TagSoup
+  ( TagParser
+  , space
+  , whitespace
+  , lexeme
+  , satisfy
+  , anyTag
+  , anyTagOpen
+  , anyTagClose
+  , tagText
+  , tagOpen
+  , tagClose
+  ) where
+
+import Data.Char (isSpace)
+import Data.List (intercalate)
+import Text.HTML.TagSoup
+import Text.StringLike
+import Text.Megaparsec.Combinator
+import Text.Megaparsec.Error
+import Text.Megaparsec.Pos
+import Text.Megaparsec.Prim
+import Text.Megaparsec.ShowToken
+
+-- | Different modules corresponding to various types of streams (@String@,
+-- @Text@, @ByteString@) define it differently, so user can use “abstract”
+-- @Parser@ type and easily change it by importing different “type
+-- modules”. This one is for TagSoup tags.
+type TagParser str = Parsec [Tag str]
+
+instance (Show str) => ShowToken (Tag str) where
+    showToken tag = show tag
+
+instance (ShowToken (Tag str)) => ShowToken [Tag str] where
+    showToken tags = intercalate " " (map showToken tags)
+
+updatePosTag :: Int         -- ^ Tab width
+             -> SourcePos   -- ^ Initial position
+             -> (Tag str)   -- ^ Tag at the position
+             -> SourcePos
+updatePosTag width sourcePos tag = incSourceColumn sourcePos 1
+
+-- | Parses a text block containing only characters which satisfy 'isSpace'.
+space :: (Show str, StringLike str, MonadParsec s m (Tag str)) => m (Tag str)
+space = satisfy (\tag -> case tag of
+                           TagText x | all isSpace (toString x) -> True
+                           _ -> False)
+
+-- | Parses any whitespace. Whitespace consists of zero or more ocurrences of 'space'.
+whitespace :: (Show str, StringLike str, MonadParsec s m (Tag str)) => m ()
+whitespace = skipMany space
+
+-- | @lexeme p@ first applies parser @p@ and then 'whitespace', returning the value of @p@.
+--
+--    @lexeme = (<* whitespace)@
+--
+--   Every tag parser is defined using 'lexeme', this way every parse starts at a point
+--   without whitespace.
+--
+--   The only point where 'whitespace' should be called explicitly is at the start of
+--   the top level parser, in order to skip any leading whitespace.
+lexeme :: (Show str, StringLike str, MonadParsec s m (Tag str)) => m (Tag str) -> m (Tag str)
+lexeme p = p <* whitespace
+
+-- | Parses any tag.
+-- As all the tag parsers, it consumes the whitespace immediately after the parsed tag.
+anyTag :: (Show str, StringLike str, MonadParsec s m (Tag str)) => m (Tag str)
+anyTag = lexeme $ token updatePosTag Right
+
+-- | Parse a tag if it satisfies the predicate.
+-- As all the tag parsers, it consumes the whitespace immediately after the parsed tag.
+satisfy :: (Show str, StringLike str, MonadParsec s m (Tag str)) => (Tag str -> Bool) -> m (Tag str)
+satisfy f = lexeme $ token updatePosTag testTag
+  where testTag x = if f x
+                       then Right x
+                       else Left . pure . Unexpected . showToken $ x
+
+-- | Parse any opening tag.
+-- As all the tag parsers, it consumes the whitespace immediately after the parsed tag.
+anyTagOpen :: (Show str, StringLike str, MonadParsec s m (Tag str)) => m (Tag str)
+anyTagOpen = satisfy isTagOpen <?> "any tag open"
+
+-- | Parse any closing tag.
+-- As all the tag parsers, it consumes the whitespace immediately after the parsed tag.
+anyTagClose :: (Show str, StringLike str, MonadParsec s m (Tag str)) => m (Tag str)
+anyTagClose = satisfy isTagClose <?> "any tag close"
+
+-- | Parses a chunk of text.
+-- As all the tag parsers, it consumes the whitespace immediately after the parsed tag.
+tagText :: (Show str, StringLike str, MonadParsec s m (Tag str)) => m (Tag str)
+tagText = satisfy isTagText <?> "text"
+
+-- | Parse the given opening tag.
+-- As all the tag parsers, these consume the whitespace immediately after the parsed tag.
+tagOpen :: (Show str, StringLike str, MonadParsec s m (Tag str)) => str -> m (Tag str)
+tagOpen s = satisfy (isTagOpenName s) <?> "tag open"
+
+-- | Parse the given closing tag.
+-- As all the tag parsers, these consume the whitespace immediately after the parsed tag.
+tagClose :: (Show str, StringLike str, MonadParsec s m (Tag str)) => str -> m (Tag str)
+tagClose s = satisfy (isTagCloseName s) <?> "tag close"
+
diff --git a/tagsoup-megaparsec.cabal b/tagsoup-megaparsec.cabal
new file mode 100644
--- /dev/null
+++ b/tagsoup-megaparsec.cabal
@@ -0,0 +1,39 @@
+name:                tagsoup-megaparsec
+version:             0.1.0.0
+synopsis:            A Tag token parser and Tag specific parsing combinators
+description:         Please see README.md
+homepage:            https://github.com/kseo/tagsoup-megaparsec#readme
+license:             BSD3
+license-file:        LICENSE
+author:              Kwang Yul Seo
+maintainer:          kwangyul.seo@gmail.com
+copyright:           BSD3
+category:            XML
+build-type:          Simple
+extra-source-files:  README.md
+cabal-version:       >=1.10
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Text.Megaparsec.TagSoup
+  build-depends:       base >= 4.7 && < 5
+                     , megaparsec >= 4.4 && < 5
+                     , tagsoup >= 0.13 && < 0.15
+  default-language:    Haskell2010
+
+test-suite tagsoup-megaparsec-test
+  type:                exitcode-stdio-1.0
+  hs-source-dirs:      test
+  main-is:             Spec.hs
+  build-depends:       base
+                     , hspec
+                     , megaparsec
+                     , raw-strings-qq
+                     , tagsoup
+                     , tagsoup-megaparsec
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/kseo/tagsoup-megaparsec
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,39 @@
+{-# LANGUAGE QuasiQuotes #-}
+import Test.Hspec
+import Text.RawString.QQ
+import Text.HTML.TagSoup
+import Text.Megaparsec
+import Text.Megaparsec.TagSoup
+
+type StringTagParser = TagParser String
+
+testDoc = [r|
+<ul>
+<li>Item 1</li>
+<li>Item 2</li>
+</ul>
+|]
+
+liParser :: StringTagParser String
+liParser = do
+  tagOpen "li"
+  text <- tagText
+  tagClose "li"
+  return (fromTagText text)
+
+ulParser :: StringTagParser [String]
+ulParser = do
+  tagOpen "ul"
+  texts <- many liParser
+  tagClose "ul"
+  return texts
+
+tagParserSpec :: Spec
+tagParserSpec = do
+  let input = parseTags testDoc
+  describe "TagParser" $ do
+    it "parses a xml doc" $
+      parse (whitespace *> ulParser) "" input `shouldBe` Right ["Item 1", "Item 2"]
+
+main :: IO ()
+main = hspec tagParserSpec
