ConduitMcp.Plugs.RateLimit (ConduitMCP v0.9.0)

Copy Markdown View Source

Rate limiting plug for MCP servers.

This plug is completely optional. If you don't need rate limiting, simply omit the :rate_limit option from your transport config — no additional dependencies are required.

Dependencies

Rate limiting requires the hammer package. Add it to your mix.exs only if you intend to use this plug:

{:hammer, "~> 7.2"}

How it works

You define your own Hammer module, supervise it in your application, and pass it as the :backend option. This gives you full control over the backend (:ets, :atomic), algorithm (:fix_window, :leaky_bucket, etc.), and supervision strategy.

Options

  • :backend - Required when enabled. A module that implements hit/3 (e.g., a module defined with use Hammer, backend: :ets). You must supervise this module in your own application supervision tree.
  • :enabled - Enable/disable rate limiting (default: true)
  • :scale - Time window in milliseconds (default: 60_000)
  • :limit - Maximum requests per window (default: 60)
  • :key_func - Function to derive the rate limit key from the connection (default: IP-based). Signature: (Plug.Conn.t()) -> String.t()

Setup

1. Define your Hammer module

defmodule MyApp.RateLimiter do
  use Hammer, backend: :ets
end

2. Add to your supervision tree

children = [
  {MyApp.RateLimiter, [clean_period: :timer.minutes(1)]}
]

3. Pass as :backend in transport config

{Bandit,
 plug: {ConduitMcp.Transport.StreamableHTTP,
        server_module: MyApp.MCPServer,
        rate_limit: [
          backend: MyApp.RateLimiter,
          scale: :timer.seconds(60),
          limit: 100
        ]},
 port: 4001}

Per-user rate limiting

rate_limit: [
  backend: MyApp.RateLimiter,
  limit: 100,
  key_func: fn conn ->
    case conn.assigns[:current_user] do
      %{id: id} -> "user:#{id}"
      _ -> conn.remote_ip |> :inet.ntoa() |> to_string()
    end
  end
]

Without rate limiting

Simply omit the :rate_limit option from your transport config. The hammer dependency is not required and won't be compiled.