Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions src/server/src/fbi/handlers/mcp_servers.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import fbi/context.{type Context}
import fbi/db/connection
import fbi/db/mcp_servers
import fbi/json/mcp_server as mcp_server_json
import gleam/dict.{type Dict}
import gleam/dynamic/decode
import gleam/http
import gleam/int
import gleam/json
import gleam/list
import gleam/option.{type Option, None, Some}
import wisp.{type Request, type Response}

Expand All @@ -18,7 +20,11 @@ pub fn handle_global(req: Request, ctx: Context) -> Response {
}
}

pub fn handle_global_one(req: Request, ctx: Context, id_str: String) -> Response {
pub fn handle_global_one(
req: Request,
ctx: Context,
id_str: String,
) -> Response {
case int.parse(id_str) {
Error(_) -> wisp.bad_request("Invalid MCP server ID")
Ok(id) ->
Expand Down Expand Up @@ -97,6 +103,17 @@ fn show(ctx: Context, id: Int) -> Response {
}
}

fn encode_string_list(xs: List(String)) -> String {
json.array(xs, json.string) |> json.to_string()
}

fn encode_string_dict(d: Dict(String, String)) -> String {
dict.to_list(d)
|> list.map(fn(pair) { #(pair.0, json.string(pair.1)) })
|> json.object
|> json.to_string()
}

fn decode_body(
body: decode.Dynamic,
) -> Result(
Expand All @@ -111,14 +128,25 @@ fn decode_body(
None,
decode.optional(decode.string),
)
use args_json <- decode.optional_field("args_json", "[]", decode.string)
use args <- decode.optional_field("args", [], decode.list(decode.string))
use url <- decode.optional_field(
"url",
None,
decode.optional(decode.string),
)
use env_json <- decode.optional_field("env_json", "{}", decode.string)
decode.success(#(name, server_type, command, args_json, url, env_json))
use env <- decode.optional_field(
"env",
dict.new(),
decode.dict(decode.string, decode.string),
)
decode.success(#(
name,
server_type,
command,
encode_string_list(args),
url,
encode_string_dict(env),
))
}
decode.run(body, decoder)
}
Expand Down Expand Up @@ -199,36 +227,36 @@ fn update(req: Request, ctx: Context, id: Int) -> Response {
None,
decode.optional(decode.optional(decode.string)),
)
use args_json <- decode.optional_field(
"args_json",
use args <- decode.optional_field(
"args",
None,
decode.optional(decode.string),
decode.optional(decode.list(decode.string)),
)
use url <- decode.optional_field(
"url",
None,
decode.optional(decode.optional(decode.string)),
)
use env_json <- decode.optional_field(
"env_json",
use env <- decode.optional_field(
"env",
None,
decode.optional(decode.string),
decode.optional(decode.dict(decode.string, decode.string)),
)
decode.success(#(name, server_type, command, args_json, url, env_json))
decode.success(#(name, server_type, command, args, url, env))
}
case decode.run(body, decoder) {
Error(_) -> wisp.bad_request("Invalid request body")
Ok(#(name, server_type, command, args_json, url, env_json)) ->
Ok(#(name, server_type, command, args, url, env)) ->
case
mcp_servers.update(
ctx.db,
id,
name,
server_type,
command,
args_json,
option.map(args, encode_string_list),
url,
env_json,
option.map(env, encode_string_dict),
)
{
Ok(s) ->
Expand Down
26 changes: 23 additions & 3 deletions src/server/src/fbi/json/mcp_server.gleam
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
import fbi/db/mcp_servers.{type McpServer}
import gleam/dict.{type Dict}
import gleam/dynamic/decode
import gleam/json
import gleam/list
import gleam/result

fn parse_string_list(raw: String) -> List(String) {
json.parse(raw, decode.list(decode.string))
|> result.unwrap([])
}

fn parse_string_dict(raw: String) -> Dict(String, String) {
json.parse(raw, decode.dict(decode.string, decode.string))
|> result.unwrap(dict.new())
}

fn dict_to_json(d: Dict(String, String)) -> json.Json {
dict.to_list(d)
|> list.map(fn(pair) { #(pair.0, json.string(pair.1)) })
|> json.object
}

pub fn encode(s: McpServer) -> json.Json {
json.object([
#("id", json.int(s.id)),
#("project_id", json.nullable(s.project_id, json.int)),
#("name", json.string(s.name)),
#("server_type", json.string(s.server_type)),
#("type", json.string(s.server_type)),
#("command", json.nullable(s.command, json.string)),
#("args_json", json.string(s.args_json)),
#("args", json.array(parse_string_list(s.args_json), json.string)),
#("url", json.nullable(s.url, json.string)),
#("env_json", json.string(s.env_json)),
#("env", dict_to_json(parse_string_dict(s.env_json))),
#("created_at", json.int(s.created_at)),
])
}
Loading