Model Context Protocol in OCaml
at main 19 kB view raw
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