(input: {
transport: string;
createTransport: (sdk: McpClientSdk) => Parameters<Client["connect"]>[0];
versionNegotiation?: { readonly mode: "auto" };
})
| 500 | }); |
| 501 | |
| 502 | const connectClient = (input: { |
| 503 | transport: string; |
| 504 | createTransport: (sdk: McpClientSdk) => Parameters<Client["connect"]>[0]; |
| 505 | versionNegotiation?: { readonly mode: "auto" }; |
| 506 | }): Effect.Effect<McpConnection, McpConnectionError | McpOAuthReauthorizationRequired> => |
| 507 | Effect.gen(function* () { |
| 508 | const sdk = yield* Effect.tryPromise({ |
| 509 | try: () => loadMcpClientSdk(), |
| 510 | catch: () => |
| 511 | new McpConnectionError({ |
| 512 | transport: input.transport, |
| 513 | message: "Failed to load MCP client module", |
| 514 | }), |
| 515 | }); |
| 516 | const client = createClient(sdk, input.versionNegotiation); |
| 517 | const transportInstance = input.createTransport(sdk); |
| 518 | |
| 519 | yield* Effect.tryPromise({ |
| 520 | // Interruption (an HTTP 499 cancelling a health check, the discovery |
| 521 | // timeout) aborts this signal; the SDK then fails the in-flight |
| 522 | // handshake and closes the transport. Without it the abandoned connect |
| 523 | // kept the spawned stdio child alive forever; `docker run -i --rm` |
| 524 | // integrations stranded a container per interrupted dial (#1631). |
| 525 | try: (signal) => client.connect(transportInstance, { signal }), |
| 526 | catch: (cause) => |
| 527 | connectionFailure(input.transport, `Failed connecting via ${input.transport}`, cause), |
| 528 | }).pipe( |
| 529 | // The negotiated era ("modern" = 2026-07-28 server/discover, "legacy" = |
| 530 | // 2025 initialize) is otherwise invisible: both eras list and call tools |
| 531 | // identically, so traces are the one place an integration author can |
| 532 | // verify which handshake a connection actually used. |
| 533 | Effect.tap(() => |
| 534 | Effect.annotateCurrentSpan({ |
| 535 | "plugin.mcp.protocol_era": client.getProtocolEra() ?? "unknown", |
| 536 | }), |
| 537 | ), |
| 538 | Effect.withSpan("plugin.mcp.connection.handshake", { |
| 539 | attributes: { "plugin.mcp.transport": input.transport }, |
| 540 | }), |
| 541 | ); |
| 542 | |
| 543 | return connectionFromClient(client); |
| 544 | }); |
| 545 | |
| 546 | // --------------------------------------------------------------------------- |
| 547 | // Public factory |
no test coverage detected