Hermolaos.Pool (Hermolaos v0.3.0)

View Source

Connection pool for managing multiple MCP connections.

The Pool provides load balancing and fault tolerance for MCP operations by maintaining multiple connections to one or more servers.

Use Cases

  1. High throughput: Distribute requests across multiple connections
  2. Redundancy: Multiple connections to the same server for failover
  3. Multi-server: Connect to multiple MCP servers simultaneously

Architecture

The Pool uses a DynamicSupervisor to manage connections. Each connection is a supervised Hermolaos.Client.Connection process. The pool uses a Registry for efficient connection lookup.

Example

# Start a pool
{:ok, pool} = Hermolaos.Pool.start_link(
  name: MyApp.MCPPool,
  connections: [
    [transport: :stdio, command: "server1"],
    [transport: :stdio, command: "server2"]
  ]
)

# Use checkout/checkin pattern
{:ok, conn} = Hermolaos.Pool.checkout(MyApp.MCPPool)
result = Hermolaos.call_tool(conn, "my_tool", %{})
Hermolaos.Pool.checkin(MyApp.MCPPool, conn)

# Or use transaction for automatic checkin
result = Hermolaos.Pool.transaction(MyApp.MCPPool, fn conn ->
  Hermolaos.call_tool(conn, "my_tool", %{})
end)

Strategies

  • :round_robin - Rotate through available connections (default)
  • :random - Randomly select a connection
  • :least_busy - Select connection with fewest pending requests

Pool as Hermolaos Client

The pool itself implements the same interface as a single connection, so you can use Hermolaos.call_tool/4 etc. directly with the pool name.

Summary

Functions

Adds a new connection to the pool.

Checks a connection back into the pool.

Checks out a connection from the pool.

Returns a specification to start this module under a supervisor.

Returns the list of all connections in the pool.

Removes a connection from the pool.

Starts a connection pool.

Returns pool statistics.

Executes a function with a checked-out connection.

Types

pool()

@type pool() :: Supervisor.supervisor()

pool_option()

@type pool_option() ::
  {:name, atom()}
  | {:connections, [keyword()]}
  | {:size, pos_integer()}
  | {:strategy, strategy()}
  | {:connection_opts, keyword()}

strategy()

@type strategy() :: :round_robin | :random | :least_busy

Functions

add_connection(pool, opts)

@spec add_connection(
  pool(),
  keyword()
) :: {:ok, Hermolaos.Client.Connection.t()} | {:error, term()}

Adds a new connection to the pool.

Examples

{:ok, conn} = Hermolaos.Pool.add_connection(MyPool, transport: :stdio, command: "new-server")

checkin(pool, conn)

@spec checkin(pool(), Hermolaos.Client.Connection.t()) :: :ok

Checks a connection back into the pool.

This is a no-op in the current implementation but is included for API compatibility with checkout/checkin patterns.

checkout(pool, opts \\ [])

@spec checkout(
  pool(),
  keyword()
) :: {:ok, Hermolaos.Client.Connection.t()} | {:error, :no_connections}

Checks out a connection from the pool.

Returns a connection that should be checked back in after use, or used within a transaction/2 block.

Options

  • :timeout - Maximum time to wait for a connection (default: 5000)

Examples

{:ok, conn} = Hermolaos.Pool.checkout(MyPool)
# use conn...
Hermolaos.Pool.checkin(MyPool, conn)

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

connections(pool)

@spec connections(pool()) :: [Hermolaos.Client.Connection.t()]

Returns the list of all connections in the pool.

handle_info(arg, state)

remove_connection(pool, conn)

@spec remove_connection(pool(), Hermolaos.Client.Connection.t()) ::
  :ok | {:error, :not_found}

Removes a connection from the pool.

start_link(opts)

@spec start_link(keyword()) :: {:ok, pid()} | {:error, term()}

Starts a connection pool.

Options

  • :name - Pool name (required, used for registration)
  • :connections - List of connection option keyword lists
  • :size - Number of identical connections (alternative to :connections)
  • :connection_opts - Common options for all connections when using :size
  • :strategy - Load balancing strategy (default: :round_robin)

Examples

# Multiple connections with explicit configs
{:ok, pool} = Hermolaos.Pool.start_link(
  name: MyPool,
  connections: [
    [transport: :stdio, command: "server1"],
    [transport: :http, url: "http://localhost:3000/mcp"]
  ]
)

# Pool of identical connections
{:ok, pool} = Hermolaos.Pool.start_link(
  name: MyPool,
  size: 4,
  connection_opts: [transport: :stdio, command: "my-server"]
)

stats(pool)

@spec stats(pool()) :: map()

Returns pool statistics.

transaction(pool, fun)

@spec transaction(pool(), (Hermolaos.Client.Connection.t() -> result)) :: result
when result: term()

Executes a function with a checked-out connection.

Automatically checks in the connection after the function completes.

Examples

result = Hermolaos.Pool.transaction(MyPool, fn conn ->
  Hermolaos.call_tool(conn, "my_tool", %{arg: "value"})
end)