packages feed

mcp-server 0.1.0.5 → 0.1.0.6

raw patch · 7 files changed

+63/−88 lines, 7 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- MCP.Server.Protocol: [promptsListCursor] :: PromptsListRequest -> Maybe Cursor
- MCP.Server.Protocol: [promptsListNextCursor] :: PromptsListResponse -> Maybe Cursor
- MCP.Server.Protocol: [resourcesListCursor] :: ResourcesListRequest -> Maybe Cursor
- MCP.Server.Protocol: [resourcesListNextCursor] :: ResourcesListResponse -> Maybe Cursor
- MCP.Server.Protocol: [toolsListCursor] :: ToolsListRequest -> Maybe Cursor
- MCP.Server.Protocol: [toolsListNextCursor] :: ToolsListResponse -> Maybe Cursor
- MCP.Server.Types: Cursor :: Text -> Cursor
- MCP.Server.Types: PaginatedResult :: a -> Maybe Cursor -> PaginatedResult a
- MCP.Server.Types: [paginatedItems] :: PaginatedResult a -> a
- MCP.Server.Types: [paginatedNextCursor] :: PaginatedResult a -> Maybe Cursor
- MCP.Server.Types: data PaginatedResult a
- MCP.Server.Types: instance Data.Aeson.Types.FromJSON.FromJSON MCP.Server.Types.Cursor
- MCP.Server.Types: instance Data.Aeson.Types.ToJSON.ToJSON MCP.Server.Types.Cursor
- MCP.Server.Types: instance GHC.Classes.Eq MCP.Server.Types.Cursor
- MCP.Server.Types: instance GHC.Classes.Eq a => GHC.Classes.Eq (MCP.Server.Types.PaginatedResult a)
- MCP.Server.Types: instance GHC.Internal.Generics.Generic (MCP.Server.Types.PaginatedResult a)
- MCP.Server.Types: instance GHC.Internal.Generics.Generic MCP.Server.Types.Cursor
- MCP.Server.Types: instance GHC.Internal.Show.Show MCP.Server.Types.Cursor
- MCP.Server.Types: instance GHC.Internal.Show.Show a => GHC.Internal.Show.Show (MCP.Server.Types.PaginatedResult a)
- MCP.Server.Types: newtype Cursor
- MCP.Server.Protocol: PromptsListRequest :: Maybe Cursor -> PromptsListRequest
+ MCP.Server.Protocol: PromptsListRequest :: PromptsListRequest
- MCP.Server.Protocol: PromptsListResponse :: [PromptDefinition] -> Maybe Cursor -> PromptsListResponse
+ MCP.Server.Protocol: PromptsListResponse :: [PromptDefinition] -> PromptsListResponse
- MCP.Server.Protocol: ResourcesListRequest :: Maybe Cursor -> ResourcesListRequest
+ MCP.Server.Protocol: ResourcesListRequest :: ResourcesListRequest
- MCP.Server.Protocol: ResourcesListResponse :: [ResourceDefinition] -> Maybe Cursor -> ResourcesListResponse
+ MCP.Server.Protocol: ResourcesListResponse :: [ResourceDefinition] -> ResourcesListResponse
- MCP.Server.Protocol: ToolsListRequest :: Maybe Cursor -> ToolsListRequest
+ MCP.Server.Protocol: ToolsListRequest :: ToolsListRequest
- MCP.Server.Protocol: ToolsListResponse :: [ToolDefinition] -> Maybe Cursor -> ToolsListResponse
+ MCP.Server.Protocol: ToolsListResponse :: [ToolDefinition] -> ToolsListResponse
- MCP.Server.Types: type PromptListHandler (m :: Type -> Type) = Maybe Cursor -> m PaginatedResult [PromptDefinition]
+ MCP.Server.Types: type PromptListHandler (m :: Type -> k) = m [PromptDefinition]
- MCP.Server.Types: type ResourceListHandler (m :: Type -> Type) = Maybe Cursor -> m PaginatedResult [ResourceDefinition]
+ MCP.Server.Types: type ResourceListHandler (m :: Type -> k) = m [ResourceDefinition]
- MCP.Server.Types: type ToolListHandler (m :: Type -> Type) = Maybe Cursor -> m PaginatedResult [ToolDefinition]
+ MCP.Server.Types: type ToolListHandler (m :: Type -> k) = m [ToolDefinition]

