Model Context Protocol in OCaml

Refactor message types into Mcp_message module with consistent structure

This commit moves the RPC message types from Mcp to a separate Mcp_message
module with a consistent structure:

1. Each message type (ResourcesList, ResourcesRead, etc.) has its own module
2. Each module contains Request, Response, and other relevant submodules
3. Each submodule has a single `type t` with JSON conversion functions
4. Each submodule includes the Json.Jsonable.S interface

This restructuring provides better type safety and a more consistent API
for handling JSON-RPC messages in the OCaml MCP implementation.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

+1
bin/dune
···
(name ocaml_eval_sdk)
(modes byte)
(modules ocaml_eval_sdk)
+
(flags (:standard -w -32 -w -33))
(libraries mcp mcp_sdk mcp_server yojson eio_main eio compiler-libs.toplevel))
+183 -144
bin/ocaml_eval_sdk.ml
···
+
open Mcp
open Mcp_sdk
+
open Mcp_message
-
(* Set up the formatter for capturing evaluation output *)
-
let capture_output f =
-
let buffer = Buffer.create 1024 in
-
let fmt = Format.formatter_of_buffer buffer in
-
let result = f fmt in
-
Format.pp_print_flush fmt ();
-
(result, Buffer.contents buffer)
+
(* Create a server *)
+
let server = create_server
+
~name:"OCaml MCP Structured API Demo"
+
~version:"0.1.0"
+
~protocol_version:"2024-11-05" () |>
+
fun server ->
+
(* Set default capabilities *)
+
configure_server server ~with_tools:true ~with_resources:true ~with_prompts:true ()
(* Helper for extracting string value from JSON *)
let get_string_param json name =
···
| `Assoc fields ->
(match List.assoc_opt name fields with
| Some (`String value) -> value
-
| _ -> failwith (Printf.sprintf "Missing or invalid parameter: %s" name))
-
| _ -> failwith "Expected JSON object"
-
-
(* Initialize the OCaml toploop with standard libraries *)
-
let initialize_toploop () =
-
(* Initialize the toplevel environment *)
-
Toploop.initialize_toplevel_env ();
-
-
(* Set up the toplevel as if using the standard OCaml REPL *)
-
Clflags.nopervasives := false;
-
Clflags.real_paths := true;
-
Clflags.recursive_types := false;
-
Clflags.strict_sequence := false;
-
Clflags.applicative_functors := true;
-
-
(* Return success message *)
-
"OCaml evaluation environment initialized"
-
-
(* Evaluate an OCaml toplevel phrase *)
-
let evaluate_phrase phrase =
-
(* Parse the input text as a toplevel phrase *)
-
let lexbuf = Lexing.from_string phrase in
-
-
(* Capture both success/failure status and output *)
-
try
-
let parsed_phrase = !Toploop.parse_toplevel_phrase lexbuf in
-
let (success, output) = capture_output (fun fmt ->
-
Toploop.execute_phrase true fmt parsed_phrase
-
) in
-
-
(* Return structured result with status and captured output *)
-
if success then
-
`Assoc [
-
("success", `Bool true);
-
("output", `String output);
-
]
-
else
-
`Assoc [
-
("success", `Bool false);
-
("error", `String "Execution failed");
-
("output", `String output);
-
]
-
with e ->
-
(* Handle parsing or other errors with more detailed messages *)
-
let error_msg = match e with
-
| Syntaxerr.Error err ->
-
let msg = match err with
-
| Syntaxerr.Unclosed _ -> "Syntax error: Unclosed delimiter"
-
| Syntaxerr.Expecting _ -> "Syntax error: Expecting a different token"
-
| Syntaxerr.Not_expecting _ -> "Syntax error: Unexpected token"
-
| Syntaxerr.Applicative_path _ -> "Syntax error: Invalid applicative path"
-
| Syntaxerr.Variable_in_scope _ -> "Syntax error: Variable in scope"
-
| Syntaxerr.Other _ -> "Syntax error"
-
| _ -> "Syntax error (unknown kind)"
-
in
-
msg
-
-
| Lexer.Error (err, _) ->
-
let msg = match err with
-
| Lexer.Illegal_character _ -> "Lexer error: Illegal character"
-
| Lexer.Illegal_escape _ -> "Lexer error: Illegal escape sequence"
-
| Lexer.Unterminated_comment _ -> "Lexer error: Unterminated comment"
-
| Lexer.Unterminated_string -> "Lexer error: Unterminated string"
-
| Lexer.Unterminated_string_in_comment _ -> "Lexer error: Unterminated string in comment"
-
| Lexer.Invalid_literal _ -> "Lexer error: Invalid literal"
-
| _ -> "Lexer error (unknown kind)"
-
in
-
msg
-
| _ -> Printexc.to_string e
-
in
-
`Assoc [
-
("success", `Bool false);
-
("error", `String error_msg);
-
]
+
| _ -> raise (Failure (Printf.sprintf "Missing or invalid parameter: %s" name)))
+
| _ -> raise (Failure "Expected JSON object")
-
(* Create evaluation server *)
-
let server = create_server
-
~name:"OCaml Evaluation Server"
-
~version:"0.1.0" () |>
-
fun server ->
-
(* Set default capabilities *)
-
configure_server server ~with_tools:true ()
-
-
(* Toplevel environment state management *)
-
let toplevel_initialized = ref false
-
-
(* Initialize OCaml toplevel on first use *)
-
let ensure_toploop_initialized () =
-
if not !toplevel_initialized then begin
-
let _ = initialize_toploop () in
-
toplevel_initialized := true;
-
end
-
-
(* Register eval tool *)
+
(* Register a ping tool that demonstrates the typed API *)
let _ = add_tool server
-
~name:"ocaml_eval"
-
~description:"Evaluates OCaml toplevel phrases and returns the result"
+
~name:"ping"
+
~description:"A simple ping tool that demonstrates the structured API"
~schema_properties:[
-
("code", "string", "OCaml code to evaluate")
+
("message", "string", "The message to echo back")
]
-
~schema_required:["code"]
+
~schema_required:["message"]
(fun args ->
-
ensure_toploop_initialized ();
-
try
-
(* Extract code parameter *)
-
let code = get_string_param args "code" in
-
-
(* Execute the code *)
-
let result = evaluate_phrase code in
-
-
(* Return formatted result *)
-
let success = match result with
-
| `Assoc fields -> (
-
match List.assoc_opt "success" fields with
-
| Some (`Bool true) -> true
-
| _ -> false
-
)
-
| _ -> false
-
in
-
-
let output = match result with
-
| `Assoc fields -> (
-
match List.assoc_opt "output" fields with
-
| Some (`String s) -> s
-
| _ -> (
-
match List.assoc_opt "error" fields with
-
| Some (`String s) -> s
-
| _ -> "Unknown result"
-
)
-
)
-
| _ -> "Unknown result"
-
in
-
-
(* Create a tool result with colorized output *)
-
create_tool_result [
-
TextContent output
-
] ~is_error:(not success)
-
+
let message = get_string_param args "message" in
+
(* Create a typed tool response using the new API *)
+
let content = [
+
ToolsCall.ToolContent.Text (TextContent.{
+
text = Printf.sprintf "Pong: %s" message;
+
annotations = None
+
})
+
] in
+
(* Convert to JSON for the response *)
+
ToolsCall.Response.yojson_of_t {
+
content;
+
is_error = false
+
}
with
| Failure msg ->
-
Log.error (Printf.sprintf "Error in OCaml eval tool: %s" msg);
-
create_tool_result [TextContent (Printf.sprintf "Error: %s" msg)] ~is_error:true
+
Log.error (Printf.sprintf "Error in ping tool: %s" msg);
+
ToolsCall.Response.yojson_of_t {
+
content = [
+
ToolsCall.ToolContent.Text (TextContent.{
+
text = Printf.sprintf "Error: %s" msg;
+
annotations = None
+
})
+
];
+
is_error = true
+
}
+
)
+
+
(* Register a timestamp resource that uses the typed API *)
+
let _ = add_resource server
+
~uri_template:"timestamp://{format}"
+
~description:"Get the current timestamp in the specified format"
+
~mime_type:"text/plain"
+
(fun params ->
+
let format =
+
match params with
+
| [format] -> format
+
| _ -> "iso" (* default format *)
+
in
+
let timestamp =
+
match format with
+
| "unix" -> string_of_float (Unix.time ())
+
| "iso" | _ ->
+
let tm = Unix.gmtime (Unix.time ()) in
+
Printf.sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ"
+
(tm.tm_year + 1900) (tm.tm_mon + 1) tm.tm_mday
+
tm.tm_hour tm.tm_min tm.tm_sec
+
in
+
timestamp
)
-
(* Run the server with the default scheduler *)
+
(* Register a structured prompt that uses the typed API *)
+
let _ = add_prompt server
+
~name:"greet"
+
~description:"A prompt to greet someone using the structured API"
+
~arguments:[
+
("name", Some "The name of the person to greet", true);
+
("formal", Some "Whether to use formal greetings", false)
+
]
+
(fun args ->
+
let name = try List.assoc "name" args with Not_found -> "friend" in
+
let formal = try List.assoc "formal" args = "true" with Not_found -> false in
+
+
let greeting =
+
if formal then
+
Printf.sprintf "Greetings, %s. It's a pleasure to make your acquaintance." name
+
else
+
Printf.sprintf "Hey %s! Nice to meet you!" name
+
in
+
+
[
+
PromptMessage.{
+
role = `User;
+
content = make_text_content "I'd like to meet someone new."
+
};
+
PromptMessage.{
+
role = `Assistant;
+
content = make_text_content greeting
+
};
+
PromptMessage.{
+
role = `User;
+
content = make_text_content "What should I say next?"
+
}
+
]
+
)
+
+
(* Process a resources/list request using the typed API *)
+
let handle_resources_list_request request_id =
+
let resources = [
+
ResourcesList.Resource.{
+
uri = "timestamp://iso";
+
name = "ISO Timestamp";
+
description = Some "Current time in ISO format";
+
mime_type = Some "text/plain";
+
size = None;
+
};
+
ResourcesList.Resource.{
+
uri = "timestamp://unix";
+
name = "Unix Timestamp";
+
description = Some "Current time as Unix epoch";
+
mime_type = Some "text/plain";
+
size = None;
+
}
+
] in
+
+
(* Create a typed response *)
+
create_resources_list_response ~id:request_id ~resources ()
+
+
(* Process a tools/list request using the typed API *)
+
let handle_tools_list_request request_id =
+
let tools = [
+
ToolsList.Tool.{
+
name = "ping";
+
description = Some "A simple ping tool that demonstrates the structured API";
+
input_schema = `Assoc [
+
("type", `String "object");
+
("properties", `Assoc [
+
("message", `Assoc [
+
("type", `String "string");
+
("description", `String "The message to echo back")
+
])
+
]);
+
("required", `List [`String "message"])
+
];
+
annotations = None;
+
}
+
] in
+
+
(* Create a typed response *)
+
create_tools_list_response ~id:request_id ~tools ()
+
+
(* Process a prompts/list request using the typed API *)
+
let handle_prompts_list_request request_id =
+
let prompts = [
+
PromptsList.Prompt.{
+
name = "greet";
+
description = Some "A prompt to greet someone using the structured API";
+
arguments = [
+
PromptsList.PromptArgument.{
+
name = "name";
+
description = Some "The name of the person to greet";
+
required = true;
+
};
+
PromptsList.PromptArgument.{
+
name = "formal";
+
description = Some "Whether to use formal greetings";
+
required = false;
+
}
+
];
+
}
+
] in
+
+
(* Create a typed response *)
+
create_prompts_list_response ~id:request_id ~prompts ()
+
+
(* Run the server *)
let () =
+
(* Example of creating a structured message directly - not actually used in the server *)
+
let example_structured_request =
+
ToolsCall.create_request
+
~name:"ping"
+
~arguments:(`Assoc [("message", `String "hello")])
+
~id:(`Int 12345)
+
()
+
in
+
+
(* Log the example request for demonstration *)
+
let json_str = Yojson.Safe.to_string (JSONRPCMessage.yojson_of_t example_structured_request) in
+
Log.info (Printf.sprintf "Example structured request: %s" json_str);
+
+
(* Run the server with the default scheduler *)
Eio_main.run @@ fun env->
-
Mcp_server.run_server env server
+
Mcp_server.run_server env server
+8 -1
lib/dune
···
(modules mcp))
(library
+
(name mcp_message)
+
(public_name mcp.message)
+
(libraries mcp jsonrpc unix yojson)
+
(modules mcp_message)
+
(flags (:standard -w -67 -w -27 -w -32 -w -33 -w -34)))
+
+
(library
(name mcp_sdk)
(public_name mcp.sdk)
-
(libraries mcp jsonrpc unix yojson)
+
(libraries mcp mcp_message jsonrpc unix yojson)
(modules mcp_sdk)
(flags (:standard -w -67 -w -27 -w -32)))
+29
lib/mcp.ml
···
open Jsonrpc
+
(* Protocol method strings *)
+
module Method = struct
+
(* Initialization and lifecycle methods *)
+
let initialize = "initialize"
+
let initialized = "notifications/initialized"
+
+
(* Resource methods *)
+
let resources_list = "resources/list"
+
let resources_read = "resources/read"
+
let resources_templates_list = "resources/templates/list"
+
let resources_subscribe = "resources/subscribe"
+
let resources_list_changed = "notifications/resources/list_changed"
+
let resources_updated = "notifications/resources/updated"
+
+
(* Tool methods *)
+
let tools_list = "tools/list"
+
let tools_call = "tools/call"
+
let tools_list_changed = "notifications/tools/list_changed"
+
+
(* Prompt methods *)
+
let prompts_list = "prompts/list"
+
let prompts_get = "prompts/get"
+
let prompts_list_changed = "notifications/prompts/list_changed"
+
+
(* Progress notifications *)
+
let progress = "notifications/progress"
+
end
+
(* Common types *)
module Role = struct
···
JSONRPCMessage.create_notification ~method_:"notifications/initialized" ~params ()
end
end
+
(* Export the main interface for using the MCP protocol *)
+36
lib/mcp.mli
···
open Jsonrpc
+
(** MCP Protocol Methods - Standard method names used in JSON-RPC messages *)
+
module Method : sig
+
(** Standard protocol methods used in MCP JSON-RPC messages *)
+
+
val initialize : string (** "initialize" - Start the MCP lifecycle *)
+
+
val initialized : string (** "notifications/initialized" - Signal readiness after initialization *)
+
+
val resources_list : string (** "resources/list" - Discover available resources *)
+
+
val resources_read : string (** "resources/read" - Retrieve resource contents *)
+
+
val resources_templates_list : string (** "resources/templates/list" - List available resource templates *)
+
+
val resources_subscribe : string (** "resources/subscribe" - Subscribe to resource changes *)
+
+
val resources_list_changed : string (** "notifications/resources/list_changed" - Resource list has changed *)
+
+
val resources_updated : string (** "notifications/resources/updated" - Resource has been updated *)
+
+
val tools_list : string (** "tools/list" - Discover available tools *)
+
+
val tools_call : string (** "tools/call" - Invoke a tool *)
+
+
val tools_list_changed : string (** "notifications/tools/list_changed" - Tool list has changed *)
+
+
val prompts_list : string (** "prompts/list" - Discover available prompts *)
+
+
val prompts_get : string (** "prompts/get" - Retrieve a prompt template with arguments *)
+
+
val prompts_list_changed : string (** "notifications/prompts/list_changed" - Prompt list has changed *)
+
+
val progress : string (** "notifications/progress" - Progress update for long-running operations *)
+
end
+
+
(** Common types *)
(** Roles for conversation participants *)
+726
lib/mcp_message.ml
···
+
(* Mcp_message - High-level RPC message definitions for Model Context Protocol *)
+
+
open Mcp
+
open Jsonrpc
+
+
(* Resources/List *)
+
module ResourcesList = struct
+
module Request = struct
+
type t = {
+
cursor: Cursor.t option;
+
}
+
+
let yojson_of_t { cursor } =
+
let assoc = [] in
+
let assoc = match cursor with
+
| Some c -> ("cursor", Cursor.yojson_of_t c) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let cursor = List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson in
+
{ cursor }
+
| j -> raise (Json.Of_json ("Expected object for ResourcesList.Request.t", j))
+
+
end
+
+
module Resource = struct
+
type t = {
+
uri: string;
+
name: string;
+
description: string option;
+
mime_type: string option;
+
size: int option;
+
}
+
+
let yojson_of_t { uri; name; description; mime_type; size } =
+
let assoc = [
+
("uri", `String uri);
+
("name", `String name);
+
] in
+
let assoc = match description with
+
| Some desc -> ("description", `String desc) :: assoc
+
| None -> assoc
+
in
+
let assoc = match mime_type with
+
| Some mime -> ("mimeType", `String mime) :: assoc
+
| None -> assoc
+
in
+
let assoc = match size with
+
| Some s -> ("size", `Int s) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let uri = match List.assoc_opt "uri" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'uri' field", `Assoc fields))
+
in
+
let name = match List.assoc_opt "name" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'name' field", `Assoc fields))
+
in
+
let description = List.assoc_opt "description" fields |> Option.map (function
+
| `String s -> s
+
| j -> raise (Json.Of_json ("Expected string for description", j))
+
) in
+
let mime_type = List.assoc_opt "mimeType" fields |> Option.map (function
+
| `String s -> s
+
| j -> raise (Json.Of_json ("Expected string for mimeType", j))
+
) in
+
let size = List.assoc_opt "size" fields |> Option.map (function
+
| `Int i -> i
+
| j -> raise (Json.Of_json ("Expected int for size", j))
+
) in
+
{ uri; name; description; mime_type; size }
+
| j -> raise (Json.Of_json ("Expected object for ResourcesList.Resource.t", j))
+
end
+
+
module Response = struct
+
type t = {
+
resources: Resource.t list;
+
next_cursor: Cursor.t option;
+
}
+
+
let yojson_of_t { resources; next_cursor } =
+
let assoc = [
+
("resources", `List (List.map Resource.yojson_of_t resources));
+
] in
+
let assoc = match next_cursor with
+
| Some c -> ("nextCursor", Cursor.yojson_of_t c) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let resources = match List.assoc_opt "resources" fields with
+
| Some (`List items) -> List.map Resource.t_of_yojson items
+
| _ -> raise (Json.Of_json ("Missing or invalid 'resources' field", `Assoc fields))
+
in
+
let next_cursor = List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson in
+
{ resources; next_cursor }
+
| j -> raise (Json.Of_json ("Expected object for ResourcesList.Response.t", j))
+
+
end
+
+
(* Request/response creation helpers *)
+
let create_request ?cursor ?id () =
+
let id = match id with
+
| Some i -> i
+
| None -> `Int (Random.int 10000)
+
in
+
let params = Request.yojson_of_t { cursor } in
+
JSONRPCMessage.create_request ~id ~method_:Method.resources_list ~params:(Some params) ()
+
+
let create_response ~id ~resources ?next_cursor () =
+
let result = Response.yojson_of_t { resources; next_cursor } in
+
JSONRPCMessage.create_response ~id ~result
+
end
+
+
(* Resources/Read *)
+
module ResourcesRead = struct
+
module Request = struct
+
type t = {
+
uri: string;
+
}
+
+
let yojson_of_t { uri } =
+
`Assoc [
+
("uri", `String uri);
+
]
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let uri = match List.assoc_opt "uri" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'uri' field", `Assoc fields))
+
in
+
{ uri }
+
| j -> raise (Json.Of_json ("Expected object for ResourcesRead.Request.t", j))
+
+
end
+
+
module ResourceContent = struct
+
type t =
+
| TextResource of TextResourceContents.t
+
| BlobResource of BlobResourceContents.t
+
+
let yojson_of_t = function
+
| TextResource tr -> TextResourceContents.yojson_of_t tr
+
| BlobResource br -> BlobResourceContents.yojson_of_t br
+
+
let t_of_yojson json =
+
match json with
+
| `Assoc fields ->
+
if List.mem_assoc "text" fields then
+
TextResource (TextResourceContents.t_of_yojson json)
+
else if List.mem_assoc "blob" fields then
+
BlobResource (BlobResourceContents.t_of_yojson json)
+
else
+
raise (Json.Of_json ("Invalid resource content", json))
+
| j -> raise (Json.Of_json ("Expected object for ResourcesRead.ResourceContent.t", j))
+
+
end
+
+
module Response = struct
+
type t = {
+
contents: ResourceContent.t list;
+
}
+
+
let yojson_of_t { contents } =
+
`Assoc [
+
("contents", `List (List.map ResourceContent.yojson_of_t contents));
+
]
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let contents = match List.assoc_opt "contents" fields with
+
| Some (`List items) -> List.map ResourceContent.t_of_yojson items
+
| _ -> raise (Json.Of_json ("Missing or invalid 'contents' field", `Assoc fields))
+
in
+
{ contents }
+
| j -> raise (Json.Of_json ("Expected object for ResourcesRead.Response.t", j))
+
+
end
+
+
(* Request/response creation helpers *)
+
let create_request ~uri ?id () =
+
let id = match id with
+
| Some i -> i
+
| None -> `Int (Random.int 10000)
+
in
+
let params = Request.yojson_of_t { uri } in
+
JSONRPCMessage.create_request ~id ~method_:Method.resources_read ~params:(Some params) ()
+
+
let create_response ~id ~contents () =
+
let result = Response.yojson_of_t { contents } in
+
JSONRPCMessage.create_response ~id ~result
+
end
+
+
(* Tools/List *)
+
module ToolsList = struct
+
module Request = struct
+
type t = {
+
cursor: Cursor.t option;
+
}
+
+
let yojson_of_t { cursor } =
+
let assoc = [] in
+
let assoc = match cursor with
+
| Some c -> ("cursor", Cursor.yojson_of_t c) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let cursor = List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson in
+
{ cursor }
+
| j -> raise (Json.Of_json ("Expected object for ToolsList.Request.t", j))
+
+
end
+
+
module Tool = struct
+
type t = {
+
name: string;
+
description: string option;
+
input_schema: Json.t;
+
annotations: Json.t option;
+
}
+
+
let yojson_of_t { name; description; input_schema; annotations } =
+
let assoc = [
+
("name", `String name);
+
("inputSchema", input_schema);
+
] in
+
let assoc = match description with
+
| Some desc -> ("description", `String desc) :: assoc
+
| None -> assoc
+
in
+
let assoc = match annotations with
+
| Some anno -> ("annotations", anno) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let name = match List.assoc_opt "name" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'name' field", `Assoc fields))
+
in
+
let description = List.assoc_opt "description" fields |> Option.map (function
+
| `String s -> s
+
| j -> raise (Json.Of_json ("Expected string for description", j))
+
) in
+
let input_schema = match List.assoc_opt "inputSchema" fields with
+
| Some schema -> schema
+
| None -> raise (Json.Of_json ("Missing 'inputSchema' field", `Assoc fields))
+
in
+
let annotations = List.assoc_opt "annotations" fields in
+
{ name; description; input_schema; annotations }
+
| j -> raise (Json.Of_json ("Expected object for ToolsList.Tool.t", j))
+
+
end
+
+
module Response = struct
+
type t = {
+
tools: Tool.t list;
+
next_cursor: Cursor.t option;
+
}
+
+
let yojson_of_t { tools; next_cursor } =
+
let assoc = [
+
("tools", `List (List.map Tool.yojson_of_t tools));
+
] in
+
let assoc = match next_cursor with
+
| Some c -> ("nextCursor", Cursor.yojson_of_t c) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let tools = match List.assoc_opt "tools" fields with
+
| Some (`List items) -> List.map Tool.t_of_yojson items
+
| _ -> raise (Json.Of_json ("Missing or invalid 'tools' field", `Assoc fields))
+
in
+
let next_cursor = List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson in
+
{ tools; next_cursor }
+
| j -> raise (Json.Of_json ("Expected object for ToolsList.Response.t", j))
+
+
end
+
+
(* Request/response creation helpers *)
+
let create_request ?cursor ?id () =
+
let id = match id with
+
| Some i -> i
+
| None -> `Int (Random.int 10000)
+
in
+
let params = Request.yojson_of_t { cursor } in
+
JSONRPCMessage.create_request ~id ~method_:Method.tools_list ~params:(Some params) ()
+
+
let create_response ~id ~tools ?next_cursor () =
+
let result = Response.yojson_of_t { tools; next_cursor } in
+
JSONRPCMessage.create_response ~id ~result
+
end
+
+
(* Tools/Call *)
+
module ToolsCall = struct
+
module Request = struct
+
type t = {
+
name: string;
+
arguments: Json.t;
+
}
+
+
let yojson_of_t { name; arguments } =
+
`Assoc [
+
("name", `String name);
+
("arguments", arguments);
+
]
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let name = match List.assoc_opt "name" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'name' field", `Assoc fields))
+
in
+
let arguments = match List.assoc_opt "arguments" fields with
+
| Some json -> json
+
| None -> raise (Json.Of_json ("Missing 'arguments' field", `Assoc fields))
+
in
+
{ name; arguments }
+
| j -> raise (Json.Of_json ("Expected object for ToolsCall.Request.t", j))
+
+
end
+
+
module ToolContent = struct
+
type t =
+
| Text of TextContent.t
+
| Image of ImageContent.t
+
| Audio of AudioContent.t
+
| Resource of EmbeddedResource.t
+
+
let yojson_of_t = function
+
| Text t -> TextContent.yojson_of_t t
+
| Image i -> ImageContent.yojson_of_t i
+
| Audio a -> AudioContent.yojson_of_t a
+
| Resource r -> EmbeddedResource.yojson_of_t r
+
+
let t_of_yojson json =
+
match json with
+
| `Assoc fields ->
+
(match List.assoc_opt "type" fields with
+
| Some (`String "text") -> Text (TextContent.t_of_yojson json)
+
| Some (`String "image") -> Image (ImageContent.t_of_yojson json)
+
| Some (`String "audio") -> Audio (AudioContent.t_of_yojson json)
+
| Some (`String "resource") -> Resource (EmbeddedResource.t_of_yojson json)
+
| _ -> raise (Json.Of_json ("Invalid or missing content type", json)))
+
| j -> raise (Json.Of_json ("Expected object for ToolsCall.ToolContent.t", j))
+
+
end
+
+
module Response = struct
+
type t = {
+
content: ToolContent.t list;
+
is_error: bool;
+
}
+
+
let yojson_of_t { content; is_error } =
+
`Assoc [
+
("content", `List (List.map ToolContent.yojson_of_t content));
+
("isError", `Bool is_error);
+
]
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let content = match List.assoc_opt "content" fields with
+
| Some (`List items) -> List.map ToolContent.t_of_yojson items
+
| _ -> raise (Json.Of_json ("Missing or invalid 'content' field", `Assoc fields))
+
in
+
let is_error = match List.assoc_opt "isError" fields with
+
| Some (`Bool b) -> b
+
| _ -> false
+
in
+
{ content; is_error }
+
| j -> raise (Json.Of_json ("Expected object for ToolsCall.Response.t", j))
+
+
end
+
+
(* Request/response creation helpers *)
+
let create_request ~name ~arguments ?id () =
+
let id = match id with
+
| Some i -> i
+
| None -> `Int (Random.int 10000)
+
in
+
let params = Request.yojson_of_t { name; arguments } in
+
JSONRPCMessage.create_request ~id ~method_:Method.tools_call ~params:(Some params) ()
+
+
let create_response ~id ~content ~is_error () =
+
let result = Response.yojson_of_t { content; is_error } in
+
JSONRPCMessage.create_response ~id ~result
+
end
+
+
(* Prompts/List *)
+
module PromptsList = struct
+
module PromptArgument = struct
+
type t = {
+
name: string;
+
description: string option;
+
required: bool;
+
}
+
+
let yojson_of_t { name; description; required } =
+
let assoc = [
+
("name", `String name);
+
] in
+
let assoc = match description with
+
| Some desc -> ("description", `String desc) :: assoc
+
| None -> assoc
+
in
+
let assoc = if required then
+
("required", `Bool true) :: assoc
+
else
+
assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let name = match List.assoc_opt "name" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'name' field", `Assoc fields))
+
in
+
let description = List.assoc_opt "description" fields |> Option.map (function
+
| `String s -> s
+
| j -> raise (Json.Of_json ("Expected string for description", j))
+
) in
+
let required = match List.assoc_opt "required" fields with
+
| Some (`Bool b) -> b
+
| _ -> false
+
in
+
{ name; description; required }
+
| j -> raise (Json.Of_json ("Expected object for PromptsList.PromptArgument.t", j))
+
+
end
+
+
module Prompt = struct
+
type t = {
+
name: string;
+
description: string option;
+
arguments: PromptArgument.t list;
+
}
+
+
let yojson_of_t { name; description; arguments } =
+
let assoc = [
+
("name", `String name);
+
] in
+
let assoc = match description with
+
| Some desc -> ("description", `String desc) :: assoc
+
| None -> assoc
+
in
+
let assoc = if arguments <> [] then
+
("arguments", `List (List.map PromptArgument.yojson_of_t arguments)) :: assoc
+
else
+
assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let name = match List.assoc_opt "name" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'name' field", `Assoc fields))
+
in
+
let description = List.assoc_opt "description" fields |> Option.map (function
+
| `String s -> s
+
| j -> raise (Json.Of_json ("Expected string for description", j))
+
) in
+
let arguments = match List.assoc_opt "arguments" fields with
+
| Some (`List items) -> List.map PromptArgument.t_of_yojson items
+
| _ -> []
+
in
+
{ name; description; arguments }
+
| j -> raise (Json.Of_json ("Expected object for PromptsList.Prompt.t", j))
+
+
end
+
+
module Request = struct
+
type t = {
+
cursor: Cursor.t option;
+
}
+
+
let yojson_of_t { cursor } =
+
let assoc = [] in
+
let assoc = match cursor with
+
| Some c -> ("cursor", Cursor.yojson_of_t c) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let cursor = List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson in
+
{ cursor }
+
| j -> raise (Json.Of_json ("Expected object for PromptsList.Request.t", j))
+
+
end
+
+
module Response = struct
+
type t = {
+
prompts: Prompt.t list;
+
next_cursor: Cursor.t option;
+
}
+
+
let yojson_of_t { prompts; next_cursor } =
+
let assoc = [
+
("prompts", `List (List.map Prompt.yojson_of_t prompts));
+
] in
+
let assoc = match next_cursor with
+
| Some c -> ("nextCursor", Cursor.yojson_of_t c) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let prompts = match List.assoc_opt "prompts" fields with
+
| Some (`List items) -> List.map Prompt.t_of_yojson items
+
| _ -> raise (Json.Of_json ("Missing or invalid 'prompts' field", `Assoc fields))
+
in
+
let next_cursor = List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson in
+
{ prompts; next_cursor }
+
| j -> raise (Json.Of_json ("Expected object for PromptsList.Response.t", j))
+
+
end
+
+
(* Request/response creation helpers *)
+
let create_request ?cursor ?id () =
+
let id = match id with
+
| Some i -> i
+
| None -> `Int (Random.int 10000)
+
in
+
let params = Request.yojson_of_t { cursor } in
+
JSONRPCMessage.create_request ~id ~method_:Method.prompts_list ~params:(Some params) ()
+
+
let create_response ~id ~prompts ?next_cursor () =
+
let result = Response.yojson_of_t { prompts; next_cursor } in
+
JSONRPCMessage.create_response ~id ~result
+
end
+
+
(* Prompts/Get *)
+
module PromptsGet = struct
+
module Request = struct
+
type t = {
+
name: string;
+
arguments: (string * string) list;
+
}
+
+
let yojson_of_t { name; arguments } =
+
let args_json = `Assoc (List.map (fun (k, v) -> (k, `String v)) arguments) in
+
`Assoc [
+
("name", `String name);
+
("arguments", args_json);
+
]
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let name = match List.assoc_opt "name" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'name' field", `Assoc fields))
+
in
+
let arguments = match List.assoc_opt "arguments" fields with
+
| Some (`Assoc args) ->
+
List.map (fun (k, v) ->
+
match v with
+
| `String s -> (k, s)
+
| _ -> raise (Json.Of_json ("Expected string value for argument", v))
+
) args
+
| _ -> []
+
in
+
{ name; arguments }
+
| j -> raise (Json.Of_json ("Expected object for PromptsGet.Request.t", j))
+
+
end
+
+
module Response = struct
+
type t = {
+
description: string option;
+
messages: PromptMessage.t list;
+
}
+
+
let yojson_of_t { description; messages } =
+
let assoc = [
+
("messages", `List (List.map PromptMessage.yojson_of_t messages));
+
] in
+
let assoc = match description with
+
| Some desc -> ("description", `String desc) :: assoc
+
| None -> assoc
+
in
+
`Assoc assoc
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let messages = match List.assoc_opt "messages" fields with
+
| Some (`List items) -> List.map PromptMessage.t_of_yojson items
+
| _ -> raise (Json.Of_json ("Missing or invalid 'messages' field", `Assoc fields))
+
in
+
let description = List.assoc_opt "description" fields |> Option.map (function
+
| `String s -> s
+
| j -> raise (Json.Of_json ("Expected string for description", j))
+
) in
+
{ description; messages }
+
| j -> raise (Json.Of_json ("Expected object for PromptsGet.Response.t", j))
+
+
end
+
+
(* Request/response creation helpers *)
+
let create_request ~name ~arguments ?id () =
+
let id = match id with
+
| Some i -> i
+
| None -> `Int (Random.int 10000)
+
in
+
let params = Request.yojson_of_t { name; arguments } in
+
JSONRPCMessage.create_request ~id ~method_:Method.prompts_get ~params:(Some params) ()
+
+
let create_response ~id ?description ~messages () =
+
let result = Response.yojson_of_t { description; messages } in
+
JSONRPCMessage.create_response ~id ~result
+
end
+
+
(* List Changed Notifications *)
+
module ListChanged = struct
+
(* No parameters for these notifications *)
+
+
let create_resources_notification () =
+
JSONRPCMessage.create_notification ~method_:Method.resources_list_changed ()
+
+
let create_tools_notification () =
+
JSONRPCMessage.create_notification ~method_:Method.tools_list_changed ()
+
+
let create_prompts_notification () =
+
JSONRPCMessage.create_notification ~method_:Method.prompts_list_changed ()
+
end
+
+
(* Resource Updated Notification *)
+
module ResourceUpdated = struct
+
module Notification = struct
+
type t = {
+
uri: string;
+
}
+
+
let yojson_of_t { uri } =
+
`Assoc [
+
("uri", `String uri);
+
]
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let uri = match List.assoc_opt "uri" fields with
+
| Some (`String s) -> s
+
| _ -> raise (Json.Of_json ("Missing or invalid 'uri' field", `Assoc fields))
+
in
+
{ uri }
+
| j -> raise (Json.Of_json ("Expected object for ResourceUpdated.Notification.t", j))
+
+
end
+
+
let create_notification ~uri () =
+
let params = Notification.yojson_of_t { uri } in
+
JSONRPCMessage.create_notification ~method_:Method.resources_updated ~params:(Some params) ()
+
end
+
+
(* Progress Notification *)
+
module Progress = struct
+
module Notification = struct
+
type t = {
+
progress: float;
+
total: float;
+
progress_token: ProgressToken.t;
+
}
+
+
let yojson_of_t { progress; total; progress_token } =
+
`Assoc [
+
("progress", `Float progress);
+
("total", `Float total);
+
("progressToken", ProgressToken.yojson_of_t progress_token);
+
]
+
+
let t_of_yojson = function
+
| `Assoc fields ->
+
let progress = match List.assoc_opt "progress" fields with
+
| Some (`Float f) -> f
+
| _ -> raise (Json.Of_json ("Missing or invalid 'progress' field", `Assoc fields))
+
in
+
let total = match List.assoc_opt "total" fields with
+
| Some (`Float f) -> f
+
| _ -> raise (Json.Of_json ("Missing or invalid 'total' field", `Assoc fields))
+
in
+
let progress_token = match List.assoc_opt "progressToken" fields with
+
| Some token -> ProgressToken.t_of_yojson token
+
| _ -> raise (Json.Of_json ("Missing or invalid 'progressToken' field", `Assoc fields))
+
in
+
{ progress; total; progress_token }
+
| j -> raise (Json.Of_json ("Expected object for Progress.Notification.t", j))
+
+
end
+
+
let create_notification ~progress ~total ~progress_token () =
+
let params = Notification.yojson_of_t { progress; total; progress_token } in
+
JSONRPCMessage.create_notification ~method_:Method.progress ~params:(Some params) ()
+
end
+
+
(* Type aliases for backward compatibility *)
+
type request = ResourcesList.Request.t
+
type response = ResourcesList.Response.t
+
type resource = ResourcesList.Resource.t
+
type resource_content = ResourcesRead.ResourceContent.t
+
type tool = ToolsList.Tool.t
+
type tool_content = ToolsCall.ToolContent.t
+
type prompt = PromptsList.Prompt.t
+
type prompt_argument = PromptsList.PromptArgument.t
+264
lib/mcp_message.mli
···
+
(** Mcp_message - High-level RPC message definitions for Model Context Protocol *)
+
+
open Mcp
+
open Jsonrpc
+
+
(** Resources/List - Request to list available resources *)
+
module ResourcesList : sig
+
(** Request parameters *)
+
module Request : sig
+
type t = {
+
cursor: Cursor.t option; (** Optional pagination cursor *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Resource definition *)
+
module Resource : sig
+
type t = {
+
uri: string; (** Unique identifier for the resource *)
+
name: string; (** Human-readable name *)
+
description: string option; (** Optional description *)
+
mime_type: string option; (** Optional MIME type *)
+
size: int option; (** Optional size in bytes *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Response result *)
+
module Response : sig
+
type t = {
+
resources: Resource.t list; (** List of available resources *)
+
next_cursor: Cursor.t option; (** Optional cursor for the next page *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Create a resources/list request *)
+
val create_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
+
(** Create a resources/list response *)
+
val create_response : id:RequestId.t -> resources:Resource.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
+
end
+
+
(** Resources/Read - Request to read resource contents *)
+
module ResourcesRead : sig
+
(** Request parameters *)
+
module Request : sig
+
type t = {
+
uri: string; (** URI of the resource to read *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Resource content *)
+
module ResourceContent : sig
+
type t =
+
| TextResource of TextResourceContents.t (** Text content *)
+
| BlobResource of BlobResourceContents.t (** Binary content *)
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Response result *)
+
module Response : sig
+
type t = {
+
contents: ResourceContent.t list; (** List of resource contents *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Create a resources/read request *)
+
val create_request : uri:string -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
+
(** Create a resources/read response *)
+
val create_response : id:RequestId.t -> contents:ResourceContent.t list -> unit -> JSONRPCMessage.t
+
end
+
+
(** Tools/List - Request to list available tools *)
+
module ToolsList : sig
+
(** Request parameters *)
+
module Request : sig
+
type t = {
+
cursor: Cursor.t option; (** Optional pagination cursor *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Tool definition *)
+
module Tool : sig
+
type t = {
+
name: string; (** Unique identifier for the tool *)
+
description: string option; (** Human-readable description *)
+
input_schema: Json.t; (** JSON Schema defining expected parameters *)
+
annotations: Json.t option; (** Optional properties describing tool behavior *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Response result *)
+
module Response : sig
+
type t = {
+
tools: Tool.t list; (** List of available tools *)
+
next_cursor: Cursor.t option; (** Optional cursor for the next page *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Create a tools/list request *)
+
val create_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
+
(** Create a tools/list response *)
+
val create_response : id:RequestId.t -> tools:Tool.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
+
end
+
+
(** Tools/Call - Request to invoke a tool *)
+
module ToolsCall : sig
+
(** Request parameters *)
+
module Request : sig
+
type t = {
+
name: string; (** Name of the tool to call *)
+
arguments: Json.t; (** Arguments for the tool invocation *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Tool content *)
+
module ToolContent : sig
+
type t =
+
| Text of TextContent.t (** Text content *)
+
| Image of ImageContent.t (** Image content *)
+
| Audio of AudioContent.t (** Audio content *)
+
| Resource of EmbeddedResource.t (** Resource content *)
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Response result *)
+
module Response : sig
+
type t = {
+
content: ToolContent.t list; (** List of content items returned by the tool *)
+
is_error: bool; (** Whether the result represents an error *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Create a tools/call request *)
+
val create_request : name:string -> arguments:Json.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
+
(** Create a tools/call response *)
+
val create_response : id:RequestId.t -> content:ToolContent.t list -> is_error:bool -> unit -> JSONRPCMessage.t
+
end
+
+
(** Prompts/List - Request to list available prompts *)
+
module PromptsList : sig
+
(** Prompt argument *)
+
module PromptArgument : sig
+
type t = {
+
name: string; (** Name of the argument *)
+
description: string option; (** Description of the argument *)
+
required: bool; (** Whether the argument is required *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Prompt definition *)
+
module Prompt : sig
+
type t = {
+
name: string; (** Unique identifier for the prompt *)
+
description: string option; (** Human-readable description *)
+
arguments: PromptArgument.t list; (** Arguments for customization *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Request parameters *)
+
module Request : sig
+
type t = {
+
cursor: Cursor.t option; (** Optional pagination cursor *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Response result *)
+
module Response : sig
+
type t = {
+
prompts: Prompt.t list; (** List of available prompts *)
+
next_cursor: Cursor.t option; (** Optional cursor for the next page *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Create a prompts/list request *)
+
val create_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
+
(** Create a prompts/list response *)
+
val create_response : id:RequestId.t -> prompts:Prompt.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
+
end
+
+
(** Prompts/Get - Request to get a prompt with arguments *)
+
module PromptsGet : sig
+
(** Request parameters *)
+
module Request : sig
+
type t = {
+
name: string; (** Name of the prompt to get *)
+
arguments: (string * string) list; (** Arguments for the prompt *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Response result *)
+
module Response : sig
+
type t = {
+
description: string option; (** Description of the prompt *)
+
messages: PromptMessage.t list; (** List of messages in the prompt *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Create a prompts/get request *)
+
val create_request : name:string -> arguments:(string * string) list -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
+
(** Create a prompts/get response *)
+
val create_response : id:RequestId.t -> ?description:string -> messages:PromptMessage.t list -> unit -> JSONRPCMessage.t
+
end
+
+
(** List Changed Notifications *)
+
module ListChanged : sig
+
(** Create a resources/list_changed notification *)
+
val create_resources_notification : unit -> JSONRPCMessage.t
+
+
(** Create a tools/list_changed notification *)
+
val create_tools_notification : unit -> JSONRPCMessage.t
+
+
(** Create a prompts/list_changed notification *)
+
val create_prompts_notification : unit -> JSONRPCMessage.t
+
end
+
+
(** Resource Updated Notification *)
+
module ResourceUpdated : sig
+
(** Notification parameters *)
+
module Notification : sig
+
type t = {
+
uri: string; (** URI of the updated resource *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Create a resources/updated notification *)
+
val create_notification : uri:string -> unit -> JSONRPCMessage.t
+
end
+
+
(** Progress Notification *)
+
module Progress : sig
+
(** Notification parameters *)
+
module Notification : sig
+
type t = {
+
progress: float; (** Current progress value *)
+
total: float; (** Total progress value *)
+
progress_token: ProgressToken.t; (** Token identifying the operation *)
+
}
+
include Json.Jsonable.S with type t := t
+
end
+
+
(** Create a progress notification *)
+
val create_notification : progress:float -> total:float -> progress_token:ProgressToken.t -> unit -> JSONRPCMessage.t
+
end
+57
lib/mcp_sdk.ml
···
let capabilities = default_capabilities ~with_tools ~with_resources ~with_prompts () in
set_capabilities server capabilities;
server
+
+
(* MCP Protocol Message Helpers *)
+
+
(* Resources helpers *)
+
let create_resources_list_request ?cursor ?id () =
+
Mcp_message.ResourcesList.create_request ?cursor ?id ()
+
+
let create_resources_list_response ~id ~resources ?next_cursor () =
+
Mcp_message.ResourcesList.create_response ~id ~resources ?next_cursor ()
+
+
let create_resources_read_request ~uri ?id () =
+
Mcp_message.ResourcesRead.create_request ~uri ?id ()
+
+
let create_resources_read_response ~id ~contents () =
+
Mcp_message.ResourcesRead.create_response ~id ~contents ()
+
+
let create_resources_list_changed_notification () =
+
Mcp_message.ListChanged.create_resources_notification ()
+
+
let create_resources_updated_notification ~uri () =
+
Mcp_message.ResourceUpdated.create_notification ~uri ()
+
+
(* Tools helpers *)
+
let create_tools_list_request ?cursor ?id () =
+
Mcp_message.ToolsList.create_request ?cursor ?id ()
+
+
let create_tools_list_response ~id ~tools ?next_cursor () =
+
Mcp_message.ToolsList.create_response ~id ~tools ?next_cursor ()
+
+
let create_tools_call_request ~name ~arguments ?id () =
+
Mcp_message.ToolsCall.create_request ~name ~arguments ?id ()
+
+
let create_tools_call_response ~id ~content ~is_error () =
+
Mcp_message.ToolsCall.create_response ~id ~content ~is_error ()
+
+
let create_tools_list_changed_notification () =
+
Mcp_message.ListChanged.create_tools_notification ()
+
+
(* Prompts helpers *)
+
let create_prompts_list_request ?cursor ?id () =
+
Mcp_message.PromptsList.create_request ?cursor ?id ()
+
+
let create_prompts_list_response ~id ~prompts ?next_cursor () =
+
Mcp_message.PromptsList.create_response ~id ~prompts ?next_cursor ()
+
+
let create_prompts_get_request ~name ~arguments ?id () =
+
Mcp_message.PromptsGet.create_request ~name ~arguments ?id ()
+
+
let create_prompts_get_response ~id ?description ~messages () =
+
Mcp_message.PromptsGet.create_response ~id ?description ~messages ()
+
+
let create_prompts_list_changed_notification () =
+
Mcp_message.ListChanged.create_prompts_notification ()
+
+
(* Progress notification *)
+
let create_progress_notification ~progress ~total ~progress_token () =
+
Mcp_message.Progress.create_notification ~progress ~total ~progress_token ()
+29 -1
lib/mcp_sdk.mli
···
open Mcp
open Jsonrpc
+
open Mcp_message
(** SDK version *)
val version : string
···
unit -> Json.t
(** Helper functions for creating common objects *)
-
val make_tool_schema : (string * string * string) list -> string list -> Json.t
+
val make_tool_schema : (string * string * string) list -> string list -> Json.t
+
+
(** MCP Protocol Message Helpers for handling JSON-RPC messages *)
+
+
(** Resource message functions *)
+
val create_resources_list_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
val create_resources_list_response : id:RequestId.t -> resources:ResourcesList.Resource.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
+
val create_resources_read_request : uri:string -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
val create_resources_read_response : id:RequestId.t -> contents:ResourcesRead.ResourceContent.t list -> unit -> JSONRPCMessage.t
+
val create_resources_list_changed_notification : unit -> JSONRPCMessage.t
+
val create_resources_updated_notification : uri:string -> unit -> JSONRPCMessage.t
+
+
(** Tool message functions *)
+
val create_tools_list_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
val create_tools_list_response : id:RequestId.t -> tools:ToolsList.Tool.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
+
val create_tools_call_request : name:string -> arguments:Json.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
val create_tools_call_response : id:RequestId.t -> content:ToolsCall.ToolContent.t list -> is_error:bool -> unit -> JSONRPCMessage.t
+
val create_tools_list_changed_notification : unit -> JSONRPCMessage.t
+
+
(** Prompt message functions *)
+
val create_prompts_list_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
val create_prompts_list_response : id:RequestId.t -> prompts:PromptsList.Prompt.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
+
val create_prompts_get_request : name:string -> arguments:(string * string) list -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
+
val create_prompts_get_response : id:RequestId.t -> ?description:string -> messages:PromptMessage.t list -> unit -> JSONRPCMessage.t
+
val create_prompts_list_changed_notification : unit -> JSONRPCMessage.t
+
+
(** Progress notification *)
+
val create_progress_notification : progress:float -> total:float -> progress_token:ProgressToken.t -> unit -> JSONRPCMessage.t