···
Bytes.sub_string result 0 (loop 0 0)
50
-
(* Generate a random image as SVG format *)
50
+
(* Generate a simple GIF format image *)
let generate_random_image width height =
52
-
(* Helper to get random color with param control *)
53
-
let random_color ?(min=0) ?(max=255) () =
54
-
let r = min + Random.int (max - min + 1) in
55
-
let g = min + Random.int (max - min + 1) in
56
-
let b = min + Random.int (max - min + 1) in
57
-
Printf.sprintf "#%02x%02x%02x" r g b
52
+
(* Ensure dimensions are reasonable *)
53
+
let width = min 256 (max 16 width) in
54
+
let height = min 256 (max 16 height) in
60
-
(* Create SVG header *)
61
-
let svg_buffer = Buffer.create 10240 in
62
-
Buffer.add_string svg_buffer (Printf.sprintf
63
-
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\
64
-
<svg width=\"%d\" height=\"%d\" xmlns=\"http://www.w3.org/2000/svg\">\n\
65
-
<rect width=\"%d\" height=\"%d\" fill=\"%s\"/>\n"
66
-
width height width height (random_color ~min:200 ~max:240 ())
56
+
(* Create a buffer for GIF data *)
57
+
let buf = Buffer.create 1024 in
69
-
(* Generate different SVG shapes based on image size and randomness *)
70
-
let shape_count = (width * height) / 5000 + 5 in
59
+
(* GIF Header - "GIF89a" *)
60
+
Buffer.add_string buf "GIF89a";
72
-
(* Add random circles *)
73
-
for _ = 1 to shape_count / 2 do
74
-
let cx = Random.int width in
75
-
let cy = Random.int height in
76
-
let r = 5 + Random.int (min width height / 8) in
77
-
let color = random_color ~min:50 ~max:200 () in
78
-
let opacity = 0.3 +. (Random.float 0.7) in
79
-
Buffer.add_string svg_buffer (Printf.sprintf
80
-
"<circle cx=\"%d\" cy=\"%d\" r=\"%d\" fill=\"%s\" fill-opacity=\"%.2f\" />\n"
81
-
cx cy r color opacity
62
+
(* Logical Screen Descriptor *)
63
+
(* Width - 2 bytes little endian *)
64
+
Buffer.add_char buf (Char.chr (width land 0xff));
65
+
Buffer.add_char buf (Char.chr ((width lsr 8) land 0xff));
85
-
(* Add random rectangles *)
86
-
for _ = 1 to shape_count / 3 do
87
-
let x = Random.int width in
88
-
let y = Random.int height in
89
-
let w = 10 + Random.int (width / 5) in
90
-
let h = 10 + Random.int (height / 5) in
91
-
let color = random_color ~min:50 ~max:200 () in
92
-
let opacity = 0.2 +. (Random.float 0.6) in
93
-
let rx = 2 + Random.int 20 in (* Rounded corners *)
94
-
Buffer.add_string svg_buffer (Printf.sprintf
95
-
"<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" rx=\"%d\" fill=\"%s\" fill-opacity=\"%.2f\" />\n"
96
-
x y w h rx color opacity
67
+
(* Height - 2 bytes little endian *)
68
+
Buffer.add_char buf (Char.chr (height land 0xff));
69
+
Buffer.add_char buf (Char.chr ((height lsr 8) land 0xff));
100
-
(* Add random lines *)
101
-
for _ = 1 to shape_count do
102
-
let x1 = Random.int width in
103
-
let y1 = Random.int height in
104
-
let x2 = Random.int width in
105
-
let y2 = Random.int height in
106
-
let stroke = random_color () in
107
-
let sw = 1 + Random.int 5 in
108
-
Buffer.add_string svg_buffer (Printf.sprintf
109
-
"<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke=\"%s\" stroke-width=\"%d\" />\n"
110
-
x1 y1 x2 y2 stroke sw
71
+
(* Packed fields - 1 byte:
72
+
Global Color Table Flag - 1 bit (1)
73
+
Color Resolution - 3 bits (7 = 8 bits per color)
74
+
Sort Flag - 1 bit (0)
75
+
Size of Global Color Table - 3 bits (2 = 8 colors) *)
76
+
Buffer.add_char buf (Char.chr 0xF2);
78
+
(* Background color index - 1 byte *)
79
+
Buffer.add_char buf (Char.chr 0);
81
+
(* Pixel aspect ratio - 1 byte *)
82
+
Buffer.add_char buf (Char.chr 0);
84
+
(* Global Color Table - 8 colors x 3 bytes (R,G,B) *)
85
+
(* Simple 8-color palette *)
86
+
Buffer.add_string buf "\xFF\xFF\xFF"; (* White (0) *)
87
+
Buffer.add_string buf "\xFF\x00\x00"; (* Red (1) *)
88
+
Buffer.add_string buf "\x00\xFF\x00"; (* Green (2) *)
89
+
Buffer.add_string buf "\x00\x00\xFF"; (* Blue (3) *)
90
+
Buffer.add_string buf "\xFF\xFF\x00"; (* Yellow (4) *)
91
+
Buffer.add_string buf "\xFF\x00\xFF"; (* Magenta (5) *)
92
+
Buffer.add_string buf "\x00\xFF\xFF"; (* Cyan (6) *)
93
+
Buffer.add_string buf "\x00\x00\x00"; (* Black (7) *)
95
+
(* Graphics Control Extension (optional) *)
96
+
Buffer.add_char buf (Char.chr 0x21); (* Extension Introducer *)
97
+
Buffer.add_char buf (Char.chr 0xF9); (* Graphic Control Label *)
98
+
Buffer.add_char buf (Char.chr 0x04); (* Block Size *)
99
+
Buffer.add_char buf (Char.chr 0x01); (* Packed field: 1 bit for transparency *)
100
+
Buffer.add_char buf (Char.chr 0x00); (* Delay time (1/100s) - 2 bytes *)
101
+
Buffer.add_char buf (Char.chr 0x00);
102
+
Buffer.add_char buf (Char.chr 0x00); (* Transparent color index *)
103
+
Buffer.add_char buf (Char.chr 0x00); (* Block terminator *)
105
+
(* Image Descriptor *)
106
+
Buffer.add_char buf (Char.chr 0x2C); (* Image Separator *)
107
+
Buffer.add_char buf (Char.chr 0x00); (* Left position - 2 bytes *)
108
+
Buffer.add_char buf (Char.chr 0x00);
109
+
Buffer.add_char buf (Char.chr 0x00); (* Top position - 2 bytes *)
110
+
Buffer.add_char buf (Char.chr 0x00);
112
+
(* Image width - 2 bytes little endian *)
113
+
Buffer.add_char buf (Char.chr (width land 0xff));
114
+
Buffer.add_char buf (Char.chr ((width lsr 8) land 0xff));
116
+
(* Image height - 2 bytes little endian *)
117
+
Buffer.add_char buf (Char.chr (height land 0xff));
118
+
Buffer.add_char buf (Char.chr ((height lsr 8) land 0xff));
120
+
(* Packed fields - 1 byte - no local color table *)
121
+
Buffer.add_char buf (Char.chr 0x00);
123
+
(* LZW Minimum Code Size - 1 byte *)
124
+
Buffer.add_char buf (Char.chr 0x03); (* Minimum code size 3 for 8 colors *)
126
+
(* Generate a simple image - a checkerboard pattern *)
127
+
let step = width / 8 in
128
+
let image_data = Buffer.create (width * height / 4) in
130
+
(* Very simple LZW compression - just store raw clear codes and color indexes *)
131
+
(* Start with Clear code *)
132
+
Buffer.add_char image_data (Char.chr 0x08); (* Clear code 8 *)
134
+
(* For very simple encoding, we'll just use a sequence of color indexes *)
135
+
for y = 0 to height - 1 do
136
+
for x = 0 to width - 1 do
137
+
(* Checkerboard pattern with different colors *)
139
+
if ((x / step) + (y / step)) mod 2 = 0 then
144
+
Buffer.add_char image_data (Char.chr color);
114
-
(* Add some random polygons *)
115
-
for _ = 1 to shape_count / 4 do
116
-
let points = 3 + Random.int 5 in (* 3 to 7 points *)
117
-
let cx = Random.int width in
118
-
let cy = Random.int height in
119
-
let radius = 10 + Random.int (min width height / 6) in
120
-
let points_str = Buffer.create 100 in
122
-
for i = 0 to points - 1 do
123
-
let angle = 2.0 *. Float.pi *. (float_of_int i) /. (float_of_int points) in
124
-
let px = cx + int_of_float (float_of_int radius *. cos angle) in
125
-
let py = cy + int_of_float (float_of_int radius *. sin angle) in
126
-
Buffer.add_string points_str (Printf.sprintf "%d,%d " px py);
148
+
(* End with End of Information code *)
149
+
Buffer.add_char image_data (Char.chr 0x09);
151
+
(* Add image data blocks - GIF uses 255-byte max chunks *)
152
+
let data = Buffer.contents image_data in
153
+
let data_len = String.length data in
156
+
while !pos < data_len do
157
+
let chunk_size = min 255 (data_len - !pos) in
158
+
Buffer.add_char buf (Char.chr chunk_size);
159
+
for i = 0 to chunk_size - 1 do
160
+
Buffer.add_char buf (String.get data (!pos + i));
129
-
let fill = random_color ~min:100 ~max:220 () in
130
-
let opacity = 0.2 +. Random.float 0.5 in
132
-
Buffer.add_string svg_buffer (Printf.sprintf
133
-
"<polygon points=\"%s\" fill=\"%s\" fill-opacity=\"%.2f\" />\n"
134
-
(Buffer.contents points_str) fill opacity
162
+
pos := !pos + chunk_size;
138
-
(* Close SVG tag *)
139
-
Buffer.add_string svg_buffer "</svg>";
165
+
(* Zero-length block to end the image data *)
166
+
Buffer.add_char buf (Char.chr 0x00);
169
+
Buffer.add_char buf (Char.chr 0x3B);
141
-
(* Return the SVG directly, no need for Base64 since it's already text *)
142
-
Buffer.contents svg_buffer
171
+
(* Base64 encode the GIF data *)
172
+
Base64.encode (Buffer.contents buf)
(* Helper to write 32-bit little endian integer *)
let write_int32_le buf n =
···
let server = create_server
~name:"OCaml MCP Multimodal Example"
204
-
~protocol_version:"2025-03-26" () |>
234
+
~protocol_version:"2024-11-05" () |>
(* Set default capabilities *)
configure_server server ~with_tools:true ~with_resources:true ~with_prompts:true ()
···
(* Create a multimodal tool result *)
237
-
~image:(Some (image_data, "image/svg+xml"))
267
+
~image:(Some (image_data, "image/gif"))
~audio:(Some (audio_data, "audio/wav"))
···
let image_data = generate_random_image width height in
268
-
[ImageContent { data = image_data; mime_type = "image/svg+xml" }]
298
+
[ImageContent { data = image_data; mime_type = "image/gif" }]
···
326
-
"mimeType": "image/svg+xml"
356
+
"mimeType": "image/gif"