模型上下文协议SDK

一个纯OCaml实现的模型上下文协议SDK,支持多种协议版本和传输方式,适用于AI工具和资源管理。

  • by jeong-sik
  • OCaml
  • 本地部署
  • 更新于
在 GitHub 查看 jeong-sik/mcp-protocol-sdk

使用说明

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

项目状态

特征矩阵

协议版本

版本 新增功能
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" e

HTTP服务器(流式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" e

OAuth发现+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

文档

许可证

MIT许可证

参考文献