📑
Livebook MCPサーバを動かしてみる(hermes-mcp)
LivebookでMCPサーバを動かすことを試したのでメモ程度に記録します。
ライブラリとして下記のhermes-mcpを使いました。
本記事では、特に何か独自サーバにするわけではなく、ほぼサンプルままです。
実装
setup
Mix.install([
{:hermes_mcp, "~> 0.14.1"},
{:plug, "~> 1.17"},
{:bandit, "~> 1.6"}
])
サーバのツール実装
※ 公式GitHubのREADMEでhandle_toolを使っていますが、うまくいかなかったのでhandle_tool_callにしています。
defmodule MyApp.MCPServer do
use Hermes.Server,
name: "My Server",
version: "1.0.0",
capabilities: [:tools]
alias Hermes.Server.Response
@impl true
def init(_client_info, frame) do
{:ok,
frame
|> assign(counter: 0)
|> register_tool("echo",
input_schema: %{
text: {:required, :string, max: 150, description: "the text to be echoed"}
},
annotations: %{read_only: true},
description: "echoes everything the user says to the LLM"
)}
end
@impl true
def handle_tool_call("echo", %{text: text}, frame) do
response =
Response.tool()
|> Response.text(text)
{:reply, response, assign(frame, counter: frame.assigns.counter + 1)}
end
end
ルータ
defmodule MyRouter do
use Plug.Router
plug Plug.Parsers,
parsers: [:urlencoded, :json],
pass: ["text/*"],
json_decoder: JSON
plug :match
plug :dispatch
forward "/mcp", to: Hermes.Server.Transport.StreamableHTTP.Plug, init_opts: [server: MyApp.MCPServer]
match _ do
send_resp(conn, 404, "Not found")
end
end
起動
ポートはLivebook(とiframe)で使っているものを避けて設定が必要です。
children = [
Hermes.Server.Registry,
{MyApp.MCPServer, transport: :streamable_http},
{Bandit, plug: MyRouter, port: 4002}
]
opts = [strategy: :one_for_one, name: MyApplication.Supervisor]
Supervisor.start_link(children, opts)
接続設定の例
Claude Codeであれば.mcp.jsonあたりに設定します。
{
"mcpServers": {
"livebook": {
"type": "http",
"url": "http://localhost:4002/mcp"
}
}
}
MyApp.MCPServerをいじれば、独自のMCPサーバになります。サーバ側をいじって再起動した際は、クライアント側も再接続しないとレスポンスが返ってこずにタイムアウトするので注意がいります。
Discussion