Packages
Model Context Protocol (MCP) implementation in Elixir with Phoenix integration
Current section
Files
Jump to
Current section
Files
lib/backplane/mcp_protocol/client/cache.ex
defmodule Backplane.McpProtocol.Client.Cache do
@moduledoc false
alias Backplane.McpProtocol.Client.JSONSchemaConverter
@tool_validators_key {__MODULE__, :tool_validators}
# Public API
@doc """
Stores tool output validators in the cache.
Clears existing validators before storing new ones.
"""
@spec put_tool_validators(client_name :: String.t(), tools :: list(map())) :: :ok
def put_tool_validators(client, tools) when is_binary(client) and is_list(tools) do
table = ensure_table(client)
:ets.delete_all_objects(table)
tools
|> Enum.filter(& &1["outputSchema"])
|> Enum.flat_map(&fetch_tool_validator/1)
|> then(&:ets.insert(table, &1))
:ok
end
defp fetch_tool_validator(%{"outputSchema" => s, "name" => name}) when is_map(s) do
case JSONSchemaConverter.validator(s) do
{:ok, validator} -> [{name, validator}]
{:error, _errors} -> []
end
end
@doc """
Gets a tool output validator from the cache.
"""
@spec get_tool_validator(client_name :: String.t(), tool_name :: String.t()) ::
JSONSchemaConverter.validator() | nil
def get_tool_validator(client, tool_name) when is_binary(client) and is_binary(tool_name) do
table = ensure_table(client)
case :ets.lookup(table, tool_name) do
[{^tool_name, validator}] -> validator
[] -> nil
end
end
@doc """
Clears all tool validators from the cache.
"""
@spec clear_tool_validators(client_name :: String.t()) :: :ok
def clear_tool_validators(client) when is_binary(client) do
case table(client) do
nil -> :ok
table -> :ets.delete_all_objects(table)
end
:ok
end
@doc """
Cleans up all cache tables for a client process.
Should be called when the client process terminates.
"""
@spec cleanup(client_name :: String.t()) :: :ok
def cleanup(client) when is_binary(client) do
case Process.delete(tool_validators_key(client)) do
nil -> :ok
table -> :ets.delete(table)
end
:ok
end
# Private helpers
@spec ensure_table(client_name :: String.t()) :: :ets.tid()
defp ensure_table(client) do
case table(client) do
nil ->
table = :ets.new(:tool_validators, [:private, :set, read_concurrency: true])
Process.put(tool_validators_key(client), table)
table
table ->
table
end
end
defp table(client), do: Process.get(tool_validators_key(client))
defp tool_validators_key(client), do: {@tool_validators_key, client}
end