···44(* Helper for extracting string value from JSON *)
55let get_string_param json name =
66 match json with
77- | `Assoc fields ->
88- (match List.assoc_opt name fields with
99- | Some (`String value) -> value
1010- | _ -> raise (Failure (Printf.sprintf "Missing or invalid parameter: %s" name)))
77+ | `Assoc fields -> (
88+ match List.assoc_opt name fields with
99+ | Some (`String value) -> value
1010+ | _ ->
1111+ raise
1212+ (Failure (Printf.sprintf "Missing or invalid parameter: %s" name)))
1113 | _ -> raise (Failure "Expected JSON object")
12141315(* Create a server *)
1414-let server = create_server
1515- ~name:"OCaml MCP Capitalizer"
1616- ~version:"0.1.0"
1717- ~protocol_version:"2024-11-05" () |>
1818- fun server ->
1616+let server =
1717+ create_server ~name:"OCaml MCP Capitalizer" ~version:"0.1.0"
1818+ ~protocol_version:"2024-11-05" ()
1919+ |> fun server ->
1920 (* Set default capabilities *)
2020- configure_server server ~with_tools:true ~with_resources:true ~with_prompts:true ()
2121+ configure_server server ~with_tools:true ~with_resources:true
2222+ ~with_prompts:true ()
21232224(* Define and register a capitalize tool *)
2323-let _ = add_tool server
2424- ~name:"capitalize"
2525- ~description:"Capitalizes the provided text"
2626- ~schema_properties:[
2727- ("text", "string", "The text to capitalize")
2828- ]
2929- ~schema_required:["text"]
3030- (fun args ->
3131- try
3232- let text = get_string_param args "text" in
3333- let capitalized_text = String.uppercase_ascii text in
3434- TextContent.yojson_of_t TextContent.{
3535- text = capitalized_text;
3636- annotations = None
3737- }
3838- with
3939- | Failure msg ->
4040- Log.errorf "Error in capitalize tool: %s" msg;
4141- TextContent.yojson_of_t TextContent.{
4242- text = Printf.sprintf "Error: %s" msg;
4343- annotations = None
4444- }
4545- )
2525+let _ =
2626+ add_tool server ~name:"capitalize"
2727+ ~description:"Capitalizes the provided text"
2828+ ~schema_properties:[ ("text", "string", "The text to capitalize") ]
2929+ ~schema_required:[ "text" ]
3030+ (fun args ->
3131+ try
3232+ let text = get_string_param args "text" in
3333+ let capitalized_text = String.uppercase_ascii text in
3434+ TextContent.yojson_of_t
3535+ TextContent.{ text = capitalized_text; annotations = None }
3636+ with Failure msg ->
3737+ Log.errorf "Error in capitalize tool: %s" msg;
3838+ TextContent.yojson_of_t
3939+ TextContent.
4040+ { text = Printf.sprintf "Error: %s" msg; annotations = None })
46414742(* Define and register a resource template example *)
4848-let _ = add_resource_template server
4949- ~uri_template:"greeting://{name}"
5050- ~name:"Greeting"
5151- ~description:"Get a greeting for a name"
5252- ~mime_type:"text/plain"
5353- (fun params ->
5454- match params with
5555- | [name] -> Printf.sprintf "Hello, %s! Welcome to the OCaml MCP server." name
5656- | _ -> "Hello, world! Welcome to the OCaml MCP server."
5757- )
4343+let _ =
4444+ add_resource_template server ~uri_template:"greeting://{name}"
4545+ ~name:"Greeting" ~description:"Get a greeting for a name"
4646+ ~mime_type:"text/plain" (fun params ->
4747+ match params with
4848+ | [ name ] ->
4949+ Printf.sprintf "Hello, %s! Welcome to the OCaml MCP server." name
5050+ | _ -> "Hello, world! Welcome to the OCaml MCP server.")
58515952(* Define and register a prompt example *)
6060-let _ = add_prompt server
6161- ~name:"capitalize-prompt"
6262- ~description:"A prompt to help with text capitalization"
6363- ~arguments:[
6464- ("text", Some "The text to be capitalized", true)
6565- ]
6666- (fun args ->
6767- let text =
6868- try
6969- List.assoc "text" args
7070- with
7171- | Not_found -> "No text provided"
7272- in
7373- [
7474- Prompt.{
7575- role = `User;
7676- content = Mcp.make_text_content "Please help me capitalize the following text:"
7777- };
7878- Prompt.{
7979- role = `User;
8080- content = Mcp.make_text_content text
8181- };
8282- Prompt.{
8383- role = `Assistant;
8484- content = Mcp.make_text_content "Here's the capitalized version:"
8585- };
8686- Prompt.{
8787- role = `Assistant;
8888- content = Mcp.make_text_content (String.uppercase_ascii text)
8989- }
9090- ]
9191- )
5353+let _ =
5454+ add_prompt server ~name:"capitalize-prompt"
5555+ ~description:"A prompt to help with text capitalization"
5656+ ~arguments:[ ("text", Some "The text to be capitalized", true) ]
5757+ (fun args ->
5858+ let text =
5959+ try List.assoc "text" args with Not_found -> "No text provided"
6060+ in
6161+ [
6262+ Prompt.
6363+ {
6464+ role = `User;
6565+ content =
6666+ Mcp.make_text_content
6767+ "Please help me capitalize the following text:";
6868+ };
6969+ Prompt.{ role = `User; content = Mcp.make_text_content text };
7070+ Prompt.
7171+ {
7272+ role = `Assistant;
7373+ content = Mcp.make_text_content "Here's the capitalized version:";
7474+ };
7575+ Prompt.
7676+ {
7777+ role = `Assistant;
7878+ content = Mcp.make_text_content (String.uppercase_ascii text);
7979+ };
8080+ ])
92819382let () =
9483 (* Run the server with the default scheduler *)
9595- Eio_main.run @@ fun env->
9696- Mcp_server.run_server env server
8484+ Eio_main.run @@ fun env -> Mcp_server.run_server env server
···2233(* Helper module for working with markdown book chapters *)
44module BookChapter = struct
55- type t = {
66- id: string;
77- title: string;
88- contents: string;
99- }
55+ type t = { id : string; title : string; contents : string }
106117 (* Book chapters as a series of markdown files *)
1212- let chapters = [
1313- {
1414- id = "chapter1";
1515- title = "# Introduction to OCaml";
1616- contents = {|
88+ let chapters =
99+ [
1010+ {
1111+ id = "chapter1";
1212+ title = "# Introduction to OCaml";
1313+ contents =
1414+ {|
1715# Introduction to OCaml
18161917OCaml is a general-purpose, multi-paradigm programming language which extends the Caml dialect of ML with object-oriented features.
···4139- **Web Development**: Modern frameworks like Dream make web development straightforward
42404341In the following chapters, we'll explore the language features in depth and learn how to leverage OCaml's strengths for building robust, maintainable software.
4444-|}
4545- };
4646- {
4747- id = "chapter2";
4848- title = "# Basic Syntax and Types";
4949- contents = {|
4242+|};
4343+ };
4444+ {
4545+ id = "chapter2";
4646+ title = "# Basic Syntax and Types";
4747+ contents =
4848+ {|
5049# Basic Syntax and Types
51505251OCaml has a clean, consistent syntax that emphasizes readability and minimizes boilerplate.
···128127```
129128130129This introduction to basic syntax sets the foundation for understanding OCaml's more advanced features, which we'll explore in the next chapters.
131131-|}
132132- };
133133- {
134134- id = "chapter3";
135135- title = "# Data Structures";
136136- contents = {|
130130+|};
131131+ };
132132+ {
133133+ id = "chapter3";
134134+ title = "# Data Structures";
135135+ contents =
136136+ {|
137137# Data Structures
138138139139OCaml provides several built-in data structures and makes it easy to define custom ones.
···264264```
265265266266These data structures form the backbone of OCaml programming and allow for expressing complex data relationships in a type-safe way.
267267-|}
268268- };
269269- {
270270- id = "chapter4";
271271- title = "# Modules and Functors";
272272- contents = {|
267267+|};
268268+ };
269269+ {
270270+ id = "chapter4";
271271+ title = "# Modules and Functors";
272272+ contents =
273273+ {|
273274# Modules and Functors
274275275276OCaml's module system is one of its most powerful features. It allows for organizing code into reusable components with clear interfaces.
···430431```
431432432433The module system enables OCaml programmers to build highly modular, reusable code with clear boundaries between components.
433433-|}
434434- };
435435- {
436436- id = "chapter5";
437437- title = "# Advanced Features";
438438- contents = {|
434434+|};
435435+ };
436436+ {
437437+ id = "chapter5";
438438+ title = "# Advanced Features";
439439+ contents =
440440+ {|
439441# Advanced Features
440442441443OCaml offers several advanced features that set it apart from other languages. This chapter explores some of the more powerful language constructs.
···648650```
649651650652These advanced features make OCaml a uniquely powerful language for expressing complex programs with strong guarantees about correctness.
651651-|}
652652- };
653653- ]
653653+|};
654654+ };
655655+ ]
654656655657 (* Get a chapter by ID *)
656658 let get_by_id id =
657657- try Some (List.find (fun c -> c.id = id) chapters)
658658- with Not_found -> None
659659-659659+ try Some (List.find (fun c -> c.id = id) chapters) with Not_found -> None
660660+660661 (* Get chapter titles *)
661661- let get_all_titles () =
662662- List.map (fun c -> (c.id, c.title)) chapters
662662+ let get_all_titles () = List.map (fun c -> (c.id, c.title)) chapters
663663end
664664665665(* Create a server *)
666666-let server = create_server
667667- ~name:"OCaml MCP Book Resource Example"
668668- ~version:"0.1.0" () |>
669669- fun server ->
670670- (* Set default capabilities *)
671671- configure_server server
672672- ~with_tools:false
673673- ~with_resources:true
674674- ~with_resource_templates:true
675675- ~with_prompts:false ()
666666+let server =
667667+ create_server ~name:"OCaml MCP Book Resource Example" ~version:"0.1.0" ()
668668+ |> fun server ->
669669+ (* Set default capabilities *)
670670+ configure_server server ~with_tools:false ~with_resources:true
671671+ ~with_resource_templates:true ~with_prompts:false ()
676672677673(* Add a resource template to get book chapters *)
678678-let _ = add_resource_template server
679679- ~uri_template:"book/chapter/{id}"
680680- ~name:"Chapter Resource"
681681- ~description:"Get a specific chapter from the OCaml book by its ID"
682682- ~mime_type:"text/markdown"
683683- (fun params ->
684684- match params with
685685- | [id] ->
686686- (match BookChapter.get_by_id id with
687687- | Some chapter -> chapter.contents
688688- | None -> Printf.sprintf "# Error\n\nChapter with ID '%s' not found." id)
689689- | _ -> "# Error\n\nInvalid parameters. Expected chapter ID."
690690- )
674674+let _ =
675675+ add_resource_template server ~uri_template:"book/chapter/{id}"
676676+ ~name:"Chapter Resource"
677677+ ~description:"Get a specific chapter from the OCaml book by its ID"
678678+ ~mime_type:"text/markdown" (fun params ->
679679+ match params with
680680+ | [ id ] -> (
681681+ match BookChapter.get_by_id id with
682682+ | Some chapter -> chapter.contents
683683+ | None ->
684684+ Printf.sprintf "# Error\n\nChapter with ID '%s' not found." id)
685685+ | _ -> "# Error\n\nInvalid parameters. Expected chapter ID.")
691686692687(* Add a regular resource to get table of contents (no variables) *)
693693-let _ = add_resource server
694694- ~uri:"book/toc"
695695- ~name:"Table of Contents"
696696- ~description:"Get the table of contents for the OCaml book"
697697- ~mime_type:"text/markdown"
698698- (fun _params ->
699699- let titles = BookChapter.get_all_titles() in
700700- let toc = "# OCaml Book - Table of Contents\n\n" ^
701701- (List.mapi (fun i (id, title) ->
702702- Printf.sprintf "%d. [%s](book/chapter/%s)\n"
703703- (i + 1)
704704- (String.sub title 2 (String.length title - 2)) (* Remove "# " prefix *)
705705- id
706706- ) titles |> String.concat "")
707707- in
708708- toc
709709- )
688688+let _ =
689689+ add_resource server ~uri:"book/toc" ~name:"Table of Contents"
690690+ ~description:"Get the table of contents for the OCaml book"
691691+ ~mime_type:"text/markdown" (fun _params ->
692692+ let titles = BookChapter.get_all_titles () in
693693+ let toc =
694694+ "# OCaml Book - Table of Contents\n\n"
695695+ ^ (List.mapi
696696+ (fun i (id, title) ->
697697+ Printf.sprintf "%d. [%s](book/chapter/%s)\n" (i + 1)
698698+ (String.sub title 2 (String.length title - 2))
699699+ (* Remove "# " prefix *)
700700+ id)
701701+ titles
702702+ |> String.concat "")
703703+ in
704704+ toc)
710705711706(* Add a regular resource for a complete book (no variables) *)
712712-let _ = add_resource server
713713- ~uri:"book/complete"
714714- ~name:"Full contents"
715715- ~description:"Get the complete OCaml book as a single document"
716716- ~mime_type:"text/markdown"
717717- (fun _params ->
718718- let chapter_contents = List.map (fun c -> c.BookChapter.contents) BookChapter.chapters in
719719- let content = "# The OCaml Book\n\n*A comprehensive guide to OCaml programming*\n\n" ^
720720- (String.concat "\n\n---\n\n" chapter_contents)
721721- in
722722- content
723723- )
707707+let _ =
708708+ add_resource server ~uri:"book/complete" ~name:"Full contents"
709709+ ~description:"Get the complete OCaml book as a single document"
710710+ ~mime_type:"text/markdown" (fun _params ->
711711+ let chapter_contents =
712712+ List.map (fun c -> c.BookChapter.contents) BookChapter.chapters
713713+ in
714714+ let content =
715715+ "# The OCaml Book\n\n*A comprehensive guide to OCaml programming*\n\n"
716716+ ^ String.concat "\n\n---\n\n" chapter_contents
717717+ in
718718+ content)
724719725720(* Run the server with the default scheduler *)
726726-let () =
727727- Eio_main.run @@ fun env ->
728728- Mcp_server.run_server env server
721721+let () = Eio_main.run @@ fun env -> Mcp_server.run_server env server
+265-204
bin/multimodal_sdk.ml
···33(* Helper for extracting string value from JSON *)
44let get_string_param json name =
55 match json with
66- | `Assoc fields ->
77- (match List.assoc_opt name fields with
88- | Some (`String value) -> value
99- | _ -> raise (Failure (Printf.sprintf "Missing or invalid parameter: %s" name)))
66+ | `Assoc fields -> (
77+ match List.assoc_opt name fields with
88+ | Some (`String value) -> value
99+ | _ ->
1010+ raise
1111+ (Failure (Printf.sprintf "Missing or invalid parameter: %s" name)))
1012 | _ -> raise (Failure "Expected JSON object")
11131214(* Helper for extracting integer value from JSON *)
1315let get_int_param json name =
1416 match json with
1515- | `Assoc fields ->
1616- (match List.assoc_opt name fields with
1717- | Some (`Int value) -> value
1818- | Some (`String value) -> int_of_string value
1919- | _ -> raise (Failure (Printf.sprintf "Missing or invalid parameter: %s" name)))
1717+ | `Assoc fields -> (
1818+ match List.assoc_opt name fields with
1919+ | Some (`Int value) -> value
2020+ | Some (`String value) -> int_of_string value
2121+ | _ ->
2222+ raise
2323+ (Failure (Printf.sprintf "Missing or invalid parameter: %s" name)))
2024 | _ -> raise (Failure "Expected JSON object")
21252226(* Base64 encoding - simplified version *)
2327module Base64 = struct
2428 let encode_char idx =
2529 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".[idx]
2626-3030+2731 let encode s =
2832 let len = String.length s in
2929- let result = Bytes.create (((len + 2) / 3) * 4) in
3030-3333+ let result = Bytes.create ((len + 2) / 3 * 4) in
3434+3135 let rec loop i j =
3236 if i >= len then j
3337 else
3438 let n =
3539 let n = Char.code s.[i] lsl 16 in
3636- let n = if i + 1 < len then n lor (Char.code s.[i+1] lsl 8) else n in
3737- if i + 2 < len then n lor Char.code s.[i+2] else n
4040+ let n =
4141+ if i + 1 < len then n lor (Char.code s.[i + 1] lsl 8) else n
4242+ in
4343+ if i + 2 < len then n lor Char.code s.[i + 2] else n
3844 in
3945 Bytes.set result j (encode_char ((n lsr 18) land 63));
4040- Bytes.set result (j+1) (encode_char ((n lsr 12) land 63));
4141- Bytes.set result (j+2)
4646+ Bytes.set result (j + 1) (encode_char ((n lsr 12) land 63));
4747+ Bytes.set result (j + 2)
4248 (if i + 1 < len then encode_char ((n lsr 6) land 63) else '=');
4343- Bytes.set result (j+3)
4949+ Bytes.set result (j + 3)
4450 (if i + 2 < len then encode_char (n land 63) else '=');
4551 loop (i + 3) (j + 4)
4652 in
···5056(* Generate a simple GIF format image *)
5157let generate_random_image width height =
5258 (* Ensure dimensions are reasonable *)
5353- let width = min 256 (max 16 width) in
5959+ let width = min 256 (max 16 width) in
5460 let height = min 256 (max 16 height) in
5555-6161+5662 (* Create a buffer for GIF data *)
5763 let buf = Buffer.create 1024 in
5858-6464+5965 (* GIF Header - "GIF89a" *)
6066 Buffer.add_string buf "GIF89a";
6161-6767+6268 (* Logical Screen Descriptor *)
6369 (* Width - 2 bytes little endian *)
6470 Buffer.add_char buf (Char.chr (width land 0xff));
6571 Buffer.add_char buf (Char.chr ((width lsr 8) land 0xff));
6666-7272+6773 (* Height - 2 bytes little endian *)
6874 Buffer.add_char buf (Char.chr (height land 0xff));
6975 Buffer.add_char buf (Char.chr ((height lsr 8) land 0xff));
7070-7676+7177 (* Packed fields - 1 byte:
7278 Global Color Table Flag - 1 bit (1)
7379 Color Resolution - 3 bits (7 = 8 bits per color)
7480 Sort Flag - 1 bit (0)
7581 Size of Global Color Table - 3 bits (2 = 8 colors) *)
7682 Buffer.add_char buf (Char.chr 0xF2);
7777-8383+7884 (* Background color index - 1 byte *)
7985 Buffer.add_char buf (Char.chr 0);
8080-8686+8187 (* Pixel aspect ratio - 1 byte *)
8288 Buffer.add_char buf (Char.chr 0);
8383-8989+8490 (* Global Color Table - 8 colors x 3 bytes (R,G,B) *)
8591 (* Simple 8-color palette *)
8686- Buffer.add_string buf "\xFF\xFF\xFF"; (* White (0) *)
8787- Buffer.add_string buf "\xFF\x00\x00"; (* Red (1) *)
8888- Buffer.add_string buf "\x00\xFF\x00"; (* Green (2) *)
8989- Buffer.add_string buf "\x00\x00\xFF"; (* Blue (3) *)
9090- Buffer.add_string buf "\xFF\xFF\x00"; (* Yellow (4) *)
9191- Buffer.add_string buf "\xFF\x00\xFF"; (* Magenta (5) *)
9292- Buffer.add_string buf "\x00\xFF\xFF"; (* Cyan (6) *)
9393- Buffer.add_string buf "\x00\x00\x00"; (* Black (7) *)
9494-9292+ Buffer.add_string buf "\xFF\xFF\xFF";
9393+ (* White (0) *)
9494+ Buffer.add_string buf "\xFF\x00\x00";
9595+ (* Red (1) *)
9696+ Buffer.add_string buf "\x00\xFF\x00";
9797+ (* Green (2) *)
9898+ Buffer.add_string buf "\x00\x00\xFF";
9999+ (* Blue (3) *)
100100+ Buffer.add_string buf "\xFF\xFF\x00";
101101+ (* Yellow (4) *)
102102+ Buffer.add_string buf "\xFF\x00\xFF";
103103+ (* Magenta (5) *)
104104+ Buffer.add_string buf "\x00\xFF\xFF";
105105+ (* Cyan (6) *)
106106+ Buffer.add_string buf "\x00\x00\x00";
107107+108108+ (* Black (7) *)
109109+95110 (* Graphics Control Extension (optional) *)
9696- Buffer.add_char buf (Char.chr 0x21); (* Extension Introducer *)
9797- Buffer.add_char buf (Char.chr 0xF9); (* Graphic Control Label *)
9898- Buffer.add_char buf (Char.chr 0x04); (* Block Size *)
9999- Buffer.add_char buf (Char.chr 0x01); (* Packed field: 1 bit for transparency *)
100100- Buffer.add_char buf (Char.chr 0x00); (* Delay time (1/100s) - 2 bytes *)
111111+ Buffer.add_char buf (Char.chr 0x21);
112112+ (* Extension Introducer *)
113113+ Buffer.add_char buf (Char.chr 0xF9);
114114+ (* Graphic Control Label *)
115115+ Buffer.add_char buf (Char.chr 0x04);
116116+ (* Block Size *)
117117+ Buffer.add_char buf (Char.chr 0x01);
118118+ (* Packed field: 1 bit for transparency *)
119119+ Buffer.add_char buf (Char.chr 0x00);
120120+ (* Delay time (1/100s) - 2 bytes *)
121121+ Buffer.add_char buf (Char.chr 0x00);
122122+ Buffer.add_char buf (Char.chr 0x00);
123123+ (* Transparent color index *)
101124 Buffer.add_char buf (Char.chr 0x00);
102102- Buffer.add_char buf (Char.chr 0x00); (* Transparent color index *)
103103- Buffer.add_char buf (Char.chr 0x00); (* Block terminator *)
104104-125125+126126+ (* Block terminator *)
127127+105128 (* Image Descriptor *)
106106- Buffer.add_char buf (Char.chr 0x2C); (* Image Separator *)
107107- Buffer.add_char buf (Char.chr 0x00); (* Left position - 2 bytes *)
129129+ Buffer.add_char buf (Char.chr 0x2C);
130130+ (* Image Separator *)
131131+ Buffer.add_char buf (Char.chr 0x00);
132132+ (* Left position - 2 bytes *)
108133 Buffer.add_char buf (Char.chr 0x00);
109109- Buffer.add_char buf (Char.chr 0x00); (* Top position - 2 bytes *)
134134+ Buffer.add_char buf (Char.chr 0x00);
135135+ (* Top position - 2 bytes *)
110136 Buffer.add_char buf (Char.chr 0x00);
111111-137137+112138 (* Image width - 2 bytes little endian *)
113139 Buffer.add_char buf (Char.chr (width land 0xff));
114140 Buffer.add_char buf (Char.chr ((width lsr 8) land 0xff));
115115-141141+116142 (* Image height - 2 bytes little endian *)
117143 Buffer.add_char buf (Char.chr (height land 0xff));
118144 Buffer.add_char buf (Char.chr ((height lsr 8) land 0xff));
119119-145145+120146 (* Packed fields - 1 byte - no local color table *)
121147 Buffer.add_char buf (Char.chr 0x00);
122122-148148+123149 (* LZW Minimum Code Size - 1 byte *)
124124- Buffer.add_char buf (Char.chr 0x03); (* Minimum code size 3 for 8 colors *)
125125-150150+ Buffer.add_char buf (Char.chr 0x03);
151151+152152+ (* Minimum code size 3 for 8 colors *)
153153+126154 (* Generate a simple image - a checkerboard pattern *)
127155 let step = width / 8 in
128156 let image_data = Buffer.create (width * height / 4) in
129129-157157+130158 (* Very simple LZW compression - just store raw clear codes and color indexes *)
131159 (* Start with Clear code *)
132132- Buffer.add_char image_data (Char.chr 0x08); (* Clear code 8 *)
133133-160160+ Buffer.add_char image_data (Char.chr 0x08);
161161+162162+ (* Clear code 8 *)
163163+134164 (* For very simple encoding, we'll just use a sequence of color indexes *)
135165 for y = 0 to height - 1 do
136166 for x = 0 to width - 1 do
137167 (* Checkerboard pattern with different colors *)
138168 let color =
139139- if ((x / step) + (y / step)) mod 2 = 0 then
140140- 3 (* Blue *)
141141- else
142142- 1 (* Red *)
169169+ if ((x / step) + (y / step)) mod 2 = 0 then 3 (* Blue *)
170170+ else 1 (* Red *)
143171 in
144144- Buffer.add_char image_data (Char.chr color);
172172+ Buffer.add_char image_data (Char.chr color)
145173 done
146174 done;
147147-175175+148176 (* End with End of Information code *)
149177 Buffer.add_char image_data (Char.chr 0x09);
150150-178178+151179 (* Add image data blocks - GIF uses 255-byte max chunks *)
152180 let data = Buffer.contents image_data in
153181 let data_len = String.length data in
154182 let pos = ref 0 in
155155-183183+156184 while !pos < data_len do
157185 let chunk_size = min 255 (data_len - !pos) in
158186 Buffer.add_char buf (Char.chr chunk_size);
159187 for i = 0 to chunk_size - 1 do
160160- Buffer.add_char buf (String.get data (!pos + i));
188188+ Buffer.add_char buf (String.get data (!pos + i))
161189 done;
162162- pos := !pos + chunk_size;
190190+ pos := !pos + chunk_size
163191 done;
164164-192192+165193 (* Zero-length block to end the image data *)
166194 Buffer.add_char buf (Char.chr 0x00);
167167-195195+168196 (* GIF Trailer *)
169197 Buffer.add_char buf (Char.chr 0x3B);
170170-198198+171199 (* Base64 encode the GIF data *)
172200 Base64.encode (Buffer.contents buf)
173201···189217 let sample_rate = 8000 in
190218 let num_samples = sample_rate * duration in
191219 let header_buf = Buffer.create 44 in
192192-220220+193221 (* Fill WAV header properly *)
194222 Buffer.add_string header_buf "RIFF";
195195- write_int32_le header_buf (36 + num_samples * 2); (* File size minus 8 *)
223223+ write_int32_le header_buf (36 + (num_samples * 2));
224224+ (* File size minus 8 *)
196225 Buffer.add_string header_buf "WAVE";
197197-226226+198227 (* Format chunk *)
199228 Buffer.add_string header_buf "fmt ";
200200- write_int32_le header_buf 16; (* Format chunk size *)
201201- write_int16_le header_buf 1; (* PCM format *)
202202- write_int16_le header_buf 1; (* Mono *)
203203- write_int32_le header_buf sample_rate; (* Sample rate *)
204204- write_int32_le header_buf (sample_rate * 2); (* Byte rate *)
205205- write_int16_le header_buf 2; (* Block align *)
206206- write_int16_le header_buf 16; (* Bits per sample *)
207207-229229+ write_int32_le header_buf 16;
230230+ (* Format chunk size *)
231231+ write_int16_le header_buf 1;
232232+ (* PCM format *)
233233+ write_int16_le header_buf 1;
234234+ (* Mono *)
235235+ write_int32_le header_buf sample_rate;
236236+ (* Sample rate *)
237237+ write_int32_le header_buf (sample_rate * 2);
238238+ (* Byte rate *)
239239+ write_int16_le header_buf 2;
240240+ (* Block align *)
241241+ write_int16_le header_buf 16;
242242+243243+ (* Bits per sample *)
244244+208245 (* Data chunk *)
209246 Buffer.add_string header_buf "data";
210210- write_int32_le header_buf (num_samples * 2); (* Data size *)
211211-247247+ write_int32_le header_buf (num_samples * 2);
248248+249249+ (* Data size *)
250250+212251 (* Generate sine wave samples *)
213252 let samples_buf = Buffer.create (num_samples * 2) in
214214- let amplitude = 16384.0 in (* 16-bit with headroom *)
215215-253253+ let amplitude = 16384.0 in
254254+ (* 16-bit with headroom *)
255255+216256 for i = 0 to num_samples - 1 do
217257 let t = float_of_int i /. float_of_int sample_rate in
218258 let value = amplitude *. sin (2.0 *. Float.pi *. frequency *. t) in
219259 let sample = int_of_float value in
220220-260260+221261 (* Convert to 16-bit little-endian *)
222262 let sample = if sample < 0 then sample + 65536 else sample in
223223- write_int16_le samples_buf sample;
263263+ write_int16_le samples_buf sample
224264 done;
225225-265265+226266 (* Combine header and samples, then encode as Base64 *)
227267 let wav_data = Buffer.contents header_buf ^ Buffer.contents samples_buf in
228268 Base64.encode wav_data
229269230270(* Create a server *)
231231-let server = create_server
232232- ~name:"OCaml MCP Multimodal Example"
233233- ~version:"0.1.0"
234234- ~protocol_version:"2024-11-05" () |>
235235- fun server ->
236236- (* Set default capabilities *)
237237- configure_server server ~with_tools:true ~with_resources:true ~with_prompts:true ()
271271+let server =
272272+ create_server ~name:"OCaml MCP Multimodal Example" ~version:"0.1.0"
273273+ ~protocol_version:"2024-11-05" ()
274274+ |> fun server ->
275275+ (* Set default capabilities *)
276276+ configure_server server ~with_tools:true ~with_resources:true
277277+ ~with_prompts:true ()
238278239279(* Define and register a multimodal tool that returns text, images, and audio *)
240240-let _ = add_tool server
241241- ~name:"multimodal_demo"
242242- ~description:"Demonstrates multimodal content with text, image, and audio"
243243- ~schema_properties:[
244244- ("width", "integer", "Width of the generated image (pixels)");
245245- ("height", "integer", "Height of the generated image (pixels)");
246246- ("frequency", "integer", "Frequency of the generated audio tone (Hz)");
247247- ("duration", "integer", "Duration of the generated audio (seconds)");
248248- ("message", "string", "Text message to include")
249249- ]
250250- ~schema_required:["message"]
251251- (fun args ->
252252- try
253253- (* Extract parameters with defaults if not provided *)
254254- let message = get_string_param args "message" in
255255- let width = try get_int_param args "width" with _ -> 128 in
256256- let height = try get_int_param args "height" with _ -> 128 in
257257- let frequency = try get_int_param args "frequency" with _ -> 440 in
258258- let duration = try get_int_param args "duration" with _ -> 1 in
259259-260260- (* Generate image and audio data *)
261261- let image_data = generate_random_image width height in
262262- let audio_data = generate_sine_wave_audio (float_of_int frequency) duration in
263263-264264- (* Create a multimodal tool result *)
265265- Tool.create_tool_result [
266266- Mcp.make_text_content message;
267267- Mcp.make_image_content image_data "image/gif";
268268- Mcp.make_audio_content audio_data "audio/wav"
269269- ] ~is_error:false
270270- with
271271- | Failure msg ->
272272- Log.errorf "Error in multimodal tool: %s" msg;
273273- Tool.create_tool_result [Mcp.make_text_content (Printf.sprintf "Error: %s" msg)] ~is_error:true
274274- )
280280+let _ =
281281+ add_tool server ~name:"multimodal_demo"
282282+ ~description:"Demonstrates multimodal content with text, image, and audio"
283283+ ~schema_properties:
284284+ [
285285+ ("width", "integer", "Width of the generated image (pixels)");
286286+ ("height", "integer", "Height of the generated image (pixels)");
287287+ ("frequency", "integer", "Frequency of the generated audio tone (Hz)");
288288+ ("duration", "integer", "Duration of the generated audio (seconds)");
289289+ ("message", "string", "Text message to include");
290290+ ]
291291+ ~schema_required:[ "message" ]
292292+ (fun args ->
293293+ try
294294+ (* Extract parameters with defaults if not provided *)
295295+ let message = get_string_param args "message" in
296296+ let width = try get_int_param args "width" with _ -> 128 in
297297+ let height = try get_int_param args "height" with _ -> 128 in
298298+ let frequency = try get_int_param args "frequency" with _ -> 440 in
299299+ let duration = try get_int_param args "duration" with _ -> 1 in
275300276276-(* Define and register a tool for generating only images *)
277277-let _ = add_tool server
278278- ~name:"generate_image"
279279- ~description:"Generates a random image with specified dimensions"
280280- ~schema_properties:[
281281- ("width", "integer", "Width of the generated image (pixels)");
282282- ("height", "integer", "Height of the generated image (pixels)")
283283- ]
284284- ~schema_required:["width"; "height"]
285285- (fun args ->
286286- try
287287- let width = get_int_param args "width" in
288288- let height = get_int_param args "height" in
289289-290290- if width < 1 || width > 1024 || height < 1 || height > 1024 then
291291- Tool.create_tool_result
292292- [Mcp.make_text_content "Error: Dimensions must be between 1 and 1024 pixels"]
293293- ~is_error:true
294294- else
301301+ (* Generate image and audio data *)
295302 let image_data = generate_random_image width height in
296296- Tool.create_tool_result
297297- [Mcp.make_image_content image_data "image/gif"]
303303+ let audio_data =
304304+ generate_sine_wave_audio (float_of_int frequency) duration
305305+ in
306306+307307+ (* Create a multimodal tool result *)
308308+ Tool.create_tool_result
309309+ [
310310+ Mcp.make_text_content message;
311311+ Mcp.make_image_content image_data "image/gif";
312312+ Mcp.make_audio_content audio_data "audio/wav";
313313+ ]
298314 ~is_error:false
299299- with
300300- | Failure msg ->
301301- Log.errorf "Error in generate_image tool: %s" msg;
302302- Tool.create_tool_result [Mcp.make_text_content (Printf.sprintf "Error: %s" msg)] ~is_error:true
303303- )
315315+ with Failure msg ->
316316+ Log.errorf "Error in multimodal tool: %s" msg;
317317+ Tool.create_tool_result
318318+ [ Mcp.make_text_content (Printf.sprintf "Error: %s" msg) ]
319319+ ~is_error:true)
320320+321321+(* Define and register a tool for generating only images *)
322322+let _ =
323323+ add_tool server ~name:"generate_image"
324324+ ~description:"Generates a random image with specified dimensions"
325325+ ~schema_properties:
326326+ [
327327+ ("width", "integer", "Width of the generated image (pixels)");
328328+ ("height", "integer", "Height of the generated image (pixels)");
329329+ ]
330330+ ~schema_required:[ "width"; "height" ]
331331+ (fun args ->
332332+ try
333333+ let width = get_int_param args "width" in
334334+ let height = get_int_param args "height" in
335335+336336+ if width < 1 || width > 1024 || height < 1 || height > 1024 then
337337+ Tool.create_tool_result
338338+ [
339339+ Mcp.make_text_content
340340+ "Error: Dimensions must be between 1 and 1024 pixels";
341341+ ]
342342+ ~is_error:true
343343+ else
344344+ let image_data = generate_random_image width height in
345345+ Tool.create_tool_result
346346+ [ Mcp.make_image_content image_data "image/gif" ]
347347+ ~is_error:false
348348+ with Failure msg ->
349349+ Log.errorf "Error in generate_image tool: %s" msg;
350350+ Tool.create_tool_result
351351+ [ Mcp.make_text_content (Printf.sprintf "Error: %s" msg) ]
352352+ ~is_error:true)
304353305354(* Define and register a tool for generating only audio *)
306306-let _ = add_tool server
307307- ~name:"generate_audio"
308308- ~description:"Generates an audio tone with specified frequency and duration"
309309- ~schema_properties:[
310310- ("frequency", "integer", "Frequency of the tone in Hz (20-20000)");
311311- ("duration", "integer", "Duration of the tone in seconds (1-10)")
312312- ]
313313- ~schema_required:["frequency"; "duration"]
314314- (fun args ->
315315- try
316316- let frequency = get_int_param args "frequency" in
317317- let duration = get_int_param args "duration" in
318318-319319- if frequency < 20 || frequency > 20000 then
320320- Tool.create_tool_result
321321- [Mcp.make_text_content "Error: Frequency must be between 20Hz and 20,000Hz"]
322322- ~is_error:true
323323- else if duration < 1 || duration > 10 then
324324- Tool.create_tool_result
325325- [Mcp.make_text_content "Error: Duration must be between 1 and 10 seconds"]
326326- ~is_error:true
327327- else
328328- let audio_data = generate_sine_wave_audio (float_of_int frequency) duration in
329329- Tool.create_tool_result
330330- [Mcp.make_audio_content audio_data "audio/wav"]
331331- ~is_error:false
332332- with
333333- | Failure msg ->
334334- Log.errorf "Error in generate_audio tool: %s" msg;
335335- Tool.create_tool_result [Mcp.make_text_content (Printf.sprintf "Error: %s" msg)] ~is_error:true
336336- )
355355+let _ =
356356+ add_tool server ~name:"generate_audio"
357357+ ~description:"Generates an audio tone with specified frequency and duration"
358358+ ~schema_properties:
359359+ [
360360+ ("frequency", "integer", "Frequency of the tone in Hz (20-20000)");
361361+ ("duration", "integer", "Duration of the tone in seconds (1-10)");
362362+ ]
363363+ ~schema_required:[ "frequency"; "duration" ]
364364+ (fun args ->
365365+ try
366366+ let frequency = get_int_param args "frequency" in
367367+ let duration = get_int_param args "duration" in
368368+369369+ if frequency < 20 || frequency > 20000 then
370370+ Tool.create_tool_result
371371+ [
372372+ Mcp.make_text_content
373373+ "Error: Frequency must be between 20Hz and 20,000Hz";
374374+ ]
375375+ ~is_error:true
376376+ else if duration < 1 || duration > 10 then
377377+ Tool.create_tool_result
378378+ [
379379+ Mcp.make_text_content
380380+ "Error: Duration must be between 1 and 10 seconds";
381381+ ]
382382+ ~is_error:true
383383+ else
384384+ let audio_data =
385385+ generate_sine_wave_audio (float_of_int frequency) duration
386386+ in
387387+ Tool.create_tool_result
388388+ [ Mcp.make_audio_content audio_data "audio/wav" ]
389389+ ~is_error:false
390390+ with Failure msg ->
391391+ Log.errorf "Error in generate_audio tool: %s" msg;
392392+ Tool.create_tool_result
393393+ [ Mcp.make_text_content (Printf.sprintf "Error: %s" msg) ]
394394+ ~is_error:true)
337395338396(* Define and register a resource template example with multimodal content *)
339339-let _ = add_resource_template server
340340- ~uri_template:"multimodal://{name}"
341341- ~name:"Multimodal Greeting"
342342- ~description:"Get a multimodal greeting with text, image and audio"
343343- ~mime_type:"application/json"
344344- (fun params ->
345345- match params with
346346- | [name] ->
347347- let greeting = Printf.sprintf "Hello, %s! Welcome to the multimodal MCP example." name in
348348- let image_data = generate_random_image 128 128 in
349349- let audio_data = generate_sine_wave_audio 440.0 1 in
350350-351351- Printf.sprintf {|
397397+let _ =
398398+ add_resource_template server ~uri_template:"multimodal://{name}"
399399+ ~name:"Multimodal Greeting"
400400+ ~description:"Get a multimodal greeting with text, image and audio"
401401+ ~mime_type:"application/json" (fun params ->
402402+ match params with
403403+ | [ name ] ->
404404+ let greeting =
405405+ Printf.sprintf "Hello, %s! Welcome to the multimodal MCP example."
406406+ name
407407+ in
408408+ let image_data = generate_random_image 128 128 in
409409+ let audio_data = generate_sine_wave_audio 440.0 1 in
410410+411411+ Printf.sprintf
412412+ {|
352413 {
353414 "greeting": "%s",
354415 "image": {
···360421 "mimeType": "audio/wav"
361422 }
362423 }
363363- |} greeting image_data audio_data
364364- | _ -> Printf.sprintf {|{"error": "Invalid parameters"}|}
365365- )
424424+ |}
425425+ greeting image_data audio_data
426426+ | _ -> Printf.sprintf {|{"error": "Invalid parameters"}|})
366427367428(* Run the server with the default scheduler *)
368429let () =
369369- Random.self_init(); (* Initialize random generator *)
370370- Eio_main.run @@ fun env ->
371371- Mcp_server.run_server env server
430430+ Random.self_init ();
431431+ (* Initialize random generator *)
432432+ Eio_main.run @@ fun env -> Mcp_server.run_server env server
+104-111
bin/ocaml_eval_sdk.ml
···1212(* Helper for extracting string value from JSON *)
1313let get_string_param json name =
1414 match json with
1515- | `Assoc fields ->
1616- (match List.assoc_opt name fields with
1717- | Some (`String value) -> value
1818- | _ -> failwith (Printf.sprintf "Missing or invalid parameter: %s" name))
1515+ | `Assoc fields -> (
1616+ match List.assoc_opt name fields with
1717+ | Some (`String value) -> value
1818+ | _ -> failwith (Printf.sprintf "Missing or invalid parameter: %s" name))
1919 | _ -> failwith "Expected JSON object"
2020-2020+2121(* Initialize the OCaml toploop with standard libraries *)
2222let initialize_toploop () =
2323 (* Initialize the toplevel environment *)
2424 Toploop.initialize_toplevel_env ();
2525-2525+2626 (* Set up the toplevel as if using the standard OCaml REPL *)
2727 Clflags.nopervasives := false;
2828 Clflags.real_paths := true;
2929 Clflags.recursive_types := false;
3030 Clflags.strict_sequence := false;
3131 Clflags.applicative_functors := true;
3232-3232+3333 (* Return success message *)
3434 "OCaml evaluation environment initialized"
3535···3737let evaluate_phrase phrase =
3838 (* Parse the input text as a toplevel phrase *)
3939 let lexbuf = Lexing.from_string phrase in
4040-4040+4141 (* Capture both success/failure status and output *)
4242 try
4343 let parsed_phrase = !Toploop.parse_toplevel_phrase lexbuf in
4444- let (success, output) = capture_output (fun fmt ->
4545- Toploop.execute_phrase true fmt parsed_phrase
4646- ) in
4747-4444+ let success, output =
4545+ capture_output (fun fmt -> Toploop.execute_phrase true fmt parsed_phrase)
4646+ in
4747+4848 (* Return structured result with status and captured output *)
4949 if success then
5050- `Assoc [
5151- ("success", `Bool true);
5252- ("output", `String output);
5353- ]
5050+ `Assoc [ ("success", `Bool true); ("output", `String output) ]
5451 else
5555- `Assoc [
5656- ("success", `Bool false);
5757- ("error", `String "Execution failed");
5858- ("output", `String output);
5959- ]
5252+ `Assoc
5353+ [
5454+ ("success", `Bool false);
5555+ ("error", `String "Execution failed");
5656+ ("output", `String output);
5757+ ]
6058 with e ->
6159 (* Handle parsing or other errors with more detailed messages *)
6262- let error_msg = match e with
6363- | Syntaxerr.Error err ->
6464- let msg = match err with
6565- | Syntaxerr.Unclosed _ -> "Syntax error: Unclosed delimiter"
6666- | Syntaxerr.Expecting _ -> "Syntax error: Expecting a different token"
6767- | Syntaxerr.Not_expecting _ -> "Syntax error: Unexpected token"
6868- | Syntaxerr.Applicative_path _ -> "Syntax error: Invalid applicative path"
6969- | Syntaxerr.Variable_in_scope _ -> "Syntax error: Variable in scope"
7070- | Syntaxerr.Other _ -> "Syntax error"
7171- | _ -> "Syntax error (unknown kind)"
7272- in
7373- msg
7474-7575- | Lexer.Error (err, _) ->
7676- let msg = match err with
7777- | Lexer.Illegal_character _ -> "Lexer error: Illegal character"
7878- | Lexer.Illegal_escape _ -> "Lexer error: Illegal escape sequence"
7979- | Lexer.Unterminated_comment _ -> "Lexer error: Unterminated comment"
8080- | Lexer.Unterminated_string -> "Lexer error: Unterminated string"
8181- | Lexer.Unterminated_string_in_comment _ -> "Lexer error: Unterminated string in comment"
8282- | Lexer.Invalid_literal _ -> "Lexer error: Invalid literal"
8383- | _ -> "Lexer error (unknown kind)"
8484- in
8585- msg
8686- | _ -> Printexc.to_string e
6060+ let error_msg =
6161+ match e with
6262+ | Syntaxerr.Error err ->
6363+ let msg =
6464+ match err with
6565+ | Syntaxerr.Unclosed _ -> "Syntax error: Unclosed delimiter"
6666+ | Syntaxerr.Expecting _ ->
6767+ "Syntax error: Expecting a different token"
6868+ | Syntaxerr.Not_expecting _ -> "Syntax error: Unexpected token"
6969+ | Syntaxerr.Applicative_path _ ->
7070+ "Syntax error: Invalid applicative path"
7171+ | Syntaxerr.Variable_in_scope _ -> "Syntax error: Variable in scope"
7272+ | Syntaxerr.Other _ -> "Syntax error"
7373+ | _ -> "Syntax error (unknown kind)"
7474+ in
7575+ msg
7676+ | Lexer.Error (err, _) ->
7777+ let msg =
7878+ match err with
7979+ | Lexer.Illegal_character _ -> "Lexer error: Illegal character"
8080+ | Lexer.Illegal_escape _ -> "Lexer error: Illegal escape sequence"
8181+ | Lexer.Unterminated_comment _ ->
8282+ "Lexer error: Unterminated comment"
8383+ | Lexer.Unterminated_string -> "Lexer error: Unterminated string"
8484+ | Lexer.Unterminated_string_in_comment _ ->
8585+ "Lexer error: Unterminated string in comment"
8686+ | Lexer.Invalid_literal _ -> "Lexer error: Invalid literal"
8787+ | _ -> "Lexer error (unknown kind)"
8888+ in
8989+ msg
9090+ | _ -> Printexc.to_string e
8791 in
8888- `Assoc [
8989- ("success", `Bool false);
9090- ("error", `String error_msg);
9191- ]
9292+ `Assoc [ ("success", `Bool false); ("error", `String error_msg) ]
92939394(* Create evaluation server *)
9494-let server = create_server
9595- ~name:"OCaml Evaluation Server"
9696- ~version:"0.1.0" () |>
9797- fun server ->
9898- (* Set default capabilities *)
9999- configure_server server ~with_tools:true ()
9595+let server =
9696+ create_server ~name:"OCaml Evaluation Server" ~version:"0.1.0" ()
9797+ |> fun server ->
9898+ (* Set default capabilities *)
9999+ configure_server server ~with_tools:true ()
100100101101(* Toplevel environment state management *)
102102let toplevel_initialized = ref false
103103104104(* Initialize OCaml toplevel on first use *)
105105let ensure_toploop_initialized () =
106106- if not !toplevel_initialized then begin
106106+ if not !toplevel_initialized then
107107 let _ = initialize_toploop () in
108108- toplevel_initialized := true;
109109- end
108108+ toplevel_initialized := true
110109111110(* Register eval tool *)
112112-let _ = add_tool server
113113- ~name:"ocaml_eval"
114114- ~description:"Evaluates OCaml toplevel phrases and returns the result"
115115- ~schema_properties:[
116116- ("code", "string", "OCaml code to evaluate")
117117- ]
118118- ~schema_required:["code"]
119119- (fun args ->
120120- ensure_toploop_initialized ();
121121-122122- try
123123- (* Extract code parameter *)
124124- let code = get_string_param args "code" in
125125-126126- (* Execute the code *)
127127- let result = evaluate_phrase code in
128128-129129- (* Return formatted result *)
130130- let success = match result with
131131- | `Assoc fields -> (
132132- match List.assoc_opt "success" fields with
133133- | Some (`Bool true) -> true
111111+let _ =
112112+ add_tool server ~name:"ocaml_eval"
113113+ ~description:"Evaluates OCaml toplevel phrases and returns the result"
114114+ ~schema_properties:[ ("code", "string", "OCaml code to evaluate") ]
115115+ ~schema_required:[ "code" ]
116116+ (fun args ->
117117+ ensure_toploop_initialized ();
118118+119119+ try
120120+ (* Extract code parameter *)
121121+ let code = get_string_param args "code" in
122122+123123+ (* Execute the code *)
124124+ let result = evaluate_phrase code in
125125+126126+ (* Return formatted result *)
127127+ let success =
128128+ match result with
129129+ | `Assoc fields -> (
130130+ match List.assoc_opt "success" fields with
131131+ | Some (`Bool true) -> true
132132+ | _ -> false)
134133 | _ -> false
135135- )
136136- | _ -> false
137137- in
138138-139139- let output = match result with
140140- | `Assoc fields -> (
141141- match List.assoc_opt "output" fields with
142142- | Some (`String s) -> s
143143- | _ -> (
144144- match List.assoc_opt "error" fields with
145145- | Some (`String s) -> s
146146- | _ -> "Unknown result"
147147- )
148148- )
149149- | _ -> "Unknown result"
150150- in
151151-152152- (* Create a tool result with colorized output *)
153153- Tool.create_tool_result [
154154- Mcp.make_text_content output
155155- ] ~is_error:(not success)
156156-157157- with
158158- | Failure msg ->
159159- Log.errorf "Error in OCaml eval tool: %s" msg;
160160- Tool.create_tool_result [Mcp.make_text_content (Printf.sprintf "Error: %s" msg)] ~is_error:true
161161- )
134134+ in
135135+136136+ let output =
137137+ match result with
138138+ | `Assoc fields -> (
139139+ match List.assoc_opt "output" fields with
140140+ | Some (`String s) -> s
141141+ | _ -> (
142142+ match List.assoc_opt "error" fields with
143143+ | Some (`String s) -> s
144144+ | _ -> "Unknown result"))
145145+ | _ -> "Unknown result"
146146+ in
147147+148148+ (* Create a tool result with colorized output *)
149149+ Tool.create_tool_result
150150+ [ Mcp.make_text_content output ]
151151+ ~is_error:(not success)
152152+ with Failure msg ->
153153+ Log.errorf "Error in OCaml eval tool: %s" msg;
154154+ Tool.create_tool_result
155155+ [ Mcp.make_text_content (Printf.sprintf "Error: %s" msg) ]
156156+ ~is_error:true)
162157163158(* Run the server with the default scheduler *)
164164-let () =
165165- Eio_main.run @@ fun env->
166166- Mcp_server.run_server env server
159159+let () = Eio_main.run @@ fun env -> Mcp_server.run_server env server
···33(* Utility functions for JSON parsing *)
44module Util = struct
55 (* Helper to raise a Json.Of_json exception with formatted message *)
66- let json_error fmt json =
66+ let json_error fmt json =
77 Printf.ksprintf (fun msg -> raise (Json.Of_json (msg, json))) fmt
88-88+99 (* Extract a string field from JSON object or raise an error *)
1010 let get_string_field fields name json =
1111 match List.assoc_opt name fields with
1212 | Some (`String s) -> s
1313 | _ -> json_error "Missing or invalid '%s' field" json name
1414-1414+1515 (* Extract an optional string field from JSON object *)
1616 let get_optional_string_field fields name =
1717- List.assoc_opt name fields |> Option.map (function
1818- | `String s -> s
1919- | j -> json_error "Expected string for %s" j name
2020- )
2121-1717+ List.assoc_opt name fields
1818+ |> Option.map (function
1919+ | `String s -> s
2020+ | j -> json_error "Expected string for %s" j name)
2121+2222 (* Extract an int field from JSON object or raise an error *)
2323 let get_int_field fields name json =
2424 match List.assoc_opt name fields with
2525 | Some (`Int i) -> i
2626 | _ -> json_error "Missing or invalid '%s' field" json name
2727-2727+2828 (* Extract a float field from JSON object or raise an error *)
2929 let get_float_field fields name json =
3030 match List.assoc_opt name fields with
3131 | Some (`Float f) -> f
3232 | _ -> json_error "Missing or invalid '%s' field" json name
3333-3333+3434 (* Extract a boolean field from JSON object or raise an error *)
3535 let get_bool_field fields name json =
3636 match List.assoc_opt name fields with
3737 | Some (`Bool b) -> b
3838 | _ -> json_error "Missing or invalid '%s' field" json name
3939-3939+4040 (* Extract an object field from JSON object or raise an error *)
4141 let get_object_field fields name json =
4242 match List.assoc_opt name fields with
4343 | Some (`Assoc obj) -> obj
4444 | _ -> json_error "Missing or invalid '%s' field" json name
4545-4545+4646 (* Extract a list field from JSON object or raise an error *)
4747 let get_list_field fields name json =
4848 match List.assoc_opt name fields with
4949 | Some (`List items) -> items
5050 | _ -> json_error "Missing or invalid '%s' field" json name
5151-5151+5252 (* Verify a specific string value in a field *)
5353 let verify_string_field fields name expected_value json =
5454 match List.assoc_opt name fields with
5555 | Some (`String s) when s = expected_value -> ()
5656- | _ -> json_error "Field '%s' missing or not equal to '%s'" json name expected_value
5656+ | _ ->
5757+ json_error "Field '%s' missing or not equal to '%s'" json name
5858+ expected_value
5759end
58605961(* Error codes for JSON-RPC *)
6062module ErrorCode = struct
6161- type t =
6262- | ParseError (* -32700 - Invalid JSON *)
6363- | InvalidRequest (* -32600 - Invalid JSON-RPC request *)
6464- | MethodNotFound (* -32601 - Method not available *)
6565- | InvalidParams (* -32602 - Invalid method parameters *)
6666- | InternalError (* -32603 - Internal JSON-RPC error *)
6767- | ResourceNotFound (* -32002 - Custom MCP error: requested resource not found *)
6868- | AuthRequired (* -32001 - Custom MCP error: authentication required *)
6363+ type t =
6464+ | ParseError (* -32700 - Invalid JSON *)
6565+ | InvalidRequest (* -32600 - Invalid JSON-RPC request *)
6666+ | MethodNotFound (* -32601 - Method not available *)
6767+ | InvalidParams (* -32602 - Invalid method parameters *)
6868+ | InternalError (* -32603 - Internal JSON-RPC error *)
6969+ | ResourceNotFound
7070+ (* -32002 - Custom MCP error: requested resource not found *)
7171+ | AuthRequired (* -32001 - Custom MCP error: authentication required *)
6972 | CustomError of int (* For any other error codes *)
7070-7373+7174 (* Convert the error code to its integer representation *)
7275 let to_int = function
7376 | ParseError -> -32700
···7881 | ResourceNotFound -> -32002
7982 | AuthRequired -> -32001
8083 | CustomError code -> code
8181-8484+8285 (* Get error message for standard error codes *)
8386 let to_message = function
8487 | ParseError -> "Parse error"
···98101 (* Initialization and lifecycle methods *)
99102 | Initialize
100103 | Initialized
101101-102104 (* Resource methods *)
103105 | ResourcesList
104106 | ResourcesRead
···106108 | ResourcesSubscribe
107109 | ResourcesListChanged
108110 | ResourcesUpdated
109109-110111 (* Tool methods *)
111112 | ToolsList
112113 | ToolsCall
113114 | ToolsListChanged
114114-115115 (* Prompt methods *)
116116 | PromptsList
117117 | PromptsGet
118118 | PromptsListChanged
119119-120119 (* Progress notifications *)
121120 | Progress
122122-121121+123122 (* Convert method type to string representation *)
124123 let to_string = function
125124 | Initialize -> "initialize"
···137136 | PromptsGet -> "prompts/get"
138137 | PromptsListChanged -> "notifications/prompts/list_changed"
139138 | Progress -> "notifications/progress"
140140-139139+141140 (* Convert string to method type *)
142141 let of_string = function
143142 | "initialize" -> Initialize
···163162module Role = struct
164163 type t = [ `User | `Assistant ]
165164166166- let to_string = function
167167- | `User -> "user"
168168- | `Assistant -> "assistant"
165165+ let to_string = function `User -> "user" | `Assistant -> "assistant"
169166170167 let of_string = function
171168 | "user" -> `User
···173170 | s -> Util.json_error "Unknown role: %s" (`String s) s
174171175172 let yojson_of_t t = `String (to_string t)
173173+176174 let t_of_yojson = function
177175 | `String s -> of_string s
178176 | j -> Util.json_error "Expected string for Role" j
···190188 type t = string
191189192190 let yojson_of_t t = `String t
191191+193192 let t_of_yojson = function
194193 | `String s -> s
195194 | j -> Util.json_error "Expected string for Cursor" j
···198197(* Annotations *)
199198200199module Annotated = struct
201201- type t = {
202202- annotations: annotation option;
203203- }
204204- and annotation = {
205205- audience: Role.t list option;
206206- priority: float option;
207207- }
200200+ type t = { annotations : annotation option }
201201+ and annotation = { audience : Role.t list option; priority : float option }
208202209203 let yojson_of_annotation { audience; priority } =
210204 let assoc = [] in
211211- let assoc = match audience with
212212- | Some audience -> ("audience", `List (List.map Role.yojson_of_t audience)) :: assoc
205205+ let assoc =
206206+ match audience with
207207+ | Some audience ->
208208+ ("audience", `List (List.map Role.yojson_of_t audience)) :: assoc
213209 | None -> assoc
214210 in
215215- let assoc = match priority with
211211+ let assoc =
212212+ match priority with
216213 | Some priority -> ("priority", `Float priority) :: assoc
217214 | None -> assoc
218215 in
···220217221218 let annotation_of_yojson = function
222219 | `Assoc fields ->
223223- let audience = List.assoc_opt "audience" fields |> Option.map (function
224224- | `List items -> List.map Role.t_of_yojson items
225225- | j -> Util.json_error "Expected list for audience" j
226226- ) in
227227- let priority = List.assoc_opt "priority" fields |> Option.map (function
228228- | `Float f -> f
229229- | j -> Util.json_error "Expected float for priority" j
230230- ) in
231231- { audience; priority }
220220+ let audience =
221221+ List.assoc_opt "audience" fields
222222+ |> Option.map (function
223223+ | `List items -> List.map Role.t_of_yojson items
224224+ | j -> Util.json_error "Expected list for audience" j)
225225+ in
226226+ let priority =
227227+ List.assoc_opt "priority" fields
228228+ |> Option.map (function
229229+ | `Float f -> f
230230+ | j -> Util.json_error "Expected float for priority" j)
231231+ in
232232+ { audience; priority }
232233 | j -> Util.json_error "Expected object for annotation" j
233234234235 let yojson_of_t { annotations } =
235236 match annotations with
236236- | Some annotations -> `Assoc [ "annotations", yojson_of_annotation annotations ]
237237+ | Some annotations ->
238238+ `Assoc [ ("annotations", yojson_of_annotation annotations) ]
237239 | None -> `Assoc []
238240239241 let t_of_yojson = function
240242 | `Assoc fields ->
241241- let annotations = List.assoc_opt "annotations" fields |> Option.map annotation_of_yojson in
242242- { annotations }
243243+ let annotations =
244244+ List.assoc_opt "annotations" fields |> Option.map annotation_of_yojson
245245+ in
246246+ { annotations }
243247 | j -> Util.json_error "Expected object for Annotated" j
244248end
245249246250(* Content types *)
247251248252module TextContent = struct
249249- type t = {
250250- text: string;
251251- annotations: Annotated.annotation option;
252252- }
253253+ type t = { text : string; annotations : Annotated.annotation option }
253254254255 let yojson_of_t { text; annotations } =
255255- let assoc = [
256256- ("text", `String text);
257257- ("type", `String "text");
258258- ] in
259259- let assoc = match annotations with
260260- | Some annotations -> ("annotations", Annotated.yojson_of_annotation annotations) :: assoc
256256+ let assoc = [ ("text", `String text); ("type", `String "text") ] in
257257+ let assoc =
258258+ match annotations with
259259+ | Some annotations ->
260260+ ("annotations", Annotated.yojson_of_annotation annotations) :: assoc
261261 | None -> assoc
262262 in
263263 `Assoc assoc
264264265265 let t_of_yojson = function
266266 | `Assoc fields as json ->
267267- let text = Util.get_string_field fields "text" json in
268268- Util.verify_string_field fields "type" "text" json;
269269- let annotations = List.assoc_opt "annotations" fields |> Option.map Annotated.annotation_of_yojson in
270270- { text; annotations }
267267+ let text = Util.get_string_field fields "text" json in
268268+ Util.verify_string_field fields "type" "text" json;
269269+ let annotations =
270270+ List.assoc_opt "annotations" fields
271271+ |> Option.map Annotated.annotation_of_yojson
272272+ in
273273+ { text; annotations }
271274 | j -> Util.json_error "Expected object for TextContent" j
272275end
273276274277module ImageContent = struct
275278 type t = {
276276- data: string;
277277- mime_type: string;
278278- annotations: Annotated.annotation option;
279279+ data : string;
280280+ mime_type : string;
281281+ annotations : Annotated.annotation option;
279282 }
280283281284 let yojson_of_t { data; mime_type; annotations } =
282282- let assoc = [
283283- ("type", `String "image");
284284- ("data", `String data);
285285- ("mimeType", `String mime_type);
286286- ] in
287287- let assoc = match annotations with
288288- | Some annotations -> ("annotations", Annotated.yojson_of_annotation annotations) :: assoc
285285+ let assoc =
286286+ [
287287+ ("type", `String "image");
288288+ ("data", `String data);
289289+ ("mimeType", `String mime_type);
290290+ ]
291291+ in
292292+ let assoc =
293293+ match annotations with
294294+ | Some annotations ->
295295+ ("annotations", Annotated.yojson_of_annotation annotations) :: assoc
289296 | None -> assoc
290297 in
291298 `Assoc assoc
292299293300 let t_of_yojson = function
294301 | `Assoc fields as json ->
295295- let data = Util.get_string_field fields "data" json in
296296- let mime_type = Util.get_string_field fields "mimeType" json in
297297- Util.verify_string_field fields "type" "image" json;
298298- let annotations = List.assoc_opt "annotations" fields |> Option.map Annotated.annotation_of_yojson in
299299- { data; mime_type; annotations }
302302+ let data = Util.get_string_field fields "data" json in
303303+ let mime_type = Util.get_string_field fields "mimeType" json in
304304+ Util.verify_string_field fields "type" "image" json;
305305+ let annotations =
306306+ List.assoc_opt "annotations" fields
307307+ |> Option.map Annotated.annotation_of_yojson
308308+ in
309309+ { data; mime_type; annotations }
300310 | j -> Util.json_error "Expected object for ImageContent" j
301311end
302312303313module AudioContent = struct
304314 type t = {
305305- data: string;
306306- mime_type: string;
307307- annotations: Annotated.annotation option;
315315+ data : string;
316316+ mime_type : string;
317317+ annotations : Annotated.annotation option;
308318 }
309319310320 let yojson_of_t { data; mime_type; annotations } =
311311- let assoc = [
312312- ("type", `String "audio");
313313- ("data", `String data);
314314- ("mimeType", `String mime_type);
315315- ] in
316316- let assoc = match annotations with
317317- | Some annotations -> ("annotations", Annotated.yojson_of_annotation annotations) :: assoc
321321+ let assoc =
322322+ [
323323+ ("type", `String "audio");
324324+ ("data", `String data);
325325+ ("mimeType", `String mime_type);
326326+ ]
327327+ in
328328+ let assoc =
329329+ match annotations with
330330+ | Some annotations ->
331331+ ("annotations", Annotated.yojson_of_annotation annotations) :: assoc
318332 | None -> assoc
319333 in
320334 `Assoc assoc
321335322336 let t_of_yojson = function
323337 | `Assoc fields as json ->
324324- let data = Util.get_string_field fields "data" json in
325325- let mime_type = Util.get_string_field fields "mimeType" json in
326326- Util.verify_string_field fields "type" "audio" json;
327327- let annotations = List.assoc_opt "annotations" fields |> Option.map Annotated.annotation_of_yojson in
328328- { data; mime_type; annotations }
338338+ let data = Util.get_string_field fields "data" json in
339339+ let mime_type = Util.get_string_field fields "mimeType" json in
340340+ Util.verify_string_field fields "type" "audio" json;
341341+ let annotations =
342342+ List.assoc_opt "annotations" fields
343343+ |> Option.map Annotated.annotation_of_yojson
344344+ in
345345+ { data; mime_type; annotations }
329346 | j -> Util.json_error "Expected object for AudioContent" j
330347end
331348332349module ResourceContents = struct
333333- type t = {
334334- uri: string;
335335- mime_type: string option;
336336- }
350350+ type t = { uri : string; mime_type : string option }
337351338352 let yojson_of_t { uri; mime_type } =
339339- let assoc = [
340340- ("uri", `String uri);
341341- ] in
342342- let assoc = match mime_type with
353353+ let assoc = [ ("uri", `String uri) ] in
354354+ let assoc =
355355+ match mime_type with
343356 | Some mime_type -> ("mimeType", `String mime_type) :: assoc
344357 | None -> assoc
345358 in
···347360348361 let t_of_yojson = function
349362 | `Assoc fields as json ->
350350- let uri = Util.get_string_field fields "uri" json in
351351- let mime_type = Util.get_optional_string_field fields "mimeType" in
352352- { uri; mime_type }
363363+ let uri = Util.get_string_field fields "uri" json in
364364+ let mime_type = Util.get_optional_string_field fields "mimeType" in
365365+ { uri; mime_type }
353366 | j -> Util.json_error "Expected object for ResourceContents" j
354367end
355368356369module TextResourceContents = struct
357357- type t = {
358358- uri: string;
359359- text: string;
360360- mime_type: string option;
361361- }
370370+ type t = { uri : string; text : string; mime_type : string option }
362371363372 let yojson_of_t { uri; text; mime_type } =
364364- let assoc = [
365365- ("uri", `String uri);
366366- ("text", `String text);
367367- ] in
368368- let assoc = match mime_type with
373373+ let assoc = [ ("uri", `String uri); ("text", `String text) ] in
374374+ let assoc =
375375+ match mime_type with
369376 | Some mime_type -> ("mimeType", `String mime_type) :: assoc
370377 | None -> assoc
371378 in
···373380374381 let t_of_yojson = function
375382 | `Assoc fields as json ->
376376- let uri = Util.get_string_field fields "uri" json in
377377- let text = Util.get_string_field fields "text" json in
378378- let mime_type = Util.get_optional_string_field fields "mimeType" in
379379- { uri; text; mime_type }
383383+ let uri = Util.get_string_field fields "uri" json in
384384+ let text = Util.get_string_field fields "text" json in
385385+ let mime_type = Util.get_optional_string_field fields "mimeType" in
386386+ { uri; text; mime_type }
380387 | j -> Util.json_error "Expected object for TextResourceContents" j
381388end
382389383390module BlobResourceContents = struct
384384- type t = {
385385- uri: string;
386386- blob: string;
387387- mime_type: string option;
388388- }
391391+ type t = { uri : string; blob : string; mime_type : string option }
389392390393 let yojson_of_t { uri; blob; mime_type } =
391391- let assoc = [
392392- ("uri", `String uri);
393393- ("blob", `String blob);
394394- ] in
395395- let assoc = match mime_type with
394394+ let assoc = [ ("uri", `String uri); ("blob", `String blob) ] in
395395+ let assoc =
396396+ match mime_type with
396397 | Some mime_type -> ("mimeType", `String mime_type) :: assoc
397398 | None -> assoc
398399 in
···400401401402 let t_of_yojson = function
402403 | `Assoc fields as json ->
403403- let uri = Util.get_string_field fields "uri" json in
404404- let blob = Util.get_string_field fields "blob" json in
405405- let mime_type = Util.get_optional_string_field fields "mimeType" in
406406- { uri; blob; mime_type }
404404+ let uri = Util.get_string_field fields "uri" json in
405405+ let blob = Util.get_string_field fields "blob" json in
406406+ let mime_type = Util.get_optional_string_field fields "mimeType" in
407407+ { uri; blob; mime_type }
407408 | j -> Util.json_error "Expected object for BlobResourceContents" j
408409end
409410410411module EmbeddedResource = struct
411412 type t = {
412412- resource: [ `Text of TextResourceContents.t | `Blob of BlobResourceContents.t ];
413413- annotations: Annotated.annotation option;
413413+ resource :
414414+ [ `Text of TextResourceContents.t | `Blob of BlobResourceContents.t ];
415415+ annotations : Annotated.annotation option;
414416 }
415417416418 let yojson_of_t { resource; annotations } =
417417- let resource_json = match resource with
419419+ let resource_json =
420420+ match resource with
418421 | `Text txt -> TextResourceContents.yojson_of_t txt
419422 | `Blob blob -> BlobResourceContents.yojson_of_t blob
420423 in
421421- let assoc = [
422422- ("resource", resource_json);
423423- ("type", `String "resource");
424424- ] in
425425- let assoc = match annotations with
426426- | Some annotations -> ("annotations", Annotated.yojson_of_annotation annotations) :: assoc
424424+ let assoc = [ ("resource", resource_json); ("type", `String "resource") ] in
425425+ let assoc =
426426+ match annotations with
427427+ | Some annotations ->
428428+ ("annotations", Annotated.yojson_of_annotation annotations) :: assoc
427429 | None -> assoc
428430 in
429431 `Assoc assoc
430432431433 let t_of_yojson = function
432434 | `Assoc fields as json ->
433433- Util.verify_string_field fields "type" "resource" json;
434434- let resource_fields = match List.assoc_opt "resource" fields with
435435- | Some (`Assoc res_fields) -> res_fields
436436- | _ -> Util.json_error "Missing or invalid 'resource' field" json
437437- in
438438- let resource =
439439- if List.mem_assoc "text" resource_fields then
440440- `Text (TextResourceContents.t_of_yojson (`Assoc resource_fields))
441441- else if List.mem_assoc "blob" resource_fields then
442442- `Blob (BlobResourceContents.t_of_yojson (`Assoc resource_fields))
443443- else
444444- Util.json_error "Invalid resource content" (`Assoc resource_fields)
445445- in
446446- let annotations = List.assoc_opt "annotations" fields |> Option.map Annotated.annotation_of_yojson in
447447- { resource; annotations }
435435+ Util.verify_string_field fields "type" "resource" json;
436436+ let resource_fields =
437437+ match List.assoc_opt "resource" fields with
438438+ | Some (`Assoc res_fields) -> res_fields
439439+ | _ -> Util.json_error "Missing or invalid 'resource' field" json
440440+ in
441441+ let resource =
442442+ if List.mem_assoc "text" resource_fields then
443443+ `Text (TextResourceContents.t_of_yojson (`Assoc resource_fields))
444444+ else if List.mem_assoc "blob" resource_fields then
445445+ `Blob (BlobResourceContents.t_of_yojson (`Assoc resource_fields))
446446+ else
447447+ Util.json_error "Invalid resource content" (`Assoc resource_fields)
448448+ in
449449+ let annotations =
450450+ List.assoc_opt "annotations" fields
451451+ |> Option.map Annotated.annotation_of_yojson
452452+ in
453453+ { resource; annotations }
448454 | j -> Util.json_error "Expected object for EmbeddedResource" j
449455end
450456451451-type content =
457457+type content =
452458 | Text of TextContent.t
453459 | Image of ImageContent.t
454460 | Audio of AudioContent.t
···461467 | Resource r -> EmbeddedResource.yojson_of_t r
462468463469let content_of_yojson = function
464464- | `Assoc fields as json ->
465465- (match List.assoc_opt "type" fields with
466466- | Some (`String "text") -> Text (TextContent.t_of_yojson json)
467467- | Some (`String "image") -> Image (ImageContent.t_of_yojson json)
468468- | Some (`String "audio") -> Audio (AudioContent.t_of_yojson json)
469469- | Some (`String "resource") -> Resource (EmbeddedResource.t_of_yojson json)
470470- | _ -> Util.json_error "Invalid or missing content type" json)
470470+ | `Assoc fields as json -> (
471471+ match List.assoc_opt "type" fields with
472472+ | Some (`String "text") -> Text (TextContent.t_of_yojson json)
473473+ | Some (`String "image") -> Image (ImageContent.t_of_yojson json)
474474+ | Some (`String "audio") -> Audio (AudioContent.t_of_yojson json)
475475+ | Some (`String "resource") ->
476476+ Resource (EmbeddedResource.t_of_yojson json)
477477+ | _ -> Util.json_error "Invalid or missing content type" json)
471478 | j -> Util.json_error "Expected object for content" j
472479473480(* Message types *)
474481475482module PromptMessage = struct
476476- type t = {
477477- role: Role.t;
478478- content: content;
479479- }
483483+ type t = { role : Role.t; content : content }
480484481485 let yojson_of_t { role; content } =
482482- `Assoc [
483483- ("role", Role.yojson_of_t role);
484484- ("content", yojson_of_content content);
485485- ]
486486+ `Assoc
487487+ [
488488+ ("role", Role.yojson_of_t role); ("content", yojson_of_content content);
489489+ ]
486490487491 let t_of_yojson = function
488492 | `Assoc fields as json ->
489489- let role = match List.assoc_opt "role" fields with
490490- | Some json -> Role.t_of_yojson json
491491- | None -> Util.json_error "Missing role field" json
492492- in
493493- let content = match List.assoc_opt "content" fields with
494494- | Some json -> content_of_yojson json
495495- | None -> Util.json_error "Missing content field" json
496496- in
497497- { role; content }
493493+ let role =
494494+ match List.assoc_opt "role" fields with
495495+ | Some json -> Role.t_of_yojson json
496496+ | None -> Util.json_error "Missing role field" json
497497+ in
498498+ let content =
499499+ match List.assoc_opt "content" fields with
500500+ | Some json -> content_of_yojson json
501501+ | None -> Util.json_error "Missing content field" json
502502+ in
503503+ { role; content }
498504 | j -> Util.json_error "Expected object for PromptMessage" j
499505end
500506501507module SamplingMessage = struct
502508 type t = {
503503- role: Role.t;
504504- content: [ `Text of TextContent.t | `Image of ImageContent.t | `Audio of AudioContent.t ];
509509+ role : Role.t;
510510+ content :
511511+ [ `Text of TextContent.t
512512+ | `Image of ImageContent.t
513513+ | `Audio of AudioContent.t ];
505514 }
506515507516 let yojson_of_t { role; content } =
508508- let content_json = match content with
517517+ let content_json =
518518+ match content with
509519 | `Text t -> TextContent.yojson_of_t t
510520 | `Image i -> ImageContent.yojson_of_t i
511521 | `Audio a -> AudioContent.yojson_of_t a
512522 in
513513- `Assoc [
514514- ("role", Role.yojson_of_t role);
515515- ("content", content_json);
516516- ]
523523+ `Assoc [ ("role", Role.yojson_of_t role); ("content", content_json) ]
517524518525 let t_of_yojson = function
519526 | `Assoc fields as json ->
520520- let role = match List.assoc_opt "role" fields with
521521- | Some json -> Role.t_of_yojson json
522522- | None -> Util.json_error "Missing role field" json
523523- in
524524- let content_obj = match List.assoc_opt "content" fields with
525525- | Some (`Assoc content_fields) -> content_fields
526526- | _ -> Util.json_error "Missing or invalid content field" json
527527- in
528528- let content_type = match List.assoc_opt "type" content_obj with
529529- | Some (`String ty) -> ty
530530- | _ -> Util.json_error "Missing or invalid content type" (`Assoc content_obj)
531531- in
532532- let content =
533533- match content_type with
534534- | "text" -> `Text (TextContent.t_of_yojson (`Assoc content_obj))
535535- | "image" -> `Image (ImageContent.t_of_yojson (`Assoc content_obj))
536536- | "audio" -> `Audio (AudioContent.t_of_yojson (`Assoc content_obj))
537537- | _ -> Util.json_error "Invalid content type: %s" (`Assoc content_obj) content_type
538538- in
539539- { role; content }
527527+ let role =
528528+ match List.assoc_opt "role" fields with
529529+ | Some json -> Role.t_of_yojson json
530530+ | None -> Util.json_error "Missing role field" json
531531+ in
532532+ let content_obj =
533533+ match List.assoc_opt "content" fields with
534534+ | Some (`Assoc content_fields) -> content_fields
535535+ | _ -> Util.json_error "Missing or invalid content field" json
536536+ in
537537+ let content_type =
538538+ match List.assoc_opt "type" content_obj with
539539+ | Some (`String ty) -> ty
540540+ | _ ->
541541+ Util.json_error "Missing or invalid content type"
542542+ (`Assoc content_obj)
543543+ in
544544+ let content =
545545+ match content_type with
546546+ | "text" -> `Text (TextContent.t_of_yojson (`Assoc content_obj))
547547+ | "image" -> `Image (ImageContent.t_of_yojson (`Assoc content_obj))
548548+ | "audio" -> `Audio (AudioContent.t_of_yojson (`Assoc content_obj))
549549+ | _ ->
550550+ Util.json_error "Invalid content type: %s" (`Assoc content_obj)
551551+ content_type
552552+ in
553553+ { role; content }
540554 | j -> Util.json_error "Expected object for SamplingMessage" j
541555end
542556543557(* Implementation info *)
544558545559module Implementation = struct
546546- type t = {
547547- name: string;
548548- version: string;
549549- }
560560+ type t = { name : string; version : string }
550561551562 let yojson_of_t { name; version } =
552552- `Assoc [
553553- ("name", `String name);
554554- ("version", `String version);
555555- ]
563563+ `Assoc [ ("name", `String name); ("version", `String version) ]
556564557565 let t_of_yojson = function
558566 | `Assoc fields as json ->
559559- let name = Util.get_string_field fields "name" json in
560560- let version = Util.get_string_field fields "version" json in
561561- { name; version }
567567+ let name = Util.get_string_field fields "name" json in
568568+ let version = Util.get_string_field fields "version" json in
569569+ { name; version }
562570 | j -> Util.json_error "Expected object for Implementation" j
563571end
564572565573(* JSONRPC Message types *)
566574567575module JSONRPCMessage = struct
568568- type notification = {
569569- meth: Method.t;
570570- params: Json.t option;
571571- }
576576+ type notification = { meth : Method.t; params : Json.t option }
572577573578 type request = {
574574- id: RequestId.t;
575575- meth: Method.t;
576576- params: Json.t option;
577577- progress_token: ProgressToken.t option;
579579+ id : RequestId.t;
580580+ meth : Method.t;
581581+ params : Json.t option;
582582+ progress_token : ProgressToken.t option;
578583 }
579584580580- type response = {
581581- id: RequestId.t;
582582- result: Json.t;
583583- }
585585+ type response = { id : RequestId.t; result : Json.t }
584586585587 type error = {
586586- id: RequestId.t;
587587- code: int;
588588- message: string;
589589- data: Json.t option;
588588+ id : RequestId.t;
589589+ code : int;
590590+ message : string;
591591+ data : Json.t option;
590592 }
591593592594 type t =
···595597 | Response of response
596598 | Error of error
597599598598- let yojson_of_notification (n: notification) =
599599- let assoc = [
600600- ("jsonrpc", `String "2.0");
601601- ("method", `String (Method.to_string n.meth));
602602- ] in
603603- let assoc = match n.params with
600600+ let yojson_of_notification (n : notification) =
601601+ let assoc =
602602+ [
603603+ ("jsonrpc", `String "2.0"); ("method", `String (Method.to_string n.meth));
604604+ ]
605605+ in
606606+ let assoc =
607607+ match n.params with
604608 | Some params -> ("params", params) :: assoc
605609 | None -> assoc
606610 in
607611 `Assoc assoc
608612609609- let yojson_of_request (r: request) =
610610- let assoc = [
611611- ("jsonrpc", `String "2.0");
612612- ("id", Id.yojson_of_t r.id);
613613- ("method", `String (Method.to_string r.meth));
614614- ] in
615615- let assoc = match r.params with
613613+ let yojson_of_request (r : request) =
614614+ let assoc =
615615+ [
616616+ ("jsonrpc", `String "2.0");
617617+ ("id", Id.yojson_of_t r.id);
618618+ ("method", `String (Method.to_string r.meth));
619619+ ]
620620+ in
621621+ let assoc =
622622+ match r.params with
616623 | Some params ->
617617- let params_json = match params with
618618- | `Assoc fields ->
619619- let fields = match r.progress_token with
620620- | Some token ->
621621- let meta = `Assoc [ "progressToken", ProgressToken.yojson_of_t token ] in
622622- ("_meta", meta) :: fields
623623- | None -> fields
624624- in
625625- `Assoc fields
626626- | _ -> params
627627- in
628628- ("params", params_json) :: assoc
624624+ let params_json =
625625+ match params with
626626+ | `Assoc fields ->
627627+ let fields =
628628+ match r.progress_token with
629629+ | Some token ->
630630+ let meta =
631631+ `Assoc
632632+ [ ("progressToken", ProgressToken.yojson_of_t token) ]
633633+ in
634634+ ("_meta", meta) :: fields
635635+ | None -> fields
636636+ in
637637+ `Assoc fields
638638+ | _ -> params
639639+ in
640640+ ("params", params_json) :: assoc
629641 | None -> assoc
630642 in
631643 `Assoc assoc
632644633633- let yojson_of_response (r: response) =
634634- `Assoc [
635635- ("jsonrpc", `String "2.0");
636636- ("id", Id.yojson_of_t r.id);
637637- ("result", r.result);
638638- ]
645645+ let yojson_of_response (r : response) =
646646+ `Assoc
647647+ [
648648+ ("jsonrpc", `String "2.0");
649649+ ("id", Id.yojson_of_t r.id);
650650+ ("result", r.result);
651651+ ]
639652640640- let yojson_of_error (e: error) =
641641- let error_assoc = [
642642- ("code", `Int e.code);
643643- ("message", `String e.message);
644644- ] in
645645- let error_assoc = match e.data with
653653+ let yojson_of_error (e : error) =
654654+ let error_assoc =
655655+ [ ("code", `Int e.code); ("message", `String e.message) ]
656656+ in
657657+ let error_assoc =
658658+ match e.data with
646659 | Some data -> ("data", data) :: error_assoc
647660 | None -> error_assoc
648661 in
649649- `Assoc [
650650- ("jsonrpc", `String "2.0");
651651- ("id", Id.yojson_of_t e.id);
652652- ("error", `Assoc error_assoc);
653653- ]
662662+ `Assoc
663663+ [
664664+ ("jsonrpc", `String "2.0");
665665+ ("id", Id.yojson_of_t e.id);
666666+ ("error", `Assoc error_assoc);
667667+ ]
654668655669 let yojson_of_t = function
656670 | Notification n -> yojson_of_notification n
···660674661675 let notification_of_yojson = function
662676 | `Assoc fields ->
663663- let meth = match List.assoc_opt "method" fields with
664664- | Some (`String s) ->
665665- (try Method.of_string s
666666- with Failure msg -> Util.json_error "%s" (`String s) msg)
667667- | _ -> Util.json_error "Missing or invalid 'method' field" (`Assoc fields)
668668- in
669669- let params = List.assoc_opt "params" fields in
670670- { meth; params }
677677+ let meth =
678678+ match List.assoc_opt "method" fields with
679679+ | Some (`String s) -> (
680680+ try Method.of_string s
681681+ with Failure msg -> Util.json_error "%s" (`String s) msg)
682682+ | _ ->
683683+ Util.json_error "Missing or invalid 'method' field"
684684+ (`Assoc fields)
685685+ in
686686+ let params = List.assoc_opt "params" fields in
687687+ { meth; params }
671688 | j -> Util.json_error "Expected object for notification" j
672689673690 let request_of_yojson = function
674691 | `Assoc fields ->
675675- let id = match List.assoc_opt "id" fields with
676676- | Some id_json -> Id.t_of_yojson id_json
677677- | _ -> Util.json_error "Missing or invalid 'id' field" (`Assoc fields)
678678- in
679679- let meth = match List.assoc_opt "method" fields with
680680- | Some (`String s) ->
681681- (try Method.of_string s
682682- with Failure msg -> Util.json_error "%s" (`String s) msg)
683683- | _ -> Util.json_error "Missing or invalid 'method' field" (`Assoc fields)
684684- in
685685- let params = List.assoc_opt "params" fields in
686686- let progress_token =
687687- match params with
688688- | Some (`Assoc param_fields) ->
689689- (match List.assoc_opt "_meta" param_fields with
690690- | Some (`Assoc meta_fields) ->
691691- (match List.assoc_opt "progressToken" meta_fields with
692692- | Some token_json -> Some (ProgressToken.t_of_yojson token_json)
693693- | None -> None)
694694- | _ -> None)
695695- | _ -> None
696696- in
697697- { id; meth; params; progress_token }
692692+ let id =
693693+ match List.assoc_opt "id" fields with
694694+ | Some id_json -> Id.t_of_yojson id_json
695695+ | _ -> Util.json_error "Missing or invalid 'id' field" (`Assoc fields)
696696+ in
697697+ let meth =
698698+ match List.assoc_opt "method" fields with
699699+ | Some (`String s) -> (
700700+ try Method.of_string s
701701+ with Failure msg -> Util.json_error "%s" (`String s) msg)
702702+ | _ ->
703703+ Util.json_error "Missing or invalid 'method' field"
704704+ (`Assoc fields)
705705+ in
706706+ let params = List.assoc_opt "params" fields in
707707+ let progress_token =
708708+ match params with
709709+ | Some (`Assoc param_fields) -> (
710710+ match List.assoc_opt "_meta" param_fields with
711711+ | Some (`Assoc meta_fields) -> (
712712+ match List.assoc_opt "progressToken" meta_fields with
713713+ | Some token_json ->
714714+ Some (ProgressToken.t_of_yojson token_json)
715715+ | None -> None)
716716+ | _ -> None)
717717+ | _ -> None
718718+ in
719719+ { id; meth; params; progress_token }
698720 | j -> Util.json_error "Expected object for request" j
699721700722 let response_of_yojson = function
701723 | `Assoc fields ->
702702- let id = match List.assoc_opt "id" fields with
703703- | Some id_json -> Id.t_of_yojson id_json
704704- | _ -> Util.json_error "Missing or invalid 'id' field" (`Assoc fields)
705705- in
706706- let result = match List.assoc_opt "result" fields with
707707- | Some result -> result
708708- | _ -> Util.json_error "Missing 'result' field" (`Assoc fields)
709709- in
710710- { id; result }
724724+ let id =
725725+ match List.assoc_opt "id" fields with
726726+ | Some id_json -> Id.t_of_yojson id_json
727727+ | _ -> Util.json_error "Missing or invalid 'id' field" (`Assoc fields)
728728+ in
729729+ let result =
730730+ match List.assoc_opt "result" fields with
731731+ | Some result -> result
732732+ | _ -> Util.json_error "Missing 'result' field" (`Assoc fields)
733733+ in
734734+ { id; result }
711735 | j -> Util.json_error "Expected object for response" j
712736713737 let error_of_yojson = function
714738 | `Assoc fields as json ->
715715- let id = match List.assoc_opt "id" fields with
716716- | Some id_json -> Id.t_of_yojson id_json
717717- | _ -> Util.json_error "Missing or invalid 'id' field" json
718718- in
719719- let error = match List.assoc_opt "error" fields with
720720- | Some (`Assoc error_fields) -> error_fields
721721- | _ -> Util.json_error "Missing or invalid 'error' field" json
722722- in
723723- let code = match List.assoc_opt "code" error with
724724- | Some (`Int code) -> code
725725- | _ -> Util.json_error "Missing or invalid 'code' field in error" (`Assoc error)
726726- in
727727- let message = match List.assoc_opt "message" error with
728728- | Some (`String msg) -> msg
729729- | _ -> Util.json_error "Missing or invalid 'message' field in error" (`Assoc error)
730730- in
731731- let data = List.assoc_opt "data" error in
732732- { id; code; message; data }
739739+ let id =
740740+ match List.assoc_opt "id" fields with
741741+ | Some id_json -> Id.t_of_yojson id_json
742742+ | _ -> Util.json_error "Missing or invalid 'id' field" json
743743+ in
744744+ let error =
745745+ match List.assoc_opt "error" fields with
746746+ | Some (`Assoc error_fields) -> error_fields
747747+ | _ -> Util.json_error "Missing or invalid 'error' field" json
748748+ in
749749+ let code =
750750+ match List.assoc_opt "code" error with
751751+ | Some (`Int code) -> code
752752+ | _ ->
753753+ Util.json_error "Missing or invalid 'code' field in error"
754754+ (`Assoc error)
755755+ in
756756+ let message =
757757+ match List.assoc_opt "message" error with
758758+ | Some (`String msg) -> msg
759759+ | _ ->
760760+ Util.json_error "Missing or invalid 'message' field in error"
761761+ (`Assoc error)
762762+ in
763763+ let data = List.assoc_opt "data" error in
764764+ { id; code; message; data }
733765 | j -> Util.json_error "Expected object for error" j
734766735767 let t_of_yojson json =
736768 match json with
737769 | `Assoc fields ->
738738- let _jsonrpc = match List.assoc_opt "jsonrpc" fields with
739739- | Some (`String "2.0") -> ()
740740- | _ -> Util.json_error "Missing or invalid 'jsonrpc' field" json
741741- in
742742- if List.mem_assoc "method" fields then
743743- if List.mem_assoc "id" fields then
744744- Request (request_of_yojson json)
745745- else
746746- Notification (notification_of_yojson json)
747747- else if List.mem_assoc "result" fields then
748748- Response (response_of_yojson json)
749749- else if List.mem_assoc "error" fields then
750750- Error (error_of_yojson json)
751751- else
752752- Util.json_error "Invalid JSONRPC message format" json
770770+ let _jsonrpc =
771771+ match List.assoc_opt "jsonrpc" fields with
772772+ | Some (`String "2.0") -> ()
773773+ | _ -> Util.json_error "Missing or invalid 'jsonrpc' field" json
774774+ in
775775+ if List.mem_assoc "method" fields then
776776+ if List.mem_assoc "id" fields then Request (request_of_yojson json)
777777+ else Notification (notification_of_yojson json)
778778+ else if List.mem_assoc "result" fields then
779779+ Response (response_of_yojson json)
780780+ else if List.mem_assoc "error" fields then Error (error_of_yojson json)
781781+ else Util.json_error "Invalid JSONRPC message format" json
753782 | j -> Util.json_error "Expected object for JSONRPC message" j
754783755755- let create_notification ?(params=None) ~meth () =
784784+ let create_notification ?(params = None) ~meth () =
756785 Notification { meth; params }
757786758758- let create_request ?(params=None) ?(progress_token=None) ~id ~meth () =
787787+ let create_request ?(params = None) ?(progress_token = None) ~id ~meth () =
759788 Request { id; meth; params; progress_token }
760789761761- let create_response ~id ~result =
762762- Response { id; result }
790790+ let create_response ~id ~result = Response { id; result }
763791764764- let create_error ~id ~code ~message ?(data=None) () =
792792+ let create_error ~id ~code ~message ?(data = None) () =
765793 Error { id; code; message; data }
766794end
767795···770798module Initialize = struct
771799 module Request = struct
772800 type t = {
773773- capabilities: Json.t; (* ClientCapabilities *)
774774- client_info: Implementation.t;
775775- protocol_version: string;
801801+ capabilities : Json.t; (* ClientCapabilities *)
802802+ client_info : Implementation.t;
803803+ protocol_version : string;
776804 }
777805778806 let yojson_of_t { capabilities; client_info; protocol_version } =
779779- `Assoc [
780780- ("capabilities", capabilities);
781781- ("clientInfo", Implementation.yojson_of_t client_info);
782782- ("protocolVersion", `String protocol_version);
783783- ]
807807+ `Assoc
808808+ [
809809+ ("capabilities", capabilities);
810810+ ("clientInfo", Implementation.yojson_of_t client_info);
811811+ ("protocolVersion", `String protocol_version);
812812+ ]
784813785814 let t_of_yojson = function
786815 | `Assoc fields as json ->
787787- let capabilities = match List.assoc_opt "capabilities" fields with
788788- | Some json -> json
789789- | None -> Util.json_error "Missing capabilities field" json
790790- in
791791- let client_info = match List.assoc_opt "clientInfo" fields with
792792- | Some json -> Implementation.t_of_yojson json
793793- | None -> Util.json_error "Missing clientInfo field" json
794794- in
795795- let protocol_version = Util.get_string_field fields "protocolVersion" json in
796796- { capabilities; client_info; protocol_version }
816816+ let capabilities =
817817+ match List.assoc_opt "capabilities" fields with
818818+ | Some json -> json
819819+ | None -> Util.json_error "Missing capabilities field" json
820820+ in
821821+ let client_info =
822822+ match List.assoc_opt "clientInfo" fields with
823823+ | Some json -> Implementation.t_of_yojson json
824824+ | None -> Util.json_error "Missing clientInfo field" json
825825+ in
826826+ let protocol_version =
827827+ Util.get_string_field fields "protocolVersion" json
828828+ in
829829+ { capabilities; client_info; protocol_version }
797830 | j -> Util.json_error "Expected object for InitializeRequest" j
798831799832 let create ~capabilities ~client_info ~protocol_version =
···801834802835 let to_jsonrpc ~id t =
803836 let params = yojson_of_t t in
804804- JSONRPCMessage.create_request ~id ~meth:Method.Initialize ~params:(Some params) ()
837837+ JSONRPCMessage.create_request ~id ~meth:Method.Initialize
838838+ ~params:(Some params) ()
805839 end
806840807841 module Result = struct
808842 type t = {
809809- capabilities: Json.t; (* ServerCapabilities *)
810810- server_info: Implementation.t;
811811- protocol_version: string;
812812- instructions: string option;
813813- meta: Json.t option;
843843+ capabilities : Json.t; (* ServerCapabilities *)
844844+ server_info : Implementation.t;
845845+ protocol_version : string;
846846+ instructions : string option;
847847+ meta : Json.t option;
814848 }
815849816816- let yojson_of_t { capabilities; server_info; protocol_version; instructions; meta } =
817817- let assoc = [
818818- ("capabilities", capabilities);
819819- ("serverInfo", Implementation.yojson_of_t server_info);
820820- ("protocolVersion", `String protocol_version);
821821- ] in
822822- let assoc = match instructions with
850850+ let yojson_of_t
851851+ { capabilities; server_info; protocol_version; instructions; meta } =
852852+ let assoc =
853853+ [
854854+ ("capabilities", capabilities);
855855+ ("serverInfo", Implementation.yojson_of_t server_info);
856856+ ("protocolVersion", `String protocol_version);
857857+ ]
858858+ in
859859+ let assoc =
860860+ match instructions with
823861 | Some instr -> ("instructions", `String instr) :: assoc
824862 | None -> assoc
825863 in
826826- let assoc = match meta with
827827- | Some meta -> ("_meta", meta) :: assoc
828828- | None -> assoc
864864+ let assoc =
865865+ match meta with Some meta -> ("_meta", meta) :: assoc | None -> assoc
829866 in
830867 `Assoc assoc
831868832869 let t_of_yojson = function
833870 | `Assoc fields as json ->
834834- let capabilities = match List.assoc_opt "capabilities" fields with
835835- | Some json -> json
836836- | None -> Util.json_error "Missing capabilities field" json
837837- in
838838- let server_info = match List.assoc_opt "serverInfo" fields with
839839- | Some json -> Implementation.t_of_yojson json
840840- | None -> Util.json_error "Missing serverInfo field" json
841841- in
842842- let protocol_version = Util.get_string_field fields "protocolVersion" json in
843843- let instructions = Util.get_optional_string_field fields "instructions" in
844844- let meta = List.assoc_opt "_meta" fields in
845845- { capabilities; server_info; protocol_version; instructions; meta }
871871+ let capabilities =
872872+ match List.assoc_opt "capabilities" fields with
873873+ | Some json -> json
874874+ | None -> Util.json_error "Missing capabilities field" json
875875+ in
876876+ let server_info =
877877+ match List.assoc_opt "serverInfo" fields with
878878+ | Some json -> Implementation.t_of_yojson json
879879+ | None -> Util.json_error "Missing serverInfo field" json
880880+ in
881881+ let protocol_version =
882882+ Util.get_string_field fields "protocolVersion" json
883883+ in
884884+ let instructions =
885885+ Util.get_optional_string_field fields "instructions"
886886+ in
887887+ let meta = List.assoc_opt "_meta" fields in
888888+ { capabilities; server_info; protocol_version; instructions; meta }
846889 | j -> Util.json_error "Expected object for InitializeResult" j
847890848848- let create ~capabilities ~server_info ~protocol_version ?instructions ?meta () =
891891+ let create ~capabilities ~server_info ~protocol_version ?instructions ?meta
892892+ () =
849893 { capabilities; server_info; protocol_version; instructions; meta }
850894851895 let to_jsonrpc ~id t =
···855899856900module Initialized = struct
857901 module Notification = struct
858858- type t = {
859859- meta: Json.t option;
860860- }
902902+ type t = { meta : Json.t option }
861903862904 let yojson_of_t { meta } =
863905 let assoc = [] in
864864- let assoc = match meta with
865865- | Some meta -> ("_meta", meta) :: assoc
866866- | None -> assoc
906906+ let assoc =
907907+ match meta with Some meta -> ("_meta", meta) :: assoc | None -> assoc
867908 in
868909 `Assoc assoc
869910870911 let t_of_yojson = function
871912 | `Assoc fields ->
872872- let meta = List.assoc_opt "_meta" fields in
873873- { meta }
913913+ let meta = List.assoc_opt "_meta" fields in
914914+ { meta }
874915 | j -> Util.json_error "Expected object for InitializedNotification" j
875916876917 let create ?meta () = { meta }
877918878919 let to_jsonrpc t =
879879- let params = match yojson_of_t t with
880880- | `Assoc [] -> None
881881- | json -> Some json
920920+ let params =
921921+ match yojson_of_t t with `Assoc [] -> None | json -> Some json
882922 in
883923 JSONRPCMessage.create_notification ~meth:Method.Initialized ~params ()
884924 end
885925end
886926887887-888927(* Export the main interface for using the MCP protocol *)
889928890890-let parse_message json =
891891- JSONRPCMessage.t_of_yojson json
929929+let parse_message json = JSONRPCMessage.t_of_yojson json
892930893893-let create_notification ?(params=None) ~meth () =
931931+let create_notification ?(params = None) ~meth () =
894932 JSONRPCMessage.create_notification ~params ~meth ()
895933896896-let create_request ?(params=None) ?(progress_token=None) ~id ~meth () =
934934+let create_request ?(params = None) ?(progress_token = None) ~id ~meth () =
897935 JSONRPCMessage.create_request ~params ~progress_token ~id ~meth ()
898936899937let create_response = JSONRPCMessage.create_response
900938let create_error = JSONRPCMessage.create_error
901939902940(* Content type constructors *)
903903-let make_text_content text =
904904- Text (TextContent.{ text; annotations = None })
941941+let make_text_content text = Text TextContent.{ text; annotations = None }
905942906943let make_image_content data mime_type =
907907- Image (ImageContent.{ data; mime_type; annotations = None })
944944+ Image ImageContent.{ data; mime_type; annotations = None }
908945909946let make_audio_content data mime_type =
910910- Audio (AudioContent.{ data; mime_type; annotations = None })
947947+ Audio AudioContent.{ data; mime_type; annotations = None }
911948912949let make_resource_text_content uri text mime_type =
913913- Resource (EmbeddedResource.{
914914- resource = `Text TextResourceContents.{ uri; text; mime_type };
915915- annotations = None;
916916- })
950950+ Resource
951951+ EmbeddedResource.
952952+ {
953953+ resource = `Text TextResourceContents.{ uri; text; mime_type };
954954+ annotations = None;
955955+ }
917956918957let make_resource_blob_content uri blob mime_type =
919919- Resource (EmbeddedResource.{
920920- resource = `Blob BlobResourceContents.{ uri; blob; mime_type };
921921- annotations = None;
922922- })958958+ Resource
959959+ EmbeddedResource.
960960+ {
961961+ resource = `Blob BlobResourceContents.{ uri; blob; mime_type };
962962+ annotations = None;
963963+ }
+667-609
lib/mcp.mli
···11-(** MCP - Model Context Protocol implementation
22-33- The Model Context Protocol (MCP) is a standardized protocol for AI agents to exchange context
44- with servers. This module provides the core OCaml implementation of MCP including
55- all message types, content representations, and serialization functionality.
66-11+(** MCP - Model Context Protocol implementation
22+33+ The Model Context Protocol (MCP) is a standardized protocol for AI agents to
44+ exchange context with servers. This module provides the core OCaml
55+ implementation of MCP including all message types, content representations,
66+ and serialization functionality.
77+78 MCP Architecture:
89 - Uses JSON-RPC 2.0 as its underlying message format with UTF-8 encoding
99- - Follows a client-server model where clients (often LLM-integrated applications) communicate with MCP servers
1010+ - Follows a client-server model where clients (often LLM-integrated
1111+ applications) communicate with MCP servers
1012 - Supports multiple transport methods including stdio and streamable HTTP
1111- - Implements a three-phase connection lifecycle: initialization, operation, and shutdown
1212- - Provides capability negotiation during initialization to determine available features
1313- - Offers four primary context exchange mechanisms:
1414- 1. Resources: Server-exposed data that provides context to language models
1515- 2. Tools: Server-exposed functionality that can be invoked by language models
1616- 3. Prompts: Server-defined templates for structuring interactions with models
1313+ - Implements a three-phase connection lifecycle: initialization, operation,
1414+ and shutdown
1515+ - Provides capability negotiation during initialization to determine
1616+ available features
1717+ - Offers four primary context exchange mechanisms: 1. Resources:
1818+ Server-exposed data that provides context to language models 2. Tools:
1919+ Server-exposed functionality that can be invoked by language models 3.
2020+ Prompts: Server-defined templates for structuring interactions with models
1721 4. Sampling: Client-exposed ability to generate completions from LLMs
1818- - Supports multimodal content types: text, images, audio, and embedded resources
2222+ - Supports multimodal content types: text, images, audio, and embedded
2323+ resources
1924 - Includes standardized error handling with defined error codes
2020-2121- This implementation follows Protocol Revision 2025-03-26.
2222-*)
2525+2626+ This implementation follows Protocol Revision 2025-03-26. *)
23272428open Jsonrpc
25292630(** Utility functions for JSON parsing *)
2731module Util : sig
3232+ val json_error : ('a, unit, string, 'b) format4 -> Json.t -> 'a
2833 (** Helper to raise a Json.Of_json exception with formatted message
2934 @param fmt Format string for the error message
3035 @param json JSON value to include in the exception
3136 @return Never returns, always raises an exception
3232- @raise Json.Of_json with the formatted message and JSON value
3333- *)
3434- val json_error : ('a, unit, string, 'b) format4 -> Json.t -> 'a
3535-3636- (** Extract a string field from JSON object or raise an error
3737+ @raise Json.Of_json with the formatted message and JSON value *)
3838+3939+ val get_string_field : (string * Json.t) list -> string -> Json.t -> string
4040+ (** Extract a string field from JSON object or raise an error
3741 @param fields Assoc list of fields from JSON object
3842 @param name Field name to extract
3943 @param json Original JSON for error context
4044 @return The string value of the field
4141- @raise Json.Of_json if the field is missing or not a string
4242- *)
4343- val get_string_field : (string * Json.t) list -> string -> Json.t -> string
4444-4545+ @raise Json.Of_json if the field is missing or not a string *)
4646+4747+ val get_optional_string_field :
4848+ (string * Json.t) list -> string -> string option
4549 (** Extract an optional string field from JSON object
4650 @param fields Assoc list of fields from JSON object
4751 @param name Field name to extract
4852 @return Some string if present and a string, None if missing
4949- @raise Json.Of_json if the field exists but is not a string
5050- *)
5151- val get_optional_string_field : (string * Json.t) list -> string -> string option
5252-5353+ @raise Json.Of_json if the field exists but is not a string *)
5454+5555+ val get_int_field : (string * Json.t) list -> string -> Json.t -> int
5356 (** Extract an int field from JSON object or raise an error
5457 @param fields Assoc list of fields from JSON object
5558 @param name Field name to extract
5659 @param json Original JSON for error context
5760 @return The int value of the field
5858- @raise Json.Of_json if the field is missing or not an int
5959- *)
6060- val get_int_field : (string * Json.t) list -> string -> Json.t -> int
6161-6161+ @raise Json.Of_json if the field is missing or not an int *)
6262+6363+ val get_float_field : (string * Json.t) list -> string -> Json.t -> float
6264 (** Extract a float field from JSON object or raise an error
6365 @param fields Assoc list of fields from JSON object
6466 @param name Field name to extract
6567 @param json Original JSON for error context
6668 @return The float value of the field
6767- @raise Json.Of_json if the field is missing or not a float
6868- *)
6969- val get_float_field : (string * Json.t) list -> string -> Json.t -> float
7070-6969+ @raise Json.Of_json if the field is missing or not a float *)
7070+7171+ val get_bool_field : (string * Json.t) list -> string -> Json.t -> bool
7172 (** Extract a boolean field from JSON object or raise an error
7273 @param fields Assoc list of fields from JSON object
7374 @param name Field name to extract
7475 @param json Original JSON for error context
7576 @return The boolean value of the field
7676- @raise Json.Of_json if the field is missing or not a boolean
7777- *)
7878- val get_bool_field : (string * Json.t) list -> string -> Json.t -> bool
7979-7777+ @raise Json.Of_json if the field is missing or not a boolean *)
7878+7979+ val get_object_field :
8080+ (string * Json.t) list -> string -> Json.t -> (string * Json.t) list
8081 (** Extract an object field from JSON object or raise an error
8182 @param fields Assoc list of fields from JSON object
8283 @param name Field name to extract
8384 @param json Original JSON for error context
8485 @return The object as an assoc list
8585- @raise Json.Of_json if the field is missing or not an object
8686- *)
8787- val get_object_field : (string * Json.t) list -> string -> Json.t -> (string * Json.t) list
8888-8686+ @raise Json.Of_json if the field is missing or not an object *)
8787+8888+ val get_list_field : (string * Json.t) list -> string -> Json.t -> Json.t list
8989 (** Extract a list field from JSON object or raise an error
9090 @param fields Assoc list of fields from JSON object
9191 @param name Field name to extract
9292 @param json Original JSON for error context
9393 @return The list items
9494- @raise Json.Of_json if the field is missing or not a list
9595- *)
9696- val get_list_field : (string * Json.t) list -> string -> Json.t -> Json.t list
9797-9494+ @raise Json.Of_json if the field is missing or not a list *)
9595+9696+ val verify_string_field :
9797+ (string * Json.t) list -> string -> string -> Json.t -> unit
9898 (** Verify a specific string value in a field
9999 @param fields Assoc list of fields from JSON object
100100 @param name Field name to check
···102102 @param json Original JSON for error context
103103 @raise Json.Of_json if the field is missing or not equal to expected_value
104104 *)
105105- val verify_string_field : (string * Json.t) list -> string -> string -> Json.t -> unit
106105end
107106108107(** Error codes for JSON-RPC *)
109108module ErrorCode : sig
110109 (** Standard JSON-RPC error codes with MCP-specific additions *)
111111- type t =
112112- | ParseError (** -32700 - Invalid JSON *)
113113- | InvalidRequest (** -32600 - Invalid JSON-RPC request *)
114114- | MethodNotFound (** -32601 - Method not available *)
115115- | InvalidParams (** -32602 - Invalid method parameters *)
116116- | InternalError (** -32603 - Internal JSON-RPC error *)
117117- | ResourceNotFound (** -32002 - Custom MCP error: requested resource not found *)
118118- | AuthRequired (** -32001 - Custom MCP error: authentication required *)
119119- | CustomError of int (** For any other error codes *)
120120-110110+ type t =
111111+ | ParseError (** -32700 - Invalid JSON *)
112112+ | InvalidRequest (** -32600 - Invalid JSON-RPC request *)
113113+ | MethodNotFound (** -32601 - Method not available *)
114114+ | InvalidParams (** -32602 - Invalid method parameters *)
115115+ | InternalError (** -32603 - Internal JSON-RPC error *)
116116+ | ResourceNotFound
117117+ (** -32002 - Custom MCP error: requested resource not found *)
118118+ | AuthRequired (** -32001 - Custom MCP error: authentication required *)
119119+ | CustomError of int (** For any other error codes *)
120120+121121+ val to_int : t -> int
121122 (** Convert the error code to its integer representation
122123 @param code The error code to convert
123123- @return The integer error code as defined in the JSON-RPC spec
124124- *)
125125- val to_int : t -> int
126126-124124+ @return The integer error code as defined in the JSON-RPC spec *)
125125+126126+ val to_message : t -> string
127127 (** Get error message for standard error codes
128128 @param code The error code to get message for
129129- @return A standard message for the error code
130130- *)
131131- val to_message : t -> string
129129+ @return A standard message for the error code *)
132130end
133131134132(** MCP Protocol Methods - Algebraic data type representing all MCP methods *)
···136134 (** Method type representing all MCP protocol methods *)
137135 type t =
138136 (* Initialization and lifecycle methods *)
139139- | Initialize (** Start the MCP lifecycle *)
140140- | Initialized (** Signal readiness after initialization *)
141141-137137+ | Initialize (** Start the MCP lifecycle *)
138138+ | Initialized (** Signal readiness after initialization *)
142139 (* Resource methods *)
143143- | ResourcesList (** Discover available resources *)
144144- | ResourcesRead (** Retrieve resource contents *)
140140+ | ResourcesList (** Discover available resources *)
141141+ | ResourcesRead (** Retrieve resource contents *)
145142 | ResourceTemplatesList (** List available resource templates *)
146146- | ResourcesSubscribe (** Subscribe to resource changes *)
147147- | ResourcesListChanged (** Resource list has changed *)
148148- | ResourcesUpdated (** Resource has been updated *)
149149-143143+ | ResourcesSubscribe (** Subscribe to resource changes *)
144144+ | ResourcesListChanged (** Resource list has changed *)
145145+ | ResourcesUpdated (** Resource has been updated *)
150146 (* Tool methods *)
151151- | ToolsList (** Discover available tools *)
152152- | ToolsCall (** Invoke a tool *)
153153- | ToolsListChanged (** Tool list has changed *)
154154-147147+ | ToolsList (** Discover available tools *)
148148+ | ToolsCall (** Invoke a tool *)
149149+ | ToolsListChanged (** Tool list has changed *)
155150 (* Prompt methods *)
156156- | PromptsList (** Discover available prompts *)
157157- | PromptsGet (** Retrieve a prompt template with arguments *)
158158- | PromptsListChanged (** Prompt list has changed *)
159159-151151+ | PromptsList (** Discover available prompts *)
152152+ | PromptsGet (** Retrieve a prompt template with arguments *)
153153+ | PromptsListChanged (** Prompt list has changed *)
160154 (* Progress notifications *)
161161- | Progress (** Progress update for long-running operations *)
162162-155155+ | Progress (** Progress update for long-running operations *)
156156+157157+ val to_string : t -> string
163158 (** Convert method type to string representation
164159 @param meth The method to convert
165165- @return The string representation of the method (e.g., "initialize", "resources/list")
166166- *)
167167- val to_string : t -> string
168168-160160+ @return
161161+ The string representation of the method (e.g., "initialize",
162162+ "resources/list") *)
163163+164164+ val of_string : string -> t
169165 (** Convert string to method type
170166 @param s The string representation of the method
171167 @return The corresponding method type
172172- @raise Failure if the string is not a valid MCP method
173173- *)
174174- val of_string : string -> t
168168+ @raise Failure if the string is not a valid MCP method *)
175169end
176176-177170178171(** Common types *)
179172180173(** Roles for conversation participants *)
181174module Role : sig
182182- (** Role represents conversation participants in MCP messages.
183183- Roles can be either 'user' or 'assistant', determining the
184184- source of each message in a conversation. *)
185175 type t = [ `User | `Assistant ]
176176+ (** Role represents conversation participants in MCP messages. Roles can be
177177+ either 'user' or 'assistant', determining the source of each message in a
178178+ conversation. *)
179179+186180 include Json.Jsonable.S with type t := t
187181end
188182189183(** Progress tokens for long-running operations *)
190184module ProgressToken : sig
191191- (** Progress tokens identify long-running operations and enable
192192- servers to provide progress updates to clients. This is used
193193- to track operations that may take significant time to complete. *)
194185 type t = [ `String of string | `Int of int ]
186186+ (** Progress tokens identify long-running operations and enable servers to
187187+ provide progress updates to clients. This is used to track operations that
188188+ may take significant time to complete. *)
189189+195190 include Json.Jsonable.S with type t := t
196191end
197192198193(** Request IDs *)
199194module RequestId : sig
200200- (** Request IDs uniquely identify JSON-RPC requests, allowing responses
201201- to be correlated with their originating requests. They can be either
202202- string or integer values. *)
203195 type t = [ `String of string | `Int of int ]
196196+ (** Request IDs uniquely identify JSON-RPC requests, allowing responses to be
197197+ correlated with their originating requests. They can be either string or
198198+ integer values. *)
199199+204200 include Json.Jsonable.S with type t := t
205201end
206202207203(** Cursors for pagination *)
208204module Cursor : sig
209209- (** Cursors enable pagination in list operations for resources, tools, and prompts.
210210- When a server has more items than can be returned in a single response,
211211- it provides a cursor for the client to retrieve subsequent pages. *)
212205 type t = string
206206+ (** Cursors enable pagination in list operations for resources, tools, and
207207+ prompts. When a server has more items than can be returned in a single
208208+ response, it provides a cursor for the client to retrieve subsequent
209209+ pages. *)
210210+213211 include Json.Jsonable.S with type t := t
214212end
215213216214(** Annotations for objects *)
217215module Annotated : sig
218218- (** Annotations provide metadata for content objects, allowing
219219- role-specific targeting and priority settings. *)
220220- type t = {
221221- annotations: annotation option;
222222- }
216216+ type t = { annotations : annotation option }
217217+ (** Annotations provide metadata for content objects, allowing role-specific
218218+ targeting and priority settings. *)
219219+223220 and annotation = {
224224- audience: Role.t list option;
225225- (** Optional list of roles that should receive this content *)
226226- priority: float option;
227227- (** Optional priority value for this content *)
221221+ audience : Role.t list option;
222222+ (** Optional list of roles that should receive this content *)
223223+ priority : float option; (** Optional priority value for this content *)
228224 }
225225+229226 include Json.Jsonable.S with type t := t
230227end
231228232229(** Text content - Core textual message representation in MCP *)
233230module TextContent : sig
234234- (** TextContent represents plain text messages in MCP conversations.
235235- This is the most common content type used for natural language interactions
236236- between users and assistants. Text content is used in prompts, tool results,
237237- and model responses.
238238-231231+ type t = {
232232+ text : string; (** The actual text content as a UTF-8 encoded string *)
233233+ annotations : Annotated.annotation option;
234234+ (** Optional annotations for audience targeting and priority.
235235+ Annotations can restrict content visibility to specific roles
236236+ (user/assistant) and indicate relative importance of different
237237+ content elements. *)
238238+ }
239239+ (** TextContent represents plain text messages in MCP conversations. This is
240240+ the most common content type used for natural language interactions
241241+ between users and assistants. Text content is used in prompts, tool
242242+ results, and model responses.
243243+239244 In JSON-RPC, this is represented as:
240245 {v
241246 {
···243248 "text": "The text content of the message"
244249 }
245250 v}
246246-251251+247252 For security, implementations must sanitize text content to prevent
248253 injection attacks or unauthorized access to resources. *)
249249- type t = {
250250- text: string;
251251- (** The actual text content as a UTF-8 encoded string *)
252252- annotations: Annotated.annotation option;
253253- (** Optional annotations for audience targeting and priority.
254254- Annotations can restrict content visibility to specific roles (user/assistant)
255255- and indicate relative importance of different content elements. *)
256256- }
254254+257255 include Json.Jsonable.S with type t := t
258256end
259257260258(** Image content - Visual data representation in MCP *)
261259module ImageContent : sig
260260+ type t = {
261261+ data : string;
262262+ (** Base64-encoded image data. All binary image data must be encoded
263263+ using standard base64 encoding (RFC 4648) to safely transmit within
264264+ JSON. *)
265265+ mime_type : string;
266266+ (** MIME type of the image (e.g., "image/png", "image/jpeg",
267267+ "image/gif", "image/svg+xml"). This field is required and must
268268+ accurately represent the image format to ensure proper handling by
269269+ clients. *)
270270+ annotations : Annotated.annotation option;
271271+ (** Optional annotations for audience targeting and priority.
272272+ Annotations can restrict content visibility to specific roles
273273+ (user/assistant) and indicate relative importance of different
274274+ content elements. *)
275275+ }
262276 (** ImageContent enables including visual information in MCP messages,
263277 supporting multimodal interactions where visual context is important.
264264-278278+265279 Images can be used in several scenarios:
266280 - As user inputs for visual understanding tasks
267281 - As context for generating descriptions or analysis
268282 - As outputs from tools that generate visualizations
269283 - As part of prompt templates with visual components
270270-284284+271285 In JSON-RPC, this is represented as:
272286 {v
273287 {
···276290 "mimeType": "image/png"
277291 }
278292 v}
279279-293293+280294 The data MUST be base64-encoded to ensure safe transmission in JSON.
281281- Common mime types include image/png, image/jpeg, image/gif, and image/svg+xml. *)
282282- type t = {
283283- data: string;
284284- (** Base64-encoded image data. All binary image data must be encoded using
285285- standard base64 encoding (RFC 4648) to safely transmit within JSON. *)
286286- mime_type: string;
287287- (** MIME type of the image (e.g., "image/png", "image/jpeg", "image/gif", "image/svg+xml").
288288- This field is required and must accurately represent the image format to ensure
289289- proper handling by clients. *)
290290- annotations: Annotated.annotation option;
291291- (** Optional annotations for audience targeting and priority.
292292- Annotations can restrict content visibility to specific roles (user/assistant)
293293- and indicate relative importance of different content elements. *)
294294- }
295295+ Common mime types include image/png, image/jpeg, image/gif, and
296296+ image/svg+xml. *)
297297+295298 include Json.Jsonable.S with type t := t
296299end
297300298301(** Audio content - Sound data representation in MCP *)
299302module AudioContent : sig
303303+ type t = {
304304+ data : string;
305305+ (** Base64-encoded audio data. All binary audio data must be encoded
306306+ using standard base64 encoding (RFC 4648) to safely transmit within
307307+ JSON. *)
308308+ mime_type : string;
309309+ (** MIME type of the audio (e.g., "audio/wav", "audio/mp3", "audio/ogg",
310310+ "audio/mpeg"). This field is required and must accurately represent
311311+ the audio format to ensure proper handling by clients. *)
312312+ annotations : Annotated.annotation option;
313313+ (** Optional annotations for audience targeting and priority.
314314+ Annotations can restrict content visibility to specific roles
315315+ (user/assistant) and indicate relative importance of different
316316+ content elements. *)
317317+ }
300318 (** AudioContent enables including audio information in MCP messages,
301319 supporting multimodal interactions where audio context is important.
302302-320320+303321 Audio can be used in several scenarios:
304322 - As user inputs for speech recognition or audio analysis
305323 - As context for transcription or sound classification tasks
306324 - As outputs from tools that generate audio samples
307325 - As part of prompt templates with audio components
308308-326326+309327 In JSON-RPC, this is represented as:
310328 {v
311329 {
···314332 "mimeType": "audio/wav"
315333 }
316334 v}
317317-335335+318336 The data MUST be base64-encoded to ensure safe transmission in JSON.
319319- Common mime types include audio/wav, audio/mp3, audio/ogg, and audio/mpeg. *)
320320- type t = {
321321- data: string;
322322- (** Base64-encoded audio data. All binary audio data must be encoded using
323323- standard base64 encoding (RFC 4648) to safely transmit within JSON. *)
324324- mime_type: string;
325325- (** MIME type of the audio (e.g., "audio/wav", "audio/mp3", "audio/ogg", "audio/mpeg").
326326- This field is required and must accurately represent the audio format to ensure
327327- proper handling by clients. *)
328328- annotations: Annotated.annotation option;
329329- (** Optional annotations for audience targeting and priority.
330330- Annotations can restrict content visibility to specific roles (user/assistant)
331331- and indicate relative importance of different content elements. *)
332332- }
337337+ Common mime types include audio/wav, audio/mp3, audio/ogg, and audio/mpeg.
338338+ *)
339339+333340 include Json.Jsonable.S with type t := t
334341end
335342336343(** Base resource contents - Core resource metadata in MCP *)
337344module ResourceContents : sig
338338- (** ResourceContents provides basic metadata for resources in MCP.
339339-340340- Resources are server-exposed data that provides context to language models,
341341- such as files, database schemas, or application-specific information.
342342- Each resource is uniquely identified by a URI.
343343-344344- The MCP resources architecture is designed to be application-driven, with
345345- host applications determining how to incorporate context based on their needs.
346346-347347- In the protocol, resources are discovered via the 'resources/list' endpoint
348348- and retrieved via the 'resources/read' endpoint. Servers that support resources
349349- must declare the 'resources' capability during initialization. *)
350345 type t = {
351351- uri: string;
352352- (** URI that uniquely identifies the resource.
353353-354354- Resources use standard URI schemes including:
355355- - file:// - For filesystem-like resources
356356- - https:// - For web-accessible resources
357357- - git:// - For version control integration
358358-359359- The URI serves as a stable identifier even if the underlying content changes. *)
360360- mime_type: string option;
361361- (** Optional MIME type of the resource content to aid in client rendering.
362362- Common MIME types include text/plain, application/json, image/png, etc.
363363- For directories, the XDG MIME type inode/directory may be used. *)
346346+ uri : string;
347347+ (** URI that uniquely identifies the resource.
348348+349349+ Resources use standard URI schemes including:
350350+ - file:// - For filesystem-like resources
351351+ - https:// - For web-accessible resources
352352+ - git:// - For version control integration
353353+354354+ The URI serves as a stable identifier even if the underlying content
355355+ changes. *)
356356+ mime_type : string option;
357357+ (** Optional MIME type of the resource content to aid in client
358358+ rendering. Common MIME types include text/plain, application/json,
359359+ image/png, etc. For directories, the XDG MIME type inode/directory
360360+ may be used. *)
364361 }
362362+ (** ResourceContents provides basic metadata for resources in MCP.
363363+364364+ Resources are server-exposed data that provides context to language
365365+ models, such as files, database schemas, or application-specific
366366+ information. Each resource is uniquely identified by a URI.
367367+368368+ The MCP resources architecture is designed to be application-driven, with
369369+ host applications determining how to incorporate context based on their
370370+ needs.
371371+372372+ In the protocol, resources are discovered via the 'resources/list'
373373+ endpoint and retrieved via the 'resources/read' endpoint. Servers that
374374+ support resources must declare the 'resources' capability during
375375+ initialization. *)
376376+365377 include Json.Jsonable.S with type t := t
366378end
367379368380(** Text resource contents - Textual resource data *)
369381module TextResourceContents : sig
382382+ type t = {
383383+ uri : string;
384384+ (** URI that uniquely identifies the resource. This URI can be
385385+ referenced in subsequent requests to fetch updates. *)
386386+ text : string;
387387+ (** The actual text content of the resource as a UTF-8 encoded string.
388388+ This may be sanitized by the server to remove sensitive information.
389389+ *)
390390+ mime_type : string option;
391391+ (** Optional MIME type of the text content to aid in client rendering.
392392+ Common text MIME types include: text/plain, text/markdown,
393393+ text/x-python, application/json, text/html, text/csv, etc. *)
394394+ }
370395 (** TextResourceContents represents a text-based resource in MCP.
371371-396396+372397 Text resources are used for sharing code snippets, documentation, logs,
373398 configuration files, and other textual information with language models.
374374-399399+375400 The server handles access control and security, ensuring that only
376401 authorized resources are shared with clients.
377377-402402+378403 In JSON-RPC, this is represented as:
379404 {v
380405 {
···382407 "mimeType": "text/plain",
383408 "text": "Resource content"
384409 }
385385- v}
386386- *)
387387- type t = {
388388- uri: string;
389389- (** URI that uniquely identifies the resource.
390390- This URI can be referenced in subsequent requests to fetch updates. *)
391391- text: string;
392392- (** The actual text content of the resource as a UTF-8 encoded string.
393393- This may be sanitized by the server to remove sensitive information. *)
394394- mime_type: string option;
395395- (** Optional MIME type of the text content to aid in client rendering.
396396- Common text MIME types include: text/plain, text/markdown, text/x-python,
397397- application/json, text/html, text/csv, etc. *)
398398- }
410410+ v} *)
411411+399412 include Json.Jsonable.S with type t := t
400413end
401414402415(** Binary resource contents - Binary resource data *)
403416module BlobResourceContents : sig
417417+ type t = {
418418+ uri : string;
419419+ (** URI that uniquely identifies the resource. This URI can be
420420+ referenced in subsequent requests to fetch updates. *)
421421+ blob : string;
422422+ (** Base64-encoded binary data using standard base64 encoding (RFC
423423+ 4648). This encoding ensures that binary data can be safely
424424+ transmitted in JSON. *)
425425+ mime_type : string option;
426426+ (** Optional MIME type of the binary content to aid in client rendering.
427427+ Common binary MIME types include: image/png, image/jpeg,
428428+ application/pdf, audio/wav, video/mp4, application/octet-stream,
429429+ etc. *)
430430+ }
404431 (** BlobResourceContents represents a binary resource in MCP.
405405-432432+406433 Binary resources allow sharing non-textual data like images, audio files,
407407- PDFs, and other binary formats with language models that support processing
408408- such content.
409409-434434+ PDFs, and other binary formats with language models that support
435435+ processing such content.
436436+410437 In JSON-RPC, this is represented as:
411438 {v
412439 {
···415442 "blob": "base64-encoded-data"
416443 }
417444 v}
418418-419419- Binary data MUST be properly base64-encoded to ensure safe transmission
420420- in JSON payloads. *)
421421- type t = {
422422- uri: string;
423423- (** URI that uniquely identifies the resource.
424424- This URI can be referenced in subsequent requests to fetch updates. *)
425425- blob: string;
426426- (** Base64-encoded binary data using standard base64 encoding (RFC 4648).
427427- This encoding ensures that binary data can be safely transmitted in JSON. *)
428428- mime_type: string option;
429429- (** Optional MIME type of the binary content to aid in client rendering.
430430- Common binary MIME types include: image/png, image/jpeg, application/pdf,
431431- audio/wav, video/mp4, application/octet-stream, etc. *)
432432- }
445445+446446+ Binary data MUST be properly base64-encoded to ensure safe transmission in
447447+ JSON payloads. *)
448448+433449 include Json.Jsonable.S with type t := t
434450end
435451436452(** Embedded resource - Resource included directly in messages *)
437453module EmbeddedResource : sig
438438- (** EmbeddedResource allows referencing server-side resources directly
439439- in MCP messages, enabling seamless incorporation of managed content.
440440-454454+ type t = {
455455+ resource :
456456+ [ `Text of TextResourceContents.t | `Blob of BlobResourceContents.t ];
457457+ (** The resource content, either as text or binary blob. *)
458458+ annotations : Annotated.annotation option;
459459+ (** Optional annotations for audience targeting and priority.
460460+ Annotations can restrict resource visibility to specific roles
461461+ (user/assistant) and indicate relative importance of different
462462+ content elements. *)
463463+ }
464464+ (** EmbeddedResource allows referencing server-side resources directly in MCP
465465+ messages, enabling seamless incorporation of managed content.
466466+441467 Embedded resources can be included in:
442468 - Tool results to provide rich context
443469 - Prompt templates to include reference materials
444470 - Messages to provide additional context to language models
445445-471471+446472 In contrast to direct content (TextContent, ImageContent, AudioContent),
447447- embedded resources have the advantage of being persistently stored on the server
448448- with a stable URI, allowing later retrieval and updates through the resources API.
449449-450450- For example, a tool might return an embedded resource containing a chart or
451451- a large dataset that the client can later reference or update. *)
452452- type t = {
453453- resource: [ `Text of TextResourceContents.t | `Blob of BlobResourceContents.t ];
454454- (** The resource content, either as text or binary blob. *)
455455- annotations: Annotated.annotation option;
456456- (** Optional annotations for audience targeting and priority.
457457- Annotations can restrict resource visibility to specific roles (user/assistant)
458458- and indicate relative importance of different content elements. *)
459459- }
473473+ embedded resources have the advantage of being persistently stored on the
474474+ server with a stable URI, allowing later retrieval and updates through the
475475+ resources API.
476476+477477+ For example, a tool might return an embedded resource containing a chart
478478+ or a large dataset that the client can later reference or update. *)
479479+460480 include Json.Jsonable.S with type t := t
461481end
462482463463-(** Content type used in messages - Unified multimodal content representation in MCP *)
464464-type content =
465465- | Text of TextContent.t (** Text content for natural language messages. This is the most common content type for user-assistant interactions. *)
466466- | Image of ImageContent.t (** Image content for visual data. Used for sharing visual context in multimodal conversations. *)
467467- | Audio of AudioContent.t (** Audio content for audio data. Used for sharing audio context in multimodal conversations. *)
468468- | Resource of EmbeddedResource.t (** Resource content for referencing server-side resources. Used for incorporating managed server content with stable URIs. *)
483483+(** Content type used in messages - Unified multimodal content representation in
484484+ MCP *)
485485+type content =
486486+ | Text of TextContent.t
487487+ (** Text content for natural language messages. This is the most common
488488+ content type for user-assistant interactions. *)
489489+ | Image of ImageContent.t
490490+ (** Image content for visual data. Used for sharing visual context in
491491+ multimodal conversations. *)
492492+ | Audio of AudioContent.t
493493+ (** Audio content for audio data. Used for sharing audio context in
494494+ multimodal conversations. *)
495495+ | Resource of EmbeddedResource.t
496496+ (** Resource content for referencing server-side resources. Used for
497497+ incorporating managed server content with stable URIs. *)
469498470470-(** Convert content to Yojson representation
471471- @param content The content to convert
472472- @return JSON representation of the content
473473-*)
474499val yojson_of_content : content -> Json.t
500500+(** Convert content to Yojson representation
501501+ @param content The content to convert
502502+ @return JSON representation of the content *)
475503476476-(** Convert Yojson representation to content
477477- @param json JSON representation of content
478478- @return Parsed content object
479479-*)
480504val content_of_yojson : Json.t -> content
505505+(** Convert Yojson representation to content
506506+ @param json JSON representation of content
507507+ @return Parsed content object *)
481508482509(** Message for prompts - Template messages in the MCP prompts feature *)
483510module PromptMessage : sig
484484- (** PromptMessage represents a message in an MCP prompt template,
485485- containing a role and content which can be customized with arguments.
486486-511511+ type t = {
512512+ role : Role.t;
513513+ (** The role of the message sender (user or assistant). Prompt templates
514514+ typically alternate between user and assistant messages to create a
515515+ conversation structure. *)
516516+ content : content;
517517+ (** The message content, which can be text, image, audio, or resource.
518518+ This unified content type supports rich multimodal prompts. *)
519519+ }
520520+ (** PromptMessage represents a message in an MCP prompt template, containing a
521521+ role and content which can be customized with arguments.
522522+487523 Prompt messages are part of prompt templates exposed by servers through
488524 the prompts/get endpoint. They define structured conversation templates
489525 that can be instantiated with user-provided arguments.
490490-491491- The prompt feature is designed to be user-controlled, with prompts typically
492492- exposed through UI elements like slash commands that users can explicitly select.
493493-526526+527527+ The prompt feature is designed to be user-controlled, with prompts
528528+ typically exposed through UI elements like slash commands that users can
529529+ explicitly select.
530530+494531 In JSON-RPC, prompt messages are represented as:
495532 {v
496533 {
···501538 }
502539 }
503540 v}
504504-541541+505542 Where $code would be replaced with a user-provided argument. *)
506506- type t = {
507507- role: Role.t;
508508- (** The role of the message sender (user or assistant).
509509- Prompt templates typically alternate between user and assistant messages
510510- to create a conversation structure. *)
511511- content: content;
512512- (** The message content, which can be text, image, audio, or resource.
513513- This unified content type supports rich multimodal prompts. *)
514514- }
543543+515544 include Json.Jsonable.S with type t := t
516545end
517546518547(** Message for sampling - Messages used in LLM completion requests *)
519548module SamplingMessage : sig
520520- (** SamplingMessage represents a message in an MCP sampling request,
521521- used for AI model generation based on a prompt.
522522-549549+ type t = {
550550+ role : Role.t;
551551+ (** The role of the message sender (user or assistant). Typically, a
552552+ sampling request will contain multiple messages representing a
553553+ conversation history, with alternating roles. *)
554554+ content :
555555+ [ `Text of TextContent.t
556556+ | `Image of ImageContent.t
557557+ | `Audio of AudioContent.t ];
558558+ (** The message content, restricted to text, image, or audio (no
559559+ resources). Resources are not included since sampling messages
560560+ represent the actual context window for the LLM, not template
561561+ definitions. *)
562562+ }
563563+ (** SamplingMessage represents a message in an MCP sampling request, used for
564564+ AI model generation based on a prompt.
565565+523566 The sampling feature allows clients to expose language model capabilities
524567 to servers, enabling servers to request completions from the client's LLM.
525568 This is effectively the reverse of the normal MCP flow, with the server
526569 requesting generative capabilities from the client.
527527-570570+528571 Sampling messages differ from prompt messages in that they don't support
529529- embedded resources, as they represent the actual context window being
530530- sent to the LLM rather than template definitions.
531531-572572+ embedded resources, as they represent the actual context window being sent
573573+ to the LLM rather than template definitions.
574574+532575 Clients that support sampling must declare the 'sampling' capability
533576 during initialization. *)
534534- type t = {
535535- role: Role.t;
536536- (** The role of the message sender (user or assistant).
537537- Typically, a sampling request will contain multiple messages
538538- representing a conversation history, with alternating roles. *)
539539- content: [ `Text of TextContent.t | `Image of ImageContent.t | `Audio of AudioContent.t ];
540540- (** The message content, restricted to text, image, or audio (no resources).
541541- Resources are not included since sampling messages represent the
542542- actual context window for the LLM, not template definitions. *)
543543- }
577577+544578 include Json.Jsonable.S with type t := t
545579end
546580547581(** Implementation information *)
548582module Implementation : sig
583583+ type t = {
584584+ name : string; (** Name of the implementation *)
585585+ version : string; (** Version of the implementation *)
586586+ }
549587 (** Implementation provides metadata about client and server implementations,
550588 used during the initialization phase to identify each party. *)
551551- type t = {
552552- name: string;
553553- (** Name of the implementation *)
554554- version: string;
555555- (** Version of the implementation *)
556556- }
589589+557590 include Json.Jsonable.S with type t := t
558591end
559592560593(** JSONRPC message types - Core message protocol for MCP
561594562562- MCP uses JSON-RPC 2.0 as its underlying messaging protocol.
563563- All MCP messages are encoded as JSON-RPC 2.0 messages with UTF-8 encoding,
564564- following the standard JSON-RPC message formats with some MCP-specific extensions.
565565-566566- MCP defines four message types:
567567- 1. Notifications: One-way messages that don't expect a response
568568- 2. Requests: Messages that expect a corresponding response
569569- 3. Responses: Replies to requests with successful results
570570- 4. Errors: Replies to requests with error information
571571-595595+ MCP uses JSON-RPC 2.0 as its underlying messaging protocol. All MCP messages
596596+ are encoded as JSON-RPC 2.0 messages with UTF-8 encoding, following the
597597+ standard JSON-RPC message formats with some MCP-specific extensions.
598598+599599+ MCP defines four message types: 1. Notifications: One-way messages that
600600+ don't expect a response 2. Requests: Messages that expect a corresponding
601601+ response 3. Responses: Replies to requests with successful results 4.
602602+ Errors: Replies to requests with error information
603603+572604 These can be transported over multiple transport mechanisms:
573605 - stdio: Communication over standard input/output
574606 - Streamable HTTP: HTTP POST/GET with SSE for server streaming
575607 - Custom transports: Implementation-specific transports
576576-577577- Messages may be sent individually or as part of a JSON-RPC batch.
578578-*)
608608+609609+ Messages may be sent individually or as part of a JSON-RPC batch. *)
579610module JSONRPCMessage : sig
580580- (** Notification represents a JSON-RPC notification (one-way message without a response).
581581-611611+ type notification = {
612612+ meth : Method.t;
613613+ (** Method for the notification, using the Method.t type to ensure type
614614+ safety. Examples: Method.Initialized, Method.ResourcesUpdated *)
615615+ params : Json.t option;
616616+ (** Optional parameters for the notification as arbitrary JSON. The
617617+ structure depends on the specific notification method. *)
618618+ }
619619+ (** Notification represents a JSON-RPC notification (one-way message without a
620620+ response).
621621+582622 Notifications are used for events that don't require a response, such as:
583623 - The 'initialized' notification completing initialization
584624 - Resource change notifications
585625 - Progress updates for long-running operations
586626 - List changed notifications for tools, resources, and prompts
587587-627627+588628 In JSON-RPC, notifications are identified by the absence of an 'id' field:
589629 {v
590630 {
···594634 "uri": "file:///project/src/main.rs"
595635 }
596636 }
597597- v}
598598- *)
599599- type notification = {
600600- meth: Method.t;
601601- (** Method for the notification, using the Method.t type to ensure type safety.
602602- Examples: Method.Initialized, Method.ResourcesUpdated *)
603603- params: Json.t option;
604604- (** Optional parameters for the notification as arbitrary JSON.
605605- The structure depends on the specific notification method. *)
606606- }
637637+ v} *)
607638639639+ type request = {
640640+ id : RequestId.t;
641641+ (** Unique identifier for the request, which will be echoed in the
642642+ response. This can be a string or integer and should be unique
643643+ within the session. *)
644644+ meth : Method.t;
645645+ (** Method for the request, using the Method.t type to ensure type
646646+ safety. Examples: Method.Initialize, Method.ResourcesRead,
647647+ Method.ToolsCall *)
648648+ params : Json.t option;
649649+ (** Optional parameters for the request as arbitrary JSON. The structure
650650+ depends on the specific request method. *)
651651+ progress_token : ProgressToken.t option;
652652+ (** Optional progress token for long-running operations. If provided,
653653+ the server can send progress notifications using this token to
654654+ inform the client about the operation's status. *)
655655+ }
608656 (** Request represents a JSON-RPC request that expects a response.
609609-657657+610658 Requests are used for operations that require a response, such as:
611659 - Initialization
612660 - Listing resources, tools, or prompts
613661 - Reading resources
614662 - Calling tools
615663 - Getting prompts
616616-617617- In JSON-RPC, requests include an 'id' field that correlates with the response:
664664+665665+ In JSON-RPC, requests include an 'id' field that correlates with the
666666+ response:
618667 {v
619668 {
620669 "jsonrpc": "2.0",
···624673 "uri": "file:///project/src/main.rs"
625674 }
626675 }
627627- v}
628628- *)
629629- type request = {
630630- id: RequestId.t;
631631- (** Unique identifier for the request, which will be echoed in the response.
632632- This can be a string or integer and should be unique within the session. *)
633633- meth: Method.t;
634634- (** Method for the request, using the Method.t type to ensure type safety.
635635- Examples: Method.Initialize, Method.ResourcesRead, Method.ToolsCall *)
636636- params: Json.t option;
637637- (** Optional parameters for the request as arbitrary JSON.
638638- The structure depends on the specific request method. *)
639639- progress_token: ProgressToken.t option;
640640- (** Optional progress token for long-running operations.
641641- If provided, the server can send progress notifications using this token
642642- to inform the client about the operation's status. *)
643643- }
676676+ v} *)
644677678678+ type response = {
679679+ id : RequestId.t;
680680+ (** ID matching the original request, allowing clients to correlate
681681+ responses with their originating requests, especially important when
682682+ multiple requests are in flight. *)
683683+ result : Json.t;
684684+ (** Result of the successful request as arbitrary JSON. The structure
685685+ depends on the specific request method that was called. *)
686686+ }
645687 (** Response represents a successful JSON-RPC response to a request.
646646-688688+647689 Responses are sent in reply to requests and contain the successful result.
648690 Each response must include the same ID as its corresponding request.
649649-691691+650692 In JSON-RPC, responses include the 'id' field matching the request:
651693 {v
652694 {
···662704 ]
663705 }
664706 }
665665- v}
666666- *)
667667- type response = {
668668- id: RequestId.t;
669669- (** ID matching the original request, allowing clients to correlate
670670- responses with their originating requests, especially important
671671- when multiple requests are in flight. *)
672672- result: Json.t;
673673- (** Result of the successful request as arbitrary JSON.
674674- The structure depends on the specific request method that was called. *)
675675- }
707707+ v} *)
676708709709+ type error = {
710710+ id : RequestId.t;
711711+ (** ID matching the original request, allowing clients to correlate
712712+ errors with their originating requests. *)
713713+ code : int;
714714+ (** Error code indicating the type of error, following the JSON-RPC
715715+ standard. Common codes include:
716716+ - -32700: Parse error
717717+ - -32600: Invalid request
718718+ - -32601: Method not found
719719+ - -32602: Invalid params
720720+ - -32603: Internal error
721721+ - -32002: Resource not found (MCP-specific)
722722+ - -32001: Authentication required (MCP-specific) *)
723723+ message : string;
724724+ (** Human-readable error message describing the issue. This should be
725725+ concise but informative enough for debugging. *)
726726+ data : Json.t option;
727727+ (** Optional additional error data as arbitrary JSON. This can provide
728728+ more context about the error, such as which resource wasn't found or
729729+ which parameter was invalid. *)
730730+ }
677731 (** Error represents an error response to a JSON-RPC request.
678678-679679- Errors are sent in reply to requests when processing fails.
680680- Each error must include the same ID as its corresponding request.
681681-732732+733733+ Errors are sent in reply to requests when processing fails. Each error
734734+ must include the same ID as its corresponding request.
735735+682736 MCP defines several standard error codes:
683737 - Standard JSON-RPC errors (-32700 to -32603)
684738 - MCP-specific errors (-32002 for resource not found, etc.)
685685-739739+686740 In JSON-RPC, errors follow this structure:
687741 {v
688742 {
···696750 }
697751 }
698752 }
699699- v}
700700- *)
701701- type error = {
702702- id: RequestId.t;
703703- (** ID matching the original request, allowing clients to correlate
704704- errors with their originating requests. *)
705705- code: int;
706706- (** Error code indicating the type of error, following the JSON-RPC standard.
707707- Common codes include:
708708- - -32700: Parse error
709709- - -32600: Invalid request
710710- - -32601: Method not found
711711- - -32602: Invalid params
712712- - -32603: Internal error
713713- - -32002: Resource not found (MCP-specific)
714714- - -32001: Authentication required (MCP-specific) *)
715715- message: string;
716716- (** Human-readable error message describing the issue.
717717- This should be concise but informative enough for debugging. *)
718718- data: Json.t option;
719719- (** Optional additional error data as arbitrary JSON.
720720- This can provide more context about the error, such as which
721721- resource wasn't found or which parameter was invalid. *)
722722- }
753753+ v} *)
723754724724- (** Union type for all JSON-RPC message kinds, providing a single type
725725- that can represent any MCP message. *)
755755+ (** Union type for all JSON-RPC message kinds, providing a single type that
756756+ can represent any MCP message. *)
726757 type t =
727758 | Notification of notification
728759 | Request of request
729760 | Response of response
730761 | Error of error
731762732732- (** Convert notification to Yojson representation
733733- @param notification The notification to convert
734734- @return JSON representation of the notification
735735- *)
736763 val yojson_of_notification : notification -> Json.t
737737-738738- (** Convert request to Yojson representation
739739- @param request The request to convert
740740- @return JSON representation of the request
741741- *)
764764+ (** Convert notification to Yojson representation
765765+ @param notification The notification to convert
766766+ @return JSON representation of the notification *)
767767+742768 val yojson_of_request : request -> Json.t
743743-744744- (** Convert response to Yojson representation
745745- @param response The response to convert
746746- @return JSON representation of the response
747747- *)
769769+ (** Convert request to Yojson representation
770770+ @param request The request to convert
771771+ @return JSON representation of the request *)
772772+748773 val yojson_of_response : response -> Json.t
749749-750750- (** Convert error to Yojson representation
751751- @param error The error to convert
752752- @return JSON representation of the error
753753- *)
774774+ (** Convert response to Yojson representation
775775+ @param response The response to convert
776776+ @return JSON representation of the response *)
777777+754778 val yojson_of_error : error -> Json.t
755755-756756- (** Convert any message to Yojson representation
757757- @param message The message to convert
758758- @return JSON representation of the message
759759- *)
779779+ (** Convert error to Yojson representation
780780+ @param error The error to convert
781781+ @return JSON representation of the error *)
782782+760783 val yojson_of_t : t -> Json.t
784784+ (** Convert any message to Yojson representation
785785+ @param message The message to convert
786786+ @return JSON representation of the message *)
761787762762- (** Convert Yojson representation to notification
788788+ val notification_of_yojson : Json.t -> notification
789789+ (** Convert Yojson representation to notification
763790 @param json JSON representation of a notification
764791 @return Parsed notification object
765765- @raise Parse error if the JSON is not a valid notification
766766- *)
767767- val notification_of_yojson : Json.t -> notification
768768-769769- (** Convert Yojson representation to request
792792+ @raise Parse error if the JSON is not a valid notification *)
793793+794794+ val request_of_yojson : Json.t -> request
795795+ (** Convert Yojson representation to request
770796 @param json JSON representation of a request
771797 @return Parsed request object
772772- @raise Parse error if the JSON is not a valid request
773773- *)
774774- val request_of_yojson : Json.t -> request
775775-776776- (** Convert Yojson representation to response
798798+ @raise Parse error if the JSON is not a valid request *)
799799+800800+ val response_of_yojson : Json.t -> response
801801+ (** Convert Yojson representation to response
777802 @param json JSON representation of a response
778803 @return Parsed response object
779779- @raise Parse error if the JSON is not a valid response
780780- *)
781781- val response_of_yojson : Json.t -> response
782782-783783- (** Convert Yojson representation to error
804804+ @raise Parse error if the JSON is not a valid response *)
805805+806806+ val error_of_yojson : Json.t -> error
807807+ (** Convert Yojson representation to error
784808 @param json JSON representation of an error
785809 @return Parsed error object
786786- @raise Parse error if the JSON is not a valid error
787787- *)
788788- val error_of_yojson : Json.t -> error
789789-790790- (** Convert Yojson representation to any message
810810+ @raise Parse error if the JSON is not a valid error *)
811811+812812+ val t_of_yojson : Json.t -> t
813813+ (** Convert Yojson representation to any message
791814 @param json JSON representation of any message type
792815 @return Parsed message object
793793- @raise Parse error if the JSON is not a valid message
794794- *)
795795- val t_of_yojson : Json.t -> t
816816+ @raise Parse error if the JSON is not a valid message *)
796817818818+ val create_notification : ?params:Json.t option -> meth:Method.t -> unit -> t
797819 (** Create a new notification message
798820 @param params Optional parameters for the notification
799821 @param meth Method name for the notification
800800- @return A new JSON-RPC notification message
801801- *)
802802- val create_notification : ?params:Json.t option -> meth:Method.t -> unit -> t
803803-822822+ @return A new JSON-RPC notification message *)
823823+824824+ val create_request :
825825+ ?params:Json.t option ->
826826+ ?progress_token:ProgressToken.t option ->
827827+ id:RequestId.t ->
828828+ meth:Method.t ->
829829+ unit ->
830830+ t
804831 (** Create a new request message
805832 @param params Optional parameters for the request
806833 @param progress_token Optional progress token for long-running operations
807834 @param id Unique identifier for the request
808835 @param meth Method name for the request
809809- @return A new JSON-RPC request message
810810- *)
811811- val create_request : ?params:Json.t option -> ?progress_token:ProgressToken.t option -> id:RequestId.t -> meth:Method.t -> unit -> t
812812-836836+ @return A new JSON-RPC request message *)
837837+838838+ val create_response : id:RequestId.t -> result:Json.t -> t
813839 (** Create a new response message
814840 @param id ID matching the original request
815841 @param result Result of the successful request
816816- @return A new JSON-RPC response message
817817- *)
818818- val create_response : id:RequestId.t -> result:Json.t -> t
819819-842842+ @return A new JSON-RPC response message *)
843843+844844+ val create_error :
845845+ id:RequestId.t ->
846846+ code:int ->
847847+ message:string ->
848848+ ?data:Json.t option ->
849849+ unit ->
850850+ t
820851 (** Create a new error message
821852 @param id ID matching the original request
822853 @param code Error code indicating the type of error
823854 @param message Human-readable error message
824855 @param data Optional additional error data
825825- @return A new JSON-RPC error message
826826- *)
827827- val create_error : id:RequestId.t -> code:int -> message:string -> ?data:Json.t option -> unit -> t
856856+ @return A new JSON-RPC error message *)
828857end
829858830830-(** Initialize request/response - The first phase of the MCP lifecycle
831831-832832- The initialization phase is the mandatory first interaction between client and server.
833833- During this phase, the protocol version is negotiated and capabilities are exchanged
834834- to determine which optional features will be available during the session.
835835-836836- This follows a strict sequence:
837837- 1. Client sends an InitializeRequest containing its capabilities and protocol version
838838- 2. Server responds with an InitializeResult containing its capabilities and protocol version
839839- 3. Client sends an InitializedNotification to signal it's ready for normal operations
840840-841841- The Initialize module handles steps 1 and 2 of this process.
842842-*)
859859+(** Initialize request/response - The first phase of the MCP lifecycle
860860+861861+ The initialization phase is the mandatory first interaction between client
862862+ and server. During this phase, the protocol version is negotiated and
863863+ capabilities are exchanged to determine which optional features will be
864864+ available during the session.
865865+866866+ This follows a strict sequence: 1. Client sends an InitializeRequest
867867+ containing its capabilities and protocol version 2. Server responds with an
868868+ InitializeResult containing its capabilities and protocol version 3. Client
869869+ sends an InitializedNotification to signal it's ready for normal operations
870870+871871+ The Initialize module handles steps 1 and 2 of this process. *)
843872module Initialize : sig
844873 (** Initialize request *)
845874 module Request : sig
846846- (** InitializeRequest starts the MCP lifecycle, negotiating capabilities
847847- and protocol versions between client and server. This is always the first
848848- message sent by the client and MUST NOT be part of a JSON-RPC batch.
849849-850850- The client SHOULD send the latest protocol version it supports. If the server
851851- does not support this version, it will respond with a version it does support,
852852- and the client must either use that version or disconnect. *)
853875 type t = {
854854- capabilities: Json.t; (** ClientCapabilities that define supported optional features.
855855- This includes which optional protocol features the client supports,
856856- such as 'roots' (filesystem access), 'sampling' (LLM generation),
857857- and any experimental features. *)
858858- client_info: Implementation.t;
859859- (** Client implementation details (name and version) used for identification
860860- and debugging. Helps servers understand which client they're working with. *)
861861- protocol_version: string;
862862- (** MCP protocol version supported by the client, formatted as YYYY-MM-DD
863863- according to the MCP versioning scheme. Example: "2025-03-26" *)
876876+ capabilities : Json.t;
877877+ (** ClientCapabilities that define supported optional features. This
878878+ includes which optional protocol features the client supports,
879879+ such as 'roots' (filesystem access), 'sampling' (LLM generation),
880880+ and any experimental features. *)
881881+ client_info : Implementation.t;
882882+ (** Client implementation details (name and version) used for
883883+ identification and debugging. Helps servers understand which
884884+ client they're working with. *)
885885+ protocol_version : string;
886886+ (** MCP protocol version supported by the client, formatted as
887887+ YYYY-MM-DD according to the MCP versioning scheme. Example:
888888+ "2025-03-26" *)
864889 }
890890+ (** InitializeRequest starts the MCP lifecycle, negotiating capabilities and
891891+ protocol versions between client and server. This is always the first
892892+ message sent by the client and MUST NOT be part of a JSON-RPC batch.
893893+894894+ The client SHOULD send the latest protocol version it supports. If the
895895+ server does not support this version, it will respond with a version it
896896+ does support, and the client must either use that version or disconnect.
897897+ *)
898898+865899 include Json.Jsonable.S with type t := t
866900901901+ val create :
902902+ capabilities:Json.t ->
903903+ client_info:Implementation.t ->
904904+ protocol_version:string ->
905905+ t
867906 (** Create a new initialization request
868868- @param capabilities Client capabilities that define supported optional features
907907+ @param capabilities
908908+ Client capabilities that define supported optional features
869909 @param client_info Client implementation details
870910 @param protocol_version MCP protocol version supported by the client
871871- @return A new initialization request
872872- *)
873873- val create : capabilities:Json.t -> client_info:Implementation.t -> protocol_version:string -> t
874874-911911+ @return A new initialization request *)
912912+913913+ val to_jsonrpc : id:RequestId.t -> t -> JSONRPCMessage.t
875914 (** Convert to JSON-RPC message
876915 @param id Unique request identifier
877916 @param t Initialization request
878878- @return JSON-RPC message containing the initialization request
879879- *)
880880- val to_jsonrpc : id:RequestId.t -> t -> JSONRPCMessage.t
917917+ @return JSON-RPC message containing the initialization request *)
881918 end
882919883920 (** Initialize result *)
884921 module Result : sig
885885- (** InitializeResult is the server's response to an initialization request,
886886- completing capability negotiation and establishing the protocol version.
887887-888888- After receiving this message, the client must send an InitializedNotification.
889889- The server should not send any requests other than pings and logging before
890890- receiving the initialized notification. *)
891922 type t = {
892892- capabilities: Json.t; (** ServerCapabilities that define supported optional features.
893893- This declares which server features are available, including:
894894- - prompts: Server provides prompt templates
895895- - resources: Server provides readable resources
896896- - tools: Server exposes callable tools
897897- - logging: Server emits structured log messages
898898-899899- Each capability may have sub-capabilities like:
900900- - listChanged: Server will notify when available items change
901901- - subscribe: Clients can subscribe to individual resources *)
902902- server_info: Implementation.t;
903903- (** Server implementation details (name and version) used for identification
904904- and debugging. Helps clients understand which server they're working with. *)
905905- protocol_version: string;
906906- (** MCP protocol version supported by the server, formatted as YYYY-MM-DD.
907907- If the server supports the client's requested version, it responds with
908908- the same version. Otherwise, it responds with a version it does support. *)
909909- instructions: string option;
910910- (** Optional instructions for using the server. These can provide human-readable
911911- guidance on how to interact with this specific server implementation. *)
912912- meta: Json.t option;
913913- (** Optional additional metadata as arbitrary JSON. Can contain server-specific
914914- information not covered by the standard fields. *)
923923+ capabilities : Json.t;
924924+ (** ServerCapabilities that define supported optional features. This
925925+ declares which server features are available, including:
926926+ - prompts: Server provides prompt templates
927927+ - resources: Server provides readable resources
928928+ - tools: Server exposes callable tools
929929+ - logging: Server emits structured log messages
930930+931931+ Each capability may have sub-capabilities like:
932932+ - listChanged: Server will notify when available items change
933933+ - subscribe: Clients can subscribe to individual resources *)
934934+ server_info : Implementation.t;
935935+ (** Server implementation details (name and version) used for
936936+ identification and debugging. Helps clients understand which
937937+ server they're working with. *)
938938+ protocol_version : string;
939939+ (** MCP protocol version supported by the server, formatted as
940940+ YYYY-MM-DD. If the server supports the client's requested version,
941941+ it responds with the same version. Otherwise, it responds with a
942942+ version it does support. *)
943943+ instructions : string option;
944944+ (** Optional instructions for using the server. These can provide
945945+ human-readable guidance on how to interact with this specific
946946+ server implementation. *)
947947+ meta : Json.t option;
948948+ (** Optional additional metadata as arbitrary JSON. Can contain
949949+ server-specific information not covered by the standard fields. *)
915950 }
951951+ (** InitializeResult is the server's response to an initialization request,
952952+ completing capability negotiation and establishing the protocol version.
953953+954954+ After receiving this message, the client must send an
955955+ InitializedNotification. The server should not send any requests other
956956+ than pings and logging before receiving the initialized notification. *)
957957+916958 include Json.Jsonable.S with type t := t
917959960960+ val create :
961961+ capabilities:Json.t ->
962962+ server_info:Implementation.t ->
963963+ protocol_version:string ->
964964+ ?instructions:string ->
965965+ ?meta:Json.t ->
966966+ unit ->
967967+ t
918968 (** Create a new initialization result
919919- @param capabilities Server capabilities that define supported optional features
969969+ @param capabilities
970970+ Server capabilities that define supported optional features
920971 @param server_info Server implementation details
921972 @param protocol_version MCP protocol version supported by the server
922973 @param instructions Optional instructions for using the server
923974 @param meta Optional additional metadata
924924- @return A new initialization result
925925- *)
926926- val create : capabilities:Json.t -> server_info:Implementation.t -> protocol_version:string -> ?instructions:string -> ?meta:Json.t -> unit -> t
927927-975975+ @return A new initialization result *)
976976+977977+ val to_jsonrpc : id:RequestId.t -> t -> JSONRPCMessage.t
928978 (** Convert to JSON-RPC message
929979 @param id ID matching the original request
930980 @param t Initialization result
931931- @return JSON-RPC message containing the initialization result
932932- *)
933933- val to_jsonrpc : id:RequestId.t -> t -> JSONRPCMessage.t
981981+ @return JSON-RPC message containing the initialization result *)
934982 end
935983end
936984937937-(** Initialized notification - Completes the initialization phase of the MCP lifecycle *)
985985+(** Initialized notification - Completes the initialization phase of the MCP
986986+ lifecycle *)
938987module Initialized : sig
939988 module Notification : sig
940940- (** InitializedNotification is sent by the client after receiving the initialization
941941- response, indicating it's ready to begin normal operations. This completes the
942942- three-step initialization process, after which both client and server can
943943- freely exchange messages according to the negotiated capabilities.
944944-945945- Only after this notification has been sent should the client begin normal operations
946946- like listing resources, calling tools, or requesting prompts. *)
947989 type t = {
948948- meta: Json.t option;
949949- (** Optional additional metadata as arbitrary JSON. Can contain client-specific
950950- information not covered by the standard fields. *)
990990+ meta : Json.t option;
991991+ (** Optional additional metadata as arbitrary JSON. Can contain
992992+ client-specific information not covered by the standard fields. *)
951993 }
994994+ (** InitializedNotification is sent by the client after receiving the
995995+ initialization response, indicating it's ready to begin normal
996996+ operations. This completes the three-step initialization process, after
997997+ which both client and server can freely exchange messages according to
998998+ the negotiated capabilities.
999999+10001000+ Only after this notification has been sent should the client begin
10011001+ normal operations like listing resources, calling tools, or requesting
10021002+ prompts. *)
10031003+9521004 include Json.Jsonable.S with type t := t
953100510061006+ val create : ?meta:Json.t -> unit -> t
9541007 (** Create a new initialized notification
9551008 @param meta Optional additional metadata
956956- @return A new initialized notification
957957- *)
958958- val create : ?meta:Json.t -> unit -> t
959959-10091009+ @return A new initialized notification *)
10101010+10111011+ val to_jsonrpc : t -> JSONRPCMessage.t
9601012 (** Convert to JSON-RPC message
9611013 @param t Initialized notification
962962- @return JSON-RPC message containing the initialized notification
963963- *)
964964- val to_jsonrpc : t -> JSONRPCMessage.t
10141014+ @return JSON-RPC message containing the initialized notification *)
9651015 end
9661016end
9671017968968-(** Parse a JSON message into an MCP message
969969-970970- This function takes a raw JSON value and parses it into a structured MCP message.
971971- It's the primary entry point for processing incoming JSON-RPC messages in the MCP protocol.
972972-973973- The function determines the message type (notification, request, response, or error)
974974- based on the presence and values of specific fields:
10181018+val parse_message : Json.t -> JSONRPCMessage.t
10191019+(** Parse a JSON message into an MCP message
10201020+10211021+ This function takes a raw JSON value and parses it into a structured MCP
10221022+ message. It's the primary entry point for processing incoming JSON-RPC
10231023+ messages in the MCP protocol.
10241024+10251025+ The function determines the message type (notification, request, response,
10261026+ or error) based on the presence and values of specific fields:
9751027 - A message with "method" but no "id" is a notification
9761028 - A message with "method" and "id" is a request
9771029 - A message with "id" and "result" is a response
9781030 - A message with "id" and "error" is an error
979979-980980- @param json The JSON message to parse, typically received from the transport layer
10311031+10321032+ @param json
10331033+ The JSON message to parse, typically received from the transport layer
9811034 @return The parsed MCP message as a structured JSONRPCMessage.t value
982982- @raise Parse error if the JSON cannot be parsed as a valid MCP message
983983-*)
984984-val parse_message : Json.t -> JSONRPCMessage.t
10351035+ @raise Parse error if the JSON cannot be parsed as a valid MCP message *)
985103610371037+val create_notification :
10381038+ ?params:Json.t option -> meth:Method.t -> unit -> JSONRPCMessage.t
9861039(** Create a new notification message
987987-988988- Notifications are one-way messages that don't expect a response.
989989- This is a convenience wrapper around JSONRPCMessage.create_notification.
990990-10401040+10411041+ Notifications are one-way messages that don't expect a response. This is a
10421042+ convenience wrapper around JSONRPCMessage.create_notification.
10431043+9911044 Common notifications in MCP include:
9921045 - "notifications/initialized" - Sent after initialization
9931046 - "notifications/progress" - Updates on long-running operations
9941047 - "notifications/resources/updated" - Resource content changed
9951048 - "notifications/prompts/list_changed" - Available prompts changed
9961049 - "notifications/tools/list_changed" - Available tools changed
997997-10501050+9981051 @param params Optional parameters for the notification as a JSON value
9991052 @param meth Method type for the notification
10001000- @return A new JSON-RPC notification message
10011001-*)
10021002-val create_notification : ?params:Json.t option -> meth:Method.t -> unit -> JSONRPCMessage.t
10531053+ @return A new JSON-RPC notification message *)
1003105410551055+val create_request :
10561056+ ?params:Json.t option ->
10571057+ ?progress_token:ProgressToken.t option ->
10581058+ id:RequestId.t ->
10591059+ meth:Method.t ->
10601060+ unit ->
10611061+ JSONRPCMessage.t
10041062(** Create a new request message
10051005-10061006- Requests are messages that expect a corresponding response.
10071007- This is a convenience wrapper around JSONRPCMessage.create_request.
10081008-10631063+10641064+ Requests are messages that expect a corresponding response. This is a
10651065+ convenience wrapper around JSONRPCMessage.create_request.
10661066+10091067 Common requests in MCP include:
10101068 - "initialize" - Start the MCP lifecycle
10111069 - "resources/list" - Discover available resources
···10141072 - "tools/call" - Invoke a tool
10151073 - "prompts/list" - Discover available prompts
10161074 - "prompts/get" - Retrieve a prompt template
10171017-10751075+10181076 @param params Optional parameters for the request as a JSON value
10191019- @param progress_token Optional progress token for long-running operations
10201020- that can report progress updates
10211021- @param id Unique identifier for the request, used to correlate with the response
10771077+ @param progress_token
10781078+ Optional progress token for long-running operations that can report
10791079+ progress updates
10801080+ @param id
10811081+ Unique identifier for the request, used to correlate with the response
10221082 @param meth Method type for the request
10231023- @return A new JSON-RPC request message
10241024-*)
10251025-val create_request : ?params:Json.t option -> ?progress_token:ProgressToken.t option -> id:RequestId.t -> meth:Method.t -> unit -> JSONRPCMessage.t
10831083+ @return A new JSON-RPC request message *)
1026108410851085+val create_response : id:RequestId.t -> result:Json.t -> JSONRPCMessage.t
10271086(** Create a new response message
10281028-10291029- Responses are sent in reply to requests and contain successful results.
10301030- This is a convenience wrapper around JSONRPCMessage.create_response.
10311031-10321032- Each response must include the same ID as its corresponding request
10331033- to allow the client to correlate them, especially when multiple
10341034- requests are in flight simultaneously.
10351035-10871087+10881088+ Responses are sent in reply to requests and contain successful results. This
10891089+ is a convenience wrapper around JSONRPCMessage.create_response.
10901090+10911091+ Each response must include the same ID as its corresponding request to allow
10921092+ the client to correlate them, especially when multiple requests are in
10931093+ flight simultaneously.
10941094+10361095 @param id ID matching the original request
10371096 @param result Result of the successful request as a JSON value
10381038- @return A new JSON-RPC response message
10391039-*)
10401040-val create_response : id:RequestId.t -> result:Json.t -> JSONRPCMessage.t
10971097+ @return A new JSON-RPC response message *)
1041109810991099+val create_error :
11001100+ id:RequestId.t ->
11011101+ code:int ->
11021102+ message:string ->
11031103+ ?data:Json.t option ->
11041104+ unit ->
11051105+ JSONRPCMessage.t
10421106(** Create a new error message
10431043-10441044- Errors are sent in reply to requests when processing fails.
10451045- This is a convenience wrapper around JSONRPCMessage.create_error.
10461046-10471047- MCP uses standard JSON-RPC error codes as well as some protocol-specific codes:
11071107+11081108+ Errors are sent in reply to requests when processing fails. This is a
11091109+ convenience wrapper around JSONRPCMessage.create_error.
11101110+11111111+ MCP uses standard JSON-RPC error codes as well as some protocol-specific
11121112+ codes:
10481113 - -32700: Parse error (invalid JSON)
10491114 - -32600: Invalid request (malformed JSON-RPC)
10501115 - -32601: Method not found
···10521117 - -32603: Internal error
10531118 - -32002: Resource not found (MCP-specific)
10541119 - -32001: Authentication required (MCP-specific)
10551055-11201120+10561121 @param id ID matching the original request
10571122 @param code Error code indicating the type of error
10581123 @param message Human-readable error message describing the issue
10591124 @param data Optional additional error data providing more context
10601060- @return A new JSON-RPC error message
10611061-*)
10621062-val create_error : id:RequestId.t -> code:int -> message:string -> ?data:Json.t option -> unit -> JSONRPCMessage.t
11251125+ @return A new JSON-RPC error message *)
1063112611271127+val make_text_content : string -> content
10641128(** Create a new text content object
10651129 @param text The text content
10661066- @return A content value with the text
10671067-*)
10681068-val make_text_content : string -> content
11301130+ @return A content value with the text *)
1069113111321132+val make_image_content : string -> string -> content
10701133(** Create a new image content object
10711134 @param data Base64-encoded image data
10721072- @param mime_type MIME type of the image (e.g., "image/png", "image/jpeg")
10731073- @return A content value with the image
10741074-*)
10751075-val make_image_content : string -> string -> content
11351135+ @param mime_type MIME type of the image (e.g., "image/png", "image/jpeg")
11361136+ @return A content value with the image *)
1076113711381138+val make_audio_content : string -> string -> content
10771139(** Create a new audio content object
10781140 @param data Base64-encoded audio data
10791141 @param mime_type MIME type of the audio (e.g., "audio/wav", "audio/mp3")
10801080- @return A content value with the audio
10811081-*)
10821082-val make_audio_content : string -> string -> content
11421142+ @return A content value with the audio *)
1083114311441144+val make_resource_text_content : string -> string -> string option -> content
10841145(** Create a new text resource content object
10851146 @param uri URI that uniquely identifies the resource
10861147 @param text The text content of the resource
10871148 @param mime_type Optional MIME type of the text content
10881088- @return A content value with the text resource
10891089-*)
10901090-val make_resource_text_content : string -> string -> string option -> content
11491149+ @return A content value with the text resource *)
1091115011511151+val make_resource_blob_content : string -> string -> string option -> content
10921152(** Create a new binary resource content object
10931153 @param uri URI that uniquely identifies the resource
10941154 @param blob Base64-encoded binary data
10951155 @param mime_type Optional MIME type of the binary content
10961096- @return A content value with the binary resource
10971097-*)
10981098-val make_resource_blob_content : string -> string -> string option -> content
11561156+ @return A content value with the binary resource *)
+500-501
lib/mcp_rpc.ml
···66(* Resources/List *)
77module ResourcesList = struct
88 module Request = struct
99- type t = {
1010- cursor: Cursor.t option;
1111- }
1212-99+ type t = { cursor : Cursor.t option }
1010+1311 let yojson_of_t { cursor } =
1412 let assoc = [] in
1515- let assoc = match cursor with
1313+ let assoc =
1414+ match cursor with
1615 | Some c -> ("cursor", Cursor.yojson_of_t c) :: assoc
1716 | None -> assoc
1817 in
1918 `Assoc assoc
2020-1919+2120 let t_of_yojson = function
2221 | `Assoc fields ->
2323- let cursor = List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson in
2424- { cursor }
2222+ let cursor =
2323+ List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson
2424+ in
2525+ { cursor }
2526 | j -> Util.json_error "Expected object for ResourcesList.Request.t" j
2626-2727 end
2828-2828+2929 module Resource = struct
3030 type t = {
3131- uri: string;
3232- name: string;
3333- description: string option;
3434- mime_type: string option;
3535- size: int option;
3131+ uri : string;
3232+ name : string;
3333+ description : string option;
3434+ mime_type : string option;
3535+ size : int option;
3636 }
3737-3737+3838 let yojson_of_t { uri; name; description; mime_type; size } =
3939- let assoc = [
4040- ("uri", `String uri);
4141- ("name", `String name);
4242- ] in
4343- let assoc = match description with
3939+ let assoc = [ ("uri", `String uri); ("name", `String name) ] in
4040+ let assoc =
4141+ match description with
4442 | Some desc -> ("description", `String desc) :: assoc
4543 | None -> assoc
4644 in
4747- let assoc = match mime_type with
4545+ let assoc =
4646+ match mime_type with
4847 | Some mime -> ("mimeType", `String mime) :: assoc
4948 | None -> assoc
5049 in
5151- let assoc = match size with
5252- | Some s -> ("size", `Int s) :: assoc
5353- | None -> assoc
5050+ let assoc =
5151+ match size with Some s -> ("size", `Int s) :: assoc | None -> assoc
5452 in
5553 `Assoc assoc
5656-5454+5755 let t_of_yojson = function
5856 | `Assoc fields as json ->
5959- let uri = match List.assoc_opt "uri" fields with
6060- | Some (`String s) -> s
6161- | _ -> Util.json_error "Missing or invalid 'uri' field" json
6262- in
6363- let name = match List.assoc_opt "name" fields with
6464- | Some (`String s) -> s
6565- | _ -> Util.json_error "Missing or invalid 'name' field" json
6666- in
6767- let description = List.assoc_opt "description" fields |> Option.map (function
6868- | `String s -> s
6969- | j -> Util.json_error "Expected string for description" j
7070- ) in
7171- let mime_type = List.assoc_opt "mimeType" fields |> Option.map (function
7272- | `String s -> s
7373- | j -> Util.json_error "Expected string for mimeType" j
7474- ) in
7575- let size = List.assoc_opt "size" fields |> Option.map (function
7676- | `Int i -> i
7777- | j -> Util.json_error "Expected int for size" j
7878- ) in
7979- { uri; name; description; mime_type; size }
5757+ let uri =
5858+ match List.assoc_opt "uri" fields with
5959+ | Some (`String s) -> s
6060+ | _ -> Util.json_error "Missing or invalid 'uri' field" json
6161+ in
6262+ let name =
6363+ match List.assoc_opt "name" fields with
6464+ | Some (`String s) -> s
6565+ | _ -> Util.json_error "Missing or invalid 'name' field" json
6666+ in
6767+ let description =
6868+ List.assoc_opt "description" fields
6969+ |> Option.map (function
7070+ | `String s -> s
7171+ | j -> Util.json_error "Expected string for description" j)
7272+ in
7373+ let mime_type =
7474+ List.assoc_opt "mimeType" fields
7575+ |> Option.map (function
7676+ | `String s -> s
7777+ | j -> Util.json_error "Expected string for mimeType" j)
7878+ in
7979+ let size =
8080+ List.assoc_opt "size" fields
8181+ |> Option.map (function
8282+ | `Int i -> i
8383+ | j -> Util.json_error "Expected int for size" j)
8484+ in
8585+ { uri; name; description; mime_type; size }
8086 | j -> Util.json_error "Expected object for ResourcesList.Resource.t" j
8187 end
8282-8888+8389 module Response = struct
8484- type t = {
8585- resources: Resource.t list;
8686- next_cursor: Cursor.t option;
8787- }
8888-9090+ type t = { resources : Resource.t list; next_cursor : Cursor.t option }
9191+8992 let yojson_of_t { resources; next_cursor } =
9090- let assoc = [
9191- ("resources", `List (List.map Resource.yojson_of_t resources));
9292- ] in
9393- let assoc = match next_cursor with
9393+ let assoc =
9494+ [ ("resources", `List (List.map Resource.yojson_of_t resources)) ]
9595+ in
9696+ let assoc =
9797+ match next_cursor with
9498 | Some c -> ("nextCursor", Cursor.yojson_of_t c) :: assoc
9599 | None -> assoc
96100 in
97101 `Assoc assoc
9898-102102+99103 let t_of_yojson = function
100104 | `Assoc fields as json ->
101101- let resources = match List.assoc_opt "resources" fields with
102102- | Some (`List items) -> List.map Resource.t_of_yojson items
103103- | _ -> Util.json_error "Missing or invalid 'resources' field" json
104104- in
105105- let next_cursor = List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson in
106106- { resources; next_cursor }
105105+ let resources =
106106+ match List.assoc_opt "resources" fields with
107107+ | Some (`List items) -> List.map Resource.t_of_yojson items
108108+ | _ -> Util.json_error "Missing or invalid 'resources' field" json
109109+ in
110110+ let next_cursor =
111111+ List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson
112112+ in
113113+ { resources; next_cursor }
107114 | j -> Util.json_error "Expected object for ResourcesList.Response.t" j
108108-109115 end
110110-116116+111117 (* Request/response creation helpers *)
112118 let create_request ?cursor ?id () =
113113- let id = match id with
114114- | Some i -> i
115115- | None -> `Int (Random.int 10000)
116116- in
119119+ let id = match id with Some i -> i | None -> `Int (Random.int 10000) in
117120 let params = Request.yojson_of_t { cursor } in
118118- JSONRPCMessage.create_request ~id ~meth:Method.ResourcesList ~params:(Some params) ()
119119-121121+ JSONRPCMessage.create_request ~id ~meth:Method.ResourcesList
122122+ ~params:(Some params) ()
123123+120124 let create_response ~id ~resources ?next_cursor () =
121125 let result = Response.yojson_of_t { resources; next_cursor } in
122126 JSONRPCMessage.create_response ~id ~result
···124128125129(* Resources/Templates/List *)
126130module ListResourceTemplatesRequest = struct
127127- type t = {
128128- cursor: Cursor.t option;
129129- }
130130-131131+ type t = { cursor : Cursor.t option }
132132+131133 let yojson_of_t { cursor } =
132134 let assoc = [] in
133133- let assoc = match cursor with
135135+ let assoc =
136136+ match cursor with
134137 | Some c -> ("cursor", Cursor.yojson_of_t c) :: assoc
135138 | None -> assoc
136139 in
137140 `Assoc assoc
138138-141141+139142 let t_of_yojson = function
140143 | `Assoc fields ->
141141- let cursor = List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson in
142142- { cursor }
143143- | j -> Util.json_error "Expected object for ListResourceTemplatesRequest.t" j
144144-144144+ let cursor =
145145+ List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson
146146+ in
147147+ { cursor }
148148+ | j ->
149149+ Util.json_error "Expected object for ListResourceTemplatesRequest.t" j
145150end
146151147152(* Resources/Templates/List Response *)
148153module ListResourceTemplatesResult = struct
149154 module ResourceTemplate = struct
150155 type t = {
151151- uri_template: string;
152152- name: string;
153153- description: string option;
154154- mime_type: string option;
156156+ uri_template : string;
157157+ name : string;
158158+ description : string option;
159159+ mime_type : string option;
155160 }
156156-161161+157162 let yojson_of_t { uri_template; name; description; mime_type } =
158158- let assoc = [
159159- ("uriTemplate", `String uri_template);
160160- ("name", `String name);
161161- ] in
162162- let assoc = match description with
163163+ let assoc =
164164+ [ ("uriTemplate", `String uri_template); ("name", `String name) ]
165165+ in
166166+ let assoc =
167167+ match description with
163168 | Some desc -> ("description", `String desc) :: assoc
164169 | None -> assoc
165170 in
166166- let assoc = match mime_type with
171171+ let assoc =
172172+ match mime_type with
167173 | Some mime -> ("mimeType", `String mime) :: assoc
168174 | None -> assoc
169175 in
170176 `Assoc assoc
171171-177177+172178 let t_of_yojson = function
173179 | `Assoc fields as json ->
174174- let uri_template = match List.assoc_opt "uriTemplate" fields with
175175- | Some (`String s) -> s
176176- | _ -> Util.json_error "Missing or invalid 'uriTemplate' field" json
177177- in
178178- let name = match List.assoc_opt "name" fields with
179179- | Some (`String s) -> s
180180- | _ -> Util.json_error "Missing or invalid 'name' field" json
181181- in
182182- let description = List.assoc_opt "description" fields |> Option.map (function
183183- | `String s -> s
184184- | j -> Util.json_error "Expected string for description" j
185185- ) in
186186- let mime_type = List.assoc_opt "mimeType" fields |> Option.map (function
187187- | `String s -> s
188188- | j -> Util.json_error "Expected string for mimeType" j
189189- ) in
190190- { uri_template; name; description; mime_type }
191191- | j -> Util.json_error "Expected object for ListResourceTemplatesResult.ResourceTemplate.t" j
180180+ let uri_template =
181181+ match List.assoc_opt "uriTemplate" fields with
182182+ | Some (`String s) -> s
183183+ | _ -> Util.json_error "Missing or invalid 'uriTemplate' field" json
184184+ in
185185+ let name =
186186+ match List.assoc_opt "name" fields with
187187+ | Some (`String s) -> s
188188+ | _ -> Util.json_error "Missing or invalid 'name' field" json
189189+ in
190190+ let description =
191191+ List.assoc_opt "description" fields
192192+ |> Option.map (function
193193+ | `String s -> s
194194+ | j -> Util.json_error "Expected string for description" j)
195195+ in
196196+ let mime_type =
197197+ List.assoc_opt "mimeType" fields
198198+ |> Option.map (function
199199+ | `String s -> s
200200+ | j -> Util.json_error "Expected string for mimeType" j)
201201+ in
202202+ { uri_template; name; description; mime_type }
203203+ | j ->
204204+ Util.json_error
205205+ "Expected object for ListResourceTemplatesResult.ResourceTemplate.t"
206206+ j
192207 end
193193-208208+194209 type t = {
195195- resource_templates: ResourceTemplate.t list;
196196- next_cursor: Cursor.t option;
210210+ resource_templates : ResourceTemplate.t list;
211211+ next_cursor : Cursor.t option;
197212 }
198198-213213+199214 let yojson_of_t { resource_templates; next_cursor } =
200200- let assoc = [
201201- ("resourceTemplates", `List (List.map ResourceTemplate.yojson_of_t resource_templates));
202202- ] in
203203- let assoc = match next_cursor with
215215+ let assoc =
216216+ [
217217+ ( "resourceTemplates",
218218+ `List (List.map ResourceTemplate.yojson_of_t resource_templates) );
219219+ ]
220220+ in
221221+ let assoc =
222222+ match next_cursor with
204223 | Some c -> ("nextCursor", Cursor.yojson_of_t c) :: assoc
205224 | None -> assoc
206225 in
207226 `Assoc assoc
208208-227227+209228 let t_of_yojson = function
210229 | `Assoc fields as json ->
211211- let resource_templates = match List.assoc_opt "resourceTemplates" fields with
212212- | Some (`List items) -> List.map ResourceTemplate.t_of_yojson items
213213- | _ -> Util.json_error "Missing or invalid 'resourceTemplates' field" json
214214- in
215215- let next_cursor = List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson in
216216- { resource_templates; next_cursor }
230230+ let resource_templates =
231231+ match List.assoc_opt "resourceTemplates" fields with
232232+ | Some (`List items) -> List.map ResourceTemplate.t_of_yojson items
233233+ | _ ->
234234+ Util.json_error "Missing or invalid 'resourceTemplates' field"
235235+ json
236236+ in
237237+ let next_cursor =
238238+ List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson
239239+ in
240240+ { resource_templates; next_cursor }
217241 | j -> Util.json_error "Expected object for ListResourceTemplatesResult.t" j
218218-242242+219243 (* Request/response creation helpers *)
220244 let create_request ?cursor ?id () =
221221- let id = match id with
222222- | Some i -> i
223223- | None -> `Int (Random.int 10000)
224224- in
245245+ let id = match id with Some i -> i | None -> `Int (Random.int 10000) in
225246 let params = ListResourceTemplatesRequest.yojson_of_t { cursor } in
226226- JSONRPCMessage.create_request ~id ~meth:Method.ResourceTemplatesList ~params:(Some params) ()
227227-247247+ JSONRPCMessage.create_request ~id ~meth:Method.ResourceTemplatesList
248248+ ~params:(Some params) ()
249249+228250 let create_response ~id ~resource_templates ?next_cursor () =
229251 let result = yojson_of_t { resource_templates; next_cursor } in
230252 JSONRPCMessage.create_response ~id ~result
···233255(* Resources/Read *)
234256module ResourcesRead = struct
235257 module Request = struct
236236- type t = {
237237- uri: string;
238238- }
239239-240240- let yojson_of_t { uri } =
241241- `Assoc [
242242- ("uri", `String uri);
243243- ]
244244-258258+ type t = { uri : string }
259259+260260+ let yojson_of_t { uri } = `Assoc [ ("uri", `String uri) ]
261261+245262 let t_of_yojson = function
246263 | `Assoc fields as json ->
247247- let uri = match List.assoc_opt "uri" fields with
248248- | Some (`String s) -> s
249249- | _ -> Util.json_error "Missing or invalid 'uri' field" json
250250- in
251251- { uri }
264264+ let uri =
265265+ match List.assoc_opt "uri" fields with
266266+ | Some (`String s) -> s
267267+ | _ -> Util.json_error "Missing or invalid 'uri' field" json
268268+ in
269269+ { uri }
252270 | j -> Util.json_error "Expected object for ResourcesRead.Request.t" j
253253-254271 end
255255-272272+256273 module ResourceContent = struct
257257- type t =
274274+ type t =
258275 | TextResource of TextResourceContents.t
259276 | BlobResource of BlobResourceContents.t
260260-277277+261278 let yojson_of_t = function
262279 | TextResource tr -> TextResourceContents.yojson_of_t tr
263280 | BlobResource br -> BlobResourceContents.yojson_of_t br
264264-281281+265282 let t_of_yojson json =
266283 match json with
267284 | `Assoc fields ->
268268- if List.mem_assoc "text" fields then
269269- TextResource (TextResourceContents.t_of_yojson json)
270270- else if List.mem_assoc "blob" fields then
271271- BlobResource (BlobResourceContents.t_of_yojson json)
272272- else
273273- Util.json_error "Invalid resource content" json
274274- | j -> Util.json_error "Expected object for ResourcesRead.ResourceContent.t" j
275275-285285+ if List.mem_assoc "text" fields then
286286+ TextResource (TextResourceContents.t_of_yojson json)
287287+ else if List.mem_assoc "blob" fields then
288288+ BlobResource (BlobResourceContents.t_of_yojson json)
289289+ else Util.json_error "Invalid resource content" json
290290+ | j ->
291291+ Util.json_error "Expected object for ResourcesRead.ResourceContent.t"
292292+ j
276293 end
277277-294294+278295 module Response = struct
279279- type t = {
280280- contents: ResourceContent.t list;
281281- }
282282-296296+ type t = { contents : ResourceContent.t list }
297297+283298 let yojson_of_t { contents } =
284284- `Assoc [
285285- ("contents", `List (List.map ResourceContent.yojson_of_t contents));
286286- ]
287287-299299+ `Assoc
300300+ [ ("contents", `List (List.map ResourceContent.yojson_of_t contents)) ]
301301+288302 let t_of_yojson = function
289303 | `Assoc fields as json ->
290290- let contents = match List.assoc_opt "contents" fields with
291291- | Some (`List items) -> List.map ResourceContent.t_of_yojson items
292292- | _ -> Util.json_error "Missing or invalid 'contents' field" json
293293- in
294294- { contents }
304304+ let contents =
305305+ match List.assoc_opt "contents" fields with
306306+ | Some (`List items) -> List.map ResourceContent.t_of_yojson items
307307+ | _ -> Util.json_error "Missing or invalid 'contents' field" json
308308+ in
309309+ { contents }
295310 | j -> Util.json_error "Expected object for ResourcesRead.Response.t" j
296296-297311 end
298298-312312+299313 (* Request/response creation helpers *)
300314 let create_request ~uri ?id () =
301301- let id = match id with
302302- | Some i -> i
303303- | None -> `Int (Random.int 10000)
304304- in
315315+ let id = match id with Some i -> i | None -> `Int (Random.int 10000) in
305316 let params = Request.yojson_of_t { uri } in
306306- JSONRPCMessage.create_request ~id ~meth:Method.ResourcesRead ~params:(Some params) ()
307307-317317+ JSONRPCMessage.create_request ~id ~meth:Method.ResourcesRead
318318+ ~params:(Some params) ()
319319+308320 let create_response ~id ~contents () =
309321 let result = Response.yojson_of_t { contents } in
310322 JSONRPCMessage.create_response ~id ~result
···313325(* Tools/List *)
314326module ToolsList = struct
315327 module Request = struct
316316- type t = {
317317- cursor: Cursor.t option;
318318- }
319319-328328+ type t = { cursor : Cursor.t option }
329329+320330 let yojson_of_t { cursor } =
321331 let assoc = [] in
322322- let assoc = match cursor with
332332+ let assoc =
333333+ match cursor with
323334 | Some c -> ("cursor", Cursor.yojson_of_t c) :: assoc
324335 | None -> assoc
325336 in
326337 `Assoc assoc
327327-338338+328339 let t_of_yojson = function
329340 | `Assoc fields ->
330330- let cursor = List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson in
331331- { cursor }
341341+ let cursor =
342342+ List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson
343343+ in
344344+ { cursor }
332345 | j -> Util.json_error "Expected object for ToolsList.Request.t" j
333333-334346 end
335335-347347+336348 module Tool = struct
337349 type t = {
338338- name: string;
339339- description: string option;
340340- input_schema: Json.t;
341341- annotations: Json.t option;
350350+ name : string;
351351+ description : string option;
352352+ input_schema : Json.t;
353353+ annotations : Json.t option;
342354 }
343343-355355+344356 let yojson_of_t { name; description; input_schema; annotations } =
345345- let assoc = [
346346- ("name", `String name);
347347- ("inputSchema", input_schema);
348348- ] in
349349- let assoc = match description with
357357+ let assoc = [ ("name", `String name); ("inputSchema", input_schema) ] in
358358+ let assoc =
359359+ match description with
350360 | Some desc -> ("description", `String desc) :: assoc
351361 | None -> assoc
352362 in
353353- let assoc = match annotations with
363363+ let assoc =
364364+ match annotations with
354365 | Some anno -> ("annotations", anno) :: assoc
355366 | None -> assoc
356367 in
357368 `Assoc assoc
358358-369369+359370 let t_of_yojson = function
360371 | `Assoc fields as json ->
361361- let name = match List.assoc_opt "name" fields with
362362- | Some (`String s) -> s
363363- | _ -> Util.json_error "Missing or invalid 'name' field" json
364364- in
365365- let description = List.assoc_opt "description" fields |> Option.map (function
366366- | `String s -> s
367367- | j -> Util.json_error "Expected string for description" j
368368- ) in
369369- let input_schema = match List.assoc_opt "inputSchema" fields with
370370- | Some schema -> schema
371371- | None -> Util.json_error "Missing 'inputSchema' field" json
372372- in
373373- let annotations = List.assoc_opt "annotations" fields in
374374- { name; description; input_schema; annotations }
372372+ let name =
373373+ match List.assoc_opt "name" fields with
374374+ | Some (`String s) -> s
375375+ | _ -> Util.json_error "Missing or invalid 'name' field" json
376376+ in
377377+ let description =
378378+ List.assoc_opt "description" fields
379379+ |> Option.map (function
380380+ | `String s -> s
381381+ | j -> Util.json_error "Expected string for description" j)
382382+ in
383383+ let input_schema =
384384+ match List.assoc_opt "inputSchema" fields with
385385+ | Some schema -> schema
386386+ | None -> Util.json_error "Missing 'inputSchema' field" json
387387+ in
388388+ let annotations = List.assoc_opt "annotations" fields in
389389+ { name; description; input_schema; annotations }
375390 | j -> Util.json_error "Expected object for ToolsList.Tool.t" j
376376-377391 end
378378-392392+379393 module Response = struct
380380- type t = {
381381- tools: Tool.t list;
382382- next_cursor: Cursor.t option;
383383- }
384384-394394+ type t = { tools : Tool.t list; next_cursor : Cursor.t option }
395395+385396 let yojson_of_t { tools; next_cursor } =
386386- let assoc = [
387387- ("tools", `List (List.map Tool.yojson_of_t tools));
388388- ] in
389389- let assoc = match next_cursor with
397397+ let assoc = [ ("tools", `List (List.map Tool.yojson_of_t tools)) ] in
398398+ let assoc =
399399+ match next_cursor with
390400 | Some c -> ("nextCursor", Cursor.yojson_of_t c) :: assoc
391401 | None -> assoc
392402 in
393403 `Assoc assoc
394394-404404+395405 let t_of_yojson = function
396406 | `Assoc fields as json ->
397397- let tools = match List.assoc_opt "tools" fields with
398398- | Some (`List items) -> List.map Tool.t_of_yojson items
399399- | _ -> Util.json_error "Missing or invalid 'tools' field" json
400400- in
401401- let next_cursor = List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson in
402402- { tools; next_cursor }
407407+ let tools =
408408+ match List.assoc_opt "tools" fields with
409409+ | Some (`List items) -> List.map Tool.t_of_yojson items
410410+ | _ -> Util.json_error "Missing or invalid 'tools' field" json
411411+ in
412412+ let next_cursor =
413413+ List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson
414414+ in
415415+ { tools; next_cursor }
403416 | j -> Util.json_error "Expected object for ToolsList.Response.t" j
404404-405417 end
406406-418418+407419 (* Request/response creation helpers *)
408420 let create_request ?cursor ?id () =
409409- let id = match id with
410410- | Some i -> i
411411- | None -> `Int (Random.int 10000)
412412- in
421421+ let id = match id with Some i -> i | None -> `Int (Random.int 10000) in
413422 let params = Request.yojson_of_t { cursor } in
414414- JSONRPCMessage.create_request ~id ~meth:Method.ToolsList ~params:(Some params) ()
415415-423423+ JSONRPCMessage.create_request ~id ~meth:Method.ToolsList
424424+ ~params:(Some params) ()
425425+416426 let create_response ~id ~tools ?next_cursor () =
417427 let result = Response.yojson_of_t { tools; next_cursor } in
418428 JSONRPCMessage.create_response ~id ~result
···421431(* Tools/Call *)
422432module ToolsCall = struct
423433 module Request = struct
424424- type t = {
425425- name: string;
426426- arguments: Json.t;
427427- }
428428-434434+ type t = { name : string; arguments : Json.t }
435435+429436 let yojson_of_t { name; arguments } =
430430- `Assoc [
431431- ("name", `String name);
432432- ("arguments", arguments);
433433- ]
434434-437437+ `Assoc [ ("name", `String name); ("arguments", arguments) ]
438438+435439 let t_of_yojson = function
436440 | `Assoc fields as json ->
437437- let name = match List.assoc_opt "name" fields with
438438- | Some (`String s) -> s
439439- | _ -> Util.json_error "Missing or invalid 'name' field" json
440440- in
441441- let arguments = match List.assoc_opt "arguments" fields with
442442- | Some json -> json
443443- | None -> Util.json_error "Missing 'arguments' field" json
444444- in
445445- { name; arguments }
441441+ let name =
442442+ match List.assoc_opt "name" fields with
443443+ | Some (`String s) -> s
444444+ | _ -> Util.json_error "Missing or invalid 'name' field" json
445445+ in
446446+ let arguments =
447447+ match List.assoc_opt "arguments" fields with
448448+ | Some json -> json
449449+ | None -> Util.json_error "Missing 'arguments' field" json
450450+ in
451451+ { name; arguments }
446452 | j -> Util.json_error "Expected object for ToolsCall.Request.t" j
447447-448453 end
449449-454454+450455 module ToolContent = struct
451451- type t =
456456+ type t =
452457 | Text of TextContent.t
453458 | Image of ImageContent.t
454459 | Audio of AudioContent.t
455460 | Resource of EmbeddedResource.t
456456-461461+457462 let yojson_of_t = function
458463 | Text t -> TextContent.yojson_of_t t
459464 | Image i -> ImageContent.yojson_of_t i
460465 | Audio a -> AudioContent.yojson_of_t a
461466 | Resource r -> EmbeddedResource.yojson_of_t r
462462-467467+463468 let t_of_yojson json =
464469 match json with
465465- | `Assoc fields ->
466466- (match List.assoc_opt "type" fields with
467467- | Some (`String "text") -> Text (TextContent.t_of_yojson json)
468468- | Some (`String "image") -> Image (ImageContent.t_of_yojson json)
469469- | Some (`String "audio") -> Audio (AudioContent.t_of_yojson json)
470470- | Some (`String "resource") -> Resource (EmbeddedResource.t_of_yojson json)
471471- | _ -> Util.json_error "Invalid or missing content type" json)
470470+ | `Assoc fields -> (
471471+ match List.assoc_opt "type" fields with
472472+ | Some (`String "text") -> Text (TextContent.t_of_yojson json)
473473+ | Some (`String "image") -> Image (ImageContent.t_of_yojson json)
474474+ | Some (`String "audio") -> Audio (AudioContent.t_of_yojson json)
475475+ | Some (`String "resource") ->
476476+ Resource (EmbeddedResource.t_of_yojson json)
477477+ | _ -> Util.json_error "Invalid or missing content type" json)
472478 | j -> Util.json_error "Expected object for ToolsCall.ToolContent.t" j
473473-474479 end
475475-480480+476481 module Response = struct
477477- type t = {
478478- content: ToolContent.t list;
479479- is_error: bool;
480480- }
481481-482482+ type t = { content : ToolContent.t list; is_error : bool }
483483+482484 let yojson_of_t { content; is_error } =
483483- `Assoc [
484484- ("content", `List (List.map ToolContent.yojson_of_t content));
485485- ("isError", `Bool is_error);
486486- ]
487487-485485+ `Assoc
486486+ [
487487+ ("content", `List (List.map ToolContent.yojson_of_t content));
488488+ ("isError", `Bool is_error);
489489+ ]
490490+488491 let t_of_yojson = function
489492 | `Assoc fields as json ->
490490- let content = match List.assoc_opt "content" fields with
491491- | Some (`List items) -> List.map ToolContent.t_of_yojson items
492492- | _ -> Util.json_error "Missing or invalid 'content' field" json
493493- in
494494- let is_error = match List.assoc_opt "isError" fields with
495495- | Some (`Bool b) -> b
496496- | _ -> false
497497- in
498498- { content; is_error }
493493+ let content =
494494+ match List.assoc_opt "content" fields with
495495+ | Some (`List items) -> List.map ToolContent.t_of_yojson items
496496+ | _ -> Util.json_error "Missing or invalid 'content' field" json
497497+ in
498498+ let is_error =
499499+ match List.assoc_opt "isError" fields with
500500+ | Some (`Bool b) -> b
501501+ | _ -> false
502502+ in
503503+ { content; is_error }
499504 | j -> Util.json_error "Expected object for ToolsCall.Response.t" j
500500-501505 end
502502-506506+503507 (* Request/response creation helpers *)
504508 let create_request ~name ~arguments ?id () =
505505- let id = match id with
506506- | Some i -> i
507507- | None -> `Int (Random.int 10000)
508508- in
509509+ let id = match id with Some i -> i | None -> `Int (Random.int 10000) in
509510 let params = Request.yojson_of_t { name; arguments } in
510510- JSONRPCMessage.create_request ~id ~meth:Method.ToolsCall ~params:(Some params) ()
511511-511511+ JSONRPCMessage.create_request ~id ~meth:Method.ToolsCall
512512+ ~params:(Some params) ()
513513+512514 let create_response ~id ~content ~is_error () =
513515 let result = Response.yojson_of_t { content; is_error } in
514516 JSONRPCMessage.create_response ~id ~result
···517519(* Prompts/List *)
518520module PromptsList = struct
519521 module PromptArgument = struct
520520- type t = {
521521- name: string;
522522- description: string option;
523523- required: bool;
524524- }
525525-522522+ type t = { name : string; description : string option; required : bool }
523523+526524 let yojson_of_t { name; description; required } =
527527- let assoc = [
528528- ("name", `String name);
529529- ] in
530530- let assoc = match description with
525525+ let assoc = [ ("name", `String name) ] in
526526+ let assoc =
527527+ match description with
531528 | Some desc -> ("description", `String desc) :: assoc
532529 | None -> assoc
533530 in
534534- let assoc = if required then
535535- ("required", `Bool true) :: assoc
536536- else
537537- assoc
531531+ let assoc =
532532+ if required then ("required", `Bool true) :: assoc else assoc
538533 in
539534 `Assoc assoc
540540-535535+541536 let t_of_yojson = function
542537 | `Assoc fields as json ->
543543- let name = match List.assoc_opt "name" fields with
544544- | Some (`String s) -> s
545545- | _ -> Util.json_error "Missing or invalid 'name' field" json
546546- in
547547- let description = List.assoc_opt "description" fields |> Option.map (function
548548- | `String s -> s
549549- | j -> Util.json_error "Expected string for description" j
550550- ) in
551551- let required = match List.assoc_opt "required" fields with
552552- | Some (`Bool b) -> b
553553- | _ -> false
554554- in
555555- { name; description; required }
556556- | j -> Util.json_error "Expected object for PromptsList.PromptArgument.t" j
557557-538538+ let name =
539539+ match List.assoc_opt "name" fields with
540540+ | Some (`String s) -> s
541541+ | _ -> Util.json_error "Missing or invalid 'name' field" json
542542+ in
543543+ let description =
544544+ List.assoc_opt "description" fields
545545+ |> Option.map (function
546546+ | `String s -> s
547547+ | j -> Util.json_error "Expected string for description" j)
548548+ in
549549+ let required =
550550+ match List.assoc_opt "required" fields with
551551+ | Some (`Bool b) -> b
552552+ | _ -> false
553553+ in
554554+ { name; description; required }
555555+ | j ->
556556+ Util.json_error "Expected object for PromptsList.PromptArgument.t" j
558557 end
559559-558558+560559 module Prompt = struct
561560 type t = {
562562- name: string;
563563- description: string option;
564564- arguments: PromptArgument.t list;
561561+ name : string;
562562+ description : string option;
563563+ arguments : PromptArgument.t list;
565564 }
566566-565565+567566 let yojson_of_t { name; description; arguments } =
568568- let assoc = [
569569- ("name", `String name);
570570- ] in
571571- let assoc = match description with
567567+ let assoc = [ ("name", `String name) ] in
568568+ let assoc =
569569+ match description with
572570 | Some desc -> ("description", `String desc) :: assoc
573571 | None -> assoc
574572 in
575575- let assoc = if arguments <> [] then
576576- ("arguments", `List (List.map PromptArgument.yojson_of_t arguments)) :: assoc
577577- else
578578- assoc
573573+ let assoc =
574574+ if arguments <> [] then
575575+ ("arguments", `List (List.map PromptArgument.yojson_of_t arguments))
576576+ :: assoc
577577+ else assoc
579578 in
580579 `Assoc assoc
581581-580580+582581 let t_of_yojson = function
583582 | `Assoc fields as json ->
584584- let name = match List.assoc_opt "name" fields with
585585- | Some (`String s) -> s
586586- | _ -> Util.json_error "Missing or invalid 'name' field" json
587587- in
588588- let description = List.assoc_opt "description" fields |> Option.map (function
589589- | `String s -> s
590590- | j -> Util.json_error "Expected string for description" j
591591- ) in
592592- let arguments = match List.assoc_opt "arguments" fields with
593593- | Some (`List items) -> List.map PromptArgument.t_of_yojson items
594594- | _ -> []
595595- in
596596- { name; description; arguments }
583583+ let name =
584584+ match List.assoc_opt "name" fields with
585585+ | Some (`String s) -> s
586586+ | _ -> Util.json_error "Missing or invalid 'name' field" json
587587+ in
588588+ let description =
589589+ List.assoc_opt "description" fields
590590+ |> Option.map (function
591591+ | `String s -> s
592592+ | j -> Util.json_error "Expected string for description" j)
593593+ in
594594+ let arguments =
595595+ match List.assoc_opt "arguments" fields with
596596+ | Some (`List items) -> List.map PromptArgument.t_of_yojson items
597597+ | _ -> []
598598+ in
599599+ { name; description; arguments }
597600 | j -> Util.json_error "Expected object for PromptsList.Prompt.t" j
598598-599601 end
600600-602602+601603 module Request = struct
602602- type t = {
603603- cursor: Cursor.t option;
604604- }
605605-604604+ type t = { cursor : Cursor.t option }
605605+606606 let yojson_of_t { cursor } =
607607 let assoc = [] in
608608- let assoc = match cursor with
608608+ let assoc =
609609+ match cursor with
609610 | Some c -> ("cursor", Cursor.yojson_of_t c) :: assoc
610611 | None -> assoc
611612 in
612613 `Assoc assoc
613613-614614+614615 let t_of_yojson = function
615616 | `Assoc fields ->
616616- let cursor = List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson in
617617- { cursor }
617617+ let cursor =
618618+ List.assoc_opt "cursor" fields |> Option.map Cursor.t_of_yojson
619619+ in
620620+ { cursor }
618621 | j -> Util.json_error "Expected object for PromptsList.Request.t" j
619619-620622 end
621621-623623+622624 module Response = struct
623623- type t = {
624624- prompts: Prompt.t list;
625625- next_cursor: Cursor.t option;
626626- }
627627-625625+ type t = { prompts : Prompt.t list; next_cursor : Cursor.t option }
626626+628627 let yojson_of_t { prompts; next_cursor } =
629629- let assoc = [
630630- ("prompts", `List (List.map Prompt.yojson_of_t prompts));
631631- ] in
632632- let assoc = match next_cursor with
628628+ let assoc =
629629+ [ ("prompts", `List (List.map Prompt.yojson_of_t prompts)) ]
630630+ in
631631+ let assoc =
632632+ match next_cursor with
633633 | Some c -> ("nextCursor", Cursor.yojson_of_t c) :: assoc
634634 | None -> assoc
635635 in
636636 `Assoc assoc
637637-637637+638638 let t_of_yojson = function
639639 | `Assoc fields as json ->
640640- let prompts = match List.assoc_opt "prompts" fields with
641641- | Some (`List items) -> List.map Prompt.t_of_yojson items
642642- | _ -> Util.json_error "Missing or invalid 'prompts' field" json
643643- in
644644- let next_cursor = List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson in
645645- { prompts; next_cursor }
640640+ let prompts =
641641+ match List.assoc_opt "prompts" fields with
642642+ | Some (`List items) -> List.map Prompt.t_of_yojson items
643643+ | _ -> Util.json_error "Missing or invalid 'prompts' field" json
644644+ in
645645+ let next_cursor =
646646+ List.assoc_opt "nextCursor" fields |> Option.map Cursor.t_of_yojson
647647+ in
648648+ { prompts; next_cursor }
646649 | j -> Util.json_error "Expected object for PromptsList.Response.t" j
647647-648650 end
649649-651651+650652 (* Request/response creation helpers *)
651653 let create_request ?cursor ?id () =
652652- let id = match id with
653653- | Some i -> i
654654- | None -> `Int (Random.int 10000)
655655- in
654654+ let id = match id with Some i -> i | None -> `Int (Random.int 10000) in
656655 let params = Request.yojson_of_t { cursor } in
657657- JSONRPCMessage.create_request ~id ~meth:Method.PromptsList ~params:(Some params) ()
658658-656656+ JSONRPCMessage.create_request ~id ~meth:Method.PromptsList
657657+ ~params:(Some params) ()
658658+659659 let create_response ~id ~prompts ?next_cursor () =
660660 let result = Response.yojson_of_t { prompts; next_cursor } in
661661 JSONRPCMessage.create_response ~id ~result
···664664(* Prompts/Get *)
665665module PromptsGet = struct
666666 module Request = struct
667667- type t = {
668668- name: string;
669669- arguments: (string * string) list;
670670- }
671671-667667+ type t = { name : string; arguments : (string * string) list }
668668+672669 let yojson_of_t { name; arguments } =
673673- let args_json = `Assoc (List.map (fun (k, v) -> (k, `String v)) arguments) in
674674- `Assoc [
675675- ("name", `String name);
676676- ("arguments", args_json);
677677- ]
678678-670670+ let args_json =
671671+ `Assoc (List.map (fun (k, v) -> (k, `String v)) arguments)
672672+ in
673673+ `Assoc [ ("name", `String name); ("arguments", args_json) ]
674674+679675 let t_of_yojson = function
680676 | `Assoc fields as json ->
681681- let name = match List.assoc_opt "name" fields with
682682- | Some (`String s) -> s
683683- | _ -> Util.json_error "Missing or invalid 'name' field" json
684684- in
685685- let arguments = match List.assoc_opt "arguments" fields with
686686- | Some (`Assoc args) ->
687687- List.map (fun (k, v) ->
688688- match v with
689689- | `String s -> (k, s)
690690- | _ -> Util.json_error "Expected string value for argument" v
691691- ) args
692692- | _ -> []
693693- in
694694- { name; arguments }
677677+ let name =
678678+ match List.assoc_opt "name" fields with
679679+ | Some (`String s) -> s
680680+ | _ -> Util.json_error "Missing or invalid 'name' field" json
681681+ in
682682+ let arguments =
683683+ match List.assoc_opt "arguments" fields with
684684+ | Some (`Assoc args) ->
685685+ List.map
686686+ (fun (k, v) ->
687687+ match v with
688688+ | `String s -> (k, s)
689689+ | _ ->
690690+ Util.json_error "Expected string value for argument" v)
691691+ args
692692+ | _ -> []
693693+ in
694694+ { name; arguments }
695695 | j -> Util.json_error "Expected object for PromptsGet.Request.t" j
696696-697696 end
698698-697697+699698 module Response = struct
700700- type t = {
701701- description: string option;
702702- messages: PromptMessage.t list;
703703- }
704704-699699+ type t = { description : string option; messages : PromptMessage.t list }
700700+705701 let yojson_of_t { description; messages } =
706706- let assoc = [
707707- ("messages", `List (List.map PromptMessage.yojson_of_t messages));
708708- ] in
709709- let assoc = match description with
702702+ let assoc =
703703+ [ ("messages", `List (List.map PromptMessage.yojson_of_t messages)) ]
704704+ in
705705+ let assoc =
706706+ match description with
710707 | Some desc -> ("description", `String desc) :: assoc
711708 | None -> assoc
712709 in
713710 `Assoc assoc
714714-711711+715712 let t_of_yojson = function
716713 | `Assoc fields as json ->
717717- let messages = match List.assoc_opt "messages" fields with
718718- | Some (`List items) -> List.map PromptMessage.t_of_yojson items
719719- | _ -> Util.json_error "Missing or invalid 'messages' field" json
720720- in
721721- let description = List.assoc_opt "description" fields |> Option.map (function
722722- | `String s -> s
723723- | j -> Util.json_error "Expected string for description" j
724724- ) in
725725- { description; messages }
714714+ let messages =
715715+ match List.assoc_opt "messages" fields with
716716+ | Some (`List items) -> List.map PromptMessage.t_of_yojson items
717717+ | _ -> Util.json_error "Missing or invalid 'messages' field" json
718718+ in
719719+ let description =
720720+ List.assoc_opt "description" fields
721721+ |> Option.map (function
722722+ | `String s -> s
723723+ | j -> Util.json_error "Expected string for description" j)
724724+ in
725725+ { description; messages }
726726 | j -> Util.json_error "Expected object for PromptsGet.Response.t" j
727727-728727 end
729729-728728+730729 (* Request/response creation helpers *)
731730 let create_request ~name ~arguments ?id () =
732732- let id = match id with
733733- | Some i -> i
734734- | None -> `Int (Random.int 10000)
735735- in
731731+ let id = match id with Some i -> i | None -> `Int (Random.int 10000) in
736732 let params = Request.yojson_of_t { name; arguments } in
737737- JSONRPCMessage.create_request ~id ~meth:Method.PromptsGet ~params:(Some params) ()
738738-733733+ JSONRPCMessage.create_request ~id ~meth:Method.PromptsGet
734734+ ~params:(Some params) ()
735735+739736 let create_response ~id ?description ~messages () =
740737 let result = Response.yojson_of_t { description; messages } in
741738 JSONRPCMessage.create_response ~id ~result
···744741(* List Changed Notifications *)
745742module ListChanged = struct
746743 (* No parameters for these notifications *)
747747-744744+748745 let create_resources_notification () =
749746 JSONRPCMessage.create_notification ~meth:Method.ResourcesListChanged ()
750750-747747+751748 let create_tools_notification () =
752749 JSONRPCMessage.create_notification ~meth:Method.ToolsListChanged ()
753753-750750+754751 let create_prompts_notification () =
755752 JSONRPCMessage.create_notification ~meth:Method.PromptsListChanged ()
756753end
···758755(* Resource Updated Notification *)
759756module ResourceUpdated = struct
760757 module Notification = struct
761761- type t = {
762762- uri: string;
763763- }
764764-765765- let yojson_of_t { uri } =
766766- `Assoc [
767767- ("uri", `String uri);
768768- ]
769769-758758+ type t = { uri : string }
759759+760760+ let yojson_of_t { uri } = `Assoc [ ("uri", `String uri) ]
761761+770762 let t_of_yojson = function
771763 | `Assoc fields as json ->
772772- let uri = match List.assoc_opt "uri" fields with
773773- | Some (`String s) -> s
774774- | _ -> Util.json_error "Missing or invalid 'uri' field" json
775775- in
776776- { uri }
777777- | j -> Util.json_error "Expected object for ResourceUpdated.Notification.t" j
778778-764764+ let uri =
765765+ match List.assoc_opt "uri" fields with
766766+ | Some (`String s) -> s
767767+ | _ -> Util.json_error "Missing or invalid 'uri' field" json
768768+ in
769769+ { uri }
770770+ | j ->
771771+ Util.json_error "Expected object for ResourceUpdated.Notification.t" j
779772 end
780780-773773+781774 let create_notification ~uri () =
782775 let params = Notification.yojson_of_t { uri } in
783783- JSONRPCMessage.create_notification ~meth:Method.ResourcesUpdated ~params:(Some params) ()
776776+ JSONRPCMessage.create_notification ~meth:Method.ResourcesUpdated
777777+ ~params:(Some params) ()
784778end
785779786780(* Progress Notification *)
787781module Progress = struct
788782 module Notification = struct
789783 type t = {
790790- progress: float;
791791- total: float;
792792- progress_token: ProgressToken.t;
784784+ progress : float;
785785+ total : float;
786786+ progress_token : ProgressToken.t;
793787 }
794794-788788+795789 let yojson_of_t { progress; total; progress_token } =
796796- `Assoc [
797797- ("progress", `Float progress);
798798- ("total", `Float total);
799799- ("progressToken", ProgressToken.yojson_of_t progress_token);
800800- ]
801801-790790+ `Assoc
791791+ [
792792+ ("progress", `Float progress);
793793+ ("total", `Float total);
794794+ ("progressToken", ProgressToken.yojson_of_t progress_token);
795795+ ]
796796+802797 let t_of_yojson = function
803798 | `Assoc fields as json ->
804804- let progress = match List.assoc_opt "progress" fields with
805805- | Some (`Float f) -> f
806806- | _ -> Util.json_error "Missing or invalid 'progress' field" json
807807- in
808808- let total = match List.assoc_opt "total" fields with
809809- | Some (`Float f) -> f
810810- | _ -> Util.json_error "Missing or invalid 'total' field" json
811811- in
812812- let progress_token = match List.assoc_opt "progressToken" fields with
813813- | Some token -> ProgressToken.t_of_yojson token
814814- | _ -> Util.json_error "Missing or invalid 'progressToken' field" json
815815- in
816816- { progress; total; progress_token }
799799+ let progress =
800800+ match List.assoc_opt "progress" fields with
801801+ | Some (`Float f) -> f
802802+ | _ -> Util.json_error "Missing or invalid 'progress' field" json
803803+ in
804804+ let total =
805805+ match List.assoc_opt "total" fields with
806806+ | Some (`Float f) -> f
807807+ | _ -> Util.json_error "Missing or invalid 'total' field" json
808808+ in
809809+ let progress_token =
810810+ match List.assoc_opt "progressToken" fields with
811811+ | Some token -> ProgressToken.t_of_yojson token
812812+ | _ ->
813813+ Util.json_error "Missing or invalid 'progressToken' field" json
814814+ in
815815+ { progress; total; progress_token }
817816 | j -> Util.json_error "Expected object for Progress.Notification.t" j
818818-819817 end
820820-818818+821819 let create_notification ~progress ~total ~progress_token () =
822820 let params = Notification.yojson_of_t { progress; total; progress_token } in
823823- JSONRPCMessage.create_notification ~meth:Method.Progress ~params:(Some params) ()
821821+ JSONRPCMessage.create_notification ~meth:Method.Progress
822822+ ~params:(Some params) ()
824823end
825824826825(* Type aliases for backward compatibility *)
827826type request = ResourcesList.Request.t
828828-type response = ResourcesList.Response.t
827827+type response = ResourcesList.Response.t
829828type resource = ResourcesList.Resource.t
830829type resource_content = ResourcesRead.ResourceContent.t
831830type tool = ToolsList.Tool.t
832831type tool_content = ToolsCall.ToolContent.t
833832type prompt = PromptsList.Prompt.t
834834-type prompt_argument = PromptsList.PromptArgument.t833833+type prompt_argument = PromptsList.PromptArgument.t
+184-116
lib/mcp_rpc.mli
···11-(** Mcp_message - High-level RPC message definitions for Model Context Protocol *)
11+(** Mcp_message - High-level RPC message definitions for Model Context Protocol
22+*)
2334open Mcp
45open Jsonrpc
···78module ResourcesList : sig
89 (** Request parameters *)
910 module Request : sig
1010- type t = {
1111- cursor: Cursor.t option; (** Optional pagination cursor *)
1212- }
1111+ type t = { cursor : Cursor.t option (** Optional pagination cursor *) }
1212+1313 include Json.Jsonable.S with type t := t
1414 end
1515-1515+1616 (** Resource definition *)
1717 module Resource : sig
1818 type t = {
1919- uri: string; (** Unique identifier for the resource *)
2020- name: string; (** Human-readable name *)
2121- description: string option; (** Optional description *)
2222- mime_type: string option; (** Optional MIME type *)
2323- size: int option; (** Optional size in bytes *)
1919+ uri : string; (** Unique identifier for the resource *)
2020+ name : string; (** Human-readable name *)
2121+ description : string option; (** Optional description *)
2222+ mime_type : string option; (** Optional MIME type *)
2323+ size : int option; (** Optional size in bytes *)
2424 }
2525+2526 include Json.Jsonable.S with type t := t
2627 end
2727-2828+2829 (** Response result *)
2930 module Response : sig
3031 type t = {
3131- resources: Resource.t list; (** List of available resources *)
3232- next_cursor: Cursor.t option; (** Optional cursor for the next page *)
3232+ resources : Resource.t list; (** List of available resources *)
3333+ next_cursor : Cursor.t option; (** Optional cursor for the next page *)
3334 }
3535+3436 include Json.Jsonable.S with type t := t
3537 end
3636-3838+3939+ val create_request :
4040+ ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
3741 (** Create a resources/list request *)
3838- val create_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
3939-4242+4343+ val create_response :
4444+ id:RequestId.t ->
4545+ resources:Resource.t list ->
4646+ ?next_cursor:Cursor.t ->
4747+ unit ->
4848+ JSONRPCMessage.t
4049 (** Create a resources/list response *)
4141- val create_response : id:RequestId.t -> resources:Resource.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
4250end
43514452(** Resources/Templates/List - Request to list available resource templates *)
4553module ListResourceTemplatesRequest : sig
4646- type t = {
4747- cursor: Cursor.t option; (** Optional pagination cursor *)
4848- }
5454+ type t = { cursor : Cursor.t option (** Optional pagination cursor *) }
5555+4956 include Json.Jsonable.S with type t := t
5057end
5158···5461 (** Resource Template definition *)
5562 module ResourceTemplate : sig
5663 type t = {
5757- uri_template: string; (** URI template for the resource *)
5858- name: string; (** Human-readable name *)
5959- description: string option; (** Optional description *)
6060- mime_type: string option; (** Optional MIME type *)
6464+ uri_template : string; (** URI template for the resource *)
6565+ name : string; (** Human-readable name *)
6666+ description : string option; (** Optional description *)
6767+ mime_type : string option; (** Optional MIME type *)
6168 }
6969+6270 include Json.Jsonable.S with type t := t
6371 end
6464-7272+6573 type t = {
6666- resource_templates: ResourceTemplate.t list; (** List of available resource templates *)
6767- next_cursor: Cursor.t option; (** Optional cursor for the next page *)
7474+ resource_templates : ResourceTemplate.t list;
7575+ (** List of available resource templates *)
7676+ next_cursor : Cursor.t option; (** Optional cursor for the next page *)
6877 }
7878+6979 include Json.Jsonable.S with type t := t
7070-8080+8181+ val create_request :
8282+ ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
7183 (** Create a resources/templates/list request *)
7272- val create_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
7373-8484+8585+ val create_response :
8686+ id:RequestId.t ->
8787+ resource_templates:ResourceTemplate.t list ->
8888+ ?next_cursor:Cursor.t ->
8989+ unit ->
9090+ JSONRPCMessage.t
7491 (** Create a resources/templates/list response *)
7575- val create_response : id:RequestId.t -> resource_templates:ResourceTemplate.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
7692end
77937894(** Resources/Read - Request to read resource contents *)
7995module ResourcesRead : sig
8096 (** Request parameters *)
8197 module Request : sig
8282- type t = {
8383- uri: string; (** URI of the resource to read *)
8484- }
9898+ type t = { uri : string (** URI of the resource to read *) }
9999+85100 include Json.Jsonable.S with type t := t
86101 end
8787-102102+88103 (** Resource content *)
89104 module ResourceContent : sig
9090- type t =
9191- | TextResource of TextResourceContents.t (** Text content *)
9292- | BlobResource of BlobResourceContents.t (** Binary content *)
105105+ type t =
106106+ | TextResource of TextResourceContents.t (** Text content *)
107107+ | BlobResource of BlobResourceContents.t (** Binary content *)
108108+93109 include Json.Jsonable.S with type t := t
94110 end
9595-111111+96112 (** Response result *)
97113 module Response : sig
98114 type t = {
9999- contents: ResourceContent.t list; (** List of resource contents *)
115115+ contents : ResourceContent.t list; (** List of resource contents *)
100116 }
117117+101118 include Json.Jsonable.S with type t := t
102119 end
103103-120120+121121+ val create_request : uri:string -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
104122 (** Create a resources/read request *)
105105- val create_request : uri:string -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
106106-123123+124124+ val create_response :
125125+ id:RequestId.t ->
126126+ contents:ResourceContent.t list ->
127127+ unit ->
128128+ JSONRPCMessage.t
107129 (** Create a resources/read response *)
108108- val create_response : id:RequestId.t -> contents:ResourceContent.t list -> unit -> JSONRPCMessage.t
109130end
110131111132(** Tools/List - Request to list available tools *)
112133module ToolsList : sig
113134 (** Request parameters *)
114135 module Request : sig
115115- type t = {
116116- cursor: Cursor.t option; (** Optional pagination cursor *)
117117- }
136136+ type t = { cursor : Cursor.t option (** Optional pagination cursor *) }
137137+118138 include Json.Jsonable.S with type t := t
119139 end
120120-140140+121141 (** Tool definition *)
122142 module Tool : sig
123143 type t = {
124124- name: string; (** Unique identifier for the tool *)
125125- description: string option; (** Human-readable description *)
126126- input_schema: Json.t; (** JSON Schema defining expected parameters *)
127127- annotations: Json.t option; (** Optional properties describing tool behavior *)
144144+ name : string; (** Unique identifier for the tool *)
145145+ description : string option; (** Human-readable description *)
146146+ input_schema : Json.t; (** JSON Schema defining expected parameters *)
147147+ annotations : Json.t option;
148148+ (** Optional properties describing tool behavior *)
128149 }
150150+129151 include Json.Jsonable.S with type t := t
130152 end
131131-153153+132154 (** Response result *)
133155 module Response : sig
134156 type t = {
135135- tools: Tool.t list; (** List of available tools *)
136136- next_cursor: Cursor.t option; (** Optional cursor for the next page *)
157157+ tools : Tool.t list; (** List of available tools *)
158158+ next_cursor : Cursor.t option; (** Optional cursor for the next page *)
137159 }
160160+138161 include Json.Jsonable.S with type t := t
139162 end
140140-163163+164164+ val create_request :
165165+ ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
141166 (** Create a tools/list request *)
142142- val create_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
143143-167167+168168+ val create_response :
169169+ id:RequestId.t ->
170170+ tools:Tool.t list ->
171171+ ?next_cursor:Cursor.t ->
172172+ unit ->
173173+ JSONRPCMessage.t
144174 (** Create a tools/list response *)
145145- val create_response : id:RequestId.t -> tools:Tool.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
146175end
147176148177(** Tools/Call - Request to invoke a tool *)
···150179 (** Request parameters *)
151180 module Request : sig
152181 type t = {
153153- name: string; (** Name of the tool to call *)
154154- arguments: Json.t; (** Arguments for the tool invocation *)
182182+ name : string; (** Name of the tool to call *)
183183+ arguments : Json.t; (** Arguments for the tool invocation *)
155184 }
185185+156186 include Json.Jsonable.S with type t := t
157187 end
158158-188188+159189 (** Tool content *)
160190 module ToolContent : sig
161161- type t =
162162- | Text of TextContent.t (** Text content *)
163163- | Image of ImageContent.t (** Image content *)
164164- | Audio of AudioContent.t (** Audio content *)
165165- | Resource of EmbeddedResource.t (** Resource content *)
191191+ type t =
192192+ | Text of TextContent.t (** Text content *)
193193+ | Image of ImageContent.t (** Image content *)
194194+ | Audio of AudioContent.t (** Audio content *)
195195+ | Resource of EmbeddedResource.t (** Resource content *)
196196+166197 include Json.Jsonable.S with type t := t
167198 end
168168-199199+169200 (** Response result *)
170201 module Response : sig
171202 type t = {
172172- content: ToolContent.t list; (** List of content items returned by the tool *)
173173- is_error: bool; (** Whether the result represents an error *)
203203+ content : ToolContent.t list;
204204+ (** List of content items returned by the tool *)
205205+ is_error : bool; (** Whether the result represents an error *)
174206 }
207207+175208 include Json.Jsonable.S with type t := t
176209 end
177177-210210+211211+ val create_request :
212212+ name:string ->
213213+ arguments:Json.t ->
214214+ ?id:RequestId.t ->
215215+ unit ->
216216+ JSONRPCMessage.t
178217 (** Create a tools/call request *)
179179- val create_request : name:string -> arguments:Json.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
180180-218218+219219+ val create_response :
220220+ id:RequestId.t ->
221221+ content:ToolContent.t list ->
222222+ is_error:bool ->
223223+ unit ->
224224+ JSONRPCMessage.t
181225 (** Create a tools/call response *)
182182- val create_response : id:RequestId.t -> content:ToolContent.t list -> is_error:bool -> unit -> JSONRPCMessage.t
183226end
184227185228(** Prompts/List - Request to list available prompts *)
···187230 (** Prompt argument *)
188231 module PromptArgument : sig
189232 type t = {
190190- name: string; (** Name of the argument *)
191191- description: string option; (** Description of the argument *)
192192- required: bool; (** Whether the argument is required *)
233233+ name : string; (** Name of the argument *)
234234+ description : string option; (** Description of the argument *)
235235+ required : bool; (** Whether the argument is required *)
193236 }
237237+194238 include Json.Jsonable.S with type t := t
195239 end
196196-240240+197241 (** Prompt definition *)
198242 module Prompt : sig
199243 type t = {
200200- name: string; (** Unique identifier for the prompt *)
201201- description: string option; (** Human-readable description *)
202202- arguments: PromptArgument.t list; (** Arguments for customization *)
244244+ name : string; (** Unique identifier for the prompt *)
245245+ description : string option; (** Human-readable description *)
246246+ arguments : PromptArgument.t list; (** Arguments for customization *)
203247 }
248248+204249 include Json.Jsonable.S with type t := t
205250 end
206206-251251+207252 (** Request parameters *)
208253 module Request : sig
209209- type t = {
210210- cursor: Cursor.t option; (** Optional pagination cursor *)
211211- }
254254+ type t = { cursor : Cursor.t option (** Optional pagination cursor *) }
255255+212256 include Json.Jsonable.S with type t := t
213257 end
214214-258258+215259 (** Response result *)
216260 module Response : sig
217261 type t = {
218218- prompts: Prompt.t list; (** List of available prompts *)
219219- next_cursor: Cursor.t option; (** Optional cursor for the next page *)
262262+ prompts : Prompt.t list; (** List of available prompts *)
263263+ next_cursor : Cursor.t option; (** Optional cursor for the next page *)
220264 }
265265+221266 include Json.Jsonable.S with type t := t
222267 end
223223-268268+269269+ val create_request :
270270+ ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
224271 (** Create a prompts/list request *)
225225- val create_request : ?cursor:Cursor.t -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
226226-272272+273273+ val create_response :
274274+ id:RequestId.t ->
275275+ prompts:Prompt.t list ->
276276+ ?next_cursor:Cursor.t ->
277277+ unit ->
278278+ JSONRPCMessage.t
227279 (** Create a prompts/list response *)
228228- val create_response : id:RequestId.t -> prompts:Prompt.t list -> ?next_cursor:Cursor.t -> unit -> JSONRPCMessage.t
229280end
230281231282(** Prompts/Get - Request to get a prompt with arguments *)
···233284 (** Request parameters *)
234285 module Request : sig
235286 type t = {
236236- name: string; (** Name of the prompt to get *)
237237- arguments: (string * string) list; (** Arguments for the prompt *)
287287+ name : string; (** Name of the prompt to get *)
288288+ arguments : (string * string) list; (** Arguments for the prompt *)
238289 }
290290+239291 include Json.Jsonable.S with type t := t
240292 end
241241-293293+242294 (** Response result *)
243295 module Response : sig
244296 type t = {
245245- description: string option; (** Description of the prompt *)
246246- messages: PromptMessage.t list; (** List of messages in the prompt *)
297297+ description : string option; (** Description of the prompt *)
298298+ messages : PromptMessage.t list; (** List of messages in the prompt *)
247299 }
300300+248301 include Json.Jsonable.S with type t := t
249302 end
250250-303303+304304+ val create_request :
305305+ name:string ->
306306+ arguments:(string * string) list ->
307307+ ?id:RequestId.t ->
308308+ unit ->
309309+ JSONRPCMessage.t
251310 (** Create a prompts/get request *)
252252- val create_request : name:string -> arguments:(string * string) list -> ?id:RequestId.t -> unit -> JSONRPCMessage.t
253253-311311+312312+ val create_response :
313313+ id:RequestId.t ->
314314+ ?description:string ->
315315+ messages:PromptMessage.t list ->
316316+ unit ->
317317+ JSONRPCMessage.t
254318 (** Create a prompts/get response *)
255255- val create_response : id:RequestId.t -> ?description:string -> messages:PromptMessage.t list -> unit -> JSONRPCMessage.t
256319end
257320258321(** List Changed Notifications *)
259322module ListChanged : sig
260260- (** Create a resources/list_changed notification *)
261323 val create_resources_notification : unit -> JSONRPCMessage.t
262262-263263- (** Create a tools/list_changed notification *)
324324+ (** Create a resources/list_changed notification *)
325325+264326 val create_tools_notification : unit -> JSONRPCMessage.t
265265-327327+ (** Create a tools/list_changed notification *)
328328+329329+ val create_prompts_notification : unit -> JSONRPCMessage.t
266330 (** Create a prompts/list_changed notification *)
267267- val create_prompts_notification : unit -> JSONRPCMessage.t
268331end
269332270333(** Resource Updated Notification *)
271334module ResourceUpdated : sig
272335 (** Notification parameters *)
273336 module Notification : sig
274274- type t = {
275275- uri: string; (** URI of the updated resource *)
276276- }
337337+ type t = { uri : string (** URI of the updated resource *) }
338338+277339 include Json.Jsonable.S with type t := t
278340 end
279279-341341+342342+ val create_notification : uri:string -> unit -> JSONRPCMessage.t
280343 (** Create a resources/updated notification *)
281281- val create_notification : uri:string -> unit -> JSONRPCMessage.t
282344end
283345284346(** Progress Notification *)
···286348 (** Notification parameters *)
287349 module Notification : sig
288350 type t = {
289289- progress: float; (** Current progress value *)
290290- total: float; (** Total progress value *)
291291- progress_token: ProgressToken.t; (** Token identifying the operation *)
351351+ progress : float; (** Current progress value *)
352352+ total : float; (** Total progress value *)
353353+ progress_token : ProgressToken.t; (** Token identifying the operation *)
292354 }
355355+293356 include Json.Jsonable.S with type t := t
294357 end
295295-358358+359359+ val create_notification :
360360+ progress:float ->
361361+ total:float ->
362362+ progress_token:ProgressToken.t ->
363363+ unit ->
364364+ JSONRPCMessage.t
296365 (** Create a progress notification *)
297297- val create_notification : progress:float -> total:float -> progress_token:ProgressToken.t -> unit -> JSONRPCMessage.t
298366end
+316-327
lib/mcp_sdk.ml
···16161717 let logf level fmt =
1818 Printf.fprintf stderr "[%s] " (string_of_level level);
1919- Printf.kfprintf (fun oc -> Printf.fprintf oc "\n"; flush oc) stderr fmt
1919+ Printf.kfprintf
2020+ (fun oc ->
2121+ Printf.fprintf oc "\n";
2222+ flush oc)
2323+ stderr fmt
20242125 let debugf fmt = logf Debug fmt
2226 let infof fmt = logf Info fmt
2327 let warningf fmt = logf Warning fmt
2428 let errorf fmt = logf Error fmt
2525-2929+2630 (* Backward compatibility functions that take a simple string *)
2731 let log level msg = logf level "%s" msg
2832 let debug msg = debugf "%s" msg
···3438(* Context for tools and resources *)
3539module Context = struct
3640 type t = {
3737- request_id: RequestId.t option;
3838- lifespan_context: (string * Json.t) list;
3939- progress_token: ProgressToken.t option;
4141+ request_id : RequestId.t option;
4242+ lifespan_context : (string * Json.t) list;
4343+ progress_token : ProgressToken.t option;
4044 }
41454242- let create ?request_id ?progress_token ?(lifespan_context=[]) () =
4646+ let create ?request_id ?progress_token ?(lifespan_context = []) () =
4347 { request_id; lifespan_context; progress_token }
44484545- let get_context_value ctx key =
4646- List.assoc_opt key ctx.lifespan_context
4747-4949+ let get_context_value ctx key = List.assoc_opt key ctx.lifespan_context
5050+4851 let report_progress ctx value total =
4949- match ctx.progress_token, ctx.request_id with
5252+ match (ctx.progress_token, ctx.request_id) with
5053 | Some token, Some _id ->
5151- let params = `Assoc [
5252- ("progress", `Float value);
5353- ("total", `Float total);
5454- ("progressToken", ProgressToken.yojson_of_t token)
5555- ] in
5656- Some (create_notification ~meth:Method.Progress ~params:(Some params) ())
5454+ let params =
5555+ `Assoc
5656+ [
5757+ ("progress", `Float value);
5858+ ("total", `Float total);
5959+ ("progressToken", ProgressToken.yojson_of_t token);
6060+ ]
6161+ in
6262+ Some
6363+ (create_notification ~meth:Method.Progress ~params:(Some params) ())
5764 | _ -> None
5865end
5966···6269 type handler = Context.t -> Json.t -> (Json.t, string) result
63706471 type t = {
6565- name: string;
6666- description: string option;
6767- input_schema: Json.t; (* JSON Schema *)
6868- handler: handler;
7272+ name : string;
7373+ description : string option;
7474+ input_schema : Json.t; (* JSON Schema *)
7575+ handler : handler;
6976 }
70777171- let create ~name ?description ~input_schema ~handler () =
7878+ let create ~name ?description ~input_schema ~handler () =
7279 { name; description; input_schema; handler }
73807481 let to_json tool =
7575- let assoc = [
7676- ("name", `String tool.name);
7777- ("inputSchema", tool.input_schema);
7878- ] in
7979- let assoc = match tool.description with
8282+ let assoc =
8383+ [ ("name", `String tool.name); ("inputSchema", tool.input_schema) ]
8484+ in
8585+ let assoc =
8686+ match tool.description with
8087 | Some desc -> ("description", `String desc) :: assoc
8188 | None -> assoc
8289 in
8390 `Assoc assoc
8484-9191+8592 (* Convert to Mcp_rpc.ToolsList.Tool.t *)
8686- let to_rpc_tool_list_tool (tool:t) =
8787- Mcp_rpc.ToolsList.Tool.{
8888- name = tool.name;
8989- description = tool.description;
9090- input_schema = tool.input_schema;
9191- annotations = None; (* Could be extended to support annotations *)
9292- }
9393+ let to_rpc_tool_list_tool (tool : t) =
9494+ Mcp_rpc.ToolsList.Tool.
9595+ {
9696+ name = tool.name;
9797+ description = tool.description;
9898+ input_schema = tool.input_schema;
9999+ annotations = None;
100100+ (* Could be extended to support annotations *)
101101+ }
9310294103 (* Convert a list of Tool.t to the format needed for tools/list response *)
9595- let to_rpc_tools_list tools =
9696- List.map to_rpc_tool_list_tool tools
104104+ let to_rpc_tools_list tools = List.map to_rpc_tool_list_tool tools
9710598106 (* Convert Mcp_rpc.ToolsCall response content to Mcp.content list *)
99107 let rpc_content_to_mcp_content content =
100100- List.map (function
101101- | Mcp_rpc.ToolsCall.ToolContent.Text t ->
102102- Mcp.Text { TextContent.text = t.text; annotations = None }
103103- | Mcp_rpc.ToolsCall.ToolContent.Image i ->
104104- Mcp.Image {
105105- ImageContent.mime_type = i.mime_type;
106106- data = i.data;
107107- annotations = None
108108- }
109109- | Mcp_rpc.ToolsCall.ToolContent.Audio a ->
110110- Mcp.Audio {
111111- AudioContent.mime_type = a.mime_type;
112112- data = a.data;
113113- annotations = None
114114- }
115115- | Mcp_rpc.ToolsCall.ToolContent.Resource r ->
116116- (* Create a simple text resource from the embedded resource *)
117117- let uri = match r with
118118- | { EmbeddedResource.resource = `Text tr; _ } -> tr.uri
119119- | { EmbeddedResource.resource = `Blob br; _ } -> br.uri
120120- in
121121- let text_content = match r with
122122- | { EmbeddedResource.resource = `Text tr; _ } -> tr.text
123123- | { EmbeddedResource.resource = `Blob br; _ } -> "Binary content"
124124- in
125125- let mime_type = match r with
126126- | { EmbeddedResource.resource = `Text tr; _ } -> tr.mime_type
127127- | { EmbeddedResource.resource = `Blob br; _ } -> br.mime_type
128128- in
129129- let text_resource = {
130130- TextResourceContents.uri;
131131- text = text_content;
132132- mime_type
133133- } in
134134- Mcp.Resource {
135135- EmbeddedResource.resource = `Text text_resource;
136136- annotations = None
137137- }
138138- ) content
108108+ List.map
109109+ (function
110110+ | Mcp_rpc.ToolsCall.ToolContent.Text t ->
111111+ Mcp.Text { TextContent.text = t.text; annotations = None }
112112+ | Mcp_rpc.ToolsCall.ToolContent.Image i ->
113113+ Mcp.Image
114114+ {
115115+ ImageContent.mime_type = i.mime_type;
116116+ data = i.data;
117117+ annotations = None;
118118+ }
119119+ | Mcp_rpc.ToolsCall.ToolContent.Audio a ->
120120+ Mcp.Audio
121121+ {
122122+ AudioContent.mime_type = a.mime_type;
123123+ data = a.data;
124124+ annotations = None;
125125+ }
126126+ | Mcp_rpc.ToolsCall.ToolContent.Resource r ->
127127+ (* Create a simple text resource from the embedded resource *)
128128+ let uri =
129129+ match r with
130130+ | { EmbeddedResource.resource = `Text tr; _ } -> tr.uri
131131+ | { EmbeddedResource.resource = `Blob br; _ } -> br.uri
132132+ in
133133+ let text_content =
134134+ match r with
135135+ | { EmbeddedResource.resource = `Text tr; _ } -> tr.text
136136+ | { EmbeddedResource.resource = `Blob br; _ } -> "Binary content"
137137+ in
138138+ let mime_type =
139139+ match r with
140140+ | { EmbeddedResource.resource = `Text tr; _ } -> tr.mime_type
141141+ | { EmbeddedResource.resource = `Blob br; _ } -> br.mime_type
142142+ in
143143+ let text_resource =
144144+ { TextResourceContents.uri; text = text_content; mime_type }
145145+ in
146146+ Mcp.Resource
147147+ {
148148+ EmbeddedResource.resource = `Text text_resource;
149149+ annotations = None;
150150+ })
151151+ content
139152140153 (* Convert Mcp.content list to Mcp_rpc.ToolsCall.ToolContent.t list *)
141154 let mcp_content_to_rpc_content content =
142142- List.map (function
143143- | Mcp.Text t ->
144144- Mcp_rpc.ToolsCall.ToolContent.Text t
145145- | Mcp.Image img ->
146146- Mcp_rpc.ToolsCall.ToolContent.Image img
147147- | Mcp.Audio aud ->
148148- Mcp_rpc.ToolsCall.ToolContent.Audio aud
149149- | Mcp.Resource res ->
150150- let resource_data = match res.resource with
151151- | `Text txt -> `Text txt
152152- | `Blob blob -> `Blob blob
153153- in
154154- let resource = {
155155- EmbeddedResource.resource = resource_data;
156156- annotations = res.annotations
157157- } in
158158- Mcp_rpc.ToolsCall.ToolContent.Resource resource
159159- ) content
160160-155155+ List.map
156156+ (function
157157+ | Mcp.Text t -> Mcp_rpc.ToolsCall.ToolContent.Text t
158158+ | Mcp.Image img -> Mcp_rpc.ToolsCall.ToolContent.Image img
159159+ | Mcp.Audio aud -> Mcp_rpc.ToolsCall.ToolContent.Audio aud
160160+ | Mcp.Resource res ->
161161+ let resource_data =
162162+ match res.resource with
163163+ | `Text txt -> `Text txt
164164+ | `Blob blob -> `Blob blob
165165+ in
166166+ let resource =
167167+ {
168168+ EmbeddedResource.resource = resource_data;
169169+ annotations = res.annotations;
170170+ }
171171+ in
172172+ Mcp_rpc.ToolsCall.ToolContent.Resource resource)
173173+ content
174174+161175 (* Create a tool result with content *)
162176 let create_tool_result content ~is_error =
163163- `Assoc [
164164- ("content", `List (List.map Mcp.yojson_of_content content));
165165- ("isError", `Bool is_error);
166166- ]
177177+ `Assoc
178178+ [
179179+ ("content", `List (List.map Mcp.yojson_of_content content));
180180+ ("isError", `Bool is_error);
181181+ ]
167182168183 (* Create a tool error result with structured content *)
169184 let create_error_result error =
170185 Log.errorf "Error result: %s" error;
171171- create_tool_result [Mcp.make_text_content error] ~is_error:true
172172-186186+ create_tool_result [ Mcp.make_text_content error ] ~is_error:true
187187+173188 (* Handle tool execution errors *)
174189 let handle_execution_error err =
175190 create_error_result (Printf.sprintf "Error executing tool: %s" err)
176176-191191+177192 (* Handle unknown tool error *)
178193 let handle_unknown_tool_error name =
179194 create_error_result (Printf.sprintf "Unknown tool: %s" name)
180180-195195+181196 (* Handle general tool execution exception *)
182197 let handle_execution_exception exn =
183183- create_error_result (Printf.sprintf "Internal error: %s" (Printexc.to_string exn))
198198+ create_error_result
199199+ (Printf.sprintf "Internal error: %s" (Printexc.to_string exn))
184200end
185201186202(* Resources for the MCP server *)
···188204 type handler = Context.t -> string list -> (string, string) result
189205190206 type t = {
191191- uri: string; (* For resources, this is the exact URI (no variables) *)
192192- name: string;
193193- description: string option;
194194- mime_type: string option;
195195- handler: handler;
207207+ uri : string; (* For resources, this is the exact URI (no variables) *)
208208+ name : string;
209209+ description : string option;
210210+ mime_type : string option;
211211+ handler : handler;
196212 }
197213198214 let create ~uri ~name ?description ?mime_type ~handler () =
199215 (* Validate that the URI doesn't contain template variables *)
200216 if String.contains uri '{' || String.contains uri '}' then
201201- Log.warningf "Resource '%s' contains template variables. Consider using add_resource_template instead." uri;
217217+ Log.warningf
218218+ "Resource '%s' contains template variables. Consider using \
219219+ add_resource_template instead."
220220+ uri;
202221 { uri; name; description; mime_type; handler }
203222204223 let to_json resource =
205205- let assoc = [
206206- ("uri", `String resource.uri);
207207- ("name", `String resource.name);
208208- ] in
209209- let assoc = match resource.description with
224224+ let assoc =
225225+ [ ("uri", `String resource.uri); ("name", `String resource.name) ]
226226+ in
227227+ let assoc =
228228+ match resource.description with
210229 | Some desc -> ("description", `String desc) :: assoc
211230 | None -> assoc
212231 in
213213- let assoc = match resource.mime_type with
232232+ let assoc =
233233+ match resource.mime_type with
214234 | Some mime -> ("mimeType", `String mime) :: assoc
215235 | None -> assoc
216236 in
217237 `Assoc assoc
218218-238238+219239 (* Convert to Mcp_rpc.ResourcesList.Resource.t *)
220220- let to_rpc_resource_list_resource (resource:t) =
221221- Mcp_rpc.ResourcesList.Resource.{
222222- uri = resource.uri;
223223- name = resource.name;
224224- description = resource.description;
225225- mime_type = resource.mime_type;
226226- size = None; (* Size can be added when we have actual resource content *)
227227- }
228228-240240+ let to_rpc_resource_list_resource (resource : t) =
241241+ Mcp_rpc.ResourcesList.Resource.
242242+ {
243243+ uri = resource.uri;
244244+ name = resource.name;
245245+ description = resource.description;
246246+ mime_type = resource.mime_type;
247247+ size = None;
248248+ (* Size can be added when we have actual resource content *)
249249+ }
250250+229251 (* Convert a list of Resource.t to the format needed for resources/list response *)
230252 let to_rpc_resources_list resources =
231253 List.map to_rpc_resource_list_resource resources
···234256(* Prompts for the MCP server *)
235257module Prompt = struct
236258 type argument = {
237237- name: string;
238238- description: string option;
239239- required: bool;
259259+ name : string;
260260+ description : string option;
261261+ required : bool;
240262 }
241263242242- type message = {
243243- role: Role.t;
244244- content: content;
245245- }
264264+ type message = { role : Role.t; content : content }
246265247247- type handler = Context.t -> (string * string) list -> (message list, string) result
266266+ type handler =
267267+ Context.t -> (string * string) list -> (message list, string) result
248268249269 type t = {
250250- name: string;
251251- description: string option;
252252- arguments: argument list;
253253- handler: handler;
270270+ name : string;
271271+ description : string option;
272272+ arguments : argument list;
273273+ handler : handler;
254274 }
255275256256- let create ~name ?description ?(arguments=[]) ~handler () =
276276+ let create ~name ?description ?(arguments = []) ~handler () =
257277 { name; description; arguments; handler }
258278259259- let create_argument ~name ?description ?(required=false) () =
279279+ let create_argument ~name ?description ?(required = false) () =
260280 { name; description; required }
261281262282 let to_json prompt =
263263- let assoc = [
264264- ("name", `String prompt.name);
265265- ] in
266266- let assoc = match prompt.description with
283283+ let assoc = [ ("name", `String prompt.name) ] in
284284+ let assoc =
285285+ match prompt.description with
267286 | Some desc -> ("description", `String desc) :: assoc
268287 | None -> assoc
269288 in
270270- let assoc = if prompt.arguments <> [] then
271271- let args = List.map (fun (arg: argument) ->
272272- let arg_assoc = [
273273- ("name", `String arg.name);
274274- ] in
275275- let arg_assoc = match arg.description with
276276- | Some desc -> ("description", `String desc) :: arg_assoc
277277- | None -> arg_assoc
289289+ let assoc =
290290+ if prompt.arguments <> [] then
291291+ let args =
292292+ List.map
293293+ (fun (arg : argument) ->
294294+ let arg_assoc = [ ("name", `String arg.name) ] in
295295+ let arg_assoc =
296296+ match arg.description with
297297+ | Some desc -> ("description", `String desc) :: arg_assoc
298298+ | None -> arg_assoc
299299+ in
300300+ let arg_assoc =
301301+ if arg.required then ("required", `Bool true) :: arg_assoc
302302+ else arg_assoc
303303+ in
304304+ `Assoc arg_assoc)
305305+ prompt.arguments
278306 in
279279- let arg_assoc =
280280- if arg.required then
281281- ("required", `Bool true) :: arg_assoc
282282- else
283283- arg_assoc
284284- in
285285- `Assoc arg_assoc
286286- ) prompt.arguments in
287287- ("arguments", `List args) :: assoc
288288- else
289289- assoc
307307+ ("arguments", `List args) :: assoc
308308+ else assoc
290309 in
291310 `Assoc assoc
292292-311311+293312 (* Convert argument to Mcp_rpc.PromptsList.PromptArgument.t *)
294294- let argument_to_rpc_prompt_argument (arg:argument) =
295295- Mcp_rpc.PromptsList.PromptArgument.{
296296- name = arg.name;
297297- description = arg.description;
298298- required = arg.required;
299299- }
300300-313313+ let argument_to_rpc_prompt_argument (arg : argument) =
314314+ Mcp_rpc.PromptsList.PromptArgument.
315315+ {
316316+ name = arg.name;
317317+ description = arg.description;
318318+ required = arg.required;
319319+ }
320320+301321 (* Convert to Mcp_rpc.PromptsList.Prompt.t *)
302302- let to_rpc_prompt_list_prompt (prompt:t) =
303303- Mcp_rpc.PromptsList.Prompt.{
304304- name = prompt.name;
305305- description = prompt.description;
306306- arguments = List.map argument_to_rpc_prompt_argument prompt.arguments;
307307- }
308308-322322+ let to_rpc_prompt_list_prompt (prompt : t) =
323323+ Mcp_rpc.PromptsList.Prompt.
324324+ {
325325+ name = prompt.name;
326326+ description = prompt.description;
327327+ arguments = List.map argument_to_rpc_prompt_argument prompt.arguments;
328328+ }
329329+309330 (* Convert a list of Prompt.t to the format needed for prompts/list response *)
310310- let to_rpc_prompts_list prompts =
311311- List.map to_rpc_prompt_list_prompt prompts
312312-331331+ let to_rpc_prompts_list prompts = List.map to_rpc_prompt_list_prompt prompts
332332+313333 (* Convert message to Mcp_rpc.PromptMessage.t *)
314334 let message_to_rpc_prompt_message msg =
315315- {
316316- PromptMessage.role = msg.role;
317317- PromptMessage.content = msg.content;
318318- }
319319-335335+ { PromptMessage.role = msg.role; PromptMessage.content = msg.content }
336336+320337 (* Convert a list of messages to the format needed for prompts/get response *)
321338 let messages_to_rpc_prompt_messages messages =
322339 List.map message_to_rpc_prompt_message messages
323340end
324341325342let make_tool_schema properties required =
326326- let props = List.map (fun (name, schema_type, description) ->
327327- (name, `Assoc [
328328- ("type", `String schema_type);
329329- ("description", `String description)
330330- ])
331331- ) properties in
343343+ let props =
344344+ List.map
345345+ (fun (name, schema_type, description) ->
346346+ ( name,
347347+ `Assoc
348348+ [
349349+ ("type", `String schema_type); ("description", `String description);
350350+ ] ))
351351+ properties
352352+ in
332353 let required_json = `List (List.map (fun name -> `String name) required) in
333333- `Assoc [
334334- ("type", `String "object");
335335- ("properties", `Assoc props);
336336- ("required", required_json)
337337- ]
354354+ `Assoc
355355+ [
356356+ ("type", `String "object");
357357+ ("properties", `Assoc props);
358358+ ("required", required_json);
359359+ ]
338360339361(* Resource Templates for the MCP server *)
340362module ResourceTemplate = struct
341363 type handler = Context.t -> string list -> (string, string) result
342364343365 type t = {
344344- uri_template: string;
345345- name: string;
346346- description: string option;
347347- mime_type: string option;
348348- handler: handler;
366366+ uri_template : string;
367367+ name : string;
368368+ description : string option;
369369+ mime_type : string option;
370370+ handler : handler;
349371 }
350372351351- let create ~uri_template ~name ?description ?mime_type ~handler () =
373373+ let create ~uri_template ~name ?description ?mime_type ~handler () =
352374 { uri_template; name; description; mime_type; handler }
353375354376 let to_json resource_template =
355355- let assoc = [
356356- ("uriTemplate", `String resource_template.uri_template);
357357- ("name", `String resource_template.name);
358358- ] in
359359- let assoc = match resource_template.description with
377377+ let assoc =
378378+ [
379379+ ("uriTemplate", `String resource_template.uri_template);
380380+ ("name", `String resource_template.name);
381381+ ]
382382+ in
383383+ let assoc =
384384+ match resource_template.description with
360385 | Some desc -> ("description", `String desc) :: assoc
361386 | None -> assoc
362387 in
363363- let assoc = match resource_template.mime_type with
388388+ let assoc =
389389+ match resource_template.mime_type with
364390 | Some mime -> ("mimeType", `String mime) :: assoc
365391 | None -> assoc
366392 in
367393 `Assoc assoc
368368-394394+369395 (* Convert to Mcp_rpc.ResourceTemplatesList.ResourceTemplate.t *)
370370- let to_rpc_resource_template (template:t) =
371371- Mcp_rpc.ListResourceTemplatesResult.ResourceTemplate.{
372372- uri_template = template.uri_template;
373373- name = template.name;
374374- description = template.description;
375375- mime_type = template.mime_type;
376376- }
377377-396396+ let to_rpc_resource_template (template : t) =
397397+ Mcp_rpc.ListResourceTemplatesResult.ResourceTemplate.
398398+ {
399399+ uri_template = template.uri_template;
400400+ name = template.name;
401401+ description = template.description;
402402+ mime_type = template.mime_type;
403403+ }
404404+378405 (* Convert a list of ResourceTemplate.t to the format needed for resources/templates/list response *)
379406 let to_rpc_resource_templates_list templates =
380407 List.map to_rpc_resource_template templates
···382409383410(* Main server type *)
384411type server = {
385385- name: string;
386386- version: string;
387387- protocol_version: string;
388388- lifespan_context: (string * Json.t) list;
389389- mutable capabilities: Json.t;
390390- mutable tools: Tool.t list;
391391- mutable resources: Resource.t list;
392392- mutable resource_templates: ResourceTemplate.t list;
393393- mutable prompts: Prompt.t list;
394394-}
412412+ name : string;
413413+ version : string;
414414+ protocol_version : string;
415415+ lifespan_context : (string * Json.t) list;
416416+ mutable capabilities : Json.t;
417417+ mutable tools : Tool.t list;
418418+ mutable resources : Resource.t list;
419419+ mutable resource_templates : ResourceTemplate.t list;
420420+ mutable prompts : Prompt.t list;
421421+}
395422396423let name { name; _ } = name
397424let version { version; _ } = version
···404431let prompts { prompts; _ } = prompts
405432406433(* Create a new server *)
407407-let create_server ~name ?(version="0.1.0") ?(protocol_version="2024-11-05") () =
408408- {
434434+let create_server ~name ?(version = "0.1.0") ?(protocol_version = "2024-11-05")
435435+ () =
436436+ {
409437 name;
410438 version;
411439 protocol_version;
···418446 }
419447420448(* Default capabilities for the server *)
421421-let default_capabilities ?(with_tools=true) ?(with_resources=false) ?(with_resource_templates=false) ?(with_prompts=false) () =
449449+let default_capabilities ?(with_tools = true) ?(with_resources = false)
450450+ ?(with_resource_templates = false) ?(with_prompts = false) () =
422451 let caps = [] in
423423- let caps =
424424- if with_tools then
425425- ("tools", `Assoc [
426426- ("listChanged", `Bool true)
427427- ]) :: caps
428428- else
429429- caps
452452+ let caps =
453453+ if with_tools then ("tools", `Assoc [ ("listChanged", `Bool true) ]) :: caps
454454+ else caps
430455 in
431431- let caps =
456456+ let caps =
432457 if with_resources then
433433- ("resources", `Assoc [
434434- ("listChanged", `Bool true);
435435- ("subscribe", `Bool false)
436436- ]) :: caps
458458+ ( "resources",
459459+ `Assoc [ ("listChanged", `Bool true); ("subscribe", `Bool false) ] )
460460+ :: caps
437461 else if not with_resources then
438438- ("resources", `Assoc [
439439- ("listChanged", `Bool false);
440440- ("subscribe", `Bool false)
441441- ]) :: caps
442442- else
443443- caps
462462+ ( "resources",
463463+ `Assoc [ ("listChanged", `Bool false); ("subscribe", `Bool false) ] )
464464+ :: caps
465465+ else caps
444466 in
445467 let caps =
446468 if with_resource_templates then
447447- ("resourceTemplates", `Assoc [
448448- ("listChanged", `Bool true)
449449- ]) :: caps
469469+ ("resourceTemplates", `Assoc [ ("listChanged", `Bool true) ]) :: caps
450470 else if not with_resource_templates then
451451- ("resourceTemplates", `Assoc [
452452- ("listChanged", `Bool false)
453453- ]) :: caps
454454- else
455455- caps
471471+ ("resourceTemplates", `Assoc [ ("listChanged", `Bool false) ]) :: caps
472472+ else caps
456473 in
457457- let caps =
474474+ let caps =
458475 if with_prompts then
459459- ("prompts", `Assoc [
460460- ("listChanged", `Bool true)
461461- ]) :: caps
476476+ ("prompts", `Assoc [ ("listChanged", `Bool true) ]) :: caps
462477 else if not with_prompts then
463463- ("prompts", `Assoc [
464464- ("listChanged", `Bool false)
465465- ]) :: caps
466466- else
467467- caps
478478+ ("prompts", `Assoc [ ("listChanged", `Bool false) ]) :: caps
479479+ else caps
468480 in
469481 `Assoc caps
470482···474486 tool
475487476488(* Create and register a tool in one step *)
477477-let add_tool server ~name ?description ?(schema_properties=[]) ?(schema_required=[]) handler =
489489+let add_tool server ~name ?description ?(schema_properties = [])
490490+ ?(schema_required = []) handler =
478491 let input_schema = make_tool_schema schema_properties schema_required in
479492 let handler' ctx args =
480480- try
481481- Ok (handler args)
482482- with exn ->
483483- Error (Printexc.to_string exn)
493493+ try Ok (handler args) with exn -> Error (Printexc.to_string exn)
484494 in
485485- let tool = Tool.create
486486- ~name
487487- ?description
488488- ~input_schema
489489- ~handler:handler'
490490- ()
495495+ let tool =
496496+ Tool.create ~name ?description ~input_schema ~handler:handler' ()
491497 in
492498 register_tool server tool
493499···499505(* Create and register a resource in one step *)
500506let add_resource server ~uri ~name ?description ?mime_type handler =
501507 let handler' _ctx params =
502502- try
503503- Ok (handler params)
504504- with exn ->
505505- Error (Printexc.to_string exn)
508508+ try Ok (handler params) with exn -> Error (Printexc.to_string exn)
506509 in
507507- let resource = Resource.create
508508- ~uri
509509- ~name
510510- ?description
511511- ?mime_type
512512- ~handler:handler'
513513- ()
510510+ let resource =
511511+ Resource.create ~uri ~name ?description ?mime_type ~handler:handler' ()
514512 in
515513 register_resource server resource
516514···520518 template
521519522520(* Create and register a resource template in one step *)
523523-let add_resource_template server ~uri_template ~name ?description ?mime_type handler =
521521+let add_resource_template server ~uri_template ~name ?description ?mime_type
522522+ handler =
524523 let handler' _ctx params =
525525- try
526526- Ok (handler params)
527527- with exn ->
528528- Error (Printexc.to_string exn)
524524+ try Ok (handler params) with exn -> Error (Printexc.to_string exn)
529525 in
530530- let template = ResourceTemplate.create
531531- ~uri_template
532532- ~name
533533- ?description
534534- ?mime_type
535535- ~handler:handler'
536536- ()
526526+ let template =
527527+ ResourceTemplate.create ~uri_template ~name ?description ?mime_type
528528+ ~handler:handler' ()
537529 in
538530 register_resource_template server template
539531···543535 prompt
544536545537(* Create and register a prompt in one step *)
546546-let add_prompt server ~name ?description ?(arguments=[]) handler =
547547- let prompt_args = List.map (fun (name, desc, required) ->
548548- Prompt.create_argument ~name ?description:desc ~required ()
549549- ) arguments in
538538+let add_prompt server ~name ?description ?(arguments = []) handler =
539539+ let prompt_args =
540540+ List.map
541541+ (fun (name, desc, required) ->
542542+ Prompt.create_argument ~name ?description:desc ~required ())
543543+ arguments
544544+ in
550545 let handler' _ctx args =
551551- try
552552- Ok (handler args)
553553- with exn ->
554554- Error (Printexc.to_string exn)
546546+ try Ok (handler args) with exn -> Error (Printexc.to_string exn)
555547 in
556556- let prompt = Prompt.create
557557- ~name
558558- ?description
559559- ~arguments:prompt_args
560560- ~handler:handler'
561561- ()
548548+ let prompt =
549549+ Prompt.create ~name ?description ~arguments:prompt_args ~handler:handler' ()
562550 in
563551 register_prompt server prompt
564552565553(* Set server capabilities *)
566566-let set_capabilities server capabilities =
567567- server.capabilities <- capabilities
554554+let set_capabilities server capabilities = server.capabilities <- capabilities
568555569556(* Configure server with default capabilities based on registered components *)
570570-let configure_server server ?with_tools ?with_resources ?with_resource_templates ?with_prompts () =
571571- let with_tools = match with_tools with
572572- | Some b -> b
573573- | None -> server.tools <> []
557557+let configure_server server ?with_tools ?with_resources ?with_resource_templates
558558+ ?with_prompts () =
559559+ let with_tools =
560560+ match with_tools with Some b -> b | None -> server.tools <> []
574561 in
575575- let with_resources = match with_resources with
576576- | Some b -> b
577577- | None -> server.resources <> []
562562+ let with_resources =
563563+ match with_resources with Some b -> b | None -> server.resources <> []
578564 in
579579- let with_resource_templates = match with_resource_templates with
565565+ let with_resource_templates =
566566+ match with_resource_templates with
580567 | Some b -> b
581568 | None -> server.resource_templates <> []
582569 in
583583- let with_prompts = match with_prompts with
584584- | Some b -> b
585585- | None -> server.prompts <> []
570570+ let with_prompts =
571571+ match with_prompts with Some b -> b | None -> server.prompts <> []
586572 in
587587- let capabilities = default_capabilities ~with_tools ~with_resources ~with_resource_templates ~with_prompts () in
573573+ let capabilities =
574574+ default_capabilities ~with_tools ~with_resources ~with_resource_templates
575575+ ~with_prompts ()
576576+ in
588577 set_capabilities server capabilities;
589578 server
+168-80
lib/mcp_sdk.mli
···33open Mcp
44open Jsonrpc
5566-(** SDK version *)
76val version : string
77+(** SDK version *)
8899(** Logging utilities *)
1010module Log : sig
···12121313 val string_of_level : level -> string
14141515- (** Format-string based logging functions *)
1615 val logf : level -> ('a, out_channel, unit) format -> 'a
1616+ (** Format-string based logging functions *)
1717+1718 val debugf : ('a, out_channel, unit) format -> 'a
1819 val infof : ('a, out_channel, unit) format -> 'a
1920 val warningf : ('a, out_channel, unit) format -> 'a
2021 val errorf : ('a, out_channel, unit) format -> 'a
21222323+ val log : level -> string -> unit
2224 (** Simple string logging functions (for backward compatibility) *)
2323- val log : level -> string -> unit
2525+2426 val debug : string -> unit
2527 val info : string -> unit
2628 val warning : string -> unit
···3133module Context : sig
3234 type t
33353434- val create : ?request_id:RequestId.t -> ?progress_token:ProgressToken.t -> ?lifespan_context:(string * Json.t) list -> unit -> t
3636+ val create :
3737+ ?request_id:RequestId.t ->
3838+ ?progress_token:ProgressToken.t ->
3939+ ?lifespan_context:(string * Json.t) list ->
4040+ unit ->
4141+ t
4242+3543 val get_context_value : t -> string -> Json.t option
3644 val report_progress : t -> float -> float -> JSONRPCMessage.t option
3745end
···4149 type handler = Context.t -> Json.t -> (Json.t, string) result
42504351 type t = {
4444- name: string;
4545- description: string option;
4646- input_schema: Json.t;
4747- handler: handler;
5252+ name : string;
5353+ description : string option;
5454+ input_schema : Json.t;
5555+ handler : handler;
4856 }
49575050- val create : name:string -> ?description:string -> input_schema:Json.t -> handler:handler -> unit -> t
5858+ val create :
5959+ name:string ->
6060+ ?description:string ->
6161+ input_schema:Json.t ->
6262+ handler:handler ->
6363+ unit ->
6464+ t
6565+5166 val to_json : t -> Json.t
5252-5353- (** Convert to Mcp_rpc.ToolsList.Tool.t *)
6767+5468 val to_rpc_tool_list_tool : t -> Mcp_rpc.ToolsList.Tool.t
5555-5656- (** Convert a list of Tool.t to the format needed for tools/list response *)
6969+ (** Convert to Mcp_rpc.ToolsList.Tool.t *)
7070+5771 val to_rpc_tools_list : t list -> Mcp_rpc.ToolsList.Tool.t list
5858-7272+ (** Convert a list of Tool.t to the format needed for tools/list response *)
7373+7474+ val rpc_content_to_mcp_content :
7575+ Mcp_rpc.ToolsCall.ToolContent.t list -> Mcp.content list
5976 (** Convert Mcp_rpc.ToolsCall response content to Mcp.content list *)
6060- val rpc_content_to_mcp_content : Mcp_rpc.ToolsCall.ToolContent.t list -> Mcp.content list
6161-7777+7878+ val mcp_content_to_rpc_content :
7979+ Mcp.content list -> Mcp_rpc.ToolsCall.ToolContent.t list
6280 (** Convert Mcp.content list to Mcp_rpc.ToolsCall.ToolContent.t list *)
6363- val mcp_content_to_rpc_content : Mcp.content list -> Mcp_rpc.ToolsCall.ToolContent.t list
6464-8181+8282+ val create_tool_result : Mcp.content list -> is_error:bool -> Json.t
6583 (** Create a tool result with content *)
6666- val create_tool_result : Mcp.content list -> is_error:bool -> Json.t
6767-8484+8585+ val create_error_result : string -> Json.t
6886 (** Create a tool error result with structured content *)
6969- val create_error_result : string -> Json.t
7070-7171- (** Handle tool execution errors *)
8787+7288 val handle_execution_error : string -> Json.t
7373-7474- (** Handle unknown tool error *)
8989+ (** Handle tool execution errors *)
9090+7591 val handle_unknown_tool_error : string -> Json.t
7676-7777- (** Handle general tool execution exception *)
9292+ (** Handle unknown tool error *)
9393+7894 val handle_execution_exception : exn -> Json.t
9595+ (** Handle general tool execution exception *)
7996end
80978198(** Resources for the MCP server *)
···83100 type handler = Context.t -> string list -> (string, string) result
8410185102 type t = {
8686- uri: string;
8787- name: string;
8888- description: string option;
8989- mime_type: string option;
9090- handler: handler;
103103+ uri : string;
104104+ name : string;
105105+ description : string option;
106106+ mime_type : string option;
107107+ handler : handler;
91108 }
921099393- val create : uri:string -> name:string -> ?description:string -> ?mime_type:string -> handler:handler -> unit -> t
110110+ val create :
111111+ uri:string ->
112112+ name:string ->
113113+ ?description:string ->
114114+ ?mime_type:string ->
115115+ handler:handler ->
116116+ unit ->
117117+ t
118118+94119 val to_json : t -> Json.t
9595-9696- (** Convert to Mcp_rpc.ResourcesList.Resource.t *)
120120+97121 val to_rpc_resource_list_resource : t -> Mcp_rpc.ResourcesList.Resource.t
9898-9999- (** Convert a list of Resource.t to the format needed for resources/list response *)
122122+ (** Convert to Mcp_rpc.ResourcesList.Resource.t *)
123123+100124 val to_rpc_resources_list : t list -> Mcp_rpc.ResourcesList.Resource.t list
125125+ (** Convert a list of Resource.t to the format needed for resources/list
126126+ response *)
101127end
102128103129(** Resource Templates for the MCP server *)
···105131 type handler = Context.t -> string list -> (string, string) result
106132107133 type t = {
108108- uri_template: string;
109109- name: string;
110110- description: string option;
111111- mime_type: string option;
112112- handler: handler;
134134+ uri_template : string;
135135+ name : string;
136136+ description : string option;
137137+ mime_type : string option;
138138+ handler : handler;
113139 }
114140115115- val create : uri_template:string -> name:string -> ?description:string -> ?mime_type:string -> handler:handler -> unit -> t
141141+ val create :
142142+ uri_template:string ->
143143+ name:string ->
144144+ ?description:string ->
145145+ ?mime_type:string ->
146146+ handler:handler ->
147147+ unit ->
148148+ t
149149+116150 val to_json : t -> Json.t
117117-151151+152152+ val to_rpc_resource_template :
153153+ t -> Mcp_rpc.ListResourceTemplatesResult.ResourceTemplate.t
118154 (** Convert to Mcp_rpc.ResourceTemplatesList.ResourceTemplate.t *)
119119- val to_rpc_resource_template : t -> Mcp_rpc.ListResourceTemplatesResult.ResourceTemplate.t
120120-121121- (** Convert a list of ResourceTemplate.t to the format needed for resources/templates/list response *)
122122- val to_rpc_resource_templates_list : t list -> Mcp_rpc.ListResourceTemplatesResult.ResourceTemplate.t list
155155+156156+ val to_rpc_resource_templates_list :
157157+ t list -> Mcp_rpc.ListResourceTemplatesResult.ResourceTemplate.t list
158158+ (** Convert a list of ResourceTemplate.t to the format needed for
159159+ resources/templates/list response *)
123160end
124161125162(** Prompts for the MCP server *)
126163module Prompt : sig
127164 type argument = {
128128- name: string;
129129- description: string option;
130130- required: bool;
165165+ name : string;
166166+ description : string option;
167167+ required : bool;
131168 }
132169133133- type message = {
134134- role: Role.t;
135135- content: content;
136136- }
170170+ type message = { role : Role.t; content : content }
137171138138- type handler = Context.t -> (string * string) list -> (message list, string) result
172172+ type handler =
173173+ Context.t -> (string * string) list -> (message list, string) result
139174140175 type t = {
141141- name: string;
142142- description: string option;
143143- arguments: argument list;
144144- handler: handler;
176176+ name : string;
177177+ description : string option;
178178+ arguments : argument list;
179179+ handler : handler;
145180 }
146181147147- val create : name:string -> ?description:string -> ?arguments:argument list -> handler:handler -> unit -> t
148148- val create_argument : name:string -> ?description:string -> ?required:bool -> unit -> argument
182182+ val create :
183183+ name:string ->
184184+ ?description:string ->
185185+ ?arguments:argument list ->
186186+ handler:handler ->
187187+ unit ->
188188+ t
189189+190190+ val create_argument :
191191+ name:string -> ?description:string -> ?required:bool -> unit -> argument
192192+149193 val to_json : t -> Json.t
150150-194194+195195+ val argument_to_rpc_prompt_argument :
196196+ argument -> Mcp_rpc.PromptsList.PromptArgument.t
151197 (** Convert argument to Mcp_rpc.PromptsList.PromptArgument.t *)
152152- val argument_to_rpc_prompt_argument : argument -> Mcp_rpc.PromptsList.PromptArgument.t
153153-154154- (** Convert to Mcp_rpc.PromptsList.Prompt.t *)
198198+155199 val to_rpc_prompt_list_prompt : t -> Mcp_rpc.PromptsList.Prompt.t
156156-157157- (** Convert a list of Prompt.t to the format needed for prompts/list response *)
200200+ (** Convert to Mcp_rpc.PromptsList.Prompt.t *)
201201+158202 val to_rpc_prompts_list : t list -> Mcp_rpc.PromptsList.Prompt.t list
159159-160160- (** Convert message to Mcp_rpc.PromptMessage.t *)
203203+ (** Convert a list of Prompt.t to the format needed for prompts/list response
204204+ *)
205205+161206 val message_to_rpc_prompt_message : message -> PromptMessage.t
162162-163163- (** Convert a list of messages to the format needed for prompts/get response *)
207207+ (** Convert message to Mcp_rpc.PromptMessage.t *)
208208+164209 val messages_to_rpc_prompt_messages : message list -> PromptMessage.t list
210210+ (** Convert a list of messages to the format needed for prompts/get response
211211+ *)
165212end
166213214214+type server
167215(** Main server type *)
168168-type server
169216170217val name : server -> string
171218val version : server -> string
···176223val resource_templates : server -> ResourceTemplate.t list
177224val prompts : server -> Prompt.t list
178225226226+val create_server :
227227+ name:string -> ?version:string -> ?protocol_version:string -> unit -> server
179228(** Create a new server *)
180180-val create_server : name:string -> ?version:string -> ?protocol_version:string -> unit -> server
181229230230+val default_capabilities :
231231+ ?with_tools:bool ->
232232+ ?with_resources:bool ->
233233+ ?with_resource_templates:bool ->
234234+ ?with_prompts:bool ->
235235+ unit ->
236236+ Json.t
182237(** Default capabilities for the server *)
183183-val default_capabilities : ?with_tools:bool -> ?with_resources:bool -> ?with_resource_templates:bool -> ?with_prompts:bool -> unit -> Json.t
184238239239+val add_tool :
240240+ server ->
241241+ name:string ->
242242+ ?description:string ->
243243+ ?schema_properties:(string * string * string) list ->
244244+ ?schema_required:string list ->
245245+ (Json.t -> Json.t) ->
246246+ Tool.t
185247(** Create and register a tool in one step *)
186186-val add_tool : server -> name:string -> ?description:string -> ?schema_properties:(string * string * string) list -> ?schema_required:string list -> (Json.t -> Json.t) -> Tool.t
187248249249+val add_resource :
250250+ server ->
251251+ uri:string ->
252252+ name:string ->
253253+ ?description:string ->
254254+ ?mime_type:string ->
255255+ (string list -> string) ->
256256+ Resource.t
188257(** Create and register a resource in one step *)
189189-val add_resource : server -> uri:string -> name:string -> ?description:string -> ?mime_type:string -> (string list -> string) -> Resource.t
190258259259+val add_resource_template :
260260+ server ->
261261+ uri_template:string ->
262262+ name:string ->
263263+ ?description:string ->
264264+ ?mime_type:string ->
265265+ (string list -> string) ->
266266+ ResourceTemplate.t
191267(** Create and register a resource template in one step *)
192192-val add_resource_template : server -> uri_template:string -> name:string -> ?description:string -> ?mime_type:string -> (string list -> string) -> ResourceTemplate.t
193268269269+val add_prompt :
270270+ server ->
271271+ name:string ->
272272+ ?description:string ->
273273+ ?arguments:(string * string option * bool) list ->
274274+ ((string * string) list -> Prompt.message list) ->
275275+ Prompt.t
194276(** Create and register a prompt in one step *)
195195-val add_prompt : server -> name:string -> ?description:string -> ?arguments:(string * string option * bool) list -> ((string * string) list -> Prompt.message list) -> Prompt.t
196277278278+val configure_server :
279279+ server ->
280280+ ?with_tools:bool ->
281281+ ?with_resources:bool ->
282282+ ?with_resource_templates:bool ->
283283+ ?with_prompts:bool ->
284284+ unit ->
285285+ server
197286(** Configure server with default capabilities based on registered components *)
198198-val configure_server : server -> ?with_tools:bool -> ?with_resources:bool -> ?with_resource_templates:bool -> ?with_prompts:bool -> unit -> server
199287200288val make_tool_schema : (string * string * string) list -> string list -> Json.t
+280-227
lib/mcp_server.ml
···55(* Create a proper JSONRPC error with code and data *)
66let create_jsonrpc_error id code message ?data () =
77 let error_code = ErrorCode.to_int code in
88- let error_data = match data with
99- | Some d -> d
1010- | None -> `Null
1111- in
88+ let error_data = match data with Some d -> d | None -> `Null in
129 create_error ~id ~code:error_code ~message ~data:(Some error_data) ()
13101411(* Process initialize request *)
1512let handle_initialize server req =
1613 Log.debug "Processing initialize request";
1717- let result = match req.JSONRPCMessage.params with
1818- | Some params ->
1414+ let result =
1515+ match req.JSONRPCMessage.params with
1616+ | Some params ->
1917 let req_data = Initialize.Request.t_of_yojson params in
2020- Log.debugf "Client info: %s v%s"
2121- req_data.client_info.name req_data.client_info.version;
1818+ Log.debugf "Client info: %s v%s" req_data.client_info.name
1919+ req_data.client_info.version;
2220 Log.debugf "Client protocol version: %s" req_data.protocol_version;
2323-2121+2422 (* Create initialize response *)
2525- let result = Initialize.Result.create
2626- ~capabilities:(capabilities server)
2727- ~server_info:Implementation.{
2828- name = name server;
2929- version = version server
3030- }
3131- ~protocol_version:(protocol_version server)
3232- ~instructions:(Printf.sprintf "This server provides tools for %s." (name server))
3333- ()
2323+ let result =
2424+ Initialize.Result.create ~capabilities:(capabilities server)
2525+ ~server_info:
2626+ Implementation.{ name = name server; version = version server }
2727+ ~protocol_version:(protocol_version server)
2828+ ~instructions:
2929+ (Printf.sprintf "This server provides tools for %s." (name server))
3030+ ()
3431 in
3532 Initialize.Result.yojson_of_t result
3636- | None ->
3333+ | None ->
3734 Log.error "Missing params for initialize request";
3838- `Assoc [("error", `String "Missing params for initialize request")]
3535+ `Assoc [ ("error", `String "Missing params for initialize request") ]
3936 in
4037 Some (create_response ~id:req.id ~result)
41384239(* Process tools/list request *)
4343-let handle_tools_list server (req:JSONRPCMessage.request) =
4040+let handle_tools_list server (req : JSONRPCMessage.request) =
4441 Log.debug "Processing tools/list request";
4542 let tools_list = Tool.to_rpc_tools_list (tools server) in
4646- let response = Mcp_rpc.ToolsList.create_response ~id:req.id ~tools:tools_list () in
4343+ let response =
4444+ Mcp_rpc.ToolsList.create_response ~id:req.id ~tools:tools_list ()
4545+ in
4746 Some response
48474948(* Process prompts/list request *)
5050-let handle_prompts_list server (req:JSONRPCMessage.request) =
4949+let handle_prompts_list server (req : JSONRPCMessage.request) =
5150 Log.debug "Processing prompts/list request";
5251 let prompts_list = Prompt.to_rpc_prompts_list (prompts server) in
5353- let response = Mcp_rpc.PromptsList.create_response ~id:req.id ~prompts:prompts_list () in
5252+ let response =
5353+ Mcp_rpc.PromptsList.create_response ~id:req.id ~prompts:prompts_list ()
5454+ in
5455 Some response
55565657(* Process resources/list request *)
5757-let handle_resources_list server (req:JSONRPCMessage.request) =
5858+let handle_resources_list server (req : JSONRPCMessage.request) =
5859 Log.debug "Processing resources/list request";
5960 let resources_list = Resource.to_rpc_resources_list (resources server) in
6060- let response = Mcp_rpc.ResourcesList.create_response ~id:req.id ~resources:resources_list () in
6161+ let response =
6262+ Mcp_rpc.ResourcesList.create_response ~id:req.id ~resources:resources_list
6363+ ()
6464+ in
6165 Some response
62666367(* Process resources/templates/list request *)
6464-let handle_resource_templates_list server (req:JSONRPCMessage.request) =
6868+let handle_resource_templates_list server (req : JSONRPCMessage.request) =
6569 Log.debug "Processing resources/templates/list request";
6666- let templates_list = ResourceTemplate.to_rpc_resource_templates_list (resource_templates server) in
6767- let response = Mcp_rpc.ListResourceTemplatesResult.create_response ~id:req.id ~resource_templates:templates_list () in
7070+ let templates_list =
7171+ ResourceTemplate.to_rpc_resource_templates_list (resource_templates server)
7272+ in
7373+ let response =
7474+ Mcp_rpc.ListResourceTemplatesResult.create_response ~id:req.id
7575+ ~resource_templates:templates_list ()
7676+ in
6877 Some response
69787079(* Utility module for resource template matching *)
···8089 (* Simple template variable extraction - could be enhanced with regex *)
8190 let template_parts = String.split_on_char '/' template_uri in
8291 let uri_parts = String.split_on_char '/' uri in
8383-8484- if List.length template_parts <> List.length uri_parts then
8585- None
9292+9393+ if List.length template_parts <> List.length uri_parts then None
8694 else
8795 (* Match parts and extract variables *)
8896 let rec match_parts tparts uparts acc =
8989- match tparts, uparts with
9797+ match (tparts, uparts) with
9098 | [], [] -> Some (List.rev acc)
9191- | th::tt, uh::ut ->
9999+ | th :: tt, uh :: ut ->
92100 (* Check if this part is a template variable *)
9393- if String.length th > 2 &&
9494- String.get th 0 = '{' &&
9595- String.get th (String.length th - 1) = '}' then
101101+ if
102102+ String.length th > 2
103103+ && String.get th 0 = '{'
104104+ && String.get th (String.length th - 1) = '}'
105105+ then
96106 (* Extract variable value and continue *)
9797- match_parts tt ut (uh::acc)
107107+ match_parts tt ut (uh :: acc)
98108 else if th = uh then
99109 (* Fixed part matches, continue *)
100110 match_parts tt ut acc
···108118 (* Find a matching resource or template for a URI *)
109119 let find_match server uri =
110120 (* Try direct resource match first *)
111111- match List.find_opt (fun resource -> resource.Resource.uri = uri) (resources server) with
121121+ match
122122+ List.find_opt
123123+ (fun resource -> resource.Resource.uri = uri)
124124+ (resources server)
125125+ with
112126 | Some resource -> DirectResource (resource, [])
113127 | None ->
114128 (* Try template match next *)
115129 let templates = resource_templates server in
116116-130130+117131 (* Try each template to see if it matches *)
118132 let rec try_templates templates =
119133 match templates with
120134 | [] -> NoMatch
121121- | template::rest ->
122122- match extract_template_vars template.ResourceTemplate.uri_template uri with
135135+ | template :: rest -> (
136136+ match
137137+ extract_template_vars template.ResourceTemplate.uri_template uri
138138+ with
123139 | Some params -> TemplateResource (template, params)
124124- | None -> try_templates rest
140140+ | None -> try_templates rest)
125141 in
126142 try_templates templates
127143end
128144129145(* Process resources/read request *)
130130-let handle_resources_read server (req:JSONRPCMessage.request) =
146146+let handle_resources_read server (req : JSONRPCMessage.request) =
131147 Log.debug "Processing resources/read request";
132148 match req.JSONRPCMessage.params with
133149 | None ->
134150 Log.error "Missing params for resources/read request";
135135- Some (create_jsonrpc_error req.id ErrorCode.InvalidParams "Missing params for resources/read request" ())
136136- | Some params ->
151151+ Some
152152+ (create_jsonrpc_error req.id ErrorCode.InvalidParams
153153+ "Missing params for resources/read request" ())
154154+ | Some params -> (
137155 let req_data = Mcp_rpc.ResourcesRead.Request.t_of_yojson params in
138156 let uri = req_data.uri in
139157 Log.debugf "Resource URI: %s" uri;
140140-158158+141159 (* Find matching resource or template *)
142160 match Resource_matcher.find_match server uri with
143143- | Resource_matcher.DirectResource (resource, params) ->
161161+ | Resource_matcher.DirectResource (resource, params) -> (
144162 (* Create context for this request *)
145145- let ctx = Context.create
146146- ?request_id:(Some req.id)
147147- ?progress_token:req.progress_token
148148- ~lifespan_context:[("resources/read", `Assoc [("uri", `String uri)])]
149149- ()
163163+ let ctx =
164164+ Context.create ?request_id:(Some req.id)
165165+ ?progress_token:req.progress_token
166166+ ~lifespan_context:
167167+ [ ("resources/read", `Assoc [ ("uri", `String uri) ]) ]
168168+ ()
150169 in
151151-170170+152171 Log.debugf "Handling direct resource: %s" resource.name;
153153-172172+154173 (* Call the resource handler *)
155155- (match resource.handler ctx params with
156156- | Ok content ->
157157- (* Create text resource content *)
158158- let mime_type = match resource.mime_type with
159159- | Some mime -> mime
160160- | None -> "text/plain"
161161- in
162162- let text_resource = {
163163- TextResourceContents.uri;
164164- text = content;
165165- mime_type = Some mime_type
166166- } in
167167- let resource_content = Mcp_rpc.ResourcesRead.ResourceContent.TextResource text_resource in
168168- let response = Mcp_rpc.ResourcesRead.create_response ~id:req.id ~contents:[resource_content] () in
169169- Some response
170170- | Error err ->
171171- Log.errorf "Error reading resource: %s" err;
172172- Some (create_jsonrpc_error req.id ErrorCode.InternalError ("Error reading resource: " ^ err) ()))
173173-174174- | Resource_matcher.TemplateResource (template, params) ->
174174+ match resource.handler ctx params with
175175+ | Ok content ->
176176+ (* Create text resource content *)
177177+ let mime_type =
178178+ match resource.mime_type with
179179+ | Some mime -> mime
180180+ | None -> "text/plain"
181181+ in
182182+ let text_resource =
183183+ {
184184+ TextResourceContents.uri;
185185+ text = content;
186186+ mime_type = Some mime_type;
187187+ }
188188+ in
189189+ let resource_content =
190190+ Mcp_rpc.ResourcesRead.ResourceContent.TextResource text_resource
191191+ in
192192+ let response =
193193+ Mcp_rpc.ResourcesRead.create_response ~id:req.id
194194+ ~contents:[ resource_content ] ()
195195+ in
196196+ Some response
197197+ | Error err ->
198198+ Log.errorf "Error reading resource: %s" err;
199199+ Some
200200+ (create_jsonrpc_error req.id ErrorCode.InternalError
201201+ ("Error reading resource: " ^ err)
202202+ ()))
203203+ | Resource_matcher.TemplateResource (template, params) -> (
175204 (* Create context for this request *)
176176- let ctx = Context.create
177177- ?request_id:(Some req.id)
178178- ?progress_token:req.progress_token
179179- ~lifespan_context:[("resources/read", `Assoc [("uri", `String uri)])]
180180- ()
205205+ let ctx =
206206+ Context.create ?request_id:(Some req.id)
207207+ ?progress_token:req.progress_token
208208+ ~lifespan_context:
209209+ [ ("resources/read", `Assoc [ ("uri", `String uri) ]) ]
210210+ ()
181211 in
182182-183183- Log.debugf "Handling resource template: %s with params: [%s]"
184184- template.name
212212+213213+ Log.debugf "Handling resource template: %s with params: [%s]"
214214+ template.name
185215 (String.concat ", " params);
186186-216216+187217 (* Call the template handler *)
188188- (match template.handler ctx params with
189189- | Ok content ->
190190- (* Create text resource content *)
191191- let mime_type = match template.mime_type with
192192- | Some mime -> mime
193193- | None -> "text/plain"
194194- in
195195- let text_resource = {
196196- TextResourceContents.uri;
197197- text = content;
198198- mime_type = Some mime_type
199199- } in
200200- let resource_content = Mcp_rpc.ResourcesRead.ResourceContent.TextResource text_resource in
201201- let response = Mcp_rpc.ResourcesRead.create_response ~id:req.id ~contents:[resource_content] () in
202202- Some response
203203- | Error err ->
204204- Log.errorf "Error reading resource template: %s" err;
205205- Some (create_jsonrpc_error req.id ErrorCode.InternalError ("Error reading resource template: " ^ err) ()))
206206-218218+ match template.handler ctx params with
219219+ | Ok content ->
220220+ (* Create text resource content *)
221221+ let mime_type =
222222+ match template.mime_type with
223223+ | Some mime -> mime
224224+ | None -> "text/plain"
225225+ in
226226+ let text_resource =
227227+ {
228228+ TextResourceContents.uri;
229229+ text = content;
230230+ mime_type = Some mime_type;
231231+ }
232232+ in
233233+ let resource_content =
234234+ Mcp_rpc.ResourcesRead.ResourceContent.TextResource text_resource
235235+ in
236236+ let response =
237237+ Mcp_rpc.ResourcesRead.create_response ~id:req.id
238238+ ~contents:[ resource_content ] ()
239239+ in
240240+ Some response
241241+ | Error err ->
242242+ Log.errorf "Error reading resource template: %s" err;
243243+ Some
244244+ (create_jsonrpc_error req.id ErrorCode.InternalError
245245+ ("Error reading resource template: " ^ err)
246246+ ()))
207247 | Resource_matcher.NoMatch ->
208248 Log.errorf "Resource not found: %s" uri;
209209- Some (create_jsonrpc_error req.id ErrorCode.InvalidParams ("Resource not found: " ^ uri) ())
249249+ Some
250250+ (create_jsonrpc_error req.id ErrorCode.InvalidParams
251251+ ("Resource not found: " ^ uri)
252252+ ()))
210253211254(* Extract the tool name from params *)
212255let extract_tool_name params =
213256 match List.assoc_opt "name" params with
214214- | Some (`String name) ->
215215- Log.debugf "Tool name: %s" name;
216216- Some name
217217- | _ ->
218218- Log.error "Missing or invalid 'name' parameter in tool call";
219219- None
257257+ | Some (`String name) ->
258258+ Log.debugf "Tool name: %s" name;
259259+ Some name
260260+ | _ ->
261261+ Log.error "Missing or invalid 'name' parameter in tool call";
262262+ None
220263221264(* Extract the tool arguments from params *)
222265let extract_tool_arguments params =
223266 match List.assoc_opt "arguments" params with
224224- | Some (args) ->
225225- Log.debugf "Tool arguments: %s" (Yojson.Safe.to_string args);
226226- args
227227- | _ ->
228228- Log.debug "No arguments provided for tool call, using empty object";
229229- `Assoc [] (* Empty arguments is valid *)
267267+ | Some args ->
268268+ Log.debugf "Tool arguments: %s" (Yojson.Safe.to_string args);
269269+ args
270270+ | _ ->
271271+ Log.debug "No arguments provided for tool call, using empty object";
272272+ `Assoc [] (* Empty arguments is valid *)
230273231274(* Execute a tool *)
232275let execute_tool server ctx name args =
233276 try
234277 let tool = List.find (fun t -> t.Tool.name = name) (tools server) in
235278 Log.debugf "Found tool: %s" name;
236236-279279+237280 (* Call the tool handler *)
238281 match tool.handler ctx args with
239239- | Ok result ->
282282+ | Ok result ->
240283 Log.debug "Tool execution succeeded";
241284 result
242285 | Error err -> Tool.handle_execution_error err
···247290(* Convert JSON tool result to RPC content format *)
248291let json_to_rpc_content json =
249292 match json with
250250- | `Assoc fields ->
251251- (match List.assoc_opt "content" fields, List.assoc_opt "isError" fields with
252252- | Some (`List content_items), Some (`Bool is_error) ->
253253- let mcp_content = List.map Mcp.content_of_yojson content_items in
254254- let rpc_content = Tool.mcp_content_to_rpc_content mcp_content in
255255- (rpc_content, is_error)
256256- | _ ->
257257- (* Fallback for compatibility with older formats *)
258258- let text = Yojson.Safe.to_string json in
259259- let text_content = { TextContent.text = text; annotations = None } in
260260- ([Mcp_rpc.ToolsCall.ToolContent.Text text_content], false))
293293+ | `Assoc fields -> (
294294+ match
295295+ (List.assoc_opt "content" fields, List.assoc_opt "isError" fields)
296296+ with
297297+ | Some (`List content_items), Some (`Bool is_error) ->
298298+ let mcp_content = List.map Mcp.content_of_yojson content_items in
299299+ let rpc_content = Tool.mcp_content_to_rpc_content mcp_content in
300300+ (rpc_content, is_error)
301301+ | _ ->
302302+ (* Fallback for compatibility with older formats *)
303303+ let text = Yojson.Safe.to_string json in
304304+ let text_content = { TextContent.text; annotations = None } in
305305+ ([ Mcp_rpc.ToolsCall.ToolContent.Text text_content ], false))
261306 | _ ->
262262- (* Simple fallback for non-object results *)
263263- let text = Yojson.Safe.to_string json in
264264- let text_content = { TextContent.text = text; annotations = None } in
265265- ([Mcp_rpc.ToolsCall.ToolContent.Text text_content], false)
307307+ (* Simple fallback for non-object results *)
308308+ let text = Yojson.Safe.to_string json in
309309+ let text_content = { TextContent.text; annotations = None } in
310310+ ([ Mcp_rpc.ToolsCall.ToolContent.Text text_content ], false)
266311267312(* Process tools/call request *)
268313let handle_tools_call server req =
269314 Log.debug "Processing tools/call request";
270315 match req.JSONRPCMessage.params with
271271- | Some (`Assoc params) ->
272272- (match extract_tool_name params with
273273- | Some name ->
274274- let args = extract_tool_arguments params in
275275-276276- (* Create context for this request *)
277277- let ctx = Context.create
278278- ?request_id:(Some req.id)
279279- ?progress_token:req.progress_token
280280- ~lifespan_context:[("tools/call", `Assoc params)]
281281- ()
282282- in
283283-284284- (* Execute the tool *)
285285- let result_json = execute_tool server ctx name args in
286286-287287- (* Convert JSON result to RPC format *)
288288- let content, is_error = json_to_rpc_content result_json in
289289-290290- (* Create the RPC response *)
291291- let response = Mcp_rpc.ToolsCall.create_response
292292- ~id:req.id
293293- ~content
294294- ~is_error
295295- ()
296296- in
297297-298298- Some response
299299- | None ->
300300- Some (create_jsonrpc_error req.id InvalidParams "Missing tool name parameter" ()))
316316+ | Some (`Assoc params) -> (
317317+ match extract_tool_name params with
318318+ | Some name ->
319319+ let args = extract_tool_arguments params in
320320+321321+ (* Create context for this request *)
322322+ let ctx =
323323+ Context.create ?request_id:(Some req.id)
324324+ ?progress_token:req.progress_token
325325+ ~lifespan_context:[ ("tools/call", `Assoc params) ]
326326+ ()
327327+ in
328328+329329+ (* Execute the tool *)
330330+ let result_json = execute_tool server ctx name args in
331331+332332+ (* Convert JSON result to RPC format *)
333333+ let content, is_error = json_to_rpc_content result_json in
334334+335335+ (* Create the RPC response *)
336336+ let response =
337337+ Mcp_rpc.ToolsCall.create_response ~id:req.id ~content ~is_error ()
338338+ in
339339+340340+ Some response
341341+ | None ->
342342+ Some
343343+ (create_jsonrpc_error req.id InvalidParams
344344+ "Missing tool name parameter" ()))
301345 | _ ->
302302- Log.error "Invalid params format for tools/call";
303303- Some (create_jsonrpc_error req.id InvalidParams "Invalid params format for tools/call" ())
346346+ Log.error "Invalid params format for tools/call";
347347+ Some
348348+ (create_jsonrpc_error req.id InvalidParams
349349+ "Invalid params format for tools/call" ())
304350305351(* Process ping request *)
306306-let handle_ping (req:JSONRPCMessage.request) =
352352+let handle_ping (req : JSONRPCMessage.request) =
307353 Log.debug "Processing ping request";
308354 Some (create_response ~id:req.JSONRPCMessage.id ~result:(`Assoc []))
309355310356(* Handle notifications/initialized *)
311311-let handle_initialized (notif:JSONRPCMessage.notification) =
312312- Log.debug "Client initialization complete - Server is now ready to receive requests";
313313- Log.debugf "Notification params: %s"
357357+let handle_initialized (notif : JSONRPCMessage.notification) =
358358+ Log.debug
359359+ "Client initialization complete - Server is now ready to receive requests";
360360+ Log.debugf "Notification params: %s"
314361 (match notif.JSONRPCMessage.params with
315315- | Some p -> Yojson.Safe.to_string p
316316- | None -> "null");
362362+ | Some p -> Yojson.Safe.to_string p
363363+ | None -> "null");
317364 None
318365319366(* Process a single message using the MCP SDK *)
···321368 try
322369 Log.debugf "Processing message: %s" (Yojson.Safe.to_string message);
323370 match JSONRPCMessage.t_of_yojson message with
324324- | JSONRPCMessage.Request req ->
325325- Log.debugf "Received request with method: %s" (Method.to_string req.meth);
326326- (match req.meth with
327327- | Method.Initialize -> handle_initialize server req
328328- | Method.ToolsList -> handle_tools_list server req
329329- | Method.ToolsCall -> handle_tools_call server req
330330- | Method.PromptsList -> handle_prompts_list server req
331331- | Method.ResourcesList -> handle_resources_list server req
332332- | Method.ResourcesRead -> handle_resources_read server req
333333- | Method.ResourceTemplatesList -> handle_resource_templates_list server req
334334- | _ ->
335335- Log.errorf "Unknown method received: %s" (Method.to_string req.meth);
336336- Some (create_jsonrpc_error req.id ErrorCode.MethodNotFound ("Method not found: " ^ (Method.to_string req.meth)) ()))
337337- | JSONRPCMessage.Notification notif ->
338338- Log.debugf "Received notification with method: %s" (Method.to_string notif.meth);
339339- (match notif.meth with
340340- | Method.Initialized -> handle_initialized notif
341341- | _ ->
342342- Log.debugf "Ignoring notification: %s" (Method.to_string notif.meth);
343343- None)
371371+ | JSONRPCMessage.Request req -> (
372372+ Log.debugf "Received request with method: %s"
373373+ (Method.to_string req.meth);
374374+ match req.meth with
375375+ | Method.Initialize -> handle_initialize server req
376376+ | Method.ToolsList -> handle_tools_list server req
377377+ | Method.ToolsCall -> handle_tools_call server req
378378+ | Method.PromptsList -> handle_prompts_list server req
379379+ | Method.ResourcesList -> handle_resources_list server req
380380+ | Method.ResourcesRead -> handle_resources_read server req
381381+ | Method.ResourceTemplatesList ->
382382+ handle_resource_templates_list server req
383383+ | _ ->
384384+ Log.errorf "Unknown method received: %s" (Method.to_string req.meth);
385385+ Some
386386+ (create_jsonrpc_error req.id ErrorCode.MethodNotFound
387387+ ("Method not found: " ^ Method.to_string req.meth)
388388+ ()))
389389+ | JSONRPCMessage.Notification notif -> (
390390+ Log.debugf "Received notification with method: %s"
391391+ (Method.to_string notif.meth);
392392+ match notif.meth with
393393+ | Method.Initialized -> handle_initialized notif
394394+ | _ ->
395395+ Log.debugf "Ignoring notification: %s" (Method.to_string notif.meth);
396396+ None)
344397 | JSONRPCMessage.Response _ ->
345345- Log.error "Unexpected response message received";
346346- None
398398+ Log.error "Unexpected response message received";
399399+ None
347400 | JSONRPCMessage.Error _ ->
348348- Log.error "Unexpected error message received";
349349- None
401401+ Log.error "Unexpected error message received";
402402+ None
350403 with
351404 | Json.Of_json (msg, _) ->
352352- Log.errorf "JSON error: %s" msg;
353353- (* Can't respond with error because we don't have a request ID *)
354354- None
355355- | Yojson.Json_error msg ->
356356- Log.errorf "JSON parse error: %s" msg;
357357- (* Can't respond with error because we don't have a request ID *)
358358- None
405405+ Log.errorf "JSON error: %s" msg;
406406+ (* Can't respond with error because we don't have a request ID *)
407407+ None
408408+ | Yojson.Json_error msg ->
409409+ Log.errorf "JSON parse error: %s" msg;
410410+ (* Can't respond with error because we don't have a request ID *)
411411+ None
359412 | exc ->
360360- Log.errorf "Exception during message processing: %s" (Printexc.to_string exc);
361361- Log.errorf "Backtrace: %s" (Printexc.get_backtrace());
362362- Log.errorf "Message was: %s" (Yojson.Safe.to_string message);
363363- None
413413+ Log.errorf "Exception during message processing: %s"
414414+ (Printexc.to_string exc);
415415+ Log.errorf "Backtrace: %s" (Printexc.get_backtrace ());
416416+ Log.errorf "Message was: %s" (Yojson.Safe.to_string message);
417417+ None
364418365419(* Extract a request ID from a potentially malformed message *)
366420let extract_request_id json =
367421 try
368422 match json with
369369- | `Assoc fields ->
370370- (match List.assoc_opt "id" fields with
371371- | Some (`Int id) -> Some (`Int id)
372372- | Some (`String id) -> Some (`String id)
373373- | _ -> None)
423423+ | `Assoc fields -> (
424424+ match List.assoc_opt "id" fields with
425425+ | Some (`Int id) -> Some (`Int id)
426426+ | Some (`String id) -> Some (`String id)
427427+ | _ -> None)
374428 | _ -> None
375429 with _ -> None
376430···378432let process_input_line server line =
379433 if line = "" then (
380434 Log.debug "Empty line received, ignoring";
381381- None
382382- ) else (
435435+ None)
436436+ else (
383437 Log.debugf "Raw input: %s" line;
384438 try
385439 let json = Yojson.Safe.from_string line in
386440 Log.debug "Successfully parsed JSON";
387387-441441+388442 (* Process the message *)
389443 process_message server json
390390- with
391391- | Yojson.Json_error msg -> begin
392392- Log.errorf "Error parsing JSON: %s" msg;
393393- Log.errorf "Input was: %s" line;
394394- None
395395- end
396396- )
444444+ with Yojson.Json_error msg ->
445445+ Log.errorf "Error parsing JSON: %s" msg;
446446+ Log.errorf "Input was: %s" line;
447447+ None)
397448398449(* Send a response to the client *)
399450let send_response stdout response =
400451 let response_json = JSONRPCMessage.yojson_of_t response in
401452 let response_str = Yojson.Safe.to_string response_json in
402453 Log.debugf "Sending response: %s" response_str;
403403-454454+404455 (* Write the response followed by a newline *)
405456 Eio.Flow.copy_string response_str stdout;
406457 Eio.Flow.copy_string "\n" stdout
···426477 ()
427478 | None ->
428479 Log.debug "No MCP response needed";
429429- Cohttp_eio.Server.respond ~status:`No_content ~body:(Cohttp_eio.Body.of_string "") ())
480480+ Cohttp_eio.Server.respond ~status:`No_content
481481+ ~body:(Cohttp_eio.Body.of_string "")
482482+ ())
430483 | _ ->
431484 Log.infof "Unsupported method: %s" (Http.Method.to_string request.meth);
432485 Cohttp_eio.Server.respond ~status:`Method_not_allowed
···463516464517 (* Enable exception backtraces *)
465518 Printexc.record_backtrace true;
466466-519519+467520 let buf = Eio.Buf_read.of_flow stdin ~initial_size:100 ~max_size:1_000_000 in
468468-521521+469522 (* Main processing loop *)
470523 try
471524 while true do
472525 Log.debug "Waiting for message...";
473526 let line = Eio.Buf_read.line buf in
474474-527527+475528 (* Process the input and send response if needed *)
476529 match process_input_line server line with
477530 | Some response -> send_response stdout response
478531 | None -> Log.debug "No response needed for this message"
479532 done
480533 with
481481- | End_of_file ->
534534+ | End_of_file ->
482535 Log.debug "End of file received on stdin";
483536 ()
484537 | Eio.Exn.Io _ as exn ->