Model Context Protocol in OCaml
1open Mcp_sdk
2
3(* Helper module for working with markdown book chapters *)
4module BookChapter = struct
5 type t = {
6 id: string;
7 title: string;
8 contents: string;
9 }
10
11 (* Book chapters as a series of markdown files *)
12 let chapters = [
13 {
14 id = "chapter1";
15 title = "# Introduction to OCaml";
16 contents = {|
17# Introduction to OCaml
18
19OCaml is a general-purpose, multi-paradigm programming language which extends the Caml dialect of ML with object-oriented features.
20
21## Key Features
22
23- **Strong Static Typing**: Catch errors at compile time rather than runtime
24- **Type Inference**: No need to annotate every variable with a type
25- **Pattern Matching**: Express complex control flow in a clear and concise way
26- **Functional Programming**: First-class functions and immutability
27- **Module System**: Powerful abstraction capabilities with modules and functors
28- **Performance**: Native code compilation with excellent performance characteristics
29
30## History
31
32OCaml was created in 1996 by Xavier Leroy, Jérôme Vouillon, Damien Doligez, and Didier Rémy at INRIA in France. It evolved from the Caml language, which itself was an implementation of ML.
33
34## Why OCaml?
35
36OCaml offers a unique combination of features that make it particularly well-suited for certain domains:
37
38- **Program Correctness**: The strong type system catches many errors at compile time
39- **Symbolic Computing**: Excellent for manipulating complex data structures and symbolic expressions
40- **Systems Programming**: Can be used for low-level systems programming with high safety guarantees
41- **Web Development**: Modern frameworks like Dream make web development straightforward
42
43In the following chapters, we'll explore the language features in depth and learn how to leverage OCaml's strengths for building robust, maintainable software.
44|}
45 };
46 {
47 id = "chapter2";
48 title = "# Basic Syntax and Types";
49 contents = {|
50# Basic Syntax and Types
51
52OCaml has a clean, consistent syntax that emphasizes readability and minimizes boilerplate.
53
54## Variables and Basic Types
55
56In OCaml, variables are immutable by default. Once a value is bound to a name, that binding cannot change.
57
58```ocaml
59(* Binding a value to a name *)
60let x = 42
61let greeting = "Hello, World!"
62
63(* OCaml has type inference *)
64(* These are equivalent: *)
65let x = 42
66let x : int = 42
67```
68
69## Basic Types
70
71- `int`: Integer numbers
72- `float`: Floating-point numbers
73- `bool`: Boolean values (`true` or `false`)
74- `char`: Single characters
75- `string`: Text strings
76- `unit`: The empty tuple, written `()`
77
78## Functions
79
80Functions in OCaml are first-class values:
81
82```ocaml
83(* A simple function *)
84let add x y = x + y
85
86(* With type annotations *)
87let add (x : int) (y : int) : int = x + y
88
89(* Anonymous (lambda) function *)
90let increment = fun x -> x + 1
91
92(* Partial application *)
93let add5 = add 5
94let fifteen = add5 10 (* equals 15 *)
95```
96
97## Control Flow
98
99OCaml uses expressions rather than statements for control flow:
100
101```ocaml
102(* If expression *)
103let abs x =
104 if x < 0 then -x else x
105
106(* Match expression (pattern matching) *)
107let describe_sign x =
108 match x with
109 | x when x < 0 -> "negative"
110 | 0 -> "zero"
111 | _ -> "positive"
112```
113
114## Recursion
115
116Functions need the `rec` keyword to be recursive:
117
118```ocaml
119(* Recursive function *)
120let rec factorial n =
121 if n <= 1 then 1 else n * factorial (n - 1)
122
123(* Mutually recursive functions *)
124let rec is_even n =
125 if n = 0 then true else is_odd (n - 1)
126and is_odd n =
127 if n = 0 then false else is_even (n - 1)
128```
129
130This introduction to basic syntax sets the foundation for understanding OCaml's more advanced features, which we'll explore in the next chapters.
131|}
132 };
133 {
134 id = "chapter3";
135 title = "# Data Structures";
136 contents = {|
137# Data Structures
138
139OCaml provides several built-in data structures and makes it easy to define custom ones.
140
141## Tuples
142
143Tuples are fixed-length collections of values that can have different types:
144
145```ocaml
146(* A pair of an int and a string *)
147let person = (42, "Alice")
148
149(* Extracting values with pattern matching *)
150let (age, name) = person
151
152(* Accessing elements *)
153let age = fst person (* For pairs only *)
154let name = snd person (* For pairs only *)
155```
156
157## Records
158
159Records are named collections of values:
160
161```ocaml
162(* Defining a record type *)
163type person = {
164 name: string;
165 age: int;
166 email: string option;
167}
168
169(* Creating a record *)
170let alice = {
171 name = "Alice";
172 age = 42;
173 email = Some "alice@example.com";
174}
175
176(* Accessing fields *)
177let alices_name = alice.name
178
179(* Functional update (creates a new record) *)
180let alice_birthday = { alice with age = alice.age + 1 }
181```
182
183## Variants
184
185Variants (also called algebraic data types) represent values that can be one of several cases:
186
187```ocaml
188(* Defining a variant type *)
189type shape =
190 | Circle of float (* radius *)
191 | Rectangle of float * float (* width, height *)
192 | Triangle of float * float * float (* sides *)
193
194(* Creating variants *)
195let my_circle = Circle 2.5
196let my_rectangle = Rectangle (4.0, 6.0)
197
198(* Pattern matching with variants *)
199let area shape =
200 match shape with
201 | Circle r -> Float.pi *. r *. r
202 | Rectangle (w, h) -> w *. h
203 | Triangle (a, b, c) ->
204 let s = (a +. b +. c) /. 2.0 in
205 sqrt (s *. (s -. a) *. (s -. b) *. (s -. c))
206```
207
208## Lists
209
210Lists are immutable linked lists of elements of the same type:
211
212```ocaml
213(* Creating lists *)
214let empty = []
215let numbers = [1; 2; 3; 4; 5]
216let constructed = 1 :: 2 :: 3 :: []
217
218(* Pattern matching with lists *)
219let rec sum_list lst =
220 match lst with
221 | [] -> 0
222 | head :: tail -> head + sum_list tail
223
224(* Common list functions *)
225let doubled = List.map (fun x -> x * 2) numbers
226let evens = List.filter (fun x -> x mod 2 = 0) numbers
227let sum = List.fold_left (+) 0 numbers
228```
229
230## Arrays
231
232Arrays provide mutable, fixed-size collections with O(1) random access:
233
234```ocaml
235(* Creating arrays *)
236let arr = [|1; 2; 3; 4; 5|]
237
238(* Accessing elements (0-indexed) *)
239let first = arr.(0)
240
241(* Modifying elements *)
242let () = arr.(0) <- 10
243
244(* Array functions *)
245let doubled = Array.map (fun x -> x * 2) arr
246```
247
248## Option Type
249
250The option type represents values that might be absent:
251
252```ocaml
253(* Option type *)
254type 'a option = None | Some of 'a
255
256(* Using options *)
257let safe_divide x y =
258 if y = 0 then None else Some (x / y)
259
260(* Working with options *)
261match safe_divide 10 2 with
262| None -> print_endline "Division by zero"
263| Some result -> Printf.printf "Result: %d\n" result
264```
265
266These data structures form the backbone of OCaml programming and allow for expressing complex data relationships in a type-safe way.
267|}
268 };
269 {
270 id = "chapter4";
271 title = "# Modules and Functors";
272 contents = {|
273# Modules and Functors
274
275OCaml's module system is one of its most powerful features. It allows for organizing code into reusable components with clear interfaces.
276
277## Basic Modules
278
279A module is a collection of related definitions (types, values, submodules, etc.):
280
281```ocaml
282(* Defining a module *)
283module Math = struct
284 let pi = 3.14159
285 let square x = x *. x
286 let cube x = x *. x *. x
287end
288
289(* Using a module *)
290let area_of_circle r = Math.pi *. Math.square r
291```
292
293## Module Signatures
294
295Module signatures define the interface of a module, hiding implementation details:
296
297```ocaml
298(* Defining a signature *)
299module type MATH = sig
300 val pi : float
301 val square : float -> float
302 val cube : float -> float
303end
304
305(* Implementing a signature *)
306module Math : MATH = struct
307 let pi = 3.14159
308 let square x = x *. x
309 let cube x = x *. x *. x
310
311 (* This is hidden because it's not in the signature *)
312 let private_helper x = x +. 1.0
313end
314```
315
316## Functors
317
318Functors are functions from modules to modules, allowing for higher-order modularity:
319
320```ocaml
321(* Module signature for collections *)
322module type COLLECTION = sig
323 type 'a t
324 val empty : 'a t
325 val add : 'a -> 'a t -> 'a t
326 val mem : 'a -> 'a t -> bool
327end
328
329(* Functor that creates a set implementation given an element type with comparison *)
330module MakeSet (Element : sig type t val compare : t -> t -> int end) : COLLECTION with type 'a t = Element.t list = struct
331 type 'a t = Element.t list
332
333 let empty = []
334
335 let rec add x lst =
336 match lst with
337 | [] -> [x]
338 | y :: ys ->
339 let c = Element.compare x y in
340 if c < 0 then x :: lst
341 else if c = 0 then lst (* Element already exists *)
342 else y :: add x ys
343
344 let rec mem x lst =
345 match lst with
346 | [] -> false
347 | y :: ys ->
348 let c = Element.compare x y in
349 if c = 0 then true
350 else if c < 0 then false
351 else mem x ys
352end
353
354(* Creating an integer set *)
355module IntElement = struct
356 type t = int
357 let compare = Int.compare
358end
359
360module IntSet = MakeSet(IntElement)
361
362(* Using the set *)
363let my_set = IntSet.empty
364 |> IntSet.add 3
365 |> IntSet.add 1
366 |> IntSet.add 4
367 |> IntSet.add 1 (* Duplicate, not added *)
368
369let has_three = IntSet.mem 3 my_set (* true *)
370let has_five = IntSet.mem 5 my_set (* false *)
371```
372
373## First-Class Modules
374
375OCaml also supports first-class modules, allowing modules to be passed as values:
376
377```ocaml
378(* Module type for number operations *)
379module type NUMBER = sig
380 type t
381 val zero : t
382 val add : t -> t -> t
383 val to_string : t -> string
384end
385
386(* Implementations for different number types *)
387module Int : NUMBER with type t = int = struct
388 type t = int
389 let zero = 0
390 let add = (+)
391 let to_string = string_of_int
392end
393
394module Float : NUMBER with type t = float = struct
395 type t = float
396 let zero = 0.0
397 let add = (+.)
398 let to_string = string_of_float
399end
400
401(* Function that works with any NUMBER module *)
402let sum_as_string (type a) (module N : NUMBER with type t = a) numbers =
403 let sum = List.fold_left N.add N.zero numbers in
404 N.to_string sum
405
406(* Using first-class modules *)
407let int_sum = sum_as_string (module Int) [1; 2; 3; 4]
408let float_sum = sum_as_string (module Float) [1.0; 2.5; 3.7]
409```
410
411## Open and Include
412
413OCaml provides ways to bring module contents into scope:
414
415```ocaml
416(* Open brings module contents into scope temporarily *)
417let area =
418 let open Math in
419 pi *. square 2.0
420
421(* Local opening with the modern syntax *)
422let area = Math.(pi *. square 2.0)
423
424(* Include actually extends a module with another module's contents *)
425module ExtendedMath = struct
426 include Math
427 let tau = 2.0 *. pi
428 let circumference r = tau *. r
429end
430```
431
432The module system enables OCaml programmers to build highly modular, reusable code with clear boundaries between components.
433|}
434 };
435 {
436 id = "chapter5";
437 title = "# Advanced Features";
438 contents = {|
439# Advanced Features
440
441OCaml offers several advanced features that set it apart from other languages. This chapter explores some of the more powerful language constructs.
442
443## Polymorphic Variants
444
445Unlike regular variants, polymorphic variants don't need to be predefined:
446
447```ocaml
448(* Using polymorphic variants directly *)
449let weekend = `Saturday | `Sunday
450let is_weekend day =
451 match day with
452 | `Saturday | `Sunday -> true
453 | `Monday .. `Friday -> false
454
455(* Can be used in mixed contexts *)
456let shape_area = function
457 | `Circle r -> Float.pi *. r *. r
458 | `Rectangle (w, h) -> w *. h
459 | `Triangle (b, h) -> 0.5 *. b *. h
460 | `Regular_polygon(n, s) when n >= 3 ->
461 let apothem = s /. (2.0 *. tan (Float.pi /. float_of_int n)) in
462 n *. s *. apothem /. 2.0
463 | _ -> failwith "Invalid shape"
464```
465
466## Objects and Classes
467
468OCaml supports object-oriented programming:
469
470```ocaml
471(* Simple class definition *)
472class point x_init y_init =
473 object (self)
474 val mutable x = x_init
475 val mutable y = y_init
476
477 method get_x = x
478 method get_y = y
479 method move dx dy = x <- x + dx; y <- y + dy
480 method distance_from_origin =
481 sqrt (float_of_int (x * x + y * y))
482
483 (* Private method *)
484 method private to_string =
485 Printf.sprintf "(%d, %d)" x y
486
487 (* Calling another method *)
488 method print = print_endline self#to_string
489 end
490
491(* Using a class *)
492let p = new point 3 4
493let () = p#move 2 1
494let d = p#distance_from_origin
495```
496
497## Generalized Algebraic Data Types (GADTs)
498
499GADTs provide more type control than regular variants:
500
501```ocaml
502(* A GADT for type-safe expressions *)
503type _ expr =
504 | Int : int -> int expr
505 | Bool : bool -> bool expr
506 | Add : int expr * int expr -> int expr
507 | Eq : 'a expr * 'a expr -> bool expr
508
509(* Type-safe evaluation *)
510let rec eval : type a. a expr -> a = function
511 | Int n -> n
512 | Bool b -> b
513 | Add (e1, e2) -> eval e1 + eval e2
514 | Eq (e1, e2) -> eval e1 = eval e2
515
516(* These expressions are statically type-checked *)
517let e1 = Add (Int 1, Int 2) (* OK: int expr *)
518let e2 = Eq (Int 1, Int 2) (* OK: bool expr *)
519(* let e3 = Add (Int 1, Bool true) (* Type error! *) *)
520(* let e4 = Eq (Int 1, Bool true) (* Type error! *) *)
521```
522
523## Type Extensions
524
525OCaml allows extending existing types:
526
527```ocaml
528(* Original type *)
529type shape = Circle of float | Rectangle of float * float
530
531(* Extending the type in another module *)
532type shape += Triangle of float * float * float
533
534(* Pattern matching must now handle unknown cases *)
535let area = function
536 | Circle r -> Float.pi *. r *. r
537 | Rectangle (w, h) -> w *. h
538 | Triangle (a, b, c) ->
539 let s = (a +. b +. c) /. 2.0 in
540 sqrt (s *. (s -. a) *. (s -. b) *. (s -. c))
541 | _ -> failwith "Unknown shape"
542```
543
544## Effects and Effect Handlers
545
546OCaml 5 introduced algebraic effects for managing control flow:
547
548```ocaml
549(* Defining an effect *)
550type _ Effect.t += Ask : string -> string Effect.t
551
552(* Handler for the Ask effect *)
553let prompt_user () =
554 Effect.Deep.try_with
555 (fun () ->
556 let name = Effect.perform (Ask "What is your name?") in
557 Printf.printf "Hello, %s!\n" name)
558 { Effect.Deep.effc = fun (type a) (effect : a Effect.t) ->
559 match effect with
560 | Ask prompt -> fun k ->
561 Printf.printf "%s " prompt;
562 let response = read_line () in
563 k response
564 | _ -> None }
565```
566
567## Higher-Ranked Polymorphism
568
569Using the `Obj.magic` escape hatch (with caution):
570
571```ocaml
572(* This would normally not be permitted due to rank-2 polymorphism *)
573let apply_to_all_types f =
574 let magic_f : 'a -> string = Obj.magic f in
575 [
576 magic_f 42;
577 magic_f "hello";
578 magic_f 3.14;
579 magic_f true;
580 ]
581
582(* Usage - with great care! *)
583let result = apply_to_all_types (fun x -> Printf.sprintf "Value: %s" (Obj.magic x))
584```
585
586## Metaprogramming with PPX
587
588OCaml's PPX system enables powerful metaprogramming:
589
590```ocaml
591(* With ppx_deriving *)
592type person = {
593 name: string;
594 age: int;
595 email: string option;
596} [@@deriving show, eq, ord]
597
598(* With ppx_sexp_conv *)
599type config = {
600 server: string;
601 port: int;
602 timeout: float;
603} [@@deriving sexp]
604
605(* With ppx_let for monadic operations *)
606let computation =
607 [%m.let
608 let* x = get_value_from_db "key1" in
609 let* y = get_value_from_db "key2" in
610 return (x + y)
611 ]
612```
613
614## Modules for Advanced Typing
615
616Using modules to encode complex type relationships:
617
618```ocaml
619(* Phantom types for added type safety *)
620module SafeString : sig
621 type 'a t
622
623 (* Constructors for different string types *)
624 val of_raw : string -> [`Raw] t
625 val sanitize : [`Raw] t -> [`Sanitized] t
626 val validate : [`Sanitized] t -> [`Validated] t option
627
628 (* Operations that require specific string types *)
629 val to_html : [`Sanitized] t -> string
630 val to_sql : [`Validated] t -> string
631
632 (* Common operations for all string types *)
633 val length : _ t -> int
634 val concat : _ t -> _ t -> [`Raw] t
635end = struct
636 type 'a t = string
637
638 let of_raw s = s
639 let sanitize s = String.map (function '<' | '>' -> '_' | c -> c) s
640 let validate s = if String.length s > 0 then Some s else None
641
642 let to_html s = s
643 let to_sql s = "'" ^ String.map (function '\'' -> '\'' | c -> c) s ^ "'"
644
645 let length = String.length
646 let concat s1 s2 = s1 ^ s2
647end
648```
649
650These advanced features make OCaml a uniquely powerful language for expressing complex programs with strong guarantees about correctness.
651|}
652 };
653 ]
654
655 (* Get a chapter by ID *)
656 let get_by_id id =
657 try Some (List.find (fun c -> c.id = id) chapters)
658 with Not_found -> None
659
660 (* Get chapter titles *)
661 let get_all_titles () =
662 List.map (fun c -> (c.id, c.title)) chapters
663end
664
665(* Create a server *)
666let server = create_server
667 ~name:"OCaml MCP Book Resource Example"
668 ~version:"0.1.0" () |>
669 fun server ->
670 (* Set default capabilities *)
671 configure_server server
672 ~with_tools:false
673 ~with_resources:true
674 ~with_resource_templates:true
675 ~with_prompts:false ()
676
677(* Add a resource template to get book chapters *)
678let _ = add_resource_template server
679 ~uri_template:"book/chapter/{id}"
680 ~name:"Chapter Resource"
681 ~description:"Get a specific chapter from the OCaml book by its ID"
682 ~mime_type:"text/markdown"
683 (fun params ->
684 match params with
685 | [id] ->
686 (match BookChapter.get_by_id id with
687 | Some chapter -> chapter.contents
688 | None -> Printf.sprintf "# Error\n\nChapter with ID '%s' not found." id)
689 | _ -> "# Error\n\nInvalid parameters. Expected chapter ID."
690 )
691
692(* Add a regular resource to get table of contents (no variables) *)
693let _ = add_resource server
694 ~uri:"book/toc"
695 ~name:"Table of Contents"
696 ~description:"Get the table of contents for the OCaml book"
697 ~mime_type:"text/markdown"
698 (fun _params ->
699 let titles = BookChapter.get_all_titles() in
700 let toc = "# OCaml Book - Table of Contents\n\n" ^
701 (List.mapi (fun i (id, title) ->
702 Printf.sprintf "%d. [%s](book/chapter/%s)\n"
703 (i + 1)
704 (String.sub title 2 (String.length title - 2)) (* Remove "# " prefix *)
705 id
706 ) titles |> String.concat "")
707 in
708 toc
709 )
710
711(* Add a regular resource for a complete book (no variables) *)
712let _ = add_resource server
713 ~uri:"book/complete"
714 ~name:"Full contents"
715 ~description:"Get the complete OCaml book as a single document"
716 ~mime_type:"text/markdown"
717 (fun _params ->
718 let chapter_contents = List.map (fun c -> c.BookChapter.contents) BookChapter.chapters in
719 let content = "# The OCaml Book\n\n*A comprehensive guide to OCaml programming*\n\n" ^
720 (String.concat "\n\n---\n\n" chapter_contents)
721 in
722 content
723 )
724
725(* Run the server with the default scheduler *)
726let () =
727 Eio_main.run @@ fun env ->
728 Mcp_server.run_server env server