Skip to main content
Version: 1.8.0

Govern LangGraph's MCP tool calls with DVARA

langchain-mcp-adapters loads MCP tools into LangChain and LangGraph agents. Load them from DVARA instead of from each MCP server. Your agent gets the same tools, and DVARA applies your workspace's policy to every call, redacts personal data in results and records each one.

What you need​

  • A DVARA MCP Gateway with at least one MCP server behind it. The MCP quickstart gives you one in about five minutes. It runs at http://localhost:8080/mcp, and its API key is DEMO_API_KEY in the quickstart's .env.
  • A DVARA workspace API key.
  • Python 3.11 or later.
pip install langchain-mcp-adapters langchain

Load the tools from DVARA​

import os

from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient({
"dvara": {
"transport": "streamable_http",
"url": "http://localhost:8080/mcp",
"headers": {"Authorization": f"Bearer {os.environ['DVARA_API_KEY']}"},
}
})

tools = await client.get_tools()

DVARA lists each server's tools with the server's id in front, so the quickstart's tools load as demo-tools__get_order_status, demo-tools__lookup_customer and demo-tools__delete_customer.

Give the tools to your agent​

from langchain.agents import create_agent

agent = create_agent("anthropic:<model-id>", tools)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Look up customer C-42, then delete them."}]}
)

Any LangChain chat model works; the agent only sees DVARA.

What happens to each call​

You can see this without a model by calling the tools yourself:

for tool in tools:
args = {"orderId": "ORD-1001"} if tool.name.endswith("get_order_status") else {"customerId": "C-42"}
try:
print(tool.name, "->", await tool.ainvoke(args))
except Exception as e:
print(tool.name, "-> refused:", e)

Against the quickstart:

demo-tools__delete_customer -> refused: delete_customer is irreversible and not allowed in this workspace
demo-tools__lookup_customer -> [{'type': 'text', 'text': '"Customer C-42: Jane Doe, [REDACTED_EMAIL], [REDACTED_PHONE_NUMBER],\\ncard on file [REDACTED_CREDIT_CARD], plan Enterprise."', ...}]
demo-tools__get_order_status -> [{'type': 'text', 'text': '"Order ORD-1001: shipped, arriving Thursday."', ...}]
  • The delete never reaches the MCP server. The quickstart's policy denies it, and the adapter raises the refusal as an McpError with the policy's message.
  • The customer record comes back redacted. The email, phone number and card number are replaced before your agent or the model sees them.
  • Every call is recorded. Find them in Flightdeck under MCP → Tool Calls.

Govern the model calls too​

The steps above govern your agent's tool calls. Its model calls are a separate stream: point the agent's model at DVARA's LLM Gateway as well, and the same workspace governs both.

pip install langchain-openai
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
model="<model-id>",
base_url="http://localhost:8080/v1",
api_key=os.environ["DVARA_API_KEY"],
)

agent = create_agent(model, tools)

The Gateway needs a model provider for this. The MCP quickstart doesn't set one up. See Connect LangChain for the full setup, and Agent sessions to tie an agent's model and tool calls into one session in the audit trail.

Where to go next​