Anubis.Server.Session (anubis_mcp v1.6.0)

Copy Markdown

Per-client MCP session process.

Each Session is a GenServer that manages the lifecycle of a single MCP client connection. It handles protocol initialization, request/notification dispatch, server-initiated requests (sampling, roots), and session persistence.

Sessions are created by the transport layer (STDIO creates one at startup, HTTP transports create them dynamically via Anubis.Server.Supervisor).

Summary

Functions

Auto-initializes a session without a client initialize handshake.

Returns a specification to start this module under a supervisor.

Starts a Session process linked to the current process.

Types

t()

@type t() :: %{
  session_id: String.t(),
  server_module: module(),
  protocol_version: String.t() | nil,
  protocol_module: module() | nil,
  initialized: boolean(),
  client_info: map() | nil,
  client_capabilities: map() | nil,
  log_level: String.t() | nil,
  frame: Anubis.Server.Frame.t(),
  server_info: map(),
  capabilities: map(),
  instructions: String.t() | nil,
  supported_versions: [String.t()],
  transport: %{layer: module(), name: GenServer.name()},
  registry: module(),
  session_idle_timeout: pos_integer(),
  expiry_timer: reference() | nil,
  pending_requests: %{
    required(String.t()) => %{started_at: integer(), method: String.t()}
  },
  server_requests: %{
    required(String.t()) => %{method: String.t(), timer_ref: reference()}
  },
  timeout: pos_integer(),
  task_supervisor: GenServer.name(),
  task_store: %{adapter: module(), name: term()} | nil,
  tasks: %{required(String.t()) => task_runtime()},
  task_refs: %{required(reference()) => String.t()},
  in_flight:
    nil
    | %{
        ref: reference(),
        pid: pid(),
        request_id: String.t(),
        from: GenServer.from(),
        started_at: integer(),
        method: String.t()
      },
  request_queue: :queue.queue({map(), map(), GenServer.from()}),
  deferred_callbacks: :queue.queue({:cast | :info, term()})
}

task_runtime()

@type task_runtime() :: %{
  worker_ref: reference() | nil,
  worker_pid: pid() | nil,
  ttl_timer: reference() | nil,
  waiters: [task_waiter()],
  request_id: String.t() | integer()
}

task_waiter()

@type task_waiter() ::
  {from :: GenServer.from(), request_id :: String.t() | integer()}

Functions

auto_initialize(session)

@spec auto_initialize(GenServer.server()) :: :ok | {:error, term()}

Auto-initializes a session without a client initialize handshake.

This is used when a client sends a non-initialize request to an expired or unknown session. Instead of returning 404, the server can create a new session and auto-initialize it so the request can be processed transparently.

Uses the server's latest supported protocol version and synthetic client info (%{"name" => "auto-recovered", "version" => "unknown"}). Server implementations should not rely on this identity for client-specific decisions.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

get_schema(atom)

parse_options(data)

parse_options!(data)

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts a Session process linked to the current process.

Options

  • :session_id — unique session identifier (required)
  • :server_module — the MCP server module implementing Anubis.Server (required)
  • :name — GenServer registration name (required)
  • :transport — transport configuration [layer: module, name: name] (required)
  • :task_supervisor — name of the Task.Supervisor for async work (required)
  • :registry — session registry module (default: Anubis.Server.Registry)
  • :session_idle_timeout — idle timeout in ms before session expires (default: 30 min)
  • :timeout — request timeout in ms (default: 30s)