vercel/ai · error · MCPClientError
MCP HTTP Transport Error: Transport already started. Note: c
Error message
MCP HTTP Transport Error: Transport already started. Note: client.connect() calls start() automatically.
What it means
HttpMCPTransport.start() guards against double-start by checking its internal AbortController; a second start() call throws MCPClientError. The message notes that client.connect() already calls start() for you, so manually invoking start() after connect() is the typical cause.
Source
Thrown at packages/mcp/src/tool/mcp-http-transport.ts:219
}
if (!this.authPromise) {
this.authPromise = auth(this.authProvider, {
serverUrl: this.url,
resourceMetadataUrl,
scope,
fetchFn: this.fetchFn,
}).finally(() => {
this.authPromise = undefined;
});
}
return this.authPromise;
}
async start(): Promise<void> {
if (this.abortController) {
throw new MCPClientError({
message:
'MCP HTTP Transport Error: Transport already started. Note: client.connect() calls start() automatically.',
});
}
this.abortController = new AbortController();
if (
this.protocolVersion != null &&
this.protocolVersion !== LATEST_PROTOCOL_VERSION
) {
this.startInboundSse();
}
}
async close(options?: { signal?: AbortSignal }): Promise<void> {
this.inboundSseConnection?.close();
this.abortController?.abort();
View on GitHub (pinned to 69428b1f8b)
Solutions
- Do not call start() manually — just use client.connect(), which starts the transport
- Create a new HttpMCPTransport (or new client) for each connection attempt; never reuse a started transport
- Ensure each client gets its own transport instance
Example fix
// before
const client = await createMCPClient({ transport });
await transport.start(); // throws
// after
const client = await createMCPClient({ transport }); // connect() calls start() internally Defensive patterns
Strategy: try-catch
Validate before calling
// track start state yourself if you manage the transport manually
let started = false;
async function ensureStarted(transport) {
if (!started) { await transport.start(); started = true; }
} Try / catch
try {
await client.connect(); // do NOT call transport.start() yourself
} catch (error) {
if (MCPClientError.isInstance(error) && error.message.includes('Transport already started')) {
// reuse the existing connection instead of starting again
} else throw error;
} Prevention
- Rely solely on client.connect(); never call transport.start() manually
- Create a new transport per client and per reconnect attempt
- Never share a single transport instance between multiple clients
When it happens
Trigger: Calling transport.start() explicitly after (or while) client.connect() is running; sharing one transport instance between two clients; retrying connect() on the same transport instance after a failed connection attempt without creating a new transport.
Common situations: Following low-level transport examples (which call start() manually) together with the higher-level createMCPClient/connect flow; retry loops that reuse the transport object; dependency injection wiring the same transport into multiple clients.
Related errors
- StdioMCPTransport already started.
- Invalid argument for parameter requests: requests must not b
- Invalid argument for parameter requests: request IDs must no
- Invalid argument for parameter requests: request IDs must be
- Invalid argument for parameter batch: batch must be a suppor
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/3b53b25ebec4a0dc.
Report an issue: GitHub.