diff --git a/packages/darklang/languageTools/mcp-server/initialize.dark b/packages/darklang/languageTools/mcp-server/initialize.dark index 30d84348ad..48c3e01c24 100644 --- a/packages/darklang/languageTools/mcp-server/initialize.dark +++ b/packages/darklang/languageTools/mcp-server/initialize.dark @@ -14,40 +14,43 @@ let handleInitializeRequest : McpState = log "Handling initialize request" - // Build server capabilities + // Build server capabilities using proper types let serverCapabilities = - Json.Object [ - ("resources", Json.Object [ - ("subscribe", Json.Bool false); - ("listChanged", Json.Bool true) - ]); - ("tools", Json.Object [ - ("listChanged", Json.Bool true) - ]); - ("prompts", Json.Object [ - ("listChanged", Json.Bool true) - ]); - ("logging", Json.Object []); - ("roots", Json.Object [ - ("listChanged", Json.Bool true) - ]) - ] + ModelContextProtocol.ServerCapabilities { + resources = Stdlib.Option.Option.Some (ModelContextProtocol.ResourceCapabilities { + listChanged = Stdlib.Option.Option.Some true; + subscribe = Stdlib.Option.Option.Some false + }); + tools = Stdlib.Option.Option.Some (ModelContextProtocol.ToolCapabilities { + listChanged = Stdlib.Option.Option.Some true + }); + prompts = Stdlib.Option.Option.Some (ModelContextProtocol.PromptCapabilities { + listChanged = Stdlib.Option.Option.Some true + }); + logging = Stdlib.Option.Option.Some (Json.Object []); + completions = Stdlib.Option.Option.None; + experimental = Stdlib.Option.Option.None + } let serverInfo = - Json.Object [ - ("name", Json.String "Darklang MCP Server"); - ("version", Json.String "1.0.0") - ] + ModelContextProtocol.ServerInfo { + name = "Darklang MCP Server"; + version = "1.0.0" + } - let result = - Json.Object [ - ("protocolVersion", Json.String "2025-06-18"); - ("capabilities", serverCapabilities); - ("serverInfo", serverInfo) - ] + let initializeResult = + ModelContextProtocol.LifeCycle.InitializeRequest.InitializeResult.InitializeResult { + protocolVersion = ModelContextProtocol.protocolVersion; + serverInfo = serverInfo; + capabilities = serverCapabilities; + instructions = Stdlib.Option.Option.None + } + + // Convert to JSON using the typed approach + let resultJson = ModelContextProtocol.LifeCycle.InitializeRequest.InitializeResult.toJson initializeResult // Send the response - sendSuccessResponse (Stdlib.Option.Option.Some requestId) result + sendSuccessResponse (Stdlib.Option.Option.Some requestId) resultJson // Return initialized state with all capabilities loaded let state = initialState () diff --git a/packages/darklang/languageTools/mcp-server/promptHandlers.dark b/packages/darklang/languageTools/mcp-server/promptHandlers.dark index 0359833699..9dc77d30e0 100644 --- a/packages/darklang/languageTools/mcp-server/promptHandlers.dark +++ b/packages/darklang/languageTools/mcp-server/promptHandlers.dark @@ -15,28 +15,47 @@ let handleListPromptsRequest log "Handling prompts/list request" let promptsList = state.prompts |> Stdlib.Dict.values - let result = Json.Object [ - ("prompts", Json.Array (promptsList |> Stdlib.List.map (fun prompt -> - Json.Object [ - ("name", Json.String prompt.name); - ("description", Stdlib.Option.mapWithDefault prompt.description Json.Null (fun s -> Json.String s)); - ("arguments", - match prompt.arguments with - | Some args -> - Json.Array (args |> Stdlib.List.map (fun arg -> - Json.Object [ - ("name", Json.String arg.name); - ("description", Stdlib.Option.mapWithDefault arg.description Json.Null (fun s -> Json.String s)); - ("required", Stdlib.Option.mapWithDefault arg.required Json.Null (fun b -> Json.Bool b)) - ])) - | None -> Json.Array [] + + log "A" + + // Convert internal prompt format to MCP PromptDescription + let mcpPrompts = promptsList |> Stdlib.List.map (fun prompt -> + let mcpArguments = + match prompt.arguments with + | Some args -> + let convertedArgs = args |> Stdlib.List.map (fun arg -> + ModelContextProtocol.Prompts.PromptArgument.PromptArgument { + name = arg.name; + description = arg.description; + required = arg.required + } ) - ] - ))); - ("nextCursor", Json.String "") - ] + Stdlib.Option.Option.Some convertedArgs + | None -> Stdlib.Option.Option.None + + ModelContextProtocol.Prompts.PromptDescription.PromptDescription { + name = prompt.name; + description = prompt.description; + arguments = mcpArguments + } + ) + log "B" + + let listResult = + ModelContextProtocol.Prompts.ListPromptsResponse.ListPromptsResult { + prompts = mcpPrompts; + nextCursor = Stdlib.Option.Option.None + } + + log "C" + Builtin.debug "c" listResult + + + let resultJson = ModelContextProtocol.Prompts.ListPromptsResponse.toJson listResult + + log "D" - sendSuccessResponse (Stdlib.Option.Option.Some requestId) result + sendSuccessResponse (Stdlib.Option.Option.Some requestId) resultJson state /// Handle a prompts/get request diff --git a/packages/darklang/languageTools/mcp-server/resourceHandlers.dark b/packages/darklang/languageTools/mcp-server/resourceHandlers.dark index cb9c53b6e8..5a12980cfe 100644 --- a/packages/darklang/languageTools/mcp-server/resourceHandlers.dark +++ b/packages/darklang/languageTools/mcp-server/resourceHandlers.dark @@ -17,19 +17,25 @@ let handleListResourcesRequest let resourcesList = state.resources |> Stdlib.Dict.values - let response = Json.Object [ - ("resources", Json.Array (resourcesList |> Stdlib.List.map (fun resource -> - Json.Object [ - ("uri", Json.String resource.uri); - ("name", Json.String resource.name); - ("description", Stdlib.Option.mapWithDefault resource.description Json.Null (fun s -> Json.String s)); - ("mimeType", Stdlib.Option.mapWithDefault resource.mimeType Json.Null (fun s -> Json.String s)) - ] - ))); - ("nextCursor", Json.String "") - ] + // Convert internal resource format to MCP ResourceDescription + let mcpResources = resourcesList |> Stdlib.List.map (fun resource -> + ModelContextProtocol.Resources.ListResourcesResponse.ResourceDescription { + uri = resource.uri; + name = resource.name; + description = resource.description; + mimeType = resource.mimeType + } + ) + + let listResponse = + ModelContextProtocol.Resources.ListResourcesResponse.ListResourcesResponse { + resources = mcpResources; + nextCursor = Stdlib.Option.Option.None + } + + let responseJson = ModelContextProtocol.Resources.ListResourcesResponse.toJson listResponse - sendSuccessResponse (Stdlib.Option.Option.Some requestId) response + sendSuccessResponse (Stdlib.Option.Option.Some requestId) responseJson state /// Handle a resources/read request diff --git a/packages/darklang/languageTools/mcp-server/tools/searchFunctions.dark b/packages/darklang/languageTools/mcp-server/tools/searchFunctions.dark index 3041033fa7..c28b76a315 100644 --- a/packages/darklang/languageTools/mcp-server/tools/searchFunctions.dark +++ b/packages/darklang/languageTools/mcp-server/tools/searchFunctions.dark @@ -54,16 +54,8 @@ let handleToolCall (args: Json) : Json = | _ -> "" | _ -> "" - // In a real implementation, this would search actual functions - let results = [ - "Stdlib.List.map - Transform each element of a list"; - "Stdlib.String.split - Split a string by delimiter"; - "Stdlib.Dict.get - Get a value from a dictionary"; - "Builtin.printLine - Print a line to stdout" - ] - - let resultsText = - $"Search results for '{query}':\n{Stdlib.String.join results "\n"}" + // Simple hardcoded results for now + let resultsText = $"Found 4 functions matching '{query}'" (ModelContextProtocol.Tools.CallToolResponse.CallToolResult { content = [ diff --git a/packages/darklang/modelContextProtocol/common.dark b/packages/darklang/modelContextProtocol/common.dark index 6069ed244b..5006fe1401 100644 --- a/packages/darklang/modelContextProtocol/common.dark +++ b/packages/darklang/modelContextProtocol/common.dark @@ -115,8 +115,7 @@ type GetPromptResult = /// Prompt capabilities type PromptCapabilities = - { supportsPromptListing: Bool - listChanged: Stdlib.Option.Option } + { listChanged: Stdlib.Option.Option } /// Server information type ServerInfo = @@ -128,26 +127,19 @@ type ServerCapabilities = { resources: Stdlib.Option.Option tools: Stdlib.Option.Option prompts: Stdlib.Option.Option - logging: Stdlib.Option.Option - completion: Stdlib.Option.Option } + logging: Stdlib.Option.Option + completions: Stdlib.Option.Option + experimental: Stdlib.Option.Option> } /// Resource capabilities type ResourceCapabilities = - { supportsResourceListing: Bool - supportsResourceTemplates: Bool } + { listChanged: Stdlib.Option.Option + subscribe: Stdlib.Option.Option } /// Tool capabilities type ToolCapabilities = { listChanged: Stdlib.Option.Option } -/// Logging capabilities -type LoggingCapabilities = - { level: Stdlib.Option.Option } - -/// Completion capabilities -type CompletionCapabilities = - { supportsCompletion: Bool } - /// Error codes for the Model Context Protocol module ErrorCodes = let parseError = -32700L diff --git a/packages/darklang/modelContextProtocol/lifecycle/initialize.dark b/packages/darklang/modelContextProtocol/lifecycle/initialize.dark index 3b630f9873..031518237d 100644 --- a/packages/darklang/modelContextProtocol/lifecycle/initialize.dark +++ b/packages/darklang/modelContextProtocol/lifecycle/initialize.dark @@ -8,7 +8,7 @@ type ClientCapabilities = roots: Stdlib.Option.Option sampling: Stdlib.Option.Option } -/// Roots client capabilities +/// Roots client capabilities type RootsClientCapabilities = { listChanged: Stdlib.Option.Option } @@ -65,7 +65,7 @@ let fromJson (json: Json) : Stdlib.Result.Result = // Parse experimental let experimental = match Stdlib.List.findFirst capFields (fun (k, _) -> k == "experimental") with - | Some (_, Object expFields) -> + | Some (_, Object expFields) -> let dict = Stdlib.List.fold Stdlib.Dict.empty expFields (fun acc (key, value) -> Stdlib.Dict.set acc key value ) @@ -83,13 +83,13 @@ let fromJson (json: Json) : Stdlib.Result.Result = Stdlib.Option.Option.Some (RootsClientCapabilities { listChanged = listChanged }) | _ -> Stdlib.Option.Option.None - // Parse sampling + // Parse sampling let sampling = match Stdlib.List.findFirst capFields (fun (k, _) -> k == "sampling") with | Some (_, json) -> Stdlib.Option.Option.Some json | None -> Stdlib.Option.Option.None - Stdlib.Result.Result.Ok (ClientCapabilities { + Stdlib.Result.Result.Ok (ClientCapabilities { elicitation = elicitation; experimental = experimental; roots = roots; @@ -101,12 +101,11 @@ let fromJson (json: Json) : Stdlib.Result.Result = // Parse trace if present let traceResult = match Stdlib.List.findFirst fields (fun (k, _) -> k == "trace") with - | Some traceEntry -> - match traceEntry with - | (_, String "off") -> Stdlib.Result.Result.Ok (Stdlib.Option.Option.Some TraceLevel.Off) - | (_, String "messages") -> Stdlib.Result.Result.Ok (Stdlib.Option.Option.Some TraceLevel.Messages) - | (_, String "verbose") -> Stdlib.Result.Result.Ok (Stdlib.Option.Option.Some TraceLevel.Verbose) - | (_, _) -> Stdlib.Result.Result.Error "trace must be one of: 'off', 'messages', 'verbose'" + | Some (_, String s) -> + match TraceLevel.fromString s with + | Ok level -> Stdlib.Result.Result.Ok (Stdlib.Option.Option.Some level) + | Error e -> Stdlib.Result.Result.Error e + | Some _ -> Stdlib.Result.Result.Error "trace must be a string" | None -> Stdlib.Result.Result.Ok Stdlib.Option.Option.None // Combine all results @@ -119,108 +118,87 @@ let fromJson (json: Json) : Stdlib.Result.Result = | _ -> Stdlib.Result.Result.Error "params must be an object" let toJson (params: InitializeParams) : Json = - let clientInfoJson = - match params.clientInfo with - | Some info -> - let fields = [("name", Json.String info.name)] - let fieldsWithVersion = - match info.version with - | Some v -> fields @ [("version", Json.String v)] - | None -> fields - Stdlib.Option.Option.Some ("clientInfo", Json.Object fieldsWithVersion) - | None -> Stdlib.Option.Option.None - - let resourceCapabilitiesJson = - match params.capabilities.resources with - | Some res -> - let fields = [] - let fieldsWithListChanged = - match res.listChanged with - | Some b -> fields @ [("listChanged", Json.Bool b)] - | None -> fields - let fieldsWithSubscribe = - match res.subscribe with - | Some b -> fieldsWithListChanged @ [("subscribe", Json.Bool b)] - | None -> fieldsWithListChanged - Stdlib.Option.Option.Some ("resources", Json.Object fieldsWithSubscribe) - | None -> Stdlib.Option.Option.None - - let toolCapabilitiesJson = - match params.capabilities.tools with - | Some tools -> - let fields = [] - let fieldsWithListChanged = - match tools.listChanged with - | Some b -> fields @ [("listChanged", Json.Bool b)] - | None -> fields - Stdlib.Option.Option.Some ("tools", Json.Object fieldsWithListChanged) - | None -> Stdlib.Option.Option.None - + // Build capabilities object let capabilitiesFields = - [resourceCapabilitiesJson; toolCapabilitiesJson] - |> Stdlib.Option.values + [ params.capabilities.elicitation |> Stdlib.Option.map (fun e -> ("elicitation", e)) + + params.capabilities.experimental |> Stdlib.Option.map (fun exp -> + ("experimental", (Stdlib.Dict.toList exp) |> Json.Object)) - let traceJson = - match params.trace with - | Some Off -> Stdlib.Option.Option.Some ("trace", Json.String "off") - | Some Messages -> Stdlib.Option.Option.Some ("trace", Json.String "messages") - | Some Verbose -> Stdlib.Option.Option.Some ("trace", Json.String "verbose") - | None -> Stdlib.Option.Option.None + params.capabilities.roots |> Stdlib.Option.map (fun roots -> + let rootsFields = + [ roots.listChanged |> Stdlib.Option.map (fun lc -> ("listChanged", Json.Bool lc)) ] + |> Stdlib.Option.values + ("roots", Json.Object rootsFields)) - let fields = - [clientInfoJson; Stdlib.Option.Option.Some ("capabilities", Json.Object capabilitiesFields); traceJson] + params.capabilities.sampling |> Stdlib.Option.map (fun s -> ("sampling", s)) ] |> Stdlib.Option.values - Json.Object fields + // Build all top-level fields + [ params.clientInfo |> Stdlib.Option.map (fun info -> + let infoFields = + [ Stdlib.Option.Option.Some(("name", Json.String info.name)) + info.version |> Stdlib.Option.map (fun v -> ("version", Json.String v)) ] + |> Stdlib.Option.values + ("clientInfo", Json.Object infoFields)) + + Stdlib.Option.Option.Some(("capabilities", Json.Object capabilitiesFields)) + + params.trace |> Stdlib.Option.map (fun t -> + ("trace", Json.String (TraceLevel.toString t))) ] + |> Stdlib.Option.values + |> Json.Object /// Result of the initialize request module InitializeResult = type InitializeResult = - { serverInfo: Stdlib.Option.Option - capabilities: ServerCapabilities } + { protocolVersion: String + serverInfo: ServerInfo + capabilities: ServerCapabilities + instructions: Stdlib.Option.Option } let toJson (result: InitializeResult) : Json = - let serverInfoJson = - match result.serverInfo with - | Some info -> - Stdlib.Option.Option.Some (( - "serverInfo", - Json.Object [ - ("name", Json.String info.name); - ("version", Json.String info.version) - ] - )) - | None -> Stdlib.Option.Option.None - - let resourceCapabilitiesJson = - match result.capabilities.resources with - | Some res -> - Stdlib.Option.Option.Some (( - "resources", - Json.Object [ - ("supportsResourceListing", Json.Bool res.supportsResourceListing); - ("supportsResourceTemplates", Json.Bool res.supportsResourceTemplates) - ] - )) - | None -> Stdlib.Option.Option.None - - let toolCapabilitiesJson = - match result.capabilities.tools with - | Some tools -> - Stdlib.Option.Option.Some (( - "tools", - Json.Object [ - ("supportsToolListing", Json.Bool tools.supportsToolListing) - ] - )) - | None -> Stdlib.Option.Option.None - + // Build capabilities object let capabilitiesFields = - [resourceCapabilitiesJson; toolCapabilitiesJson] - |> Stdlib.Option.values - - let fields = - [serverInfoJson; Stdlib.Option.Option.Some (("capabilities", Json.Object capabilitiesFields))] + [ result.capabilities.resources |> Stdlib.Option.map (fun res -> + let resFields = + [ res.listChanged |> Stdlib.Option.map (fun lc -> ("listChanged", Json.Bool lc)) + res.subscribe |> Stdlib.Option.map (fun s -> ("subscribe", Json.Bool s)) ] + |> Stdlib.Option.values + ("resources", Json.Object resFields)) + + result.capabilities.tools |> Stdlib.Option.map (fun tools -> + let toolFields = + [ tools.listChanged |> Stdlib.Option.map (fun lc -> ("listChanged", Json.Bool lc)) ] + |> Stdlib.Option.values + ("tools", Json.Object toolFields)) + + result.capabilities.prompts |> Stdlib.Option.map (fun prompts -> + let promptFields = + [ prompts.listChanged |> Stdlib.Option.map (fun lc -> ("listChanged", Json.Bool lc)) ] + |> Stdlib.Option.values + ("prompts", Json.Object promptFields)) + + result.capabilities.logging |> Stdlib.Option.map (fun logging -> + ("logging", logging)) + + result.capabilities.completions |> Stdlib.Option.map (fun completions -> + ("completions", completions)) + + result.capabilities.experimental |> Stdlib.Option.map (fun exp -> + ("experimental", (Stdlib.Dict.toList exp) |> Json.Object)) ] |> Stdlib.Option.values - Json.Object fields \ No newline at end of file + // Build all fields + [ Stdlib.Option.Option.Some(("protocolVersion", Json.String result.protocolVersion)) + + Stdlib.Option.Option.Some(("serverInfo", Json.Object [ + ("name", Json.String result.serverInfo.name); + ("version", Json.String result.serverInfo.version) + ])) + + Stdlib.Option.Option.Some(("capabilities", Json.Object capabilitiesFields)) + + result.instructions |> Stdlib.Option.map (fun i -> ("instructions", Json.String i)) ] + |> Stdlib.Option.values + |> Json.Object \ No newline at end of file diff --git a/packages/darklang/modelContextProtocol/logging.dark b/packages/darklang/modelContextProtocol/logging.dark index ba053b8062..121f9ad7d7 100644 --- a/packages/darklang/modelContextProtocol/logging.dark +++ b/packages/darklang/modelContextProtocol/logging.dark @@ -18,30 +18,30 @@ type LoggingLevel = | Alert | Emergency -/// Convert logging level to string -let loggingLevelToString (level: LoggingLevel) : String = - match level with - | Debug -> "debug" - | Info -> "info" - | Notice -> "notice" - | Warning -> "warning" - | Error -> "error" - | Critical -> "critical" - | Alert -> "alert" - | Emergency -> "emergency" - -/// Parse logging level from string -let loggingLevelFromString (s: String) : Stdlib.Result.Result = - match Stdlib.String.toLowercase s with - | "debug" -> Stdlib.Result.Result.Ok LoggingLevel.Debug - | "info" -> Stdlib.Result.Result.Ok LoggingLevel.Info - | "notice" -> Stdlib.Result.Result.Ok LoggingLevel.Notice - | "warning" -> Stdlib.Result.Result.Ok LoggingLevel.Warning - | "error" -> Stdlib.Result.Result.Ok LoggingLevel.Error - | "critical" -> Stdlib.Result.Result.Ok LoggingLevel.Critical - | "alert" -> Stdlib.Result.Result.Ok LoggingLevel.Alert - | "emergency" -> Stdlib.Result.Result.Ok LoggingLevel.Emergency - | _ -> Stdlib.Result.Result.Error $"Invalid logging level: {s}" +/// LoggingLevel conversion utilities +module LoggingLevel = + let toString (level: LoggingLevel) : String = + match level with + | Debug -> "debug" + | Info -> "info" + | Notice -> "notice" + | Warning -> "warning" + | Error -> "error" + | Critical -> "critical" + | Alert -> "alert" + | Emergency -> "emergency" + + let fromString (s: String) : Stdlib.Result.Result = + match Stdlib.String.toLowercase s with + | "debug" -> Stdlib.Result.Result.Ok LoggingLevel.Debug + | "info" -> Stdlib.Result.Result.Ok LoggingLevel.Info + | "notice" -> Stdlib.Result.Result.Ok LoggingLevel.Notice + | "warning" -> Stdlib.Result.Result.Ok LoggingLevel.Warning + | "error" -> Stdlib.Result.Result.Ok LoggingLevel.Error + | "critical" -> Stdlib.Result.Result.Ok LoggingLevel.Critical + | "alert" -> Stdlib.Result.Result.Ok LoggingLevel.Alert + | "emergency" -> Stdlib.Result.Result.Ok LoggingLevel.Emergency + | _ -> Stdlib.Result.Result.Error $"Invalid logging level: {s}" /// Log message notification module LogMessage = @@ -53,7 +53,7 @@ module LogMessage = let toJson (params: LogMessageParams) : Json = let fields = [ - ("level", Json.String (loggingLevelToString params.level)); + ("level", Json.String (LoggingLevel.toString params.level)); ("message", Json.String params.message) ] @@ -78,7 +78,7 @@ module LogMessage = | Object fields -> let levelResult = match Stdlib.List.findFirst fields (fun (k, _) -> k == "level") with - | Some (_, String level) -> loggingLevelFromString level + | Some (_, String level) -> LoggingLevel.fromString level | Some (_, _) -> Stdlib.Result.Result.Error "level must be a string" | None -> Stdlib.Result.Result.Error "level is required" @@ -130,7 +130,7 @@ module SetLoggingLevel = | Object fields -> match Stdlib.List.findFirst fields (fun (k, _) -> k == "level") with | Some (_, String level) -> - match loggingLevelFromString level with + match LoggingLevel.fromString level with | Ok lvl -> Stdlib.Result.Result.Ok (SetLoggingLevelParams { level = lvl }) | Error e -> @@ -144,5 +144,5 @@ module SetLoggingLevel = let toJson (params: SetLoggingLevelParams) : Json = Json.Object [ - ("level", Json.String (loggingLevelToString params.level)) + ("level", Json.String (LoggingLevel.toString params.level)) ] \ No newline at end of file diff --git a/packages/darklang/modelContextProtocol/prompts/prompts.dark b/packages/darklang/modelContextProtocol/prompts/prompts.dark index 5bd7b963c2..c6e3be9350 100644 --- a/packages/darklang/modelContextProtocol/prompts/prompts.dark +++ b/packages/darklang/modelContextProtocol/prompts/prompts.dark @@ -21,48 +21,53 @@ module ListPromptsRequest = Stdlib.Result.Result.Error "params must be an object" -module ListPromptsResponse = +module PromptArgument = type PromptArgument = { name: String description: Stdlib.Option.Option required: Stdlib.Option.Option } + let toJson (arg: PromptArgument) : Json = + [ Stdlib.Option.Option.Some(("name", Json.String arg.name)) + arg.description |> Stdlib.Option.map (fun d -> ("description", Json.String d)) + arg.required |> Stdlib.Option.map (fun r -> ("required", Json.Bool r)) ] + |> Stdlib.Option.values + |> Json.Object + +module PromptDescription = type PromptDescription = { name: String description: Stdlib.Option.Option - arguments: Stdlib.Option.Option> + arguments: Stdlib.Option.Option> } + let toJson (prompt: PromptDescription) : Json = + let argsJson = + match prompt.arguments with + | Some args -> + Json.Array (args |> Stdlib.List.map PromptArgument.toJson) + | None -> Json.Array [] + + [ Stdlib.Option.Option.Some(("name", Json.String prompt.name)) + prompt.description |> Stdlib.Option.map (fun d -> ("description", Json.String d)) + Stdlib.Option.Option.Some(("arguments", argsJson)) ] + |> Stdlib.Option.values + |> Json.Object + +module ListPromptsResponse = type ListPromptsResult = { - prompts: List + prompts: List nextCursor: Stdlib.Option.Option } let toJson (result: ListPromptsResult) : Json = - let promptsJson = - result.prompts |> Stdlib.List.map (fun prompt -> - let argsJson = - match prompt.arguments with - | Some args -> - Json.Array (args |> Stdlib.List.map (fun arg -> - Json.Object [ - ("name", Json.String arg.name); - ("description", Stdlib.Option.mapToJson arg.description); - ("required", Stdlib.Option.mapToJson arg.required) - ])) - | None -> Json.Array [] - - Json.Object [ - ("name", Json.String prompt.name); - ("description", Stdlib.Option.mapToJson prompt.description); - ("arguments", argsJson) - ]) + let promptsJson = result.prompts |> Stdlib.List.map PromptDescription.toJson - Json.Object [ - ("prompts", Json.Array promptsJson); - ("nextCursor", Stdlib.Option.mapToJson result.nextCursor) - ] + [ Stdlib.Option.Option.Some(("prompts", Json.Array promptsJson)) + result.nextCursor |> Stdlib.Option.map (fun c -> ("nextCursor", Json.String c)) ] + |> Stdlib.Option.values + |> Json.Object module GetPromptRequest = @@ -131,7 +136,7 @@ module GetPromptResponse = ("content", contentJson) ]) - Json.Object [ - ("description", Stdlib.Option.mapToJson result.description); - ("messages", Json.Array messagesJson) - ] + [ result.description |> Stdlib.Option.map (fun d -> ("description", Json.String d)) + Stdlib.Option.Option.Some(("messages", Json.Array messagesJson)) ] + |> Stdlib.Option.values + |> Json.Object diff --git a/packages/darklang/modelContextProtocol/resources/resources.dark b/packages/darklang/modelContextProtocol/resources/resources.dark index 04e65d66e7..7702377b5f 100644 --- a/packages/darklang/modelContextProtocol/resources/resources.dark +++ b/packages/darklang/modelContextProtocol/resources/resources.dark @@ -65,15 +65,10 @@ module ListResourcesResponse = Json.Object fieldsWithMimeType ) - let nextCursorJson = - match response.nextCursor with - | Some cursor -> Json.String cursor - | None -> Json.Null - - Json.Object [ - ("resources", Json.Array resourcesJson); - ("nextCursor", nextCursorJson) - ] + [ Stdlib.Option.Option.Some(("resources", Json.Array resourcesJson)) + response.nextCursor |> Stdlib.Option.map (fun c -> ("nextCursor", Json.String c)) ] + |> Stdlib.Option.values + |> Json.Object /// Schema for the readResource request diff --git a/packages/darklang/modelContextProtocol/tools/tools.dark b/packages/darklang/modelContextProtocol/tools/tools.dark index f3908e00c9..bbd56cfd8e 100644 --- a/packages/darklang/modelContextProtocol/tools/tools.dark +++ b/packages/darklang/modelContextProtocol/tools/tools.dark @@ -97,15 +97,10 @@ module Darklang = Json.Object fieldsWithAnnotations ) - let nextCursorJson = - match response.nextCursor with - | Some cursor -> Json.String cursor - | None -> Json.String "" - - Json.Object [ - ("tools", Json.Array toolsJson); - ("nextCursor", nextCursorJson) - ] + [ Stdlib.Option.Option.Some(("tools", Json.Array toolsJson)) + response.nextCursor |> Stdlib.Option.map (fun c -> ("nextCursor", Json.String c)) ] + |> Stdlib.Option.values + |> Json.Object module CallToolRequest = diff --git a/packages/darklang/modelContextProtocol/tracing.dark b/packages/darklang/modelContextProtocol/tracing.dark index 5a999f249f..c574f7a2a5 100644 --- a/packages/darklang/modelContextProtocol/tracing.dark +++ b/packages/darklang/modelContextProtocol/tracing.dark @@ -7,6 +7,21 @@ type TraceLevel = | Messages | Verbose +/// TraceLevel conversion utilities +module TraceLevel = + let toString (level: TraceLevel) : String = + match level with + | Off -> "off" + | Messages -> "messages" + | Verbose -> "verbose" + + let fromString (s: String) : Stdlib.Result.Result = + match s with + | "off" -> Stdlib.Result.Result.Ok TraceLevel.Off + | "messages" -> Stdlib.Result.Result.Ok TraceLevel.Messages + | "verbose" -> Stdlib.Result.Result.Ok TraceLevel.Verbose + | _ -> Stdlib.Result.Result.Error $"Invalid trace level: {s}" + /// Trace notification parameters module TraceNotification = type TraceNotificationParams = @@ -16,28 +31,20 @@ module TraceNotification = match json with | Object fields -> match Stdlib.List.findFirst fields (fun (k, _) -> k == "value") with - | Some (_, String "off") -> - Stdlib.Result.Result.Ok (TraceNotificationParams { value = TraceLevel.Off }) - | Some (_, String "messages") -> - Stdlib.Result.Result.Ok (TraceNotificationParams { value = TraceLevel.Messages }) - | Some (_, String "verbose") -> - Stdlib.Result.Result.Ok (TraceNotificationParams { value = TraceLevel.Verbose }) + | Some (_, String s) -> + match TraceLevel.fromString s with + | Ok level -> Stdlib.Result.Result.Ok (TraceNotificationParams { value = level }) + | Error e -> Stdlib.Result.Result.Error e | Some (_, _) -> - Stdlib.Result.Result.Error "value must be one of: 'off', 'messages', 'verbose'" + Stdlib.Result.Result.Error "value must be a string" | None -> Stdlib.Result.Result.Error "value is required" | _ -> Stdlib.Result.Result.Error "params must be an object" let toJson (params: TraceNotificationParams) : Json = - let valueStr = - match params.value with - | Off -> "off" - | Messages -> "messages" - | Verbose -> "verbose" - Json.Object [ - ("value", Json.String valueStr) + ("value", Json.String (TraceLevel.toString params.value)) ] /// Log message notification parameters