Edison Watch
Developers

Mastra

Connect a Mastra agent to Edison Watch using MCPClient over streamable HTTP, keeping a stable session per conversation so data-leak protection holds across every turn.

Mastra connects to Edison with MCPClient. A server entry with just a url uses Streamable HTTP automatically. Your connection URL carries your API key, so no auth header is needed.

npm install @mastra/mcp @mastra/core @ai-sdk/openai
import { MCPClient } from '@mastra/mcp';
import { Agent } from '@mastra/core/agent';

const mcp = new MCPClient({
  id: 'edison-client',
  servers: {
    edison: {
      url: new URL(process.env.EDISON_MCP_URL!),
    },
  },
});

const agent = new Agent({
  id: 'edison-agent',
  name: 'Edison Agent',
  instructions: 'You can use Edison Watch tools.',
  model: 'openai/gpt-5.6-luna',
  tools: await mcp.listTools(),
});

const res = await agent.generate('List my available tools.');
console.log(res.text);

await mcp.disconnect();

Set EDISON_MCP_URL to your connection URL, e.g. https://mcp.edison.watch/mcp/<your-api-key>/?client=mastra. Note url takes a URL object, and cleanup is disconnect() (there is no .close()). The tool methods are listTools() (static) / listToolsets() (per-request); the older names getTools() / getToolsets() still exist as aliases, but prefer the list* forms.

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 Mastra agent, set the header under requestInit, keyed to your own conversation or thread id - and reuse that id on every turn:

const mcp = new MCPClient({
  servers: {
    edison: {
      url: new URL(process.env.EDISON_MCP_URL!),
      requestInit: {
        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, pass headers under requestInit, alongside x-edison-conversation-id:

const mcp = new MCPClient({
  servers: {
    edison: {
      url: new URL(process.env.EDISON_MCP_URL!),
      requestInit: {
        headers: {
          'x-edison-conversation-id': conversationId,
          'x-edison-secret-key': process.env.EDISON_SECRET_KEY!,
        },
      },
    },
  },
});

When each request carries a different user's credentials, prefer the dynamic await mcp.listToolsets() passed to agent.generate(prompt, { toolsets }) over binding tools at construction time.