Packages

fnord

0.8.65

AI code archaeology

Current section

Files

Jump to
fnord lib cmd config mcp check_formatter.ex
Raw

lib/cmd/config/mcp/check_formatter.ex

defmodule Cmd.Config.MCP.CheckFormatter do
@moduledoc """
Formats MCP check results in a human-friendly format with checkmarks.
"""
@doc """
Formats the test results from Services.MCP.test/1 into human-readable output.
"""
@spec format_results(map()) :: :ok
def format_results(%{servers: servers}) when map_size(servers) == 0 do
UI.puts("Checking MCP servers...")
UI.puts("")
UI.puts("No MCP servers configured")
:ok
end
def format_results(%{servers: servers}) do
UI.puts("Checking MCP servers...")
UI.puts("")
servers
|> Enum.sort_by(fn {name, _} -> name end)
|> Enum.each(fn {name, data} ->
format_server(name, data)
UI.puts("")
end)
:ok
end
defp format_server(name, data) do
# Server name with OAuth indicator if present
server_label =
if data[:has_oauth] do
"#{name} (OAuth)"
else
name
end
UI.puts(IO.ANSI.format([:bright, server_label, :reset], UI.colorize?()))
# Connection status
format_connection_status(data)
# Authentication status
format_auth_status(data)
# Tools status
format_tools_status(data)
# Capabilities status
format_capabilities_status(data)
# If we have tools, show the list
case data do
%{tools: tools} when is_list(tools) and length(tools) > 0 ->
UI.newline()
format_tools_list(tools)
_ ->
:ok
end
# If authentication is a problem, suggest login
case data do
%{auth_status: status} when status in [:missing, :expired] ->
UI.puts("")
UI.puts(IO.ANSI.format([:cyan, " fnord config mcp login #{name}"], UI.colorize?()))
_ ->
:ok
end
end
defp format_connection_status(%{status: "ok"}) do
UI.puts(" #{success_symbol()} Connection")
end
defp format_connection_status(%{status: "error", error: error}) do
UI.puts(" #{error_symbol()} Connection #{format_error_detail(error)}")
end
defp format_connection_status(_) do
UI.puts(" #{error_symbol()} Connection (unknown)")
end
defp format_auth_status(%{has_oauth: true, auth_status: :valid}) do
UI.puts(" #{success_symbol()} Authentication")
end
defp format_auth_status(%{has_oauth: true, auth_status: :expired}) do
UI.puts(" #{warning_symbol()} Authentication (expired)")
end
defp format_auth_status(%{has_oauth: true, auth_status: :missing}) do
UI.puts(" #{error_symbol()} Authentication (no credentials)")
end
defp format_auth_status(%{has_oauth: false}) do
UI.puts(" #{na_symbol()} Authentication (N/A)")
end
defp format_auth_status(_) do
UI.puts(" #{na_symbol()} Authentication (N/A)")
end
defp format_tools_status(%{status: "error"}) do
UI.puts(" #{na_symbol()} Tools (unavailable)")
end
defp format_tools_status(%{tools: tools}) when is_list(tools) do
count = length(tools)
if count > 0 do
UI.puts(" #{success_symbol()} Tools (#{count} available)")
else
UI.puts(" #{warning_symbol()} Tools (none)")
end
end
defp format_tools_status(_) do
UI.puts(" #{na_symbol()} Tools (unavailable)")
end
defp format_capabilities_status(%{status: "error"}) do
UI.puts(" #{na_symbol()} Capabilities (unavailable)")
end
defp format_capabilities_status(%{capabilities: caps}) when is_map(caps) do
cap_names =
caps
|> Enum.filter(fn {_k, v} -> v end)
|> Enum.map(fn {k, _v} -> k end)
|> Enum.sort()
if length(cap_names) > 0 do
caps_str = Enum.join(cap_names, ", ")
UI.puts(" #{success_symbol()} Capabilities (#{caps_str})")
else
UI.puts(" #{warning_symbol()} Capabilities (none)")
end
end
defp format_capabilities_status(_) do
UI.puts(" #{na_symbol()} Capabilities (unavailable)")
end
defp format_tools_list(tools) do
UI.puts(" Available tools:")
Enum.each(tools, fn tool ->
name = tool["name"] || "(unnamed)"
desc = tool["description"] || ""
if desc != "" do
UI.puts(" • #{name} - #{desc}")
else
UI.puts(" • #{name}")
end
end)
end
defp format_error_detail(error) when is_binary(error) do
"(#{error})"
end
defp format_error_detail(error) do
"(#{inspect(error)})"
end
defp success_symbol do
IO.ANSI.format([:green, "✓", :reset], UI.colorize?())
end
defp error_symbol do
IO.ANSI.format([:red, "✗", :reset], UI.colorize?())
end
defp warning_symbol do
IO.ANSI.format([:yellow, "⚠", :reset], UI.colorize?())
end
defp na_symbol do
IO.ANSI.format([:light_black, "-", :reset], UI.colorize?())
end
end