Files

README.md view
@@ -8,7 +8,6 @@ - **Type-Safe API**: Leverage Haskell's type system for robust MCP servers - **Multiple Abstractions**: Both low-level fine-grained control and high-level derived interfaces - **Template Haskell Support**: Automatic handler derivation from data types-- **Pagination Support**: Cursor-based pagination for large result sets  ## Supported MCP Features @@ -21,6 +20,15 @@  ## Quick Start +Add the library `mcp-server` to your cabal file:++```cabal+build-depends:+  mcp-server+```++Create a simple module, such as this example below:+ ```haskell {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}@@ -62,6 +70,28 @@       } ``` +## Custom Descriptions++You can provide custom descriptions for constructors and fields using the `*WithDescription` variants:++```haskell+-- Define descriptions for constructors and fields+descriptions :: [(String, String)]+descriptions = +  [ ("Recipe", "Generate a recipe for a specific dish")     -- Constructor description+  , ("Search", "Search our menu database")                  -- Constructor description+  , ("idea", "The dish you want a recipe for")              -- Field description+  , ("query", "Search terms to find menu items")            -- Field description+  ]++-- Use in derivation+handlers = McpServerHandlers+  { prompts = Just $(derivePromptHandlerWithDescription ''MyPrompt 'handlePrompt descriptions)+  , tools = Just $(deriveToolHandlerWithDescription ''MyTool 'handleTool descriptions)+  , resources = Just $(deriveResourceHandlerWithDescription ''MyResource 'handleResource descriptions)+  }+```+ ## Manual Handler Implementation  For fine-grained control, implement handlers manually:@@ -70,7 +100,7 @@ import MCP.Server  -- Manual handler implementation-promptListHandler :: Maybe Cursor -> IO (PaginatedResult [PromptDefinition])+promptListHandler :: IO [PromptDefinition] promptGetHandler :: PromptName -> [(ArgumentName, ArgumentValue)] -> IO (Either Error Content) -- ... implement your custom logic @@ -86,10 +116,10 @@  ## Examples -The library includes three complete examples:+The library includes complete examples: -- **`examples/HighLevel.hs`**: Manual high-level implementation-- **`examples/TemplateHaskell.hs`**: Automatic Template Haskell derivation+- **`examples/Simple/`**: Basic key-value store using Template Haskell derivation+- **`examples/Complete/`**: Full-featured example with prompts, resources, and tools  ## Docker Usage 
mcp-server.cabal view
@@ -15,14 +15,14 @@ -- PVP summary:     +-+------- breaking API changes --                  | | +----- non-breaking API additions --                  | | | +--- code changes with no API change-version: 0.1.0.5+version: 0.1.0.6 -- A short (one-line) description of the package. synopsis: Library for building Model Context Protocol (MCP) servers -- A longer description of the package. description:   A fully featured library for building MCP (Model Context Protocol) servers.   Supports both low-level fine-grained handling and high-level derived interfaces-  for prompts, resources, and tools. Includes JSON-RPC transport, pagination,+  for prompts, resources, and tools. Includes JSON-RPC transport   and stdin/stdout communication.  -- The license under which the package is released.
src/MCP/Server.hs view
@@ -187,15 +187,9 @@       , errorData = Nothing       }     Just (listHandler, _) -> do-      let cursor = case requestParams req of-            Just params -> case fromJSON params of-              Success listReq -> promptsListCursor listReq-              _               -> Nothing-            Nothing -> Nothing-      paginatedResult <- listHandler cursor+      promptsList <- listHandler       let response = PromptsListResponse-            { promptsListPrompts = paginatedItems paginatedResult-            , promptsListNextCursor = paginatedNextCursor paginatedResult+            { promptsListPrompts = promptsList             }       return $ makeSuccessResponse (requestId req) (toJSON response) @@ -248,15 +242,9 @@       , errorData = Nothing       }     Just (listHandler, _) -> do-      let cursor = case requestParams req of-            Just params -> case fromJSON params of-              Success listReq -> resourcesListCursor listReq-              _               -> Nothing-            Nothing -> Nothing-      paginatedResult <- listHandler cursor+      resourcesList <- listHandler       let response = ResourcesListResponse-            { resourcesListResources = paginatedItems paginatedResult-            , resourcesListNextCursor = paginatedNextCursor paginatedResult+            { resourcesListResources = resourcesList             }       return $ makeSuccessResponse (requestId req) (toJSON response) @@ -307,15 +295,9 @@       , errorData = Nothing       }     Just (listHandler, _) -> do-      let cursor = case requestParams req of-            Just params -> case fromJSON params of-              Success listReq -> toolsListCursor listReq-              _               -> Nothing-            Nothing -> Nothing-      paginatedResult <- listHandler cursor+      toolsList <- listHandler       let response = ToolsListResponse-            { toolsListTools = paginatedItems paginatedResult-            , toolsListNextCursor = paginatedNextCursor paginatedResult+            { toolsListTools = toolsList             }       return $ makeSuccessResponse (requestId req) (toJSON response) 
src/MCP/Server/Derive.hs view
@@ -44,10 +44,7 @@       promptDefs <- sequence $ map (mkPromptDefWithDescription descriptions) constructors        -- Generate list handler-      listHandlerExp <- [| \_cursor -> pure $ PaginatedResult-        { paginatedItems = $(return $ ListE promptDefs)-        , paginatedNextCursor = Nothing-        } |]+      listHandlerExp <- [| pure $(return $ ListE promptDefs) |]        -- Generate get handler with cases       cases <- sequence $ map (mkPromptCase handlerName) constructors@@ -207,10 +204,7 @@       -- Generate resource definitions       resourceDefs <- sequence $ map (mkResourceDefWithDescription descriptions) constructors -      listHandlerExp <- [| \_cursor -> pure $ PaginatedResult-        { paginatedItems = $(return $ ListE resourceDefs)-        , paginatedNextCursor = Nothing-        } |]+      listHandlerExp <- [| pure $(return $ ListE resourceDefs) |]        -- Generate read handler with cases       cases <- sequence $ map (mkResourceCase handlerName) constructors@@ -268,10 +262,7 @@       -- Generate tool definitions       toolDefs <- sequence $ map (mkToolDefWithDescription descriptions) constructors -      listHandlerExp <- [| \_cursor -> pure $ PaginatedResult-        { paginatedItems = $(return $ ListE toolDefs)-        , paginatedNextCursor = Nothing-        } |]+      listHandlerExp <- [| pure $(return $ ListE toolDefs) |]        -- Generate call handler with cases       cases <- sequence $ map (mkToolCase handlerName) constructors
src/MCP/Server/Protocol.hs view
@@ -121,23 +121,20 @@  -- | Prompts list request data PromptsListRequest = PromptsListRequest-  { promptsListCursor :: Maybe Cursor-  } deriving (Show, Eq, Generic)+  deriving (Show, Eq, Generic)  instance FromJSON PromptsListRequest where-  parseJSON = withObject "PromptsListRequest" $ \o -> PromptsListRequest-    <$> o .:? "cursor"+  parseJSON _ = return PromptsListRequest  -- | Prompts list response data PromptsListResponse = PromptsListResponse   { promptsListPrompts :: [PromptDefinition]-  , promptsListNextCursor :: Maybe Cursor   } deriving (Show, Eq, Generic)  instance ToJSON PromptsListResponse where-  toJSON resp = object $+  toJSON resp = object     [ "prompts" .= promptsListPrompts resp-    ] ++ maybe [] (\c -> ["nextCursor" .= c]) (promptsListNextCursor resp)+    ]  -- | Prompts get request data PromptsGetRequest = PromptsGetRequest@@ -163,23 +160,20 @@  -- | Resources list request data ResourcesListRequest = ResourcesListRequest-  { resourcesListCursor :: Maybe Cursor-  } deriving (Show, Eq, Generic)+  deriving (Show, Eq, Generic)  instance FromJSON ResourcesListRequest where-  parseJSON = withObject "ResourcesListRequest" $ \o -> ResourcesListRequest-    <$> o .:? "cursor"+  parseJSON _ = return ResourcesListRequest  -- | Resources list response data ResourcesListResponse = ResourcesListResponse   { resourcesListResources :: [ResourceDefinition]-  , resourcesListNextCursor :: Maybe Cursor   } deriving (Show, Eq, Generic)  instance ToJSON ResourcesListResponse where-  toJSON resp = object $+  toJSON resp = object     [ "resources" .= resourcesListResources resp-    ] ++ maybe [] (\c -> ["nextCursor" .= c]) (resourcesListNextCursor resp)+    ]  -- | Resources read request data ResourcesReadRequest = ResourcesReadRequest@@ -205,23 +199,20 @@  -- | Tools list request data ToolsListRequest = ToolsListRequest-  { toolsListCursor :: Maybe Cursor-  } deriving (Show, Eq, Generic)+  deriving (Show, Eq, Generic)  instance FromJSON ToolsListRequest where-  parseJSON = withObject "ToolsListRequest" $ \o -> ToolsListRequest-    <$> o .:? "cursor"+  parseJSON _ = return ToolsListRequest  -- | Tools list response data ToolsListResponse = ToolsListResponse   { toolsListTools :: [ToolDefinition]-  , toolsListNextCursor :: Maybe Cursor   } deriving (Show, Eq, Generic)  instance ToJSON ToolsListResponse where-  toJSON resp = object $+  toJSON resp = object     [ "tools" .= toolsListTools resp-    ] ++ maybe [] (\c -> ["nextCursor" .= c]) (toolsListNextCursor resp)+    ]  -- | Tools call request data ToolsCallRequest = ToolsCallRequest
src/MCP/Server/Types.hs view
@@ -34,8 +34,6 @@   , ResourceReadHandler   , ToolListHandler   , ToolCallHandler-  , PaginatedResult(..)-  , Cursor(..)      -- * Basic Types   , PromptName@@ -289,30 +287,15 @@     , fmap ("logging" .=) (capabilityLogging caps)     ] --- | Cursor for pagination-newtype Cursor = Cursor Text-  deriving (Show, Eq, Generic) -instance ToJSON Cursor where-  toJSON (Cursor c) = toJSON c--instance FromJSON Cursor where-  parseJSON = fmap Cursor . parseJSON---- | Pagination result wrapper-data PaginatedResult a = PaginatedResult-  { paginatedItems      :: a-  , paginatedNextCursor :: Maybe Cursor-  } deriving (Show, Eq, Generic)- -- | Handler type definitions-type PromptListHandler m = Maybe Cursor -> m (PaginatedResult [PromptDefinition])+type PromptListHandler m = m [PromptDefinition] type PromptGetHandler m = PromptName -> [(ArgumentName, ArgumentValue)] -> m (Either Error Content) -type ResourceListHandler m = Maybe Cursor -> m (PaginatedResult [ResourceDefinition])+type ResourceListHandler m = m [ResourceDefinition] type ResourceReadHandler m = URI -> m (Either Error Content) -type ToolListHandler m = Maybe Cursor -> m (PaginatedResult [ToolDefinition])+type ToolListHandler m = m [ToolDefinition] type ToolCallHandler m = ToolName -> [(ArgumentName, ArgumentValue)] -> m (Either Error Content)  -- | Server handlers
test/Main.hs view
@@ -234,8 +234,7 @@ testCustomDescriptions = do     let (toolListHandler, _) = testToolHandlersWithDescriptions     -    paginatedResult <- toolListHandler Nothing-    let toolDefs = paginatedItems paginatedResult+    toolDefs <- toolListHandler          -- Find the Echo tool definition and check its description     let echoDef = filter (\def -> toolDefinitionName def == "echo") toolDefs@@ -272,8 +271,7 @@ testSchemaGeneration = do     let (toolListHandler, _) = testToolHandlers     -    paginatedResult <- toolListHandler Nothing-    let toolDefs = paginatedItems paginatedResult+    toolDefs <- toolListHandler          -- Find the Calculate tool definition     let calculateDef = filter (\def -> toolDefinitionName def == "calculate") toolDefs