Current section

Files

Jump to
hermes_mcp lib mix interactive cli.ex
Raw

lib/mix/interactive/cli.ex

defmodule Mix.Interactive.CLI do
@moduledoc """
Standalone CLI application for Hermes MCP interactive shells.
This module serves as the entry point for the standalone binary compiled with Burrito.
It can start either the SSE or STDIO interactive shell based on command-line arguments.
"""
alias Hermes.Client
alias Hermes.Transport.SSE
alias Hermes.Transport.STDIO
alias Mix.Interactive.Shell
alias Mix.Interactive.UI
@doc """
Main entry point for the standalone CLI application.
"""
def main(args) do
{opts, _, _} =
OptionParser.parse(args,
switches: [
transport: :string,
base_url: :string,
base_path: :string,
sse_path: :string,
command: :string,
args: :string
],
aliases: [t: :transport, c: :command]
)
transport = opts[:transport] || "sse"
case transport do
"sse" ->
run_sse_interactive(opts)
"stdio" ->
run_stdio_interactive(opts)
_ ->
IO.puts("""
#{UI.colors().error}ERROR: Unknown transport type "#{transport}"
Usage: hermes-mcp --transport [sse|stdio] [options]
Available transports:
sse - SSE transport implementation
stdio - STDIO transport implementation
Run with --help for more information#{UI.colors().reset}
""")
System.halt(1)
end
end
defp run_sse_interactive(opts) do
# Disable logger output to keep the UI clean
Logger.configure(level: :error)
server_options = Keyword.put_new(opts, :base_url, "http://localhost:8000")
server_url = Path.join(server_options[:base_url], server_options[:base_path] || "")
header = UI.header("HERMES MCP SSE INTERACTIVE")
IO.puts(header)
IO.puts("#{UI.colors().info}Connecting to SSE server at: #{server_url}#{UI.colors().reset}\n")
{:ok, _} =
SSE.start_link(
client: :sse_test,
server: server_options
)
IO.puts("#{UI.colors().success}✓ SSE transport started#{UI.colors().reset}")
{:ok, client} =
Client.start_link(
name: :sse_test,
transport: [layer: SSE],
client_info: %{
"name" => "Hermes.CLI.SSE",
"version" => "1.0.0"
},
capabilities: %{
"roots" => %{
"listChanged" => true
},
"sampling" => %{}
}
)
IO.puts("#{UI.colors().success}✓ Client connected successfully#{UI.colors().reset}")
IO.puts("\nType #{UI.colors().command}help#{UI.colors().reset} for available commands\n")
Shell.loop(client)
end
defp run_stdio_interactive(opts) do
# Disable logger output to keep the UI clean
Logger.configure(level: :error)
cmd = opts[:command] || "mcp"
args = String.split(opts[:args] || "run,priv/dev/echo/index.py", ",", trim: true)
header = UI.header("HERMES MCP STDIO INTERACTIVE")
IO.puts(header)
IO.puts("#{UI.colors().info}Starting STDIO interaction MCP server#{UI.colors().reset}\n")
if cmd == "mcp" and not (!!System.find_executable("mcp")) do
IO.puts(
"#{UI.colors().error}Error: mcp executable not found in PATH, maybe you need to activate venv#{UI.colors().reset}"
)
System.halt(1)
end
{:ok, _} =
STDIO.start_link(
command: cmd,
args: args,
client: :stdio_test
)
IO.puts("#{UI.colors().success}✓ STDIO transport started#{UI.colors().reset}")
{:ok, client} =
Client.start_link(
name: :stdio_test,
transport: [layer: STDIO],
client_info: %{
"name" => "Hermes.CLI.STDIO",
"version" => "1.0.0"
},
capabilities: %{
"roots" => %{
"listChanged" => true
},
"sampling" => %{}
}
)
IO.puts("#{UI.colors().success}✓ Client connected successfully#{UI.colors().reset}")
IO.puts("\nType #{UI.colors().command}help#{UI.colors().reset} for available commands\n")
Shell.loop(client)
end
end