From 380ee3eeb146ce73404e18aeeef57015cdfbf457 Mon Sep 17 00:00:00 2001 From: Assah Bismark Date: Mon, 23 Mar 2026 17:52:03 +0100 Subject: [PATCH] Add: support for `mcpServers` and `plugins` in provider options --- .../src/provider/Layers/ClaudeAdapter.test.ts | 68 +++++++++++++++++++ .../src/provider/Layers/ClaudeAdapter.ts | 6 ++ packages/contracts/src/orchestration.ts | 2 + 3 files changed, 76 insertions(+) diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.test.ts b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts index f60b2b1e90..0e2841b6b5 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.test.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts @@ -476,6 +476,74 @@ describe("ClaudeAdapterLive", () => { ); }); + it.effect("forwards mcpServers from providerOptions to query options", () => { + const harness = makeHarness(); + return Effect.gen(function* () { + const adapter = yield* ClaudeAdapter; + const mcpServers = { + filesystem: { + command: "npx", + args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"], + }, + }; + yield* adapter.startSession({ + threadId: THREAD_ID, + provider: "claudeAgent", + runtimeMode: "full-access", + providerOptions: { + claudeAgent: { mcpServers }, + }, + }); + + const createInput = harness.getLastCreateQueryInput(); + assert.deepStrictEqual(createInput?.options.mcpServers, mcpServers); + }).pipe( + Effect.provideService(Random.Random, makeDeterministicRandomService()), + Effect.provide(harness.layer), + ); + }); + + it.effect("forwards plugins from providerOptions to query options", () => { + const harness = makeHarness(); + return Effect.gen(function* () { + const adapter = yield* ClaudeAdapter; + const plugins = [{ type: "local" as const, path: "./my-plugin" }]; + yield* adapter.startSession({ + threadId: THREAD_ID, + provider: "claudeAgent", + runtimeMode: "full-access", + providerOptions: { + claudeAgent: { plugins }, + }, + }); + + const createInput = harness.getLastCreateQueryInput(); + assert.deepStrictEqual(createInput?.options.plugins, plugins); + }).pipe( + Effect.provideService(Random.Random, makeDeterministicRandomService()), + Effect.provide(harness.layer), + ); + }); + + it.effect("omits mcpServers and plugins when not provided", () => { + const harness = makeHarness(); + return Effect.gen(function* () { + const adapter = yield* ClaudeAdapter; + yield* adapter.startSession({ + threadId: THREAD_ID, + provider: "claudeAgent", + runtimeMode: "full-access", + }); + + const createInput = harness.getLastCreateQueryInput(); + assert.equal(createInput?.options.mcpServers, undefined); + assert.equal(createInput?.options.plugins, undefined); + }).pipe( + Effect.provideService(Random.Random, makeDeterministicRandomService()), + Effect.provide(harness.layer), + ); + }); + it.effect("treats ultrathink as a prompt keyword instead of a session effort", () => { const harness = makeHarness(); return Effect.gen(function* () { diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.ts b/apps/server/src/provider/Layers/ClaudeAdapter.ts index 6fbe6d43b1..a663a86107 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.ts @@ -2578,6 +2578,12 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) { env: process.env, ...(input.cwd ? { additionalDirectories: [input.cwd] } : {}), }; + if (providerOptions?.mcpServers) { + (queryOptions as Record).mcpServers = providerOptions.mcpServers; + } + if (providerOptions?.plugins) { + (queryOptions as Record).plugins = providerOptions.plugins; + } const queryRuntime = yield* Effect.try({ try: () => diff --git a/packages/contracts/src/orchestration.ts b/packages/contracts/src/orchestration.ts index 3208adc8bb..b31a2cc8fe 100644 --- a/packages/contracts/src/orchestration.ts +++ b/packages/contracts/src/orchestration.ts @@ -53,6 +53,8 @@ export const ClaudeProviderStartOptions = Schema.Struct({ binaryPath: Schema.optional(TrimmedNonEmptyString), permissionMode: Schema.optional(TrimmedNonEmptyString), maxThinkingTokens: Schema.optional(NonNegativeInt), + mcpServers: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), + plugins: Schema.optional(Schema.Array(Schema.Unknown)), }); export const ProviderStartOptions = Schema.Struct({