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/mcp

Tested 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-adapters is archived
LangChain folded the MCP adapters into 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

“Using Normi, compare the price per m² of apartments in Paris 11 by DPE class.”

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.

Troubleshooting

ImportError: cannot import name 'MCPAdapter'↓
The langchain.mcp module needs langchain[mcp] 1.4 or later. Upgrade, and uninstall langchain-mcp-adapters if it's still in the environment.
LangChainBetaWarning on import↓
Expected: langchain.mcp is still in beta. The API may change, so pin the langchain version in your dependencies.
KeyError: 'NORMI_API_KEY'↓
The variable isn't exported in the Python process. Export it in the shell, or load a .env (python-dotenv) before creating the client.
The agent makes many calls and burns through credits↓
Only pass the agent the tools it needs (filter the list returned by list_tools by name), and give it a system message that requires resolve_location before any analysis.
Error 401 — Unauthorized↓
API key: it is missing, mistyped or revoked (the normi_ prefix is part of the key). Check that the environment variable is visible to the client. OAuth: access has expired or been revoked; reconnect from the client.
“no active API key” (403) on every call↓
Your account no longer has an active key. Create one in the dashboard: an OAuth connection resumes on the next call, a key-based config needs the new key.
Insufficient credits↓
The message comes back in the tool response, not as HTTP 402. The free plan tops up to 500 credits on the 1st of each month; you can also buy credits from the dashboard.
Error 429 — Rate limited↓
You are over your plan's requests-per-minute limit. Wait a few seconds, or cap how many calls your agent makes in parallel.

Next steps