LangChain MCP
View SourceModel Context Protocol (MCP) integration for LangChain Elixir. This library enables LangChain applications to use MCP servers as tool providers, giving instant access to the growing ecosystem of MCP servers.
Features
- ๐ Easy Integration - Add MCP tools to your LangChain workflows with minimal code
- ๐ ๏ธ Tool Discovery - Automatically discover and convert MCP tools to LangChain functions
- ๐ Fallback Support - Configure fallback MCP clients for resilient tool execution
- ๐ฆ Multi-modal Content - Full support for text, images, and other content types
- โ๏ธ Configurable - Cache tool discovery, configure timeouts, async execution
- ๐งช Testing - Mock support for unit tests, live test infrastructure with Docker
- ๐ Status Monitoring - Real-time monitoring of MCP client health with LiveView support
Installation
Add langchain_mcp to your dependencies in mix.exs:
def deps do
[
{:langchain, "~> 0.4"},
{:langchain_mcp, "~> 0.1"}
]
endQuick Start
1. Define an MCP Client
defmodule MyApp.GitHubMCP do
use LangChain.MCP.Client,
name: "MyApp",
version: "1.0.0",
protocol_version: "2025-03-26"
end2. Start the Client in Your Supervision Tree
defmodule MyApp.Application do
use Application
def start(_type, _args) do
children = [
{MyApp.GitHubMCP,
transport: {:streamable_http, base_url: "http://localhost:5000"}}
]
Supervisor.start_link(children, strategy: :one_for_one)
end
end3. Use MCP Tools in Your Chain
alias LangChain.Chains.LLMChain
alias LangChain.ChatModels.ChatAnthropic
alias LangChain.Message
alias LangChain.MCP.Adapter
# Create adapter and discover tools
adapter = Adapter.new(client: MyApp.GitHubMCP)
mcp_functions = Adapter.to_functions(adapter)
# Mix with regular functions
all_functions = [
MyApp.Functions.custom_function()
] ++ mcp_functions
# Use in chain
{:ok, updated_chain} =
LLMChain.new!(%{llm: ChatAnthropic.new!()})
|> LLMChain.add_tools(all_functions)
|> LLMChain.add_message(Message.new_user!("Create a GitHub issue for this bug"))
|> LLMChain.run(mode: :while_needs_response)Configuration Options
Adapter Options
adapter = Adapter.new(
client: MyApp.MCPClient,
# Cache tool discovery (default: true)
cache_tools: true,
# Timeout for tool calls in ms (default: 30_000)
timeout: 30_000,
# Mark tools as async (default: false)
async: false,
# Fallback client if primary fails
fallback_client: MyApp.BackupMCPClient,
# Filter which tools to expose (default: all)
tool_filter: fn tool -> tool["name"] not in ["dangerous_tool"] end
)Selective Tool Discovery
# Get only specific tools
mcp_functions = Adapter.to_functions(adapter, only: ["search", "fetch"])
# Exclude certain tools
mcp_functions = Adapter.to_functions(adapter, except: ["admin_tool"])Status Monitoring
Monitor the health and status of your MCP clients in real-time.
Register Clients
Register clients from your Application module:
defmodule MyApp.Application do
use Application
alias LangChain.MCP.StatusMonitor
def start(_type, _args) do
children = [
{MyApp.GitHubMCP, transport: {:streamable_http, base_url: "http://localhost:5000"}}
]
{:ok, _pid} = Supervisor.start_link(children, strategy: :one_for_one)
# Register clients for status monitoring
StatusMonitor.register_client_by_name(MyApp.GitHubMCP, :github)
{:ok, self()}
end
endQuery Client Status
alias LangChain.MCP.StatusMonitor
# Check if registered
StatusMonitor.registered?(:github)
# => true
# Get client status
StatusMonitor.get_client_status(:github)
# => {:ok, %{pid: #PID<0.123.0>}}
# Get health summary
StatusMonitor.health_summary()
# => %{
# healthy_clients: [:github, :filesystem],
# unhealthy_clients: [],
# total_clients: 2,
# uptime_percentage: 100.0
# }
# Get dashboard-ready status
StatusMonitor.dashboard_status()Phoenix LiveView Integration
A complete LiveView example is included for real-time status monitoring:
- Auto-refreshing dashboard (every 2 seconds)
- Color-coded health indicators
- Uptime percentage tracking
- Detailed client information
See examples/phoenix_liveview_example.ex and STATUS_MONITOR.md for complete documentation.
Fallback Support
Similar to LangChain's LLM fallbacks, you can configure fallback MCP clients:
adapter = Adapter.new(
client: MyApp.PrimaryMCP,
fallback_client: MyApp.BackupMCP,
# Optional: modify behavior before fallback
before_fallback: fn _adapter, tool_name, _args ->
Logger.warning("Falling back for tool: #{tool_name}")
:continue # or :skip to skip fallback
end
)Testing
Unit Tests with Mocks
defmodule MyApp.MyAgentTest do
use ExUnit.Case
setup do
# Use Anubis mock transport for testing
{:ok, client} = MyApp.TestMCP.start_link(
transport: {:mock, responses: %{
"list_tools" => %{"tools" => [...]},
"call_tool" => %{"content" => [...]}
}}
)
{:ok, client: client}
end
test "agent uses MCP tools", %{client: _client} do
# Your test here
end
endLive Integration Tests
This project includes a built-in Elixir-based MCP test server - no Docker needed!
Step 1: Start the test server
mix test_server
This starts an MCP server on http://localhost:5000 with test tools:
get_current_time- Get current time in UTC or specified timezoneget_timestamp- Get current Unix timestampadd_numbers- Add two numbers together
Step 2: Run integration tests (in a separate terminal)
mix test --include live_call
Custom port: If you need to use a different port:
# Terminal 1: Start server on custom port
mix test_server --port 5000
# Terminal 2: Run tests with custom URL
MCP_TEST_URL=http://localhost:5000 mix test --include live_call
Example live test:
@tag :live_call
test "integrates with real MCP server" do
adapter = Adapter.new(client: MyApp.MCPClient)
functions = Adapter.to_functions(adapter)
assert length(functions) > 0
endUsing Docker (Optional)
If you prefer Docker or need to test against external MCP servers, you can use docker-compose:
# Start Docker-based MCP servers
docker-compose up -d
# Run tests
mix test --include live_call
Note: Most official MCP servers (like mcp_server_time) use stdio transport and cannot be accessed via HTTP without a wrapper. The built-in Elixir test server is the recommended approach.
Available MCP Servers
Many MCP servers are available via Docker Hub:
mcp/time- Time and timezone operationsmcp/github- GitHub API integrationmcp/postgres- PostgreSQL database accessmcp/sqlite- SQLite database operationsmcp/puppeteer- Browser automation
See Docker Hub MCP Catalog for more.
Contributing
Quality Checks
Before pushing, ensure code meets quality standards:
# Run all checks (same as CI)
mix quality_check
# Or run individually:
mix format --check-formatted # Code formatting
mix credo --strict # L linting
mix dialyzer # Type checking
mix test --exclude live_call # Unit tests only
The automated release workflow requires these checks to pass. Use mix quality_check locally before committing.
Testing
- Unit tests: Standard ExUnit with mocking via
:mimic - Integration tests: Tagged
:live_call, require running test server
# Start test server (Terminal 1)
mix test_server
# Run integration tests (Terminal 2)
mix test --include live_call
Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ LangChain.LLMChain โ
โ + tools: [Function] โ
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโ
โ
โโโโ Regular Functions
โ
โโโโ MCP Functions (via Adapter)
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโ
โ LangChain.MCP โ
โ โข Adapter โ
โ โข SchemaConverter โ
โ โข ToolExecutor โ
โ โข ContentMapper โ
โ โข ErrorHandler โ
โโโโโโโโโโฌโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโ
โ Anubis.Client โ
โ (GenServer) โ
โโโโโโโโโโฌโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโ
โ MCP Server โ
โ (Docker/External) โ
โโโโโโโโโโโโโโโโโโโโโโLicense
Apache 2.0 License. See LICENSE for details.