LangChain.MCP.Adapter (LangChain MCP v0.2.0)

View Source

Main adapter for integrating MCP tools with LangChain.

This module provides the primary API for discovering MCP tools and converting them to LangChain Functions that can be used in LLMChains.

Features

  • Tool discovery from MCP servers
  • Automatic schema conversion
  • Tool caching for performance
  • Tool filtering
  • Fallback client support
  • Async execution configuration

Usage

# Define MCP client
defmodule MyApp.MCPClient do
  use Anubis.Client,
    name: "MyApp",
    version: "1.0.0",
    protocol_version: "2025-03-26"
end

# Create adapter
adapter = Adapter.new(client: MyApp.MCPClient)

# Discover and convert tools
functions = Adapter.to_functions(adapter)

# Use in LLMChain
chain = LLMChain.new!(%{llm: model})
  |> LLMChain.add_tools(functions)
  |> LLMChain.run(mode: :while_needs_response)

With Options

adapter = Adapter.new(
  client: MyApp.MCPClient,
  cache_tools: true,
  timeout: 60_000,
  async: true,
  fallback_client: MyApp.BackupMCP,
  tool_filter: fn tool -> tool["name"] != "admin_only" end
)

Summary

Functions

Discovers tools from the MCP server without converting to Functions.

Returns the adapter's configuration.

Gets information about a specific tool.

Creates a new MCP adapter.

Refreshes the tool cache for an adapter.

Discovers tools from the MCP server and converts them to LangChain Functions.

Converts a single MCP tool to a LangChain Function.

Updates the adapter's configuration.

Validates that all required tools are available on the MCP server.

Waits for the associated server for a client to be ready.

Types

t()

@type t() :: %LangChain.MCP.Adapter{
  cached_tools: [map()] | nil,
  config: LangChain.MCP.Config.t()
}

Functions

discover_tools(adapter, opts \\ [])

@spec discover_tools(
  t(),
  keyword()
) :: {:ok, [map()]} | {:error, String.t()}

Discovers tools from the MCP server without converting to Functions.

Useful for inspecting available tools.

Parameters

  • adapter - Adapter struct
  • opts - Options (:refresh to force cache refresh)

Returns

  • {:ok, tools} - List of tool maps
  • {:error, reason} - Error message

Examples

iex> {:ok, tools} = Adapter.discover_tools(adapter)
iex> Enum.map(tools, & &1["name"])
["search", "fetch", "analyze"]

get_config(adapter)

@spec get_config(t()) :: LangChain.MCP.Config.t()

Returns the adapter's configuration.

Examples

iex> config = Adapter.get_config(adapter)
iex> config.client
MyApp.MCPClient

get_tool(adapter, tool_name)

@spec get_tool(t(), String.t()) :: {:ok, map()} | {:error, :not_found | String.t()}

Gets information about a specific tool.

Parameters

  • adapter - Adapter struct
  • tool_name - Name of the tool

Returns

  • {:ok, tool} - Tool map
  • {:error, :not_found} - Tool not found

Examples

iex> {:ok, tool} = Adapter.get_tool(adapter, "search")
iex> tool["description"]
"Search for information"

new(opts)

@spec new(keyword()) :: t()

Creates a new MCP adapter.

Options

See LangChain.MCP.Config.new!/1 for all available options.

Examples

iex> adapter = Adapter.new(client: MyApp.MCPClient)
%Adapter{config: %Config{...}}

iex> adapter = Adapter.new(
...>   client: MyApp.MCPClient,
...>   cache_tools: true,
...>   timeout: 60_000,
...>   async: true
...> )

refresh_cache(adapter)

@spec refresh_cache(t()) :: {:ok, t()} | {:error, String.t()}

Refreshes the tool cache for an adapter.

Only useful if caching is enabled.

Parameters

  • adapter - Adapter struct

Returns

  • {:ok, updated_adapter} - Adapter with refreshed cache
  • {:error, reason} - Error message

Examples

iex> {:ok, updated_adapter} = Adapter.refresh_cache(adapter)

to_functions(adapter, opts \\ [])

@spec to_functions(
  t(),
  keyword()
) :: [LangChain.Function.t()]

Discovers tools from the MCP server and converts them to LangChain Functions.

Parameters

  • adapter - Adapter struct
  • opts - Optional keyword list
    • :only - List of tool names to include
    • :except - List of tool names to exclude
    • :refresh - Force refresh cached tools (default: false)

Returns

  • List of LangChain.Function.t() structs

Examples

# Get all tools
functions = Adapter.to_functions(adapter)

# Get specific tools
functions = Adapter.to_functions(adapter, only: ["search", "fetch"])

# Exclude tools
functions = Adapter.to_functions(adapter, except: ["admin_tool"])

# Force refresh cache
functions = Adapter.to_functions(adapter, refresh: true)

tool_to_function(adapter, tool)

@spec tool_to_function(t(), map()) :: LangChain.Function.t()

Converts a single MCP tool to a LangChain Function.

Parameters

  • adapter - Adapter struct
  • tool - MCP tool map

Returns

  • LangChain.Function.t() struct

Examples

iex> tool = %{
...>   "name" => "search",
...>   "description" => "Search for information",
...>   "inputSchema" => %{
...>     "type" => "object",
...>     "properties" => %{"query" => %{"type" => "string"}},
...>     "required" => ["query"]
...>   }
...> }
iex> function = Adapter.tool_to_function(adapter, tool)
iex> function.name
"search"

update_config(adapter, updates)

@spec update_config(
  t(),
  keyword()
) :: t()

Updates the adapter's configuration.

Parameters

  • adapter - Adapter struct
  • updates - Keyword list of config updates

Returns

  • Updated adapter

Examples

iex> updated = Adapter.update_config(adapter, timeout: 60_000, async: true)
iex> updated.config.timeout
60_000

validate_tools(adapter, required_tool_names)

@spec validate_tools(t(), [String.t()]) :: :ok | {:error, [String.t()]}

Validates that all required tools are available on the MCP server.

Parameters

  • adapter - Adapter struct
  • tool_names - List of required tool names

Returns

  • :ok - All tools available
  • {:error, missing_tools} - List of missing tool names

Examples

iex> Adapter.validate_tools(adapter, ["search", "fetch"])
:ok

iex> Adapter.validate_tools(adapter, ["search", "nonexistent"])
{:error, ["nonexistent"]}

wait_for_server_ready(client_pid, timeout \\ 5000)

@spec wait_for_server_ready(pid(), timeout :: non_neg_integer()) ::
  :ok | {:error, :initialization_timeout | :invalid_client}

Waits for the associated server for a client to be ready.

If a client is started with start_link/1 the server initialization is asynchronous, so calling functions such as Adapter.discover_tools/2 or Adapter.to_functions/2 immediately after start link will produce a 'Server capabilities not set' error.

In this case, calling wait_for_server_ready/1 before calls to the Adapter ensures the server has time to initialize.

Parameters

  • client_pid - The process ID for a Anubis client.
  • timeout - Maximum time to wait in milliseconds (default: 5000)

Returns

  • :ok - Server is ready
  • {:error, :initialization_timeout} - Server didn't initialize within timeout
  • {:error, :invalid_client} - The provided PID is not a valid Anubis client

Examples

{:ok, client_pid} =
    MCPClient.start_link(
      client_info: ...,
      capabilities: ...,
      protocol_version: ...,
      transport: ...
    )

case Adapter.wait_for_server_ready(client_pid) do
  :ok ->
    adapter = Adapter.new(client: client_pid)
    functions = Adapter.to_functions(adapter)
  {:error, reason} ->
    {:error, reason}
end