···22open Jsonrpc
33open Mcp_sdk
4455+(* Create a proper JSONRPC error with code and data *)
66+let create_jsonrpc_error id code message ?data () =
77+ let error_code = ErrorCode.to_int code in
88+ let error_data = match data with
99+ | Some d -> d
1010+ | None -> `Null
1111+ in
1212+ create_error ~id ~code:error_code ~message ~data:(Some error_data) ()
1313+514(* Process initialize request *)
615let handle_initialize server req =
716 Log.debug "Processing initialize request";
···5160 let response = Mcp_rpc.ResourcesList.create_response ~id:req.id ~resources:resources_list () in
5261 Some response
53626363+(* Process resources/read request *)
6464+let handle_resources_read server (req:JSONRPCMessage.request) =
6565+ Log.debug "Processing resources/read request";
6666+ match req.JSONRPCMessage.params with
6767+ | None ->
6868+ Log.error "Missing params for resources/read request";
6969+ Some (create_jsonrpc_error req.id ErrorCode.InvalidParams "Missing params for resources/read request" ())
7070+ | Some params ->
7171+ let req_data = Mcp_rpc.ResourcesRead.Request.t_of_yojson params in
7272+ let uri = req_data.uri in
7373+ Log.debugf "Resource URI: %s" uri;
7474+7575+ (* Find matching resource handler by URI template *)
7676+ let find_resource_handler uri =
7777+ let parse_uri_template template uri =
7878+ (* Simple URI template parsing: extract parameters from a URI based on a template *)
7979+ let template_parts = String.split_on_char '/' template in
8080+ let uri_parts = String.split_on_char '/' uri in
8181+8282+ (* If parts don't match in length, this template doesn't match *)
8383+ if List.length template_parts <> List.length uri_parts then
8484+ None
8585+ else
8686+ (* Extract parameters where template has {param} format *)
8787+ let params, matches =
8888+ List.fold_left2 (fun (params, matches) template_part uri_part ->
8989+ if String.length template_part > 2 &&
9090+ template_part.[0] = '{' &&
9191+ template_part.[String.length template_part - 1] = '}' then
9292+ (* This is a parameter, extract its value *)
9393+ let _param_name = String.sub template_part 1 (String.length template_part - 2) in
9494+ (uri_part :: params, matches)
9595+ else if template_part = uri_part then
9696+ (* Constant part matches *)
9797+ (params, true && matches)
9898+ else
9999+ (* Constant part doesn't match *)
100100+ (params, false && matches)
101101+ ) ([], true) template_parts uri_parts
102102+ in
103103+104104+ if matches then Some (List.rev params) else None
105105+ in
106106+107107+ let rec find_handler = function
108108+ | [] -> None
109109+ | resource :: rest ->
110110+ match parse_uri_template resource.Resource.uri_template uri with
111111+ | Some params -> Some (resource, params)
112112+ | None -> find_handler rest
113113+ in
114114+115115+ find_handler (resources server)
116116+ in
117117+118118+ match find_resource_handler uri with
119119+ | Some (resource, params) ->
120120+ (* Create context for this request *)
121121+ let ctx = Context.create
122122+ ?request_id:(Some req.id)
123123+ ?progress_token:req.progress_token
124124+ ~lifespan_context:[("resources/read", `Assoc [("uri", `String uri)])]
125125+ ()
126126+ in
127127+128128+ (* Call the resource handler *)
129129+ (match resource.handler ctx params with
130130+ | Ok content ->
131131+ (* Create text resource content *)
132132+ let mime_type = match resource.mime_type with
133133+ | Some mime -> mime
134134+ | None -> "text/plain"
135135+ in
136136+ let text_resource = {
137137+ TextResourceContents.uri;
138138+ text = content;
139139+ mime_type = Some mime_type
140140+ } in
141141+ let resource_content = Mcp_rpc.ResourcesRead.ResourceContent.TextResource text_resource in
142142+ let response = Mcp_rpc.ResourcesRead.create_response ~id:req.id ~contents:[resource_content] () in
143143+ Some response
144144+ | Error err ->
145145+ Log.errorf "Error reading resource: %s" err;
146146+ Some (create_jsonrpc_error req.id ErrorCode.InternalError ("Error reading resource: " ^ err) ()))
147147+ | None ->
148148+ Log.errorf "Resource not found: %s" uri;
149149+ Some (create_jsonrpc_error req.id ErrorCode.InvalidParams ("Resource not found: " ^ uri) ())
150150+54151(* Extract the tool name from params *)
55152let extract_tool_name params =
56153 match List.assoc_opt "name" params with
···70167 | _ ->
71168 Log.debug "No arguments provided for tool call, using empty object";
72169 `Assoc [] (* Empty arguments is valid *)
7373-7474-(* Create a proper JSONRPC error with code and data *)
7575-let create_jsonrpc_error id code message ?data () =
7676- let error_code = ErrorCode.to_int code in
7777- let error_data = match data with
7878- | Some d -> d
7979- | None -> `Null
8080- in
8181- create_error ~id ~code:error_code ~message ~data:(Some error_data) ()
8282-8317084171(* Execute a tool *)
85172let execute_tool server ctx name args =
···182269 | Method.ToolsCall -> handle_tools_call server req
183270 | Method.PromptsList -> handle_prompts_list server req
184271 | Method.ResourcesList -> handle_resources_list server req
272272+ | Method.ResourcesRead -> handle_resources_read server req
185273 | _ ->
186274 Log.errorf "Unknown method received: %s" (Method.to_string req.meth);
187187- Some (create_jsonrpc_error req.id MethodNotFound ("Method not found: " ^ (Method.to_string req.meth)) ()))
275275+ Some (create_jsonrpc_error req.id ErrorCode.MethodNotFound ("Method not found: " ^ (Method.to_string req.meth)) ()))
188276 | JSONRPCMessage.Notification notif ->
189277 Log.debugf "Received notification with method: %s" (Method.to_string notif.meth);
190278 (match notif.meth with