perf(core): load MCP client lazily (#42468)

This commit is contained in:
Kit Langton
2026-08-13 22:48:09 -04:00
committed by GitHub
parent 49d07ffe5f
commit fec4f20736
2 changed files with 52 additions and 3 deletions
+8 -3
View File
@@ -19,8 +19,7 @@ import { KeyedMutex } from "../effect/keyed-mutex.js"
import { Location } from "../location.js"
import { waitForAbort } from "@opencode-ai/util/process"
import { State } from "../state.js"
import { MCPClient } from "./client.js"
import { MCPOAuth } from "./oauth.js"
import type { MCPClient } from "./client.js"
export const ServerName = Schema.String.pipe(Schema.brand("MCP.ServerName"))
export type ServerName = typeof ServerName.Type
@@ -245,7 +244,11 @@ export const layer = (options?: Options) =>
draft.method.update({
integrationID,
method: { id: methodID, type: "oauth", label: name },
authorize: () => MCPOAuth.authorize({ name, config: remote, methodID }),
authorize: () =>
Effect.gen(function* () {
const { MCPOAuth } = yield* Effect.promise(() => import("./oauth.js"))
return yield* MCPOAuth.authorize({ name, config: remote, methodID })
}),
})
})
.pipe(Scope.provide(scope))
@@ -264,6 +267,7 @@ export const layer = (options?: Options) =>
// opens a browser, so an auth-gated connect ends in UnauthorizedError -> needs_auth rather than a redirect.
const connectProvider = Effect.fnUntraced(function* (entry: ServerEntry) {
if (entry.config.type !== "remote" || !entry.integrationID) return undefined
const { MCPOAuth } = yield* Effect.promise(() => import("./oauth.js"))
const remote = entry.config
const oauth = remote.oauth || undefined
const base = {
@@ -505,6 +509,7 @@ export const layer = (options?: Options) =>
const scope = yield* Scope.fork(root)
entry.scope = scope
const authProvider = yield* connectProvider(entry)
const { MCPClient } = yield* Effect.promise(() => import("./client.js"))
// List tools as part of connect so a failure here marks the server failed rather than
// leaving it connected with a silently empty tool list and no path to recover.
const result = yield* MCPClient.connect(
@@ -0,0 +1,44 @@
import { expect, test } from "bun:test"
import { mkdtemp, rm } from "node:fs/promises"
import path from "node:path"
const root = path.resolve(import.meta.dir, "../../..")
test("loads the MCP SDK only when connecting or authorizing", async () => {
const temporary = await mkdtemp(path.join(import.meta.dir, ".mcp-import-boundary-"))
const metafile = path.join(temporary, "meta.json")
try {
const result = Bun.spawn(
[
process.execPath,
"build",
"packages/core/src/mcp/index.ts",
"--target=node",
"--format=esm",
"--packages=bundle",
"--splitting",
`--metafile=${metafile}`,
`--outdir=${path.join(temporary, "out")}`,
],
{ cwd: root, stdout: "pipe", stderr: "pipe" },
)
const [exitCode, stdout, stderr] = await Promise.all([
result.exited,
new Response(result.stdout).text(),
new Response(result.stderr).text(),
])
if (exitCode !== 0) throw new Error(stdout + stderr)
const metadata = await Bun.file(metafile).json()
const imports = metadata.inputs["packages/core/src/mcp/index.ts"].imports
const lazy = imports.filter(
(item: { original?: string }) => item.original === "./client.js" || item.original === "./oauth.js",
)
expect(new Set(lazy.map((item: { original: string }) => item.original))).toEqual(
new Set(["./client.js", "./oauth.js"]),
)
expect(lazy.every((item: { kind: string }) => item.kind === "dynamic-import")).toBe(true)
} finally {
await rm(temporary, { recursive: true, force: true })
}
})