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