···3344type setting_source = User | Project | Local
5566+type mcp_stdio_config = {
77+ command : string;
88+ args : string list;
99+ env : (string * string) list option;
1010+}
1111+1212+type mcp_sse_config = {
1313+ url : string;
1414+ headers : (string * string) list option;
1515+}
1616+1717+type mcp_http_config = {
1818+ url : string;
1919+ headers : (string * string) list option;
2020+}
2121+2222+type mcp_server_config =
2323+ | Stdio of mcp_stdio_config
2424+ | SSE of mcp_sse_config
2525+ | HTTP of mcp_http_config
2626+627module Unknown = struct
728 type t = Jsont.json
829 let empty = Jsont.Object ([], Jsont.Meta.none)
···3657 max_buffer_size : int option;
3758 user : string option;
3859 output_format : Structured_output.t option;
6060+ mcp_servers : (string * mcp_server_config) list;
3961 unknown : Unknown.t;
4062}
4163···6587 max_buffer_size = None;
6688 user = None;
6789 output_format = None;
9090+ mcp_servers = [];
6891 unknown = Unknown.empty;
6992}
7093···94117 ?max_buffer_size
95118 ?user
96119 ?output_format
120120+ ?(mcp_servers = [])
97121 ?(unknown = Unknown.empty)
98122 () =
99123 { allowed_tools; disallowed_tools; max_thinking_tokens;
···103127 permission_prompt_tool_name; settings; add_dirs;
104128 extra_args; debug_stderr; hooks;
105129 max_budget_usd; fallback_model; setting_sources;
106106- max_buffer_size; user; output_format; unknown }
130130+ max_buffer_size; user; output_format; mcp_servers; unknown }
107131108132let allowed_tools t = t.allowed_tools
109133let disallowed_tools t = t.disallowed_tools
···130154let max_buffer_size t = t.max_buffer_size
131155let user t = t.user
132156let output_format t = t.output_format
157157+let mcp_servers t = t.mcp_servers
133158let unknown t = t.unknown
134159135160let with_allowed_tools tools t = { t with allowed_tools = tools }
···161186let with_user user t = { t with user = Some user }
162187let with_output_format format t = { t with output_format = Some format }
163188189189+let with_mcp_server ~name ~config t =
190190+ let servers = List.filter (fun (n, _) -> n <> name) t.mcp_servers in
191191+ { t with mcp_servers = (name, config) :: servers }
192192+193193+let with_mcp_servers servers t = { t with mcp_servers = servers }
194194+195195+let with_mcp_stdio ~name ~command ?(args = []) ?env () t =
196196+ let config = Stdio { command; args; env } in
197197+ with_mcp_server ~name ~config t
198198+164199(* Helper codec for Model.t *)
165200let model_jsont : Model.t Jsont.t =
166201 Jsont.map ~kind:"Model"
···187222 Jsont.Json.object' mems)
188223 Jsont.json
189224225225+(* Helper codec for headers - list of string pairs encoded as object *)
226226+let headers_jsont : (string * string) list Jsont.t =
227227+ Jsont.map ~kind:"Headers"
228228+ ~dec:(fun obj ->
229229+ match obj with
230230+ | Jsont.Object (members, _) ->
231231+ List.map (fun ((name, _), value) ->
232232+ match value with
233233+ | Jsont.String (s, _) -> (name, s)
234234+ | _ -> (name, "")
235235+ ) members
236236+ | _ -> [])
237237+ ~enc:(fun pairs ->
238238+ let mems = List.map (fun (k, v) ->
239239+ Jsont.Json.mem (Jsont.Json.name k) (Jsont.Json.string v)
240240+ ) pairs in
241241+ Jsont.Json.object' mems)
242242+ Jsont.json
243243+244244+(* MCP server config codecs *)
245245+let mcp_stdio_config_jsont : mcp_stdio_config Jsont.t =
246246+ let make command args env : mcp_stdio_config = { command; args; env } in
247247+ Jsont.Object.map ~kind:"McpStdioConfig" make
248248+ |> Jsont.Object.mem "command" Jsont.string ~enc:(fun (c : mcp_stdio_config) -> c.command) ~dec_absent:""
249249+ |> Jsont.Object.mem "args" (Jsont.list Jsont.string) ~enc:(fun (c : mcp_stdio_config) -> c.args) ~dec_absent:[]
250250+ |> Jsont.Object.opt_mem "env" env_jsont ~enc:(fun (c : mcp_stdio_config) -> c.env)
251251+ |> Jsont.Object.finish
252252+253253+let mcp_sse_config_jsont : mcp_sse_config Jsont.t =
254254+ let make url headers : mcp_sse_config = { url; headers } in
255255+ Jsont.Object.map ~kind:"McpSseConfig" make
256256+ |> Jsont.Object.mem "url" Jsont.string ~enc:(fun (c : mcp_sse_config) -> c.url) ~dec_absent:""
257257+ |> Jsont.Object.opt_mem "headers" headers_jsont ~enc:(fun (c : mcp_sse_config) -> c.headers)
258258+ |> Jsont.Object.finish
259259+260260+let mcp_http_config_jsont : mcp_http_config Jsont.t =
261261+ let make url headers : mcp_http_config = { url; headers } in
262262+ Jsont.Object.map ~kind:"McpHttpConfig" make
263263+ |> Jsont.Object.mem "url" Jsont.string ~enc:(fun (c : mcp_http_config) -> c.url) ~dec_absent:""
264264+ |> Jsont.Object.opt_mem "headers" headers_jsont ~enc:(fun (c : mcp_http_config) -> c.headers)
265265+ |> Jsont.Object.finish
266266+267267+let mcp_server_config_jsont : mcp_server_config Jsont.t =
268268+ Jsont.map ~kind:"McpServerConfig"
269269+ ~dec:(fun obj ->
270270+ match obj with
271271+ | Jsont.Object (members, _) ->
272272+ (* Look for type field to determine variant *)
273273+ let type_field = List.find_map (fun ((name, _), value) ->
274274+ if name = "type" then
275275+ match value with
276276+ | Jsont.String (s, _) -> Some s
277277+ | _ -> None
278278+ else None
279279+ ) members in
280280+ (match type_field with
281281+ | Some "stdio" ->
282282+ let config = Jsont.Json.decode mcp_stdio_config_jsont obj in
283283+ (match config with
284284+ | Ok cfg -> Stdio cfg
285285+ | Error _ -> Stdio { command = ""; args = []; env = None })
286286+ | Some "sse" ->
287287+ let config = Jsont.Json.decode mcp_sse_config_jsont obj in
288288+ (match config with
289289+ | Ok cfg -> SSE cfg
290290+ | Error _ -> SSE { url = ""; headers = None })
291291+ | Some "http" ->
292292+ let config = Jsont.Json.decode mcp_http_config_jsont obj in
293293+ (match config with
294294+ | Ok cfg -> HTTP cfg
295295+ | Error _ -> HTTP { url = ""; headers = None })
296296+ | _ -> Stdio { command = ""; args = []; env = None })
297297+ | _ -> Stdio { command = ""; args = []; env = None })
298298+ ~enc:(fun config ->
299299+ match config with
300300+ | Stdio cfg ->
301301+ let obj = Jsont.Json.encode mcp_stdio_config_jsont cfg in
302302+ (match obj with
303303+ | Ok (Jsont.Object (members, meta)) ->
304304+ let type_mem = Jsont.Json.mem (Jsont.Json.name "type") (Jsont.Json.string "stdio") in
305305+ Jsont.Object (type_mem :: members, meta)
306306+ | Ok json -> json
307307+ | Error _ -> Jsont.Object ([], Jsont.Meta.none))
308308+ | SSE cfg ->
309309+ let obj = Jsont.Json.encode mcp_sse_config_jsont cfg in
310310+ (match obj with
311311+ | Ok (Jsont.Object (members, meta)) ->
312312+ let type_mem = Jsont.Json.mem (Jsont.Json.name "type") (Jsont.Json.string "sse") in
313313+ Jsont.Object (type_mem :: members, meta)
314314+ | Ok json -> json
315315+ | Error _ -> Jsont.Object ([], Jsont.Meta.none))
316316+ | HTTP cfg ->
317317+ let obj = Jsont.Json.encode mcp_http_config_jsont cfg in
318318+ (match obj with
319319+ | Ok (Jsont.Object (members, meta)) ->
320320+ let type_mem = Jsont.Json.mem (Jsont.Json.name "type") (Jsont.Json.string "http") in
321321+ Jsont.Object (type_mem :: members, meta)
322322+ | Ok json -> json
323323+ | Error _ -> Jsont.Object ([], Jsont.Meta.none)))
324324+ Jsont.json
325325+326326+(* Codec for MCP servers map - encoded as object with server names as keys *)
327327+let mcp_servers_jsont : (string * mcp_server_config) list Jsont.t =
328328+ Jsont.map ~kind:"McpServers"
329329+ ~dec:(fun obj ->
330330+ match obj with
331331+ | Jsont.Object (members, _) ->
332332+ List.filter_map (fun ((name, _), value) ->
333333+ match Jsont.Json.decode mcp_server_config_jsont value with
334334+ | Ok cfg -> Some (name, cfg)
335335+ | Error _ -> None
336336+ ) members
337337+ | _ -> [])
338338+ ~enc:(fun servers ->
339339+ let mems = List.map (fun (name, cfg) ->
340340+ match Jsont.Json.encode mcp_server_config_jsont cfg with
341341+ | Ok json -> Jsont.Json.mem (Jsont.Json.name name) json
342342+ | Error _ -> Jsont.Json.mem (Jsont.Json.name name) (Jsont.Object ([], Jsont.Meta.none))
343343+ ) servers in
344344+ Jsont.Json.object' mems)
345345+ Jsont.json
346346+190347let jsont : t Jsont.t =
191348 let make allowed_tools disallowed_tools max_thinking_tokens
192349 system_prompt append_system_prompt permission_mode
193193- model env unknown =
350350+ model env mcp_servers unknown =
194351 { allowed_tools; disallowed_tools; max_thinking_tokens;
195352 system_prompt; append_system_prompt; permission_mode;
196353 permission_callback = Some Permissions.default_allow_callback;
···210367 max_buffer_size = None;
211368 user = None;
212369 output_format = None;
370370+ mcp_servers;
213371 unknown }
214372 in
215373 Jsont.Object.map ~kind:"Options" make
···221379 |> Jsont.Object.opt_mem "permission_mode" Permissions.Mode.jsont ~enc:permission_mode
222380 |> Jsont.Object.opt_mem "model" model_jsont ~enc:model
223381 |> Jsont.Object.mem "env" env_jsont ~enc:env ~dec_absent:[]
382382+ |> Jsont.Object.mem "mcp_servers" mcp_servers_jsont ~enc:mcp_servers ~dec_absent:[]
224383 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
225384 |> Jsont.Object.finish
226385
+76-2
claudeio/lib/options.mli
···110110 - [Project]: Load project-level settings from .claude/ in project root
111111 - [Local]: Load local settings from current directory *)
112112113113+(** {2 MCP Server Configuration}
114114+115115+ MCP (Model Context Protocol) servers provide tools and resources.
116116+117117+ Example:
118118+ {[
119119+ let options = Options.default
120120+ |> Options.with_mcp_stdio
121121+ ~name:"filesystem"
122122+ ~command:"mcp-server-filesystem"
123123+ ~args:["/workspace"]
124124+ ()
125125+ |> Options.with_allowed_tools [
126126+ "mcp__filesystem__read_file";
127127+ "mcp__filesystem__write_file";
128128+ ]
129129+ ]}
130130+131131+ Tool Naming: MCP tools are named [mcp__<server>__<tool>] *)
132132+133133+type mcp_stdio_config = {
134134+ command : string;
135135+ args : string list;
136136+ env : (string * string) list option;
137137+}
138138+(** Stdio-based MCP server (external process) *)
139139+140140+type mcp_sse_config = {
141141+ url : string;
142142+ headers : (string * string) list option;
143143+}
144144+(** Server-Sent Events MCP server *)
145145+146146+type mcp_http_config = {
147147+ url : string;
148148+ headers : (string * string) list option;
149149+}
150150+(** HTTP-based MCP server *)
151151+152152+type mcp_server_config =
153153+ | Stdio of mcp_stdio_config
154154+ | SSE of mcp_sse_config
155155+ | HTTP of mcp_http_config
156156+(** MCP server configuration variants *)
157157+113158type t
114159(** The type of configuration options. *)
115160···146191 ?max_buffer_size:int ->
147192 ?user:string ->
148193 ?output_format:Structured_output.t ->
194194+ ?mcp_servers:(string * mcp_server_config) list ->
149195 ?unknown:Jsont.json ->
150196 unit -> t
151197(** [create ?allowed_tools ?disallowed_tools ?max_thinking_tokens ?system_prompt
152198 ?append_system_prompt ?permission_mode ?permission_callback ?model ?cwd ?env
153199 ?continue_conversation ?resume ?max_turns ?permission_prompt_tool_name ?settings
154200 ?add_dirs ?extra_args ?debug_stderr ?hooks ?max_budget_usd ?fallback_model
155155- ?setting_sources ?max_buffer_size ?user ()]
201201+ ?setting_sources ?max_buffer_size ?user ?mcp_servers ()]
156202 creates a new configuration.
157203 @param allowed_tools List of explicitly allowed tool names
158204 @param disallowed_tools List of explicitly disallowed tool names
···178224 @param setting_sources Control which settings load (user/project/local)
179225 @param max_buffer_size Control for stdout buffer size in bytes
180226 @param user Unix user for subprocess execution
181181- @param output_format Optional structured output format specification *)
227227+ @param output_format Optional structured output format specification
228228+ @param mcp_servers MCP server configurations (name -> config mapping) *)
182229183230(** {1 Accessors} *)
184231···256303257304val output_format : t -> Structured_output.t option
258305(** [output_format t] returns the optional structured output format. *)
306306+307307+val mcp_servers : t -> (string * mcp_server_config) list
308308+(** [mcp_servers t] returns the MCP server configurations.
309309+ Tools from MCP servers are named: mcp__<server_name>__<tool_name> *)
259310260311val unknown : t -> Jsont.json
261312(** [unknown t] returns any unknown JSON fields that were preserved during decoding. *)
···350401351402val with_output_format : Structured_output.t -> t -> t
352403(** [with_output_format format t] sets the structured output format. *)
404404+405405+val with_mcp_server :
406406+ name:string ->
407407+ config:mcp_server_config ->
408408+ t -> t
409409+(** [with_mcp_server ~name ~config t] adds an MCP server configuration.
410410+ If a server with the same name exists, it will be replaced. *)
411411+412412+val with_mcp_servers :
413413+ (string * mcp_server_config) list ->
414414+ t -> t
415415+(** [with_mcp_servers servers t] sets MCP servers (replaces existing).
416416+ Each element is a pair of (server_name, server_config). *)
417417+418418+val with_mcp_stdio :
419419+ name:string ->
420420+ command:string ->
421421+ ?args:string list ->
422422+ ?env:(string * string) list ->
423423+ unit ->
424424+ t -> t
425425+(** [with_mcp_stdio ~name ~command ?args ?env () t] is a convenience
426426+ function to add a stdio-based MCP server. *)
353427354428(** {1 Serialization} *)
355429
+56-27
claudeio/lib/sdk_control.ml
···11let src = Logs.Src.create "claude.sdk_control" ~doc:"Claude SDK control protocol"
22module Log = (val Logs.src_log src : Logs.LOG)
3344+(** MCP Message Routing *)
55+module Mcp_message = struct
66+ module Unknown = struct
77+ type t = Jsont.json
88+ let empty = Jsont.Object ([], Jsont.Meta.none)
99+ let is_empty = function Jsont.Object ([], _) -> true | _ -> false
1010+ let jsont = Jsont.json
1111+ end
1212+1313+ type request = {
1414+ server_name : string;
1515+ message : Jsont.json;
1616+ unknown : Unknown.t;
1717+ }
1818+1919+ type response = {
2020+ mcp_response : Jsont.json;
2121+ unknown : Unknown.t;
2222+ }
2323+2424+ let make_request ~server_name ~message ?(unknown = Unknown.empty) () =
2525+ { server_name; message; unknown }
2626+2727+ let make_response ~mcp_response ?(unknown = Unknown.empty) () =
2828+ { mcp_response; unknown }
2929+3030+ let request_jsont : request Jsont.t =
3131+ let make server_name message (unknown : Unknown.t) : request =
3232+ { server_name; message; unknown }
3333+ in
3434+ Jsont.Object.map ~kind:"McpMessageRequest" make
3535+ |> Jsont.Object.mem "server_name" Jsont.string ~enc:(fun (r : request) -> r.server_name)
3636+ |> Jsont.Object.mem "message" Jsont.json ~enc:(fun (r : request) -> r.message)
3737+ |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun (r : request) -> r.unknown)
3838+ |> Jsont.Object.finish
3939+4040+ let response_jsont : response Jsont.t =
4141+ let make mcp_response (unknown : Unknown.t) : response =
4242+ { mcp_response; unknown }
4343+ in
4444+ Jsont.Object.map ~kind:"McpMessageResponse" make
4545+ |> Jsont.Object.mem "mcp_response" Jsont.json ~enc:(fun (r : response) -> r.mcp_response)
4646+ |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun (r : response) -> r.unknown)
4747+ |> Jsont.Object.finish
4848+4949+ let pp_request fmt req =
5050+ Fmt.pf fmt "@[<2>McpMessage.Request@ { server = %S }@]" req.server_name
5151+5252+ let pp_response fmt _resp =
5353+ Fmt.pf fmt "@[<2>McpMessage.Response@ { mcp_response = <json> }@]"
5454+end
5555+456module Request = struct
557 module Unknown = struct
658 type t = Jsont.json
···4395 unknown : Unknown.t;
4496 }
45974646- type mcp_message = {
4747- subtype : [`Mcp_message];
4848- server_name : string;
4949- message : Jsont.json;
5050- unknown : Unknown.t;
5151- }
5252-5398 type set_model = {
5499 subtype : [`Set_model];
55100 model : string;
···67112 | Initialize of initialize
68113 | Set_permission_mode of set_permission_mode
69114 | Hook_callback of hook_callback
7070- | Mcp_message of mcp_message
115115+ | Mcp_message of Mcp_message.request
71116 | Set_model of set_model
72117 | Get_server_info of get_server_info
73118···100145 }
101146102147 let mcp_message ~server_name ~message ?(unknown = Unknown.empty) () =
103103- Mcp_message {
104104- subtype = `Mcp_message;
105105- server_name;
106106- message;
107107- unknown;
108108- }
148148+ Mcp_message (Mcp_message.make_request ~server_name ~message ~unknown ())
109149110150 let set_model ~model ?(unknown = Unknown.empty) () =
111151 Set_model { subtype = `Set_model; model; unknown }
···165205 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun (r : hook_callback) -> r.unknown)
166206 |> Jsont.Object.finish
167207168168- let mcp_message_jsont : mcp_message Jsont.t =
169169- let make server_name message (unknown : Unknown.t) : mcp_message =
170170- { subtype = `Mcp_message; server_name; message; unknown }
171171- in
172172- Jsont.Object.map ~kind:"McpMessage" make
173173- |> Jsont.Object.mem "server_name" Jsont.string ~enc:(fun (r : mcp_message) -> r.server_name)
174174- |> Jsont.Object.mem "message" Jsont.json ~enc:(fun (r : mcp_message) -> r.message)
175175- |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun (r : mcp_message) -> r.unknown)
176176- |> Jsont.Object.finish
177177-178208 let set_model_jsont : set_model Jsont.t =
179209 let make model (unknown : Unknown.t) : set_model = { subtype = `Set_model; model; unknown } in
180210 Jsont.Object.map ~kind:"SetModel" make
···195225 let case_initialize = Jsont.Object.Case.map "initialize" initialize_jsont ~dec:(fun v -> Initialize v) in
196226 let case_set_permission_mode = Jsont.Object.Case.map "set_permission_mode" set_permission_mode_jsont ~dec:(fun v -> Set_permission_mode v) in
197227 let case_hook_callback = Jsont.Object.Case.map "hook_callback" hook_callback_jsont ~dec:(fun v -> Hook_callback v) in
198198- let case_mcp_message = Jsont.Object.Case.map "mcp_message" mcp_message_jsont ~dec:(fun v -> Mcp_message v) in
228228+ let case_mcp_message = Jsont.Object.Case.map "mcp_message" Mcp_message.request_jsont ~dec:(fun v -> Mcp_message v) in
199229 let case_set_model = Jsont.Object.Case.map "set_model" set_model_jsont ~dec:(fun v -> Set_model v) in
200230 let case_get_server_info = Jsont.Object.Case.map "get_server_info" get_server_info_jsont ~dec:(fun v -> Get_server_info v) in
201231···242272 Fmt.pf fmt "@[<2>HookCallback@ { id = %S;@ tool_use_id = %a }@]"
243273 h.callback_id Fmt.(option string) h.tool_use_id
244274 | Mcp_message m ->
245245- Fmt.pf fmt "@[<2>McpMessage@ { server = %S }@]"
246246- m.server_name
275275+ Mcp_message.pp_request fmt m
247276 | Set_model s ->
248277 Fmt.pf fmt "@[<2>SetModel@ { model = %S }@]" s.model
249278 | Get_server_info _ ->
+73-9
claudeio/lib/sdk_control.mli
···5454(** The log source for SDK control operations *)
5555val src : Logs.Src.t
56565757+(** {1 Control Subtypes}
5858+5959+ These modules define the individual request/response subtypes for
6060+ the SDK control protocol. Each subtype represents a specific control
6161+ operation with its own request and response structure. *)
6262+6363+(** {2 MCP Message Routing}
6464+6565+ The [Mcp_message] subtype routes JSONRPC messages to in-process MCP servers.
6666+ This is used when the SDK manages MCP servers directly (SDK MCP servers).
6767+6868+ External MCP servers (stdio, HTTP, SSE) are handled by the CLI directly
6969+ and don't use this control message.
7070+7171+ Example:
7272+ {[
7373+ let req = Mcp_message.make_request
7474+ ~server_name:"calculator"
7575+ ~message:(* JSONRPC tools/list request *)
7676+7777+ (* CLI routes to SDK MCP server and returns response *)
7878+ let resp = (* receive Mcp_message response *)
7979+ let jsonrpc_response = resp.mcp_response
8080+ ]} *)
8181+module Mcp_message : sig
8282+ module Unknown : sig
8383+ type t = Jsont.json
8484+ val empty : t
8585+ val is_empty : t -> bool
8686+ val jsont : t Jsont.t
8787+ end
8888+8989+ type request = {
9090+ server_name : string;
9191+ (** Name of the SDK MCP server to route the message to *)
9292+9393+ message : Jsont.json;
9494+ (** JSONRPC message to send to the MCP server *)
9595+9696+ unknown : Unknown.t;
9797+ (** Unknown fields for forward compatibility *)
9898+ }
9999+ (** Request to route JSONRPC message to an in-process MCP server. *)
100100+101101+ type response = {
102102+ mcp_response : Jsont.json;
103103+ (** JSONRPC response from the MCP server *)
104104+105105+ unknown : Unknown.t;
106106+ (** Unknown fields for forward compatibility *)
107107+ }
108108+ (** Response containing JSONRPC response from MCP server. *)
109109+110110+ val request_jsont : request Jsont.t
111111+ (** [request_jsont] is the jsont codec for MCP message requests. *)
112112+113113+ val response_jsont : response Jsont.t
114114+ (** [response_jsont] is the jsont codec for MCP message responses. *)
115115+116116+ val make_request : server_name:string -> message:Jsont.json -> ?unknown:Unknown.t -> unit -> request
117117+ (** [make_request ~server_name ~message ?unknown ()] creates an MCP message request. *)
118118+119119+ val make_response : mcp_response:Jsont.json -> ?unknown:Unknown.t -> unit -> response
120120+ (** [make_response ~mcp_response ?unknown ()] creates an MCP message response. *)
121121+122122+ val pp_request : Format.formatter -> request -> unit
123123+ (** [pp_request fmt req] pretty-prints an MCP message request. *)
124124+125125+ val pp_response : Format.formatter -> response -> unit
126126+ (** [pp_response fmt resp] pretty-prints an MCP message response. *)
127127+end
128128+57129(** {1 Request Types} *)
5813059131module Request : sig
···105177 }
106178 (** Hook callback request. *)
107179108108- type mcp_message = {
109109- subtype : [`Mcp_message];
110110- server_name : string;
111111- message : Jsont.json;
112112- unknown : Unknown.t;
113113- }
114114- (** MCP server message request. *)
115115-116180 type set_model = {
117181 subtype : [`Set_model];
118182 model : string;
···132196 | Initialize of initialize
133197 | Set_permission_mode of set_permission_mode
134198 | Hook_callback of hook_callback
135135- | Mcp_message of mcp_message
199199+ | Mcp_message of Mcp_message.request
136200 | Set_model of set_model
137201 | Get_server_info of get_server_info
138202 (** The type of SDK control requests. *)
+82
claudeio/lib/transport.ml
···2222 | Options.Project -> "project"
2323 | Options.Local -> "local"
24242525+(* Helper functions for JSON construction *)
2626+let json_string s = Jsont.String (s, Jsont.Meta.none)
2727+2828+let json_array items =
2929+ Jsont.Array (items, Jsont.Meta.none)
3030+3131+let json_object members =
3232+ Jsont.Object (
3333+ List.map (fun (k, v) -> ((k, Jsont.Meta.none), v)) members,
3434+ Jsont.Meta.none
3535+ )
3636+3737+(* Serialize MCP server configuration to JSON string *)
3838+let serialize_mcp_config (servers : (string * Options.mcp_server_config) list) : string =
3939+ (* Serialize environment variables as JSON object *)
4040+ let serialize_env env_vars =
4141+ json_object (List.map (fun (k, v) -> (k, json_string v)) env_vars)
4242+ in
4343+4444+ (* Serialize headers as JSON object *)
4545+ let serialize_headers headers =
4646+ json_object (List.map (fun (k, v) -> (k, json_string v)) headers)
4747+ in
4848+4949+ (* Convert each server config to JSON *)
5050+ let server_jsons = List.map (fun (name, config) ->
5151+ let config_json = match config with
5252+ | Options.Stdio { command; args; env } ->
5353+ let members = [
5454+ ("command", json_string command);
5555+ ("args", json_array (List.map json_string args));
5656+ ] in
5757+ let members = match env with
5858+ | None -> members
5959+ | Some env_vars -> members @ [("env", serialize_env env_vars)]
6060+ in
6161+ json_object members
6262+6363+ | Options.SSE { url; headers } ->
6464+ let members = [
6565+ ("type", json_string "sse");
6666+ ("url", json_string url);
6767+ ] in
6868+ let members = match headers with
6969+ | None -> members
7070+ | Some hdrs -> members @ [("headers", serialize_headers hdrs)]
7171+ in
7272+ json_object members
7373+7474+ | Options.HTTP { url; headers } ->
7575+ let members = [
7676+ ("type", json_string "http");
7777+ ("url", json_string url);
7878+ ] in
7979+ let members = match headers with
8080+ | None -> members
8181+ | Some hdrs -> members @ [("headers", serialize_headers hdrs)]
8282+ in
8383+ json_object members
8484+ in
8585+ ((name, Jsont.Meta.none), config_json)
8686+ ) servers in
8787+8888+ (* Build full config object: {"mcpServers": {...}} *)
8989+ let mcp_servers_obj = Jsont.Object (server_jsons, Jsont.Meta.none) in
9090+ let full_config = Jsont.Object ([
9191+ (("mcpServers", Jsont.Meta.none), mcp_servers_obj)
9292+ ], Jsont.Meta.none) in
9393+9494+ (* Encode to string *)
9595+ match Jsont_bytesrw.encode_string' Jsont.json full_config with
9696+ | Ok s -> s
9797+ | Error err -> failwith ("Failed to encode MCP config: " ^ Jsont.Error.to_string err)
9898+2599let build_command ~claude_path ~options =
26100 let cmd = [claude_path; "--output-format"; "stream-json"; "--verbose"] in
27101···90164 in
91165 cmd @ ["--json-schema"; schema_str]
92166 | None -> cmd
167167+ in
168168+169169+ (* MCP Server Configuration *)
170170+ let cmd =
171171+ if Options.mcp_servers options = [] then cmd
172172+ else
173173+ let mcp_config_json = serialize_mcp_config (Options.mcp_servers options) in
174174+ cmd @ ["--mcp-config"; mcp_config_json]
93175 in
9417695177 (* Use streaming input mode *)
+3
claudeio/lib/transport.mli
···1717val receive_line : t -> string option
1818val interrupt : t -> unit
1919val close : t -> unit
2020+2121+val serialize_mcp_config : (string * Options.mcp_server_config) list -> string
2222+(** Serialize MCP server configuration to JSON string for CLI --mcp-config flag *)