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