SealGate

Mastra

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

Mastra connects to SealGate 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: 'sealgate-client',
  servers: {
    sealgate: {
      url: new URL(process.env.SEALGATE_MCP_URL!),
    },
  },
});

const agent = new Agent({
  id: 'sealgate-agent',
  name: 'SealGate Agent',
  instructions: 'You can use SealGate 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 SEALGATE_MCP_URL to your connection URL, e.g. https://mcp.sealgate.ai/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-sealgate-conversation-id header on every turn of the same conversation. That header is what keeps SealGate's data-leak protection intact across a multi-turn run: SealGate 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: {
    sealgate: {
      url: new URL(process.env.SEALGATE_MCP_URL!),
      requestInit: {
        headers: { 'x-sealgate-conversation-id': conversationId },
      },
    },
  },
});

Without a stable x-sealgate-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-sealgate-conversation-id:

const mcp = new MCPClient({
  servers: {
    sealgate: {
      url: new URL(process.env.SEALGATE_MCP_URL!),
      requestInit: {
        headers: {
          'x-sealgate-conversation-id': conversationId,
          'x-sealgate-secret-key': process.env.SEALGATE_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.