Prévia alfa do langchain.mcp — um adaptador oficial que transforma qualquer servidor MCP em ferramentas LangChain que você pode passar diretamente para create_agent.
O gerenciamento de conexão é do FastMCP, então os recursos do cliente estão disponíveis conforme o original, em vez de serem reimplementados por trás de uma interface mais restrita.
pip install "langchain[mcp]==1.4.0a2"
Conectar
MCPAdapter aceita qualquer destino que fastmcp.Client aceite — o transporte é inferido, então há um único ponto de entrada em vez de um por protocolo.
from langchain.agents import create_agent
from langchain.mcp import MCPAdapter
async with MCPAdapter("https://example.com/mcp") as adapter:
agent = create_agent("anthropic:claude-sonnet-5", await adapter.get_tools())
result = await agent.ainvoke({"messages": [{"role": "user", "content": "..."}]})
Alvos válidos: uma URL, um caminho de script local (executado via stdio), um servidor FastMCP em processo, uma configuração que nomeia vários servidores de uma vez ou um fastmcp.Client que você mesmo construiu.
As ferramentas retornadas por get_tools() mantêm o cliente do adaptador, então permanecem utilizáveis após a saída do contexto — o bloco async with define o escopo da descoberta, não o tempo de vida das ferramentas.
Autenticação, cache, timeouts — construa o cliente
O MCPAdapter recebe dois argumentos: o destino e elicitation. Todo o resto que o FastMCP suporta é configurado em um fastmcp.Client que você constrói e passa como destino. Esse é o padrão a ser usado sempre que você precisar de algo além de uma conexão simples:
from fastmcp.client import Client
from langchain.mcp import MCPAdapter
client = Client(
"https://example.com/mcp",
auth="oauth", # or a bearer token string, or any httpx auth
cache=True, # opt-in response caching
timeout=30,
)
async with MCPAdapter(client) as adapter:
tools = await adapter.get_tools()
O parâmetro auth aceita "oauth" para executar o fluxo OAuth, uma string de token para autenticação bearer, ou uma instância httpx.Auth para qualquer customização — veja a documentação de autenticação do FastMCP. Headers e autenticação por servidor também podem ser definidos em uma configuração multi-servidor (abaixo).
O cache é opcional e desativado por padrão: cache=True o habilita com os padrões, respeitando as dicas ttlMs e cacheScope do próprio servidor; um CacheConfig permite personalizá-lo. O cache é por cliente e em memória.
Todo o resto no fastmcp.Client — timeout, log_handler, progress_handler, message_handler, roots, sampling_handler — funciona da mesma forma. O adaptador repassa seu cliente sem alterações, então o comportamento do FastMCP não é reimplementado nem restringido.
Uma ressalva: com elicitation="interrupt", o adaptador clona seu cliente para não sobrescrever um callback que você definiu. A configuração (autenticação, configurações de cache, handlers) é transferida para o clone; as entradas em cache não, pois o clone obtém seu próprio armazenamento.
adapter.client expõe o cliente subjacente para prompts, recursos e qualquer outra coisa que o adaptador não encapsula.
Múltiplos servidores
Aponte o adaptador para uma configuração e ele se distribui para todos os servidores por meio de uma única conexão, apresentando uma lista única de ferramentas ao seu agente.
config = {
"mcpServers": {
"weather": {"url": "https://weather.example.com/mcp"},
"calendar": {
"url": "https://calendar.example.com/mcp",
"headers": {"Authorization": "Bearer ..."},
},
}
}
async with MCPAdapter(config) as adapter:
agent = create_agent("anthropic:claude-sonnet-5", await adapter.get_tools())
Com mais de um servidor, as ferramentas são colocadas em namespaces pelo nome do servidor — weather_get_forecast, calendar_create_event — o que torna impossível colisões entre servidores. Com exatamente um servidor, o adaptador conecta diretamente e os nomes não são prefixados. Cada entrada aceita seus próprios headers, auth, transport e timeout, de modo que servidores com credenciais diferentes podem ser compostos em um único agente. Um servidor local usa command/args em vez de url e é executado via stdio. A configuração segue o esquema JSON MCP do FastMCP, portanto uma configuração que você já usa em outro lugar funciona aqui sem alterações.
Servidores de protocolo antigo e novo, lado a lado
O MCP passou do handshake initialize para server/discover, e servidores em produção estão em ambos os lados dessa linha. O FastMCP negocia a era por conexão, então o adaptador alcança qualquer um sem que você precise selecionar:
# handshake-era server over SSE
legacy = MCPAdapter("https://legacy.example.com/sse")
# modern-era server over streamable HTTP
modern = MCPAdapter("https://modern.example.com/mcp")
Adaptadores separados negociam de forma independente e podem ser executados simultaneamente, cada um na sua própria era. Isso é coberto por testes de integração que levantam um servidor de cada era e chamam ambos.
A única regra que vale a pena saber: uma configuração multi-servidor expõe uma única era, portanto o backend mais antigo define a era para todo o conjunto. Misturar um servidor da era do handshake em uma configuração faz os backends modernos voltarem à era do handshake — eles ainda funcionam, mas os recursos exclusivos da era moderna se vão. Mantenha um servidor legado em seu próprio adaptador quando quiser os outros no protocolo moderno:
async with (
MCPAdapter({"mcpServers": {...modern servers...}}) as modern,
MCPAdapter("https://legacy.example.com/sse") as legacy,
):
tools = await modern.get_tools() + await legacy.get_tools()
Resultados
Cada ferramenta é assíncrona. Uma ferramenta MCP que executa e reporta falha retorna como um ToolMessage com status="error" contendo o texto de erro do próprio servidor, para que o agente possa se corrigir e tentar novamente. Falhas de transporte e conteúdo não conversível geram exceção — um modelo não pode agir sobre eles.
A saída estruturada acompanha o artefato da mensagem da ferramenta:
from langchain.mcp import MCPToolArtifact
artifact: MCPToolArtifact | None = tool_message.artifact # None when there is no structured content
artifact["structured_content"]
Elicitação — servidores que fazem perguntas no meio da chamada
Algumas ferramentas MCP precisam de entrada antes de poderem concluir. Ao optar por isso, a solicitação surge como um interrupt() do LangGraph, de modo que o humano que já está revisando o trabalho do agente também responde ao servidor.
adapter = MCPAdapter(target, elicitation="interrupt")
A capacidade é opcional, e não padrão, porque declará-la é uma promessa feita no protocolo: um agente sem acesso a um humano não pode cumpri-la. Se não for definida, nada é declarado, e um servidor cuja ferramenta exige uma resposta recusa a chamada em vez de executar sem ela.
A execução para com um payload tipado e retoma com uma resposta por chave de solicitação:
from langgraph.types import Command
result = await agent.ainvoke({"messages": [...]}, config)
[pause] = result["__interrupt__"]
pause.value["type"] # "mcp_elicitation"
pause.value["tool_name"] # the tool that is waiting
pause.value["requests"] # each question, in the order to ask them
answer = {"responses": {key: {"action": "accept", "content": {"guests": 4}}}}
result = await agent.ainvoke(Command(resume=answer), config)
As solicitações se especializam por mode: uma solicitação "form" carrega requested_schema para a resposta atender, uma solicitação "url" carrega um endereço para o humano visitar. As respostas se especializam por action — "accept" (com content), "decline" (pular a pergunta, deixar a chamada prosseguir) ou "cancel" (abandonar a chamada da ferramenta). Requer um checkpointer, como qualquer interrupt.
Sampling e roots não são respondidos por meio de interrupts; deixe-os para os handlers do seu próprio cliente.
Os tipos para handlers — MCPElicitationInterrupt, MCPElicitationRequest, MCPElicitationResponse, MCPElicitationResume e o discriminador ELICITATION_INTERRUPT_TYPE — ficam em langchain.mcp.elicitation.
Leitura adicional
- Documentação do cliente FastMCP — autenticação, cache, transportes e configuração de handlers
- Transportes do cliente — o que cada tipo de destino infere
- Elicitação — o recurso de protocolo subjacente
Esta é uma versão alfa: a interface pode mudar antes que a 1.4.0 seja final. Feedback sobre o formato da API é exatamente o que estamos buscando.



