一个用于构建模型上下文协议(MCP)服务器的全功能Haskell库。
在您的cabal文件中添加库mcp-server:
build-depends:
mcp-server
创建一个简单的模块,例如下面的示例:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
import MCP.Server
import MCP.Server.Derive
-- 定义您的数据类型
data MyPrompt = Recipe { idea :: Text } | Shopping { items :: Text }
data MyResource = Menu | Specials
data MyTool = Search { query :: Text } | Order { item :: Text }
-- 实现处理器
handlePrompt :: MyPrompt -> IO Content
handlePrompt (Recipe idea) = pure $ ContentText $ "食谱:" <> idea
handlePrompt (Shopping items) = pure $ ContentText $ "购物清单:" <> items
handleResource :: MyResource -> IO Content
handleResource Menu = pure $ ContentText "今天的菜单..."
handleResource Specials = pure $ ContentText "每日特价..."
handleTool :: MyTool -> IO Content
handleTool (Search query) = pure $ ContentText $ "搜索结果:" <> query
handleTool (Order item) = pure $ ContentText $ "已订购:" <> item
-- 自动派生处理器
main :: IO ()
main = runMcpServerStdio serverInfo handlers
where
serverInfo = McpServerInfo
{ serverName = "我的MCP服务器"
, serverVersion = "1.0.0"
, serverInstructions = "一个示例MCP服务器"
}
handlers = McpServerHandlers
{ prompts = Just $(derivePromptHandler ''MyPrompt 'handlePrompt)
, resources = Just $(deriveResourceHandler ''MyResource 'handleResource)
, tools = Just $(deriveToolHandler ''MyTool 'handleTool)
}
构造器名称会自动转换为snake_case以供MCP名称使用:
data MyTool = GetValue | SetValue | SearchItems
-- 转换为: "get_value", "set_value", "search_items"
派生系统会自动将Text参数转换为适当的Haskell类型:
data MyTool = Calculate { number :: Int, factor :: Double, enabled :: Bool }
-- Text "42" -> Int 42
-- Text "3.14" -> Double .14
-- Text "true" -> Bool True
支持的转换类型:Int, Integer, Double, Float, Bool 和 Text(无转换)。
您可以嵌套参数类型,并进行自动解包:
-- 参数记录类型
data GetValueParams = GetValueParams { _gvpKey :: Text }
data SetValueParams = SetValueParams { _svpKey :: Text, _svpValue :: Text }
-- 主工具类型
data SimpleTool
= GetValue GetValueParams
| SetValue SetValueParams
deriving (Show, Eq)
模板Haskell派生会递归地解包单参数构造器,直到达到记录类型,然后提取所有字段以生成MCP模式。
资源会根据构造器名称自动生成resource:// URI:
data MyResource = Menu | Specials
-- 生成: "resource://menu", "resource://specials"
我们不支持位置(未命名)参数:
-- ❌ 这不会工作 - 没有字段名称
data SimpleTool
= GetValue Int
| SetValue Int Text
所有参数类型最终必须解析为具有命名字段的记录,以便生成正确的MCP模式。
您可以为构造器和字段提供自定义描述,使用*WithDescription变体:
-- 定义构造器和字段的描述
descriptions :: [(String, String)]
descriptions =
[ ("Recipe", "为特定菜肴生成食谱") -- 构造器描述
, ("Search", "搜索我们的菜单数据库") -- 构造器描述
, ("idea", "您想要食谱的菜肴") -- 字段描述
, ("query", "用于查找菜单项的搜索词") -- 字段描述
]
-- 在派生中使用
handlers = McpServerHandlers
{ prompts = Just $(derivePromptHandlerWithDescription ''MyPrompt 'handlePrompt descriptions)
, tools = Just $(deriveToolHandlerWithDescription ''MyTool 'handleTool descriptions)
, resources = Just $(deriveResourceHandlerWithDescription ''MyResource 'handleResource descriptions)
}
为了精细控制,可以手动实现处理器:
import MCP.Server
-- 手动处理器实现
promptListHandler :: IO [PromptDefinition]
promptGetHandler :: PromptName -> [(ArgumentName, ArgumentValue)] -> IO (Either Error Content)
-- ... 实现您的自定义逻辑
main :: IO ()
main = runMcpServerStdio serverInfo handlers
where
handlers = McpServerHandlers
{ prompts = Just (promptListHandler, promptGetHandler)
, resources = Nothing -- 不支持
, tools = Nothing -- 不支持
}
该库现在支持MCP 2025-06-18可流式HTTP传输:
import MCP.Server.Transport.Http
-- 简单的HTTP服务器(localhost:3000/mcp)
main = runMcpServerHttp serverInfo handlers
-- 自定义配置
main = runMcpServerHttpWithConfig customConfig serverInfo handlers
where
customConfig = HttpConfig
{ httpPort = 8080
, httpHost = "0.0.0.0"
, httpEndpoint = "/api/mcp"
, httpVerbose = True -- 启用详细日志
}
特性:
/mcp 用于服务器发现/mcp 用于JSON-RPC消息该库包含几个示例:
examples/Simple/:使用模板Haskell派生的基本键值存储(STDIO)examples/Complete/:带有提示、资源和工具的全功能示例(STDIO)examples/HttpSimple/:HTTP版本的简单键值存储我喜欢将我的MCP服务器构建并发布到Docker中,这意味着配置像Claude Desktop这样的助手来运行它们会更容易。
# 构建镜像
docker build -t haskell-mcp-server .
# 运行不同的示例
docker run -i --entrypoint="/usr/local/bin/haskell-mcp-server" haskell-mcp-server
然后通过编辑claude_desktop_config.json来配置Claude:
{
"mcpServers": {
"haskell-mcp-server-example": {
"command": "docker",
"args": [
"run",
"-i",
"--entrypoint=/usr/local/bin/haskell-mcp-server",
"haskell-mcp-server"
]
}
}
}
欢迎贡献!请查看问题跟踪器中的开放问题和功能请求。
我不确定这是否有污名,但Claude帮助我编写了这个库的很多部分。我从一个非常具体的规格开始,与Claude肩并肩地实施和重构这个库,直到我对它感到满意。一些功能,如Derive函数,是我不太愿意手动编写的,因此我很感激有一个专家指导我——然而,我确实怀疑这种实现可能不是最佳的,并且我打算通过定期维护来重构和重写这个库的大片内容。
BSD-3-Clause