diff --git a/packages/protocol/src/agent-types.ts b/packages/protocol/src/agent-types.ts index 7a1f9c04b..e0728f592 100644 --- a/packages/protocol/src/agent-types.ts +++ b/packages/protocol/src/agent-types.ts @@ -14,6 +14,11 @@ export interface McpStdioServerConfig { command: string; args?: string[]; env?: Record; + /** + * When true, all tools from this server are always included in the prompt + * and never deferred behind tool search. Honored by the Claude provider. + */ + alwaysLoad?: boolean; } /** @@ -23,6 +28,11 @@ export interface McpHttpServerConfig { type: "http"; url: string; headers?: Record; + /** + * When true, all tools from this server are always included in the prompt + * and never deferred behind tool search. Honored by the Claude provider. + */ + alwaysLoad?: boolean; } /** @@ -32,6 +42,11 @@ export interface McpSseServerConfig { type: "sse"; url: string; headers?: Record; + /** + * When true, all tools from this server are always included in the prompt + * and never deferred behind tool search. Honored by the Claude provider. + */ + alwaysLoad?: boolean; } /** diff --git a/packages/protocol/src/messages.ts b/packages/protocol/src/messages.ts index b6124749e..0756754ff 100644 --- a/packages/protocol/src/messages.ts +++ b/packages/protocol/src/messages.ts @@ -266,18 +266,21 @@ const McpStdioServerConfigSchema = z.object({ command: z.string(), args: z.array(z.string()).optional(), env: z.record(z.string()).optional(), + alwaysLoad: z.boolean().optional(), }); const McpHttpServerConfigSchema = z.object({ type: z.literal("http"), url: z.string(), headers: z.record(z.string()).optional(), + alwaysLoad: z.boolean().optional(), }); const McpSseServerConfigSchema = z.object({ type: z.literal("sse"), url: z.string(), headers: z.record(z.string()).optional(), + alwaysLoad: z.boolean().optional(), }); const McpServerConfigSchema = z.discriminatedUnion("type", [ diff --git a/packages/server/src/server/agent/agent-sdk-types.ts b/packages/server/src/server/agent/agent-sdk-types.ts index 9e1f69447..93d92be51 100644 --- a/packages/server/src/server/agent/agent-sdk-types.ts +++ b/packages/server/src/server/agent/agent-sdk-types.ts @@ -15,6 +15,11 @@ export interface McpStdioServerConfig { command: string; args?: string[]; env?: Record; + /** + * When true, all tools from this server are always included in the prompt + * and never deferred behind tool search. Honored by the Claude provider. + */ + alwaysLoad?: boolean; } /** @@ -24,6 +29,11 @@ export interface McpHttpServerConfig { type: "http"; url: string; headers?: Record; + /** + * When true, all tools from this server are always included in the prompt + * and never deferred behind tool search. Honored by the Claude provider. + */ + alwaysLoad?: boolean; } /** @@ -33,6 +43,11 @@ export interface McpSseServerConfig { type: "sse"; url: string; headers?: Record; + /** + * When true, all tools from this server are always included in the prompt + * and never deferred behind tool search. Honored by the Claude provider. + */ + alwaysLoad?: boolean; } /** diff --git a/packages/server/src/server/agent/providers/claude/agent.test.ts b/packages/server/src/server/agent/providers/claude/agent.test.ts index 382885e8e..6264a0ad2 100644 --- a/packages/server/src/server/agent/providers/claude/agent.test.ts +++ b/packages/server/src/server/agent/providers/claude/agent.test.ts @@ -10,6 +10,7 @@ import { ClaudeAgentClient, convertClaudeHistoryEntry, normalizeClaudeAskUserQuestionUpdatedInput, + toClaudeSdkMcpConfig, } from "./agent.js"; import type { AgentTimelineItem, AgentUsage, AgentStreamEvent } from "../../agent-sdk-types.js"; @@ -1674,3 +1675,63 @@ describe("ClaudeAgentSession context window usage", () => { ]); }); }); + +describe("toClaudeSdkMcpConfig", () => { + test("preserves alwaysLoad on stdio servers", () => { + expect( + toClaudeSdkMcpConfig({ + type: "stdio", + command: "npx", + args: ["-y", "chrome-devtools-mcp@latest"], + alwaysLoad: true, + }), + ).toEqual({ + type: "stdio", + command: "npx", + args: ["-y", "chrome-devtools-mcp@latest"], + env: undefined, + alwaysLoad: true, + }); + }); + + test("preserves alwaysLoad on http servers", () => { + expect( + toClaudeSdkMcpConfig({ + type: "http", + url: "https://example.com/mcp", + headers: { Authorization: "Bearer x" }, + alwaysLoad: true, + }), + ).toEqual({ + type: "http", + url: "https://example.com/mcp", + headers: { Authorization: "Bearer x" }, + alwaysLoad: true, + }); + }); + + test("preserves alwaysLoad on sse servers", () => { + expect( + toClaudeSdkMcpConfig({ + type: "sse", + url: "https://example.com/sse", + alwaysLoad: true, + }), + ).toEqual({ + type: "sse", + url: "https://example.com/sse", + headers: undefined, + alwaysLoad: true, + }); + }); + + test("leaves alwaysLoad undefined when not provided (preserves default deferral)", () => { + const result = toClaudeSdkMcpConfig({ + type: "stdio", + command: "uvx", + args: ["markitdown-mcp"], + }); + expect(result.type).toBe("stdio"); + expect(result.alwaysLoad).toBeUndefined(); + }); +}); diff --git a/packages/server/src/server/agent/providers/claude/agent.ts b/packages/server/src/server/agent/providers/claude/agent.ts index 60bbf0ee5..852471e42 100644 --- a/packages/server/src/server/agent/providers/claude/agent.ts +++ b/packages/server/src/server/agent/providers/claude/agent.ts @@ -800,7 +800,7 @@ function coerceSessionMetadata(metadata: AgentMetadata | undefined): Partial