can1357/oh-my-pi · error · MCPTransportError
Transport not connected
Error message
Transport not connected
What it means
request() was called on the HTTP MCP transport before connect() completed or after the transport was disconnected. The transport guards every JSON-RPC execution with a #connected flag and throws this MCPTransportError (stage: connect, failure: closed, retryable: true).
Source
Thrown at packages/coding-agent/src/mcp/transports/http.ts:425
if (!(error instanceof SSEResumeError) && this.onAuthError && (status === 401 || status === 403)) {
const newHeaders = await this.onAuthError();
if (newHeaders) {
// Persist refreshed headers so subsequent requests use them directly
this.config = { ...this.config, headers: newHeaders };
return this.#executeRequest<T>(method, params, options);
}
}
throw error;
}
}
async #executeRequest<T>(
method: string,
params: Record<string, unknown> | undefined,
options: MCPRequestOptions | undefined,
): Promise<T> {
if (!this.#connected) {
throw new MCPTransportError({
transport: "http",
stage: "connect",
failure: "closed",
message: "Transport not connected",
retryable: true,
});
}
const id = this.#requestIds.next(this.config.requestIdFormat);
const body = {
jsonrpc: "2.0" as const,
id,
method,
params: params ?? {},
};
const generated: Record<string, string> = {
"Content-Type": "application/json",View on GitHub (pinned to 9690622007)
Solutions
- Await transport.connect() before issuing any request() calls
- Check the connected state (or listen for onClose) before enqueueing requests; queue or re-create the transport when disconnected
- Retry with a fresh connect — the error is marked retryable
- Fix lifecycle races: ensure teardown (close) completes before dropping references, and don't share one transport across async contexts without a ready-gate
Example fix
// before
transport.request("tools/call", { name: "search" }); // may throw if not connected
// after
if (!transport.isConnected()) await transport.connect();
await transport.request("tools/call", { name: "search" }); Defensive patterns
Strategy: validation
Validate before calling
// Gate all requests on a ready promise established at setup:
const ready = transport.connect();
async function safeRequest<T>(m: string, p?: Record<string, unknown>) {
await ready;
return transport.request<T>(m, p);
} Try / catch
try {
await transport.request("tools/list");
} catch (err) {
if (err instanceof MCPTransportError && err.failure === "closed" && err.stage === "connect") {
await transport.connect();
await transport.request("tools/list");
} else throw err;
} Prevention
- Always await connect() before the first request
- Subscribe to onClose and pause/queue requests until reconnected
- Serialize lifecycle: no requests during close/reconnect windows
- Check connectivity state in request wrapper helpers
When it happens
Trigger: Calling transport.request(...) without a prior successful connect(); after close(); after the SSE listener detected a fatal stream end and fired onClose while requests are still in flight.
Common situations: Application code racing a slow connect (calling tools before initialization resolves); reusing a transport singleton after teardown; a reconnect cycle dropping requests submitted in the gap.
Related errors
- MCP server not connected: ${name}
- Daemon broker client is closed
- Live transport is not connected
- Unknown server type: ${serverType}
- Server "${name}" was disconnected during initial connection
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/a6da1ca99e1ab79a.
Report an issue: GitHub.