Install guide / LangChain / LangGraph
Connect Normi to a LangChain or LangGraph agent
Load the Normi tools into a Python agent: each MCP tool becomes a LangChain tool, usable by create_agent (built on LangGraph) or in your own graph.
https://mcp.normi.fr/mcpTested on 10 October 2026 with langchain 1.4.4 and fastmcp 4.1.0 (import, connection and key authentication against mcp.normi.fr), and checked against the official LangChain documentation. LangChain MCP documentation
Before you start
- A Normi account: sign in with Google, 500 free credits a month.
- For the API-key connection or the STDIO package: a
normi_…key, created in Dashboard → Tokens. It is shown only once. - For the STDIO package: Node.js 18 or later (
npx).
langchain[mcp] (the langchain.mcp module, in beta). This page uses the new API; the old one is further down for existing projects.Installation
pip install "langchain[mcp]>=1.4" langchain-anthropic export NORMI_API_KEY=normi_YOUR_TOKEN export ANTHROPIC_API_KEY=...
Remote connection (HTTP Streamable)Recommended
MCPAdapter opens the MCP session, converts the Normi tools into LangChain tools, then closes it cleanly. The tools stay usable after the async with block.
import asyncio
import os
from fastmcp.client import Client
from langchain.agents import create_agent
from langchain.mcp import MCPAdapter
NORMI_URL = "https://mcp.normi.fr/mcp"
async def main() -> None:
# The key passed to auth= is sent as "Authorization: Bearer normi_…"
async with MCPAdapter(Client(NORMI_URL, auth=os.environ["NORMI_API_KEY"])) as adapter:
tools = await adapter.list_tools()
agent = create_agent("anthropic:claude-sonnet-5-5", tools)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Using Normi, compare the price per m² of apartments in Paris 11 by DPE class."}]}
)
print(result["messages"][-1].content)
asyncio.run(main())The same thing with a configuration dictionary in mcpServers format:
config = {
"mcpServers": {
"normi": {
"url": "https://mcp.normi.fr/mcp",
"headers": {"Authorization": f"Bearer {os.environ['NORMI_API_KEY']}"},
}
}
}
async with MCPAdapter(config) as adapter:
tools = await adapter.list_tools()Alternative: STDIO package
To run the npm package @normi/mcp-dvf as a subprocess (Node.js required), pass this dictionary to MCPAdapter.
config = {
"mcpServers": {
"normi": {
"command": "npx",
"args": ["-y", "@normi/mcp-dvf"],
"env": {"NORMI_API_KEY": os.environ["NORMI_API_KEY"]},
}
}
}Older API: langchain-mcp-adapters
Existing projects on MultiServerMCPClient: the http transport accepts headers.
# pip install langchain-mcp-adapters (archived: prefer langchain[mcp])
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient(
{
"normi": {
"transport": "http",
"url": "https://mcp.normi.fr/mcp",
"headers": {"Authorization": f"Bearer {os.environ['NORMI_API_KEY']}"},
}
}
)
tools = await client.get_tools()A first prompt to try
The agent calls analyze_dpe_price_premium (10 credits). An excerpt of the real response, captured on 10 October 2026 against the 2014–2025 DVF data:
{
"classes": {
"B": { "count": 241, "median_prix_m2": 9543, "vs_median_pct": 2.7 },
"D": { "count": 5303, "median_prix_m2": 9354, "vs_median_pct": 0.7 },
"E": { "count": 6418, "median_prix_m2": 9219, "vs_median_pct": -0.7 },
"F": { "count": 4366, "median_prix_m2": 9206, "vs_median_pct": -0.9 },
"G": { "count": 1808, "median_prix_m2": 9286, "vs_median_pct": 0 }
},
"methodology": "Each DVF sale is matched to the nearest geocoded DPE within 200 m, issued between 10 years before and 1 year after the sale (one DPE per sale)."
}The gaps stay small in Paris 11 (from -0.9% to +2.7% around the median). The methodology field comes with every response: pass it to your agent so it cites the method and its limits instead of over-reading the gap.