OCaml的MCP协议SDK
一个纯粹的OCaml 5.x实现 模型上下文协议 (MCP),涵盖规范版本2024-11-05至2025-11-25。
包裹
单层蛋白石包装 mcp_protocol 有三个子库:
| 库 | 公共名称 | 关键模块 |
|---|---|---|
| 核心 | mcp_protocol | Mcp_types, Jsonrpc, Sampling, Logging, Auth, Pagination |
| 是的 | mcp_protocol.eio | Server, Generic_server, Generic_client, Stdio_transport, Memory_transport, Middleware |
| HTTP | mcp_protocol.http | Http_server, Http_client, Oauth_client, Auth_middleware |
项目状态
- 当前版本:
1.3.0 - 路线图: ROADMAP.md
- 发布政策: docs/RELEASE-POLICY.md
- 贡献指南和问题标签: 贡献.md
- 合规性指南: 一致性/README.md
特征矩阵
协议版本
| 版本 | 新增功能 |
|---|---|
| 2024-11-05 | 工具、资源、提示(初始稳定) |
| 2025-03-26 | 可流式HTTP、OAuth 2.1、工具注释、音频内容 |
| 2025-06-18 | 结构化输出、启发、资源链接、标题字段 |
| 2025-11-25 | 采样、任务(实验)、图标、扩展 |
版本协商在初始化握手期间选择相互支持的最高版本。使用 Version.negotiate, Version.is_supported,以及 Version.features_of_version 在运行时查询功能。
运输
| 交通 | 图书馆 | 描述 |
|---|---|---|
\[UNK\]标准(NDJSON) mcp_protocol.eio | stdin/stdout上以换行符分隔的JSON | |
| 流式HTTP | mcp_protocol.http | 通过HTTP+SSE cohttp-eio,具有会话管理功能 |
| 在记忆中 | mcp_protocol.eio | 用于零IO测试的成对通道(Memory_transport) |
服务器图元
| 原始 | 字段 |
|---|---|
| 工具 | name, description, title, input_schema, output_schema, annotations (只读、破坏性、幂等、开放世界提示), icon, execution (任务支持) |
| 资源 | uri, name, title, description, mime_type, icon.模板通过 resource_template.通过订阅 subscribe/unsubscribe. |
| 提示 | name, title, description, arguments, icon |
客户特点
| 功能 | 模块 | 描述 |
|---|---|---|
| 取样 | Sampling | createMessage 和 model_preferences, sampling_tool 列表, sampling_tool_choice (自动/非/工具), include_context (无/此服务器/所有服务器) |
| 激励 | Mcp_types_elicitation | 表单模式(模式驱动)和URL模式。操作:接受、拒绝、取消 |
| 任务 | Mcp_types_tasks | 实验(2025-11-25)。状态类型:工作、输入请求、已完成、失败、已取消。分为 terminal_status 和 active_status 在类型级别 |
| 日志记录 | Logging | RFC 5424级别:调试、信息、通知、警告、错误、严重、警报、紧急。 setLevel 请求和 notifications/message |
| 根 | Mcp_types | 客户端文件系统根目录 list_changed 通知支持 |
| 竣工 | Mcp_types_completion | 及时完成资源参考 completion_context 多论证意识 |
| 进展 | Mcp_result | 进度通知 progress_token, progress, total,以及 message 字段 |
| 取消 | Mcp_result | 取消飞行中的请求 request_id 可选 reason |
异步任务
异步任务是基板拥有的MCP原语。SDK提供了导线类型(Mcp_types_tasks)以及内存生命周期存储(Task_store)对于服务器。
基材保证什么:
- 任务状态机:正在工作->已完成|失败|已取消|需要输入。无效的转换返回错误。
- 电线处理机
tasks/get,tasks/list,tasks/cancel通过add_task_handlers. - 通过GC完成终端任务
Task_store.gc_terminal. - 使用线程安全存储
Stdlib.Mutex(适用于Eio和非Eio环境)。
下游运行时间适应什么:
- 何时创建任务(例如,长时间运行的工具调用)。
- 如何向客户轮询或推送任务进度。
- 进程生命周期之外的持久性(默认情况下存储在内存中)。
服务器配方:
let store = Task_store.create () in
let server =
Server.create ~name:"my-server" ~version:"1.0.0" ()
|> Server.add_task_handlers (Task_store.to_task_handlers store)
in
(* In a tool handler: create a task, do work, update status *)
let task = Task_store.create_task store () in
(* ... run work in a fiber ... *)
Task_store.update_status store task.task_id Completed
~updated_at:(string_of_float (Unix.gettimeofday ())) |> ignore内容类型
| 类型 | 变量 | 字段 |
|---|---|---|
| 文本 | TextContent | text, annotations |
| 图片 | ImageContent | data (base64), mime_type, annotations |
| 音频 | AudioContent | data (base64), mime_type, annotations |
| 嵌入式资源 | ResourceContent | resource (uri+文本/blob) |
| 资源链接 | ResourceLinkContent | uri, name, description, mime_type, annotations |
结构化输出
工具可以声明 output_schema (JSON模式)。当存在时, tool_result.structured_content 将键入的JSON输出与人类可读的输出一起携带 content 列表。
OAuth 2.1(mcp_protocol.http)
| 能力 | RFC | 模块 |
|---|---|---|
| PKCE (S256) | RFC 7636 | Oauth_client.generate_pkce |
| 授权码交换 | RFC 6749 | Oauth_client.exchange_code |
| 令牌刷新 | RFC 6749 | Oauth_client.refresh_token |
| 发现 | RFC 8414 | Oauth_client.discover |
| 动态客户端注册 | RFC 7591 | Oauth_client.register_client |
| 承载令牌注入 | RFC 6750 | Oauth_client.inject_bearer_token |
| 服务器端承载验证 | RFC 6750 S3 | Auth_middleware.check_auth |
| 受保护的资源元数据 | RFC 9728 | Auth_middleware.resource_metadata |
| CSRF状态参数 | Oauth_client.generate_state, validate_state | |
| 凭证存储 | Oauth_client.credential_store (可插拔) | |
| 增量同意 | build_authorization_url ~scopes |
HTTPS通过以下方式自动启用 tls-eio +系统CA证书。
扩展数据
所有初始化参数/结果、工具结果、提示结果和采样消息都带有可选 _meta 现场(Yojson.Safe.t option)用于在不更改模式的情况下通过协议传递扩展数据。
扩展和实验
两者 server_capabilities 和 client_capabilities 包括 extensions 和 experimental 字段(Yojson.Safe.t option)用于非标准功能的能力协商。
建筑
基于函数的传输抽象
Generic_server.Make(T) 和 Generic_client.Make(T) 为满足以下条件的任何模块生成服务器或客户端 Transport.S 签名。这意味着相同的应用程序逻辑在stdio、HTTP或内存传输上运行,无需更改代码。
(* Stdio *)
module Stdio_server = Mcp_protocol_eio.Generic_server.Make(Stdio_transport)
(* In-memory for tests *)
module Test_server = Mcp_protocol_eio.Generic_server.Make(Memory_transport)
(* With logging middleware *)
module Logged = Mcp_protocol_eio.Middleware.Logging(Stdio_transport)
module Debug_server = Mcp_protocol_eio.Generic_server.Make(Logged)中间件
Middleware.Logging(T) 用stderr消息日志记录包装任何传输。附加的中间件可以通过链接functor来组成。
Tool_arg——类型安全的参数提取
提取工具参数,无需手动匹配JSON模式:
let handler _ctx _name args =
let open Tool_arg in
let* text = required args "text" string in
let count = optional args "count" int ~default:1 in
Ok (Mcp_types.tool_result_of_text (String.concat "" (List.init count (fun _ -> text))))可用提取器: string, int, float, bool, json, list_of. 现场访问: required (返回 Error 在丢失/解析失败时), optional (返回默认值), optional_opt (返回 'a option).
快速启动
opam pin add mcp_protocol git+https://github.com/jeong-sik/mcp-protocol-sdk.git或添加到您的 dune-project:
(depends
(mcp_protocol (>= 1.3.0)))然后在您的 dune 文件:
(libraries mcp_protocol mcp_protocol.eio mcp_protocol.http)用法
人机工程学服务器API
在一次调用中注册工具、资源和提示:
let server =
Server.create ~name:"my-server" ~version:"1.0" ()
|> Server.tool "echo" ~description:"Echo input"
(fun _ctx _name args ->
let open Tool_arg in
let* text = required args "text" string in
Ok (Mcp_types.tool_result_of_text text))
|> Server.resource ~uri:"mcp://info" "info" ~mime_type:"application/json"
(fun _ctx _uri ->
Ok [Mcp_types.{ uri = "mcp://info"; mime_type = Some "application/json";
text = Some {|{"status":"ok"}|}; blob = None }])
|> Server.prompt "greet" ~description:"Greeting"
(fun _ctx _name args ->
let who = match List.assoc_opt "name" args with Some n -> n | None -> "world" in
Ok Mcp_types.{ description = None;
messages = [{ role = User;
content = PromptText { type_ = "text"; text = "Hello, " ^ who } }];
_meta = None })内存测试
module Mt = Mcp_protocol_eio.Memory_transport
module Test_server = Mcp_protocol_eio.Generic_server.Make(Mt)
module Test_client = Mcp_protocol_eio.Generic_client.Make(Mt)
let () =
Eio_main.run @@ fun env ->
Eio.Switch.run @@ fun sw ->
let client_t, server_t = Mt.create_pair () in
let server = Test_server.create ~name:"test" ~version:"1.0" ()
|> Test_server.tool "ping" (fun _ _ _ -> Ok (Mcp_types.tool_result_of_text "pong"))
in
Eio.Fiber.fork ~sw (fun () ->
Test_server.run server ~transport:server_t ~clock:(Eio.Stdenv.clock env) ());
let client = Test_client.create ~transport:client_t ~clock:(Eio.Stdenv.clock env) () in
match Test_client.initialize client ~client_name:"test" ~client_version:"1.0" with
| Ok _ -> ignore (Test_client.call_tool client ~name:"ping" ())
| Error e -> Printf.eprintf "Failed: %s\n" eHTTP服务器(流式HTTP)
let () =
Eio_main.run @@ fun env ->
Eio.Switch.run @@ fun sw ->
let server =
Http_server.create ~name:"my-server" ~version:"1.0.0" ()
|> Http_server.add_tool
(Mcp_types.make_tool ~name:"echo" ~description:"Echo" ())
(fun _ctx _name args ->
let open Tool_arg in
let* text = required args "text" string in
Ok (Mcp_types.tool_result_of_text ("Echo: " ^ text)))
in
let net = Eio.Stdenv.net env in
let addr = `Tcp (Eio.Net.Ipaddr.V4.loopback, 8080) in
let socket = Eio.Net.listen ~sw net addr ~backlog:128 in
Cohttp_eio.Server.run socket
(Cohttp_eio.Server.make
~callback:(Http_server.callback server) ())
~on_error:(fun exn -> Printf.eprintf "%s\n" (Printexc.to_string exn))HTTP客户端
let () =
Eio_main.run @@ fun env ->
Eio.Switch.run @@ fun sw ->
let net = Eio.Stdenv.net env in
let client = Http_client.create ~endpoint:"http://127.0.0.1:8080/mcp" ~net ~sw () in
match Http_client.initialize client ~client_name:"my-client" ~client_version:"1.0" with
| Ok result ->
Printf.printf "Connected to %s\n" result.server_info.name;
ignore (Http_client.close client)
| Error e -> Printf.eprintf "Failed: %s\n" eOAuth发现+HTTPS
let () =
Eio_main.run @@ fun env ->
Eio.Switch.run @@ fun sw ->
let net = Eio.Stdenv.net env in
match Oauth_client.discover ~net ~sw ~issuer:"https://auth.example.com" with
| Error e -> Printf.eprintf "Discovery failed: %s\n" e
| Ok metadata ->
let verifier, challenge = Oauth_client.generate_pkce () in
let state = Oauth_client.generate_state () in
let auth_url = Oauth_client.build_authorization_url
~authorization_endpoint:metadata.authorization_endpoint
~client_id:"my-client" ~redirect_uri:"http://localhost:9999/callback"
~scopes:["read"] ~state ~code_challenge:challenge () in
Printf.printf "Visit: %s\n" auth_url;
ignore (Oauth_client.exchange_code ~net ~sw
~token_endpoint:metadata.token_endpoint
~client_id:"my-client" ~code:"AUTH_CODE"
~redirect_uri:"http://localhost:9999/callback"
~code_verifier:verifier)错误代码
(* JSON-RPC standard *)
Error_codes.parse_error (* -32700 *)
Error_codes.invalid_request (* -32600 *)
Error_codes.method_not_found (* -32601 *)
Error_codes.invalid_params (* -32602 *)
Error_codes.internal_error (* -32603 *)
(* MCP-specific *)
Error_codes.connection_closed (* -32001 *)
Error_codes.request_timeout (* -32002 *)
Error_codes.resource_not_found (* -32003 *)
Error_codes.tool_execution_error (* -32004 *)测试
33个测试套件(565个测试),涵盖类型、序列化、传输、服务器/客户端生命周期、OAuth、SSE和集成场景。 Memory_transport 实现了零IO的确定性测试。
dune runtest
bash scripts/check-release-metadata.sh可以对捆绑的示例服务器执行官方合规性:
bash scripts/run-conformance.sh从源头构建
git clone https://github.com/jeong-sik/mcp-protocol-sdk.git
cd mcp-protocol-sdk
opam install . --deps-only
dune build文档
- 安装检查表 --安装后验证
- MCP配置模板 --
~/.mcp.json服务器模板 - 合规性指南 --官方合规性管理流程
- 贡献 --发布标签、本地检查、发布清单
- 发布策略 --版本控制和发布元数据规则
- 路线图 --一级质量工作和后续里程碑
- 安装指南 --开发环境设置
许可证
MIT许可证
