vercel/ai · error · MCPClientError

Unsupported or invalid transport configuration. If you are u

Error message

Unsupported or invalid transport configuration. If you are using a custom transport, make sure it implements the MCPTransport interface.

What it means

createMcpTransport() is the factory that turns a user-supplied transport config into a concrete MCPTransport (stdio, SSE, or HTTP). When the config's type/discriminator is not one of the supported values (and the object is not already a valid MCPTransport instance), it throws MCPClientError. This guards against typos in the transport type and against passing an object that doesn't implement the MCPTransport interface.

Source

Thrown at packages/mcp/src/tool/mcp-transport.ts:190

   * Optional custom fetch implementation to use for HTTP requests.
   * Useful for runtimes that need a request-local fetch.
   * @default globalThis.fetch
   */
  fetch?: FetchFunction;
};

export function createMcpTransport(config: MCPTransportConfig): MCPTransport {
  switch (config.type) {
    case 'sse':
      return new SseMCPTransport(config);
    case 'http':
      return new HttpMCPTransport({
        ...config,
        initialProtocolVersion:
          config.initialProtocolVersion ?? LATEST_PROTOCOL_VERSION,
      });
    default:
      throw new MCPClientError({
        message:
          'Unsupported or invalid transport configuration. If you are using a custom transport, make sure it implements the MCPTransport interface.',
      });
  }
}

export function isCustomMcpTransport(
  transport: MCPTransportConfig | MCPTransport,
): transport is MCPTransport {
  return (
    'start' in transport &&
    typeof transport.start === 'function' &&
    'send' in transport &&
    typeof transport.send === 'function' &&
    'close' in transport &&
    typeof transport.close === 'function'
  );
}

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Check the transport config `type` value: it must be exactly 'stdio', 'sse', or 'http' (case-sensitive).
  2. If using a custom transport, make sure your class implements the full MCPTransport interface (start, send, close, and the onmessage/onerror/onclose callbacks setter) from packages/mcp/src/tool/mcp-transport.ts, and pass an instance of it directly.
  3. Don't pass transports from `@modelcontextprotocol/sdk`; wrap them in an adapter implementing the AI SDK MCPTransport interface.
  4. Log/inspect the config object right before constructing DefaultMCPClient to catch undefined/misspelled fields.
  5. Update @ai-sdk/mcp if the config keys changed between versions and check the changelog for the current transport config union.

Example fix

// before: typo'd type -> factory falls to default branch
const client = new DefaultMCPClient({ transport: { type: 'streamable-http', url: 'https://mcp.example.com' } });
// after: use a supported type
const client = new DefaultMCPClient({ transport: { type: 'http', url: 'https://mcp.example.com' } });
// custom transport: pass an MCPTransport instance
const client2 = new DefaultMCPClient({ transport: new MyMCPTransport() });
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = new Set(['stdio', 'sse', 'http']);
export function assertValidTransportConfig(config: unknown): void {
  if (config == null || typeof config !== 'object') {
    throw new TypeError('transport config must be an object');
  }
  const cfg = config as { type?: unknown };
  if ('type' in cfg && !SUPPORTED.has(String(cfg.type))) {
    throw new TypeError(`Unsupported transport type: ${String(cfg.type)}. Use stdio, sse, or http.`);
  }
}
// call before: new DefaultMCPClient({ transport: cfg })

Type guard

export function isMCPTransport(x: unknown): x is MCPTransport {
  return (
    typeof x === 'object' && x !== null &&
    typeof (x as MCPTransport).start === 'function' &&
    typeof (x as MCPTransport).send === 'function' &&
    typeof (x as MCPTransport).close === 'function'
  );
}

Try / catch

try {
  const client = new DefaultMCPClient({ transport: config });
} catch (error) {
  if (MCPClientError.isInstance(error) && error.message.startsWith('Unsupported or invalid transport configuration')) {
    console.error('Bad MCP transport config:', JSON.stringify(config));
  } else {
    throw error;
  }
}

Prevention

When it happens

Trigger: Passing `{ type: 'websocket' }` or any type other than 'stdio' | 'sse' | 'http' to the DefaultMCPClient constructor; passing a malformed config object that is neither a known config nor a class implementing MCPTransport; passing null/undefined or a plain object where an MCPTransport instance is expected; constructing a client with an object from a different/older library version whose config shape no longer matches.

Common situations: Typo like `type: 'streamable-http'` or `'streamableHttp'` when the SDK expects 'http'; copying config from older MCP SDK docs where the type names differ; passing a custom transport class instance that forgot to implement one of the MCPTransport methods so the duck-typing check fails; mixing `@modelcontextprotocol/sdk` transports with AI SDK MCP client expecting its own MCPTransport interface.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/5c291ae04ffda2a3. Report an issue: GitHub.