mastra-ai/mastra · error · Error

MCPClient was initialized multiple times with the same confi

Error message

MCPClient was initialized multiple times with the same configuration options.

This error is intended to prevent memory leaks.

To fix this you have three different options:
1. If you need multiple MCPClient class instances with identical server configurations, set an id when configuring: new MCPClient({ id: "my-unique-id" })
2. Call "await client.disconnect()" after you're done using the client and before you recreate another instance with the same options. If the identical MCPClient instance is already closed at the time
3. If you only need one instance of MCPClient in your app, refactor your code so it's only created one time (ex. move it out of a loop into a higher scope code block)

What it means

MCPClient keeps a registry (mcpClientInstances) keyed by an id derived from its configuration. Constructing a second MCPClient with identical options and no explicit id would leak the first instance's connections, so the constructor throws this plain Error with the three documented remedies. It is a guard against duplicate long-lived clients (duplicated transports, toolsets, and event handlers).

Source

Thrown at packages/mcp/src/client/configuration.ts:175

      this.id = args.id;
      const cached = mcpClientInstances.get(this.id);

      if (cached && !equal(cached.serverConfigs, args.servers)) {
        const existingInstance = mcpClientInstances.get(this.id);
        if (existingInstance) {
          void existingInstance.disconnect();
          mcpClientInstances.delete(this.id);
        }
      }
    } else {
      this.id = this.makeId();
    }

    // to prevent memory leaks return the same MCP server instance when configured the same way multiple times
    const existingInstance = mcpClientInstances.get(this.id);
    if (existingInstance) {
      if (!args.id) {
        throw new Error(`MCPClient was initialized multiple times with the same configuration options.

This error is intended to prevent memory leaks.

To fix this you have three different options:
1. If you need multiple MCPClient class instances with identical server configurations, set an id when configuring: new MCPClient({ id: "my-unique-id" })
2. Call "await client.disconnect()" after you're done using the client and before you recreate another instance with the same options. If the identical MCPClient instance is already closed at the time of re-creating it, you will not see this error.
3. If you only need one instance of MCPClient in your app, refactor your code so it's only created one time (ex. move it out of a loop into a higher scope code block)
`);
      }
      return existingInstance;
    }

    mcpClientInstances.set(this.id, this);
    this.addToInstanceCache();
    return this;
  }

  /**

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Add a stable explicit id: new MCPClient({ id: 'my-unique-id', ... }) so identical configurations reuse the same registered instance.
  2. Call await client.disconnect() when done, before creating another instance with the same options.
  3. Refactor to a singleton: create the client once at a higher scope (module level / app init) instead of per request, loop iteration, or render.
  4. In dev/HMR, guard construction with a global singleton (e.g. globalThis.__mcpClient ??= new MCPClient(...)).

Example fix

// before: per-request construction duplicates the client
async function handler() {
  const mcp = new MCPClient({ servers: { filesystem: { command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/data'] } } });
  return mcp.getTools();
}
// after: ided singleton
const mcp = new MCPClient({ id: 'fs-tools', servers: { filesystem: { command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/data'] } } });
async function handler() {
  return mcp.getTools();
}
Defensive patterns

Strategy: validation

Validate before calling

// Check whether an identical instance is already registered before constructing
const id = 'fs-tools';
// MCPClient dedupes instances by explicit id, so always pass one:
const mcp = globalThis.__mcpClient ?? (globalThis.__mcpClient = new MCPClient({ id, servers: {...} }));

Type guard

function hasExplicitId(opts: ConstructorParameters<typeof MCPClient>[0]): boolean {
  return typeof (opts as { id?: string }).id === 'string' && (opts as { id?: string }).id!.length > 0;
}

Try / catch

let mcp: MCPClient;
try {
  mcp = new MCPClient({ servers: {...} });
} catch (e) {
  if (e instanceof Error && e.message.includes('initialized multiple times')) {
    mcp = MCPClient.getInstance?.() ?? new MCPClient({ id: 'shared-client', servers: {...} });
  } else throw e;
}

Prevention

When it happens

Trigger: Calling new MCPClient({...same servers/options...}) twice (or more) while the first instance is still connected and no explicit id was supplied — commonly inside loops, React render/effect bodies, serverless cold-start handlers, or module-level accidental double-imports.

Common situations: Creating the client inside a request handler or component render; dev-mode double evaluation (HMR) of a module that constructs the client at top level; serverless functions constructing per invocation without disconnect; copy-pasting client setup in two files both executed.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/84b7f210445eb0b9. Report an issue: GitHub.