GenMCP behaviour (gen_mcp v0.9.0)

Copy Markdown View Source

The main behaviour for MCP servers.

Implement this behaviour to create a custom MCP server. If you are looking for a high-level framework to build tools and resources, see GenMCP.Suite.

Example

defmodule MyServer do
  @behaviour GenMCP

  alias GenMCP.MCP

  @impl true
  def init(_session_id, _opts) do
    {:ok, %{}}
  end

  @impl true
  def handle_request(%MCP.InitializeRequest{} = req, _channel, state) do
    # Protocol version check omitted for brevity
    result = MCP.intialize_result(
      capabilities: MCP.capabilities(tools: true),
      server_info: MCP.server_info(name: "My Server", version: "1.0.0")
    )
    {:reply, {:result, result}, state}
  end

  def handle_request(%MCP.ListToolsRequest{}, _channel, state) do
    result = MCP.list_tools_result([
      %MCP.Tool{
        name: "hello",
        description: "Say hello",
        inputSchema: %{
          type: "object",
          properties: %{
            name: %{type: "string"}
          }
        }
      }
    ])
    {:reply, {:result, result}, state}
  end

  @impl true
  def handle_notification(%MCP.InitializedNotification{}, state) do
    {:noreply, state}
  end

  def handle_notification(_notif, state) do
    {:noreply, state}
  end

  @impl true
  def handle_info(_msg, state) do
    {:noreply, state}
  end
end

Summary

Callbacks

Handles process messages.

Handles an incoming MCP notification.

Handles an incoming MCP request and returns a result or stop the server.

Initializes the server state.

Called when a session is deleted by the client.

This callback is called during session initialization when a non-initialization request (such as a call tool request) is received and there is no current OTP process tied to the session id.

Called when a session is restored by the GenMCP.Suite.SessionController implementation.

Called when a session times out.

Functions

The gen_mcp application uses telemetry events to publish various application lifecycle events. This can be used to log only what is important to you.

Returns the default logging level used by the MCP logging features on session initialization.

Returns the supported protocol versions.

Types

Callbacks

handle_info(term, state)

@callback handle_info(term(), state()) ::
  {:noreply, state()} | {:stop, reason :: term(), state()}

Handles process messages.

Invoked when the server process receives a message that is not an MCP request or notification.

handle_notification(notification, state)

@callback handle_notification(notification(), state()) :: {:noreply, state()}

Handles an incoming MCP notification.

Notifications are one-way messages that do not expect a response.

handle_request(request, t, state)

@callback handle_request(request(), GenMCP.Mux.Channel.t(), state()) ::
  {:reply, server_reply(), state()}
  | {:stop, reason :: term(), server_reply_nostream(), state()}

Handles an incoming MCP request and returns a result or stop the server.

init(session_id, init_arg)

@callback init(session_id(), init_arg :: term()) :: {:ok, state()} | {:stop, term()}

Initializes the server state.

Called when a new MCP session is established.

session_delete(state)

(optional)
@callback session_delete(state()) :: term()

Called when a session is deleted by the client.

Return value is not checked, and the server is shut down immediately.

session_fetch(session_id, channel, init_arg)

@callback session_fetch(
  session_id(),
  channel :: GenMCP.Mux.Channel.t(),
  init_arg :: term()
) ::
  {:ok, GenMCP.Suite.SessionController.restore_data()} | {:error, :not_found}

This callback is called during session initialization when a non-initialization request (such as a call tool request) is received and there is no current OTP process tied to the session id.

This is a raw callback

The call is made from the HTTP transport process, giving raw initialization args for the server. It is called before the init/2 callback is called and there is no possibility to return a new state or arg.

The returned data will be passed to the session_restore/3 callback after server process initialization.

session_restore(restore_data, channel, state)

(optional)
@callback session_restore(
  GenMCP.Suite.SessionController.restore_data(),
  channel :: GenMCP.Mux.Channel.t(),
  state()
) :: {:noreply, state()} | {:stop, reason :: term(), state()}

Called when a session is restored by the GenMCP.Suite.SessionController implementation.

Your server init/2 callback will have been called before, but there will be no call of handle_request/3 with an initialization request.

The next call will be either another request or a notification.

session_timeout(state)

(optional)
@callback session_timeout(state()) :: term()

Called when a session times out.

Functions

attach_default_logger(filters \\ [])

The gen_mcp application uses telemetry events to publish various application lifecycle events. This can be used to log only what is important to you.

The telemetry logger will log all telemetry events by default, at various log levels (debug, info, warning, error , etc.).

Two filters are supported:

  • :min_log_level - For instance if :error is given, the default logger will not log events for which it uses the lower levels. This allows you to still have logs for errors, without cluttering info and debug logs.
  • :prefixes - A list of event prefixes (which are a list too) to match. The logger will only log events whose prefixes match one of the the given prefixes. For instance, [[:gen_mcp, :cluster], [:gen_mcp, :session]] will only log events related to the cluster and sessions.

Both filters are compatible.

See GenMCP.TelemetryLogger for a list of all emitted events.

default_channel_log_level()

Returns the default logging level used by the MCP logging features on session initialization.

supported_protocol_versions()

Returns the supported protocol versions.