(input: {
transport: string;
createTransport: (sdk: McpClientSdk) => Parameters<Client["connect"]>[0];
versionNegotiation?: { readonly mode: "auto" };
})
| 393 | }); |
| 394 | |
| 395 | const connectClient = (input: { |
| 396 | transport: string; |
| 397 | createTransport: (sdk: McpClientSdk) => Parameters<Client["connect"]>[0]; |
| 398 | versionNegotiation?: { readonly mode: "auto" }; |
| 399 | }): Effect.Effect<McpConnection, McpConnectionError | McpOAuthReauthorizationRequired> => |
| 400 | Effect.gen(function* () { |
| 401 | const sdk = yield* Effect.tryPromise({ |
| 402 | try: () => loadMcpClientSdk(), |
| 403 | catch: () => |
| 404 | new McpConnectionError({ |
| 405 | transport: input.transport, |
| 406 | message: "Failed to load MCP client module", |
| 407 | }), |
| 408 | }); |
| 409 | const client = createClient(sdk, input.versionNegotiation); |
| 410 | const transportInstance = input.createTransport(sdk); |
| 411 | |
| 412 | yield* Effect.tryPromise({ |
| 413 | // Interruption (an HTTP 499 cancelling a health check, the discovery |
| 414 | // timeout) aborts this signal; the SDK then fails the in-flight |
| 415 | // handshake and closes the transport. Without it the abandoned connect |
| 416 | // kept the spawned stdio child alive forever; `docker run -i --rm` |
| 417 | // integrations stranded a container per interrupted dial (#1631). |
| 418 | try: (signal) => client.connect(transportInstance, { signal }), |
| 419 | catch: (cause) => |
| 420 | connectionFailure(input.transport, `Failed connecting via ${input.transport}`, cause), |
| 421 | }).pipe( |
| 422 | // The negotiated era ("modern" = 2026-07-28 server/discover, "legacy" = |
| 423 | // 2025 initialize) is otherwise invisible: both eras list and call tools |
| 424 | // identically, so traces are the one place an integration author can |
| 425 | // verify which handshake a connection actually used. |
| 426 | Effect.tap(() => |
| 427 | Effect.annotateCurrentSpan({ |
| 428 | "plugin.mcp.protocol_era": client.getProtocolEra() ?? "unknown", |
| 429 | }), |
| 430 | ), |
| 431 | Effect.withSpan("plugin.mcp.connection.handshake", { |
| 432 | attributes: { "plugin.mcp.transport": input.transport }, |
| 433 | }), |
| 434 | ); |
| 435 | |
| 436 | return connectionFromClient(client); |
| 437 | }); |
| 438 | |
| 439 | // --------------------------------------------------------------------------- |
| 440 | // Public factory |
no test coverage detected