vercel/ai · error · MCPClientError

Unsupported or invalid transport configuration. If you are…

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.

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.

Appendix: 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)