this repo has no description
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

mcp_server: turn into an actual server

Partly vibecoded, done using cohttp-eio

authored by

mseri.me and committed by
Anil Madhavapeddy
37c41d48 c17afd8f

+44 -30
+2
dune-project
··· 14 14 (depends 15 15 (ocaml (>= "5.2.0")) 16 16 jsonrpc 17 + http 18 + cohttp-eio 17 19 eio_main 18 20 eio)) 19 21
+1 -1
lib/dune
··· 21 21 (library 22 22 (name mcp_server) 23 23 (public_name mcp.server) 24 - (libraries mcp_sdk jsonrpc eio_main eio) 24 + (libraries mcp_sdk jsonrpc eio_main eio http cohttp-eio) 25 25 (modules mcp_server) 26 26 )
+41 -29
lib/mcp_server.ml
··· 406 406 Eio.Flow.copy_string "\n" stdout 407 407 408 408 (* Run the MCP server with the given server configuration *) 409 - let run_server env server = 410 - let stdin = Eio.Stdenv.stdin env in 411 - let stdout = Eio.Stdenv.stdout env in 409 + let callback mcp_server _conn (request : Http.Request.t) body = 410 + match request.meth with 411 + | `POST -> ( 412 + Log.debug "Received POST request"; 413 + let request_body_str = 414 + Eio.Buf_read.(parse_exn take_all) body ~max_size:max_int 415 + in 416 + match process_input_line mcp_server request_body_str with 417 + | Some mcp_response -> 418 + let response_json = JSONRPCMessage.yojson_of_t mcp_response in 419 + let response_str = Yojson.Safe.to_string response_json in 420 + Log.debugf "Sending MCP response: %s" response_str; 421 + let headers = 422 + Http.Header.of_list [ ("Content-Type", "application/json") ] 423 + in 424 + Cohttp_eio.Server.respond ~status:`OK ~headers 425 + ~body:(Cohttp_eio.Body.of_string response_str) 426 + () 427 + | None -> 428 + Log.debug "No MCP response needed"; 429 + Cohttp_eio.Server.respond ~status:`No_content ~body:(Cohttp_eio.Body.of_string "") ()) 430 + | _ -> 431 + Log.infof "Unsupported method: %s" (Http.Method.to_string request.meth); 432 + Cohttp_eio.Server.respond ~status:`Method_not_allowed 433 + ~body:(Cohttp_eio.Body.of_string "Only POST is supported") 434 + () 435 + 436 + let log_warning ex = Logs.warn (fun f -> f "%a" Eio.Exn.pp ex) 437 + 438 + let run_server ?(port = 8080) ?(on_error = log_warning) env server = 439 + let net = Eio.Stdenv.net env in 440 + let addr = `Tcp (Eio.Net.Ipaddr.V4.loopback, port) in 412 441 413 442 Log.debugf "Starting MCP server: %s v%s" (name server) (version server); 414 443 Log.debugf "Protocol version: %s" (protocol_version server); 415 444 416 - (* Enable exception backtraces *) 417 - Printexc.record_backtrace true; 418 - 419 - let buf = Eio.Buf_read.of_flow stdin ~initial_size:100 ~max_size:1_000_000 in 420 - 421 - (* Main processing loop *) 422 - try 423 - while true do 424 - Log.debug "Waiting for message..."; 425 - let line = Eio.Buf_read.line buf in 426 - 427 - (* Process the input and send response if needed *) 428 - match process_input_line server line with 429 - | Some response -> send_response stdout response 430 - | None -> Log.debug "No response needed for this message" 431 - done 432 - with 433 - | End_of_file -> 434 - Log.debug "End of file received on stdin"; 435 - () 436 - | Eio.Exn.Io _ as exn -> 437 - Log.errorf "I/O error while reading: %s" (Printexc.to_string exn); 438 - () 439 - | exn -> 440 - Log.errorf "Exception while reading: %s" (Printexc.to_string exn); 441 - () 445 + Eio.Switch.run @@ fun sw -> 446 + let server_spec = Cohttp_eio.Server.make ~callback:(callback server) () in 447 + 448 + let server_socket = 449 + Eio.Net.listen net ~sw ~backlog:128 ~reuse_addr:true addr 450 + in 451 + Log.infof "MCP HTTP Server listening on http://localhost:%d" port; 452 + 453 + Cohttp_eio.Server.run server_socket server_spec ~on_error