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
- Check the transport config `type` value: it must be exactly 'stdio', 'sse', or 'http' (case-sensitive).
- 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.
- Don't pass transports from `@modelcontextprotocol/sdk`; wrap them in an adapter implementing the AI SDK MCPTransport interface.
- Log/inspect the config object right before constructing DefaultMCPClient to catch undefined/misspelled fields.
- 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
- Type the transport config with the SDK's union type so TS catches invalid `type` values at compile time.
- Only use 'stdio' | 'sse' | 'http' as type strings — check current docs for exact names.
- Wrap foreign transports (e.g. @modelcontextprotocol/sdk) in an adapter implementing the AI SDK MCPTransport interface.
- Unit-test client construction with each config variant you ship.
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
- ACP MCP server name "ai-sdk-harness-tools" is reserved for H
- ACP MCP server name "ai-sdk-harness-tools" is reserved for H
- ACP MCP server ${JSON.stringify(name)} must be configured wi
- ACP-transport MCP servers require client-side mcp/connect ha
- Claude Code MCP server name "harness-tools" is reserved for
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/5c291ae04ffda2a3.
Report an issue: GitHub.