Edison Watch
Developers

LangChain / LangGraph

Connect a LangChain or LangGraph agent (Python or JS) to Edison Watch using langchain-mcp-adapters, keeping a stable session per conversation so data-leak protection holds across every turn.

LangChain and LangGraph connect to Edison through langchain-mcp-adapters' MultiServerMCPClient, which turns MCP tools into native LangChain tools. Your connection URL carries your API key, so no auth header is needed.

pip install langchain-mcp-adapters langgraph "langchain[openai]"
import asyncio
import os

from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent

async def main() -> None:
    client = MultiServerMCPClient({
        "edison": {
            "transport": "streamable_http",
            "url": os.environ["EDISON_MCP_URL"],
        }
    })
    tools = await client.get_tools()
    agent = create_agent("openai:gpt-5.6-luna", tools)
    result = await agent.ainvoke({"messages": "List my available tools."})
    print(result["messages"][-1].content)

asyncio.run(main())

Set EDISON_MCP_URL to your connection URL, e.g. https://mcp.edison.watch/mcp/<your-api-key>/?client=langchain.

npm install @langchain/mcp-adapters @langchain/langgraph @langchain/core @langchain/openai langchain

A server entry with only a url defaults to Streamable HTTP (with automatic SSE fallback). Disable the fallback to lock to the transport Edison serves:

import { createAgent } from "langchain";
import { ChatOpenAI } from "@langchain/openai";
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

const client = new MultiServerMCPClient({
  mcpServers: {
    edison: {
      url: process.env.EDISON_MCP_URL!,
      automaticSSEFallback: false,
    },
  },
});

const tools = await client.getTools();
const agent = createAgent({ model: new ChatOpenAI({ model: "gpt-5.6-luna" }), tools });

const res = await agent.invoke({
  messages: [{ role: "user", content: "List my available tools." }],
});
console.log(res);
await client.close();

Keep a stable session across turns to preserve data-leak protection

Send a stable x-edison-conversation-id header on every turn of the same conversation. That header is what keeps Edison's data-leak protection intact across a multi-turn run: Edison tracks lethal-trifecta risk per session, so if each turn looks like a brand-new session, that protection resets - and a later turn can leak data that the accumulated risk should have blocked.

Hosted clients (Claude Code, VS Code) send it automatically. For a custom LangChain or LangGraph agent, set the header on the server entry, keyed to your own conversation or thread id - and reuse that id on every turn:

"edison": {
    "transport": "streamable_http",
    "url": os.environ["EDISON_MCP_URL"],
    "headers": {"x-edison-conversation-id": conversation_id},
}
edison: {
  url: process.env.EDISON_MCP_URL!,
  automaticSSEFallback: false,
  headers: { "x-edison-conversation-id": conversationId },
}

Without a stable x-edison-conversation-id, each connection is treated as a fresh session that starts with empty risk state - so risk accumulated on an earlier turn won't be there to block a later exfiltration. The ?client= label is only a dashboard tag, not a session key. Use a unique id per conversation (a UUID is ideal); ids are scoped to your API key, so don't reuse one string for two different conversations.

Optional: the encrypted-secrets header

For servers with zero-knowledge-encrypted secrets, add a headers entry, alongside x-edison-conversation-id (only the http/sse transports honor runtime headers):

"edison": {
    "transport": "streamable_http",
    "url": os.environ["EDISON_MCP_URL"],
    "headers": {
        "x-edison-conversation-id": conversation_id,
        "x-edison-secret-key": os.environ["EDISON_SECRET_KEY"],
    },
}
edison: {
  url: process.env.EDISON_MCP_URL!,
  automaticSSEFallback: false,
  headers: {
    "x-edison-conversation-id": conversationId,
    "x-edison-secret-key": process.env.EDISON_SECRET_KEY!,
  },
}