Skip to content

Connect: LangGraph.js

Recipe · through our MCP server · their docs checked 2026-10-30

@langchain/mcp-adapters (2.0 or later) turns our MCP tools into LangChain.js tools. Use them with createAgent, or in a LangGraph.js graph like any other LangChain tool.

Our side

def public_app(tools: Registry, host: str, agent_token: str, reviewer_token: str) -> Any:
    """REST at /, MCP at /mcp, one bearer check for both: for a host on the internet."""
    from mcp.server.transport_security import TransportSecuritySettings

    from agent_adapter.server import create_app

    tokens = {
        agent_token: Principal("hosted-agent"),  # the token the remote framework sends
        reviewer_token: Principal("reviewer@example.com", scopes=frozenset({APPROVER_SCOPE})),
    }
    security = TransportSecuritySettings(allowed_hosts=[host], allowed_origins=[f"https://{host}"])
    return create_app(
        tools,
        authenticate=bearer_auth(tokens),
        host="0.0.0.0",  # a public bind: the public-host checks apply
        allowed_hosts=[host],  # REST: any other Host header gets 421
        mcp_options={"transport_security": security},  # MCP: the same rule
    )

In development on one machine, local_app() and http://127.0.0.1:8000/mcp are enough.

Their side

import { MCPAdapter } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";

const adapter = new MCPAdapter({
  servers: {
    shopTools: {
      url: "https://tools.example.com/mcp", // HTTP is the default for a URL
      headers: { Authorization: `Bearer ${process.env.AA_AGENT_TOKEN}` },
    },
  },
});
try {
  const tools = (await adapter.listTools()).filter((t) => t.name !== "send_invoice");
  const agent = createAgent({ model, tools });
  await agent.invoke({ messages: [{ role: "user", content: "Shipping rate to the US?" }] });
} finally {
  await adapter.close();
}
Key Meaning
servers.<name>.url our /mcp endpoint; leave transport and mode out for a new remote server
servers.<name>.headers sent on every request: the bearer token
listTools() LangChain.js tools, one per MCP tool
close() ends the connections

Older code uses MultiServerMCPClient({ mcpServers: { … } }) with getTools(); 2.0 documents MCPAdapter.

Approval

A LangGraph.js interrupt() before a tool node is a UI gate: it adds a step, it does not approve our call. Confirm tools reached over MCP park as approval required: <id> and the adapter does not send our resume keys back. Keep them out of tools (as above), or call them through the TS client, where decide runs the call.

Checklist

Check Why
confirm tools filtered out, or hosted served the adapter cannot resume a parked call
one adapter per principal the header is the identity
everything on the public-host checklist

Sources