diff --git a/docs/features/mcp.md b/docs/features/mcp.md index d16666501..d8af04533 100644 --- a/docs/features/mcp.md +++ b/docs/features/mcp.md @@ -113,15 +113,13 @@ func main() { } defer client.Stop() - // MCPServerConfig is map[string]any for flexibility session, err := client.CreateSession(ctx, &copilot.SessionConfig{ Model: "gpt-5", MCPServers: map[string]copilot.MCPServerConfig{ - "my-local-server": { - "type": "local", - "command": "node", - "args": []string{"./mcp-server.js"}, - "tools": []string{"*"}, + "my-local-server": copilot.MCPStdioServerConfig{ + Command: "node", + Args: []string{"./mcp-server.js"}, + Tools: []string{"*"}, }, }, }) @@ -143,11 +141,10 @@ await using var client = new CopilotClient(); await using var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-5", - McpServers = new Dictionary + McpServers = new Dictionary { - ["my-local-server"] = new McpLocalServerConfig + ["my-local-server"] = new McpStdioServerConfig { - Type = "local", Command = "node", Args = new List { "./mcp-server.js" }, Tools = new List { "*" }, diff --git a/docs/troubleshooting/mcp-debugging.md b/docs/troubleshooting/mcp-debugging.md index 30e05fd3e..d7b455ecf 100644 --- a/docs/troubleshooting/mcp-debugging.md +++ b/docs/troubleshooting/mcp-debugging.md @@ -250,19 +250,17 @@ public static class McpDotnetConfigExample { public static void Main() { - var servers = new Dictionary + var servers = new Dictionary { - ["my-dotnet-server"] = new McpLocalServerConfig + ["my-dotnet-server"] = new McpStdioServerConfig { - Type = "local", Command = @"C:\Tools\MyServer\MyServer.exe", Args = new List(), Cwd = @"C:\Tools\MyServer", Tools = new List { "*" }, }, - ["my-dotnet-tool"] = new McpLocalServerConfig + ["my-dotnet-tool"] = new McpStdioServerConfig { - Type = "local", Command = "dotnet", Args = new List { @"C:\Tools\MyTool\MyTool.dll" }, Cwd = @"C:\Tools\MyTool", @@ -275,9 +273,8 @@ public static class McpDotnetConfigExample ```csharp // Correct configuration for .NET exe -["my-dotnet-server"] = new McpLocalServerConfig +["my-dotnet-server"] = new McpStdioServerConfig { - Type = "local", Command = @"C:\Tools\MyServer\MyServer.exe", // Full path with .exe Args = new List(), Cwd = @"C:\Tools\MyServer", // Set working directory @@ -285,9 +282,8 @@ public static class McpDotnetConfigExample } // For dotnet tool (DLL) -["my-dotnet-tool"] = new McpLocalServerConfig +["my-dotnet-tool"] = new McpStdioServerConfig { - Type = "local", Command = "dotnet", Args = new List { @"C:\Tools\MyTool\MyTool.dll" }, Cwd = @"C:\Tools\MyTool", @@ -305,11 +301,10 @@ public static class McpNpxConfigExample { public static void Main() { - var servers = new Dictionary + var servers = new Dictionary { - ["filesystem"] = new McpLocalServerConfig + ["filesystem"] = new McpStdioServerConfig { - Type = "local", Command = "cmd", Args = new List { "/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "C:\\allowed\\path" }, Tools = new List { "*" }, @@ -321,9 +316,8 @@ public static class McpNpxConfigExample ```csharp // Windows needs cmd /c for npx -["filesystem"] = new McpLocalServerConfig +["filesystem"] = new McpStdioServerConfig { - Type = "local", Command = "cmd", Args = new List { "/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "C:\\allowed\\path" }, Tools = new List { "*" }, @@ -357,9 +351,9 @@ xattr -d com.apple.quarantine /path/to/mcp-server ```typescript -import { MCPLocalServerConfig } from "@github/copilot-sdk"; +import { MCPStdioServerConfig } from "@github/copilot-sdk"; -const mcpServers: Record = { +const mcpServers: Record = { "my-server": { command: "/opt/homebrew/bin/node", args: ["/path/to/server.js"], diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs index aad44e4eb..4c228e112 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -1637,7 +1637,7 @@ internal record CreateSessionRequest( bool? Hooks, string? WorkingDirectory, bool? Streaming, - Dictionary? McpServers, + Dictionary? McpServers, string? EnvValueMode, List? CustomAgents, string? Agent, @@ -1692,7 +1692,7 @@ internal record ResumeSessionRequest( bool? EnableConfigDiscovery, bool? DisableResume, bool? Streaming, - Dictionary? McpServers, + Dictionary? McpServers, string? EnvValueMode, List? CustomAgents, string? Agent, diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index d8262e140..3e6ecf2c7 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -1413,10 +1413,17 @@ public class AzureOptions // ============================================================================ /// -/// Configuration for a local/stdio MCP server. +/// Abstract base class for MCP server configurations. /// -public class McpLocalServerConfig +[JsonPolymorphic( + TypeDiscriminatorPropertyName = "type", + IgnoreUnrecognizedTypeDiscriminators = true)] +[JsonDerivedType(typeof(McpStdioServerConfig), "stdio")] +[JsonDerivedType(typeof(McpHttpServerConfig), "http")] +public abstract class McpServerConfig { + private protected McpServerConfig() { } + /// /// List of tools to include from this server. Empty list means none. Use "*" for all. /// @@ -1424,16 +1431,26 @@ public class McpLocalServerConfig public List Tools { get; set; } = []; /// - /// Server type. Defaults to "local". + /// The server type discriminator. /// - [JsonPropertyName("type")] - public string? Type { get; set; } + [JsonIgnore] + public virtual string Type => "unknown"; /// /// Optional timeout in milliseconds for tool calls to this server. /// [JsonPropertyName("timeout")] public int? Timeout { get; set; } +} + +/// +/// Configuration for a local/stdio MCP server. +/// +public sealed class McpStdioServerConfig : McpServerConfig +{ + /// + [JsonIgnore] + public override string Type => "stdio"; /// /// Command to run the MCP server. @@ -1463,25 +1480,11 @@ public class McpLocalServerConfig /// /// Configuration for a remote MCP server (HTTP or SSE). /// -public class McpRemoteServerConfig +public sealed class McpHttpServerConfig : McpServerConfig { - /// - /// List of tools to include from this server. Empty list means none. Use "*" for all. - /// - [JsonPropertyName("tools")] - public List Tools { get; set; } = []; - - /// - /// Server type. Must be "http" or "sse". - /// - [JsonPropertyName("type")] - public string Type { get; set; } = "http"; - - /// - /// Optional timeout in milliseconds for tool calls to this server. - /// - [JsonPropertyName("timeout")] - public int? Timeout { get; set; } + /// + [JsonIgnore] + public override string Type => "http"; /// /// URL of the remote server. @@ -1539,7 +1542,7 @@ public class CustomAgentConfig /// MCP servers specific to this agent. /// [JsonPropertyName("mcpServers")] - public Dictionary? McpServers { get; set; } + public Dictionary? McpServers { get; set; } /// /// Whether the agent should be available for model inference. @@ -1608,7 +1611,7 @@ protected SessionConfig(SessionConfig? other) Hooks = other.Hooks; InfiniteSessions = other.InfiniteSessions; McpServers = other.McpServers is not null - ? new Dictionary(other.McpServers, other.McpServers.Comparer) + ? new Dictionary(other.McpServers, other.McpServers.Comparer) : null; Model = other.Model; ModelCapabilities = other.ModelCapabilities; @@ -1740,9 +1743,9 @@ protected SessionConfig(SessionConfig? other) /// /// MCP server configurations for the session. - /// Keys are server names, values are server configurations (McpLocalServerConfig or McpRemoteServerConfig). + /// Keys are server names, values are server configurations ( or ). /// - public Dictionary? McpServers { get; set; } + public Dictionary? McpServers { get; set; } /// /// Custom agent configurations for the session. @@ -1836,7 +1839,7 @@ protected ResumeSessionConfig(ResumeSessionConfig? other) Hooks = other.Hooks; InfiniteSessions = other.InfiniteSessions; McpServers = other.McpServers is not null - ? new Dictionary(other.McpServers, other.McpServers.Comparer) + ? new Dictionary(other.McpServers, other.McpServers.Comparer) : null; Model = other.Model; ModelCapabilities = other.ModelCapabilities; @@ -1972,9 +1975,9 @@ protected ResumeSessionConfig(ResumeSessionConfig? other) /// /// MCP server configurations for the session. - /// Keys are server names, values are server configurations (McpLocalServerConfig or McpRemoteServerConfig). + /// Keys are server names, values are server configurations ( or ). /// - public Dictionary? McpServers { get; set; } + public Dictionary? McpServers { get; set; } /// /// Custom agent configurations for the session. @@ -2519,8 +2522,7 @@ public class SystemMessageTransformRpcResponse [JsonSerializable(typeof(GetForegroundSessionResponse))] [JsonSerializable(typeof(GetModelsResponse))] [JsonSerializable(typeof(GetStatusResponse))] -[JsonSerializable(typeof(McpLocalServerConfig))] -[JsonSerializable(typeof(McpRemoteServerConfig))] +[JsonSerializable(typeof(McpServerConfig))] [JsonSerializable(typeof(MessageOptions))] [JsonSerializable(typeof(ModelBilling))] [JsonSerializable(typeof(ModelCapabilities))] diff --git a/dotnet/test/CloneTests.cs b/dotnet/test/CloneTests.cs index a0051ffbc..dcde71f99 100644 --- a/dotnet/test/CloneTests.cs +++ b/dotnet/test/CloneTests.cs @@ -86,7 +86,7 @@ public void SessionConfig_Clone_CopiesAllProperties() ExcludedTools = ["tool3"], WorkingDirectory = "/workspace", Streaming = true, - McpServers = new Dictionary { ["server1"] = new object() }, + McpServers = new Dictionary { ["server1"] = new McpStdioServerConfig { Command = "echo" } }, CustomAgents = [new CustomAgentConfig { Name = "agent1" }], Agent = "agent1", SkillDirectories = ["/skills"], @@ -118,7 +118,7 @@ public void SessionConfig_Clone_CollectionsAreIndependent() { AvailableTools = ["tool1"], ExcludedTools = ["tool2"], - McpServers = new Dictionary { ["s1"] = new object() }, + McpServers = new Dictionary { ["s1"] = new McpStdioServerConfig { Command = "echo" } }, CustomAgents = [new CustomAgentConfig { Name = "a1" }], SkillDirectories = ["/skills"], DisabledSkills = ["skill1"], @@ -129,7 +129,7 @@ public void SessionConfig_Clone_CollectionsAreIndependent() // Mutate clone collections clone.AvailableTools!.Add("tool99"); clone.ExcludedTools!.Add("tool99"); - clone.McpServers!["s2"] = new object(); + clone.McpServers!["s2"] = new McpStdioServerConfig { Command = "echo" }; clone.CustomAgents!.Add(new CustomAgentConfig { Name = "a2" }); clone.SkillDirectories!.Add("/more"); clone.DisabledSkills!.Add("skill99"); @@ -146,7 +146,7 @@ public void SessionConfig_Clone_CollectionsAreIndependent() [Fact] public void SessionConfig_Clone_PreservesMcpServersComparer() { - var servers = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["server"] = new object() }; + var servers = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["server"] = new McpStdioServerConfig { Command = "echo" } }; var original = new SessionConfig { McpServers = servers }; var clone = original.Clone(); @@ -161,7 +161,7 @@ public void ResumeSessionConfig_Clone_CollectionsAreIndependent() { AvailableTools = ["tool1"], ExcludedTools = ["tool2"], - McpServers = new Dictionary { ["s1"] = new object() }, + McpServers = new Dictionary { ["s1"] = new McpStdioServerConfig { Command = "echo" } }, CustomAgents = [new CustomAgentConfig { Name = "a1" }], SkillDirectories = ["/skills"], DisabledSkills = ["skill1"], @@ -172,7 +172,7 @@ public void ResumeSessionConfig_Clone_CollectionsAreIndependent() // Mutate clone collections clone.AvailableTools!.Add("tool99"); clone.ExcludedTools!.Add("tool99"); - clone.McpServers!["s2"] = new object(); + clone.McpServers!["s2"] = new McpStdioServerConfig { Command = "echo" }; clone.CustomAgents!.Add(new CustomAgentConfig { Name = "a2" }); clone.SkillDirectories!.Add("/more"); clone.DisabledSkills!.Add("skill99"); @@ -189,7 +189,7 @@ public void ResumeSessionConfig_Clone_CollectionsAreIndependent() [Fact] public void ResumeSessionConfig_Clone_PreservesMcpServersComparer() { - var servers = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["server"] = new object() }; + var servers = new Dictionary(StringComparer.OrdinalIgnoreCase) { ["server"] = new McpStdioServerConfig { Command = "echo" } }; var original = new ResumeSessionConfig { McpServers = servers }; var clone = original.Clone(); diff --git a/dotnet/test/McpAndAgentsTests.cs b/dotnet/test/McpAndAgentsTests.cs index 1d35ffda4..782b01123 100644 --- a/dotnet/test/McpAndAgentsTests.cs +++ b/dotnet/test/McpAndAgentsTests.cs @@ -13,11 +13,10 @@ public class McpAndAgentsTests(E2ETestFixture fixture, ITestOutputHelper output) [Fact] public async Task Should_Accept_MCP_Server_Configuration_On_Session_Create() { - var mcpServers = new Dictionary + var mcpServers = new Dictionary { - ["test-server"] = new McpLocalServerConfig + ["test-server"] = new McpStdioServerConfig { - Type = "local", Command = "echo", Args = ["hello"], Tools = ["*"] @@ -50,11 +49,10 @@ public async Task Should_Accept_MCP_Server_Configuration_On_Session_Resume() await session1.SendAndWaitAsync(new MessageOptions { Prompt = "What is 1+1?" }); // Resume with MCP servers - var mcpServers = new Dictionary + var mcpServers = new Dictionary { - ["test-server"] = new McpLocalServerConfig + ["test-server"] = new McpStdioServerConfig { - Type = "local", Command = "echo", Args = ["hello"], Tools = ["*"] @@ -78,18 +76,16 @@ public async Task Should_Accept_MCP_Server_Configuration_On_Session_Resume() [Fact] public async Task Should_Handle_Multiple_MCP_Servers() { - var mcpServers = new Dictionary + var mcpServers = new Dictionary { - ["server1"] = new McpLocalServerConfig + ["server1"] = new McpStdioServerConfig { - Type = "local", Command = "echo", Args = ["server1"], Tools = ["*"] }, - ["server2"] = new McpLocalServerConfig + ["server2"] = new McpStdioServerConfig { - Type = "local", Command = "echo", Args = ["server2"], Tools = ["*"] @@ -207,11 +203,10 @@ public async Task Should_Handle_Custom_Agent_With_MCP_Servers() DisplayName = "MCP Agent", Description = "An agent with its own MCP servers", Prompt = "You are an agent with MCP servers.", - McpServers = new Dictionary + McpServers = new Dictionary { - ["agent-server"] = new McpLocalServerConfig + ["agent-server"] = new McpStdioServerConfig { - Type = "local", Command = "echo", Args = ["agent-mcp"], Tools = ["*"] @@ -264,11 +259,10 @@ public async Task Should_Handle_Multiple_Custom_Agents() public async Task Should_Pass_Literal_Env_Values_To_Mcp_Server_Subprocess() { var testHarnessDir = FindTestHarnessDir(); - var mcpServers = new Dictionary + var mcpServers = new Dictionary { - ["env-echo"] = new McpLocalServerConfig + ["env-echo"] = new McpStdioServerConfig { - Type = "local", Command = "node", Args = [Path.Combine(testHarnessDir, "test-mcp-server.mjs")], Env = new Dictionary { ["TEST_SECRET"] = "hunter2" }, @@ -299,11 +293,10 @@ public async Task Should_Pass_Literal_Env_Values_To_Mcp_Server_Subprocess() [Fact] public async Task Should_Accept_Both_MCP_Servers_And_Custom_Agents() { - var mcpServers = new Dictionary + var mcpServers = new Dictionary { - ["shared-server"] = new McpLocalServerConfig + ["shared-server"] = new McpStdioServerConfig { - Type = "local", Command = "echo", Args = ["shared"], Tools = ["*"] diff --git a/go/internal/e2e/mcp_and_agents_test.go b/go/internal/e2e/mcp_and_agents_test.go index 7b7d4d037..e05f44585 100644 --- a/go/internal/e2e/mcp_and_agents_test.go +++ b/go/internal/e2e/mcp_and_agents_test.go @@ -18,11 +18,10 @@ func TestMCPServers(t *testing.T) { ctx.ConfigureForTest(t) mcpServers := map[string]copilot.MCPServerConfig{ - "test-server": { - "type": "local", - "command": "echo", - "args": []string{"hello"}, - "tools": []string{"*"}, + "test-server": copilot.MCPStdioServerConfig{ + Command: "echo", + Args: []string{"hello"}, + Tools: []string{"*"}, }, } @@ -75,11 +74,10 @@ func TestMCPServers(t *testing.T) { // Resume with MCP servers mcpServers := map[string]copilot.MCPServerConfig{ - "test-server": { - "type": "local", - "command": "echo", - "args": []string{"hello"}, - "tools": []string{"*"}, + "test-server": copilot.MCPStdioServerConfig{ + Command: "echo", + Args: []string{"hello"}, + Tools: []string{"*"}, }, } @@ -117,13 +115,12 @@ func TestMCPServers(t *testing.T) { mcpServerDir := filepath.Dir(mcpServerPath) mcpServers := map[string]copilot.MCPServerConfig{ - "env-echo": { - "type": "local", - "command": "node", - "args": []string{mcpServerPath}, - "tools": []string{"*"}, - "env": map[string]string{"TEST_SECRET": "hunter2"}, - "cwd": mcpServerDir, + "env-echo": copilot.MCPStdioServerConfig{ + Command: "node", + Args: []string{mcpServerPath}, + Tools: []string{"*"}, + Env: map[string]string{"TEST_SECRET": "hunter2"}, + Cwd: mcpServerDir, }, } @@ -157,17 +154,15 @@ func TestMCPServers(t *testing.T) { ctx.ConfigureForTest(t) mcpServers := map[string]copilot.MCPServerConfig{ - "server1": { - "type": "local", - "command": "echo", - "args": []string{"server1"}, - "tools": []string{"*"}, + "server1": copilot.MCPStdioServerConfig{ + Command: "echo", + Args: []string{"server1"}, + Tools: []string{"*"}, }, - "server2": { - "type": "local", - "command": "echo", - "args": []string{"server2"}, - "tools": []string{"*"}, + "server2": copilot.MCPStdioServerConfig{ + Command: "echo", + Args: []string{"server2"}, + Tools: []string{"*"}, }, } @@ -327,11 +322,10 @@ func TestCustomAgents(t *testing.T) { Description: "An agent with its own MCP servers", Prompt: "You are an agent with MCP servers.", MCPServers: map[string]copilot.MCPServerConfig{ - "agent-server": { - "type": "local", - "command": "echo", - "args": []string{"agent-mcp"}, - "tools": []string{"*"}, + "agent-server": copilot.MCPStdioServerConfig{ + Command: "echo", + Args: []string{"agent-mcp"}, + Tools: []string{"*"}, }, }, }, @@ -399,11 +393,10 @@ func TestCombinedConfiguration(t *testing.T) { ctx.ConfigureForTest(t) mcpServers := map[string]copilot.MCPServerConfig{ - "shared-server": { - "type": "local", - "command": "echo", - "args": []string{"shared"}, - "tools": []string{"*"}, + "shared-server": copilot.MCPStdioServerConfig{ + Command: "echo", + Args: []string{"shared"}, + Tools: []string{"*"}, }, } diff --git a/go/types.go b/go/types.go index c26f075e3..568bcc1b9 100644 --- a/go/types.go +++ b/go/types.go @@ -382,10 +382,15 @@ type SessionHooks struct { OnErrorOccurred ErrorOccurredHandler } -// MCPLocalServerConfig configures a local/stdio MCP server -type MCPLocalServerConfig struct { +// MCPServerConfig is implemented by MCP server configuration types. +// Only MCPStdioServerConfig and MCPHTTPServerConfig implement this interface. +type MCPServerConfig interface { + mcpServerConfig() +} + +// MCPStdioServerConfig configures a local/stdio MCP server. +type MCPStdioServerConfig struct { Tools []string `json:"tools"` - Type string `json:"type,omitempty"` // "local" or "stdio" Timeout int `json:"timeout,omitempty"` Command string `json:"command"` Args []string `json:"args"` @@ -393,18 +398,41 @@ type MCPLocalServerConfig struct { Cwd string `json:"cwd,omitempty"` } -// MCPRemoteServerConfig configures a remote MCP server (HTTP or SSE) -type MCPRemoteServerConfig struct { +func (MCPStdioServerConfig) mcpServerConfig() {} + +// MarshalJSON implements json.Marshaler, injecting the "type" discriminator. +func (c MCPStdioServerConfig) MarshalJSON() ([]byte, error) { + type alias MCPStdioServerConfig + return json.Marshal(struct { + Type string `json:"type"` + alias + }{ + Type: "stdio", + alias: alias(c), + }) +} + +// MCPHTTPServerConfig configures a remote MCP server (HTTP or SSE). +type MCPHTTPServerConfig struct { Tools []string `json:"tools"` - Type string `json:"type"` // "http" or "sse" Timeout int `json:"timeout,omitempty"` URL string `json:"url"` Headers map[string]string `json:"headers,omitempty"` } -// MCPServerConfig can be either MCPLocalServerConfig or MCPRemoteServerConfig -// Use a map[string]any for flexibility, or create separate configs -type MCPServerConfig map[string]any +func (MCPHTTPServerConfig) mcpServerConfig() {} + +// MarshalJSON implements json.Marshaler, injecting the "type" discriminator. +func (c MCPHTTPServerConfig) MarshalJSON() ([]byte, error) { + type alias MCPHTTPServerConfig + return json.Marshal(struct { + Type string `json:"type"` + alias + }{ + Type: "http", + alias: alias(c), + }) +} // CustomAgentConfig configures a custom agent type CustomAgentConfig struct { diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 3fab122db..1ca8432c9 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -30,8 +30,8 @@ export type { GetStatusResponse, InfiniteSessionConfig, InputOptions, - MCPLocalServerConfig, - MCPRemoteServerConfig, + MCPStdioServerConfig, + MCPHTTPServerConfig, MCPServerConfig, MessageOptions, ModelBilling, diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index c2d095234..2e9b6ba47 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -924,8 +924,8 @@ interface MCPServerConfigBase { */ tools: string[]; /** - * Indicates "remote" or "local" server type. - * If not specified, defaults to "local". + * Indicates the server type: "stdio" for local/subprocess servers, "http"/"sse" for remote servers. + * If not specified, defaults to "stdio". */ type?: string; /** @@ -937,7 +937,7 @@ interface MCPServerConfigBase { /** * Configuration for a local/stdio MCP server. */ -export interface MCPLocalServerConfig extends MCPServerConfigBase { +export interface MCPStdioServerConfig extends MCPServerConfigBase { type?: "local" | "stdio"; command: string; args: string[]; @@ -951,7 +951,7 @@ export interface MCPLocalServerConfig extends MCPServerConfigBase { /** * Configuration for a remote MCP server (HTTP or SSE). */ -export interface MCPRemoteServerConfig extends MCPServerConfigBase { +export interface MCPHTTPServerConfig extends MCPServerConfigBase { type: "http" | "sse"; /** * URL of the remote server. @@ -966,7 +966,7 @@ export interface MCPRemoteServerConfig extends MCPServerConfigBase { /** * Union type for MCP server configurations. */ -export type MCPServerConfig = MCPLocalServerConfig | MCPRemoteServerConfig; +export type MCPServerConfig = MCPStdioServerConfig | MCPHTTPServerConfig; // ============================================================================ // Custom Agent Configuration Types diff --git a/nodejs/test/e2e/mcp_and_agents.test.ts b/nodejs/test/e2e/mcp_and_agents.test.ts index 28ebf28b5..59e6d498b 100644 --- a/nodejs/test/e2e/mcp_and_agents.test.ts +++ b/nodejs/test/e2e/mcp_and_agents.test.ts @@ -5,7 +5,7 @@ import { dirname, resolve } from "path"; import { fileURLToPath } from "url"; import { describe, expect, it } from "vitest"; -import type { CustomAgentConfig, MCPLocalServerConfig, MCPServerConfig } from "../../src/index.js"; +import type { CustomAgentConfig, MCPStdioServerConfig, MCPServerConfig } from "../../src/index.js"; import { approveAll } from "../../src/index.js"; import { createSdkTestContext } from "./harness/sdkTestContext.js"; @@ -24,7 +24,7 @@ describe("MCP Servers and Custom Agents", async () => { command: "echo", args: ["hello"], tools: ["*"], - } as MCPLocalServerConfig, + } as MCPStdioServerConfig, }; const session = await client.createSession({ @@ -56,7 +56,7 @@ describe("MCP Servers and Custom Agents", async () => { command: "echo", args: ["hello"], tools: ["*"], - } as MCPLocalServerConfig, + } as MCPStdioServerConfig, }; const session2 = await client.resumeSession(sessionId, { @@ -81,13 +81,13 @@ describe("MCP Servers and Custom Agents", async () => { command: "echo", args: ["server1"], tools: ["*"], - } as MCPLocalServerConfig, + } as MCPStdioServerConfig, server2: { type: "local", command: "echo", args: ["server2"], tools: ["*"], - } as MCPLocalServerConfig, + } as MCPStdioServerConfig, }; const session = await client.createSession({ @@ -107,7 +107,7 @@ describe("MCP Servers and Custom Agents", async () => { args: [TEST_MCP_SERVER], tools: ["*"], env: { TEST_SECRET: "hunter2" }, - } as MCPLocalServerConfig, + } as MCPStdioServerConfig, }; const session = await client.createSession({ @@ -219,7 +219,7 @@ describe("MCP Servers and Custom Agents", async () => { command: "echo", args: ["agent-mcp"], tools: ["*"], - } as MCPLocalServerConfig, + } as MCPStdioServerConfig, }, }, ]; @@ -268,7 +268,7 @@ describe("MCP Servers and Custom Agents", async () => { command: "echo", args: ["shared"], tools: ["*"], - } as MCPLocalServerConfig, + } as MCPStdioServerConfig, }; const customAgents: CustomAgentConfig[] = [ diff --git a/python/copilot/session.py b/python/copilot/session.py index b3f62789d..45e8826b7 100644 --- a/python/copilot/session.py +++ b/python/copilot/session.py @@ -725,7 +725,7 @@ class SessionHooks(TypedDict, total=False): # ============================================================================ -class MCPLocalServerConfig(TypedDict, total=False): +class MCPStdioServerConfig(TypedDict, total=False): """Configuration for a local/stdio MCP server.""" tools: list[str] # List of tools to include. [] means none. "*" means all. @@ -737,7 +737,7 @@ class MCPLocalServerConfig(TypedDict, total=False): cwd: NotRequired[str] # Working directory -class MCPRemoteServerConfig(TypedDict, total=False): +class MCPHTTPServerConfig(TypedDict, total=False): """Configuration for a remote MCP server (HTTP or SSE).""" tools: list[str] # List of tools to include. [] means none. "*" means all. @@ -747,7 +747,7 @@ class MCPRemoteServerConfig(TypedDict, total=False): headers: NotRequired[dict[str, str]] # HTTP headers -MCPServerConfig = MCPLocalServerConfig | MCPRemoteServerConfig +MCPServerConfig = MCPStdioServerConfig | MCPHTTPServerConfig # ============================================================================ # Custom Agent Configuration Types diff --git a/python/e2e/test_mcp_and_agents.py b/python/e2e/test_mcp_and_agents.py index c6a590d6c..f93ba432d 100644 --- a/python/e2e/test_mcp_and_agents.py +++ b/python/e2e/test_mcp_and_agents.py @@ -25,7 +25,6 @@ async def test_should_accept_mcp_server_configuration_on_session_create( """Test that MCP server configuration is accepted on session create""" mcp_servers: dict[str, MCPServerConfig] = { "test-server": { - "type": "local", "command": "echo", "args": ["hello"], "tools": ["*"], @@ -59,7 +58,6 @@ async def test_should_accept_mcp_server_configuration_on_session_resume( # Resume with MCP servers mcp_servers: dict[str, MCPServerConfig] = { "test-server": { - "type": "local", "command": "echo", "args": ["hello"], "tools": ["*"], @@ -86,7 +84,6 @@ async def test_should_pass_literal_env_values_to_mcp_server_subprocess( """Test that env values are passed as literals to MCP server subprocess""" mcp_servers: dict[str, MCPServerConfig] = { "env-echo": { - "type": "local", "command": "node", "args": [TEST_MCP_SERVER], "tools": ["*"], @@ -180,7 +177,6 @@ async def test_should_accept_both_mcp_servers_and_custom_agents(self, ctx: E2ETe """Test that both MCP servers and custom agents can be configured together""" mcp_servers: dict[str, MCPServerConfig] = { "shared-server": { - "type": "local", "command": "echo", "args": ["shared"], "tools": ["*"], diff --git a/test/scenarios/tools/mcp-servers/csharp/Program.cs b/test/scenarios/tools/mcp-servers/csharp/Program.cs index 2ee25aacd..e3c1ed428 100644 --- a/test/scenarios/tools/mcp-servers/csharp/Program.cs +++ b/test/scenarios/tools/mcp-servers/csharp/Program.cs @@ -10,16 +10,16 @@ try { - var mcpServers = new Dictionary(); + var mcpServers = new Dictionary(); var mcpServerCmd = Environment.GetEnvironmentVariable("MCP_SERVER_CMD"); if (!string.IsNullOrEmpty(mcpServerCmd)) { var mcpArgs = Environment.GetEnvironmentVariable("MCP_SERVER_ARGS"); - mcpServers["example"] = new Dictionary + mcpServers["example"] = new McpStdioServerConfig { - { "type", "stdio" }, - { "command", mcpServerCmd }, - { "args", string.IsNullOrEmpty(mcpArgs) ? Array.Empty() : mcpArgs.Split(' ') }, + Command = mcpServerCmd, + Args = string.IsNullOrEmpty(mcpArgs) ? [] : [.. mcpArgs.Split(' ')], + Tools = ["*"], }; } diff --git a/test/scenarios/tools/mcp-servers/go/main.go b/test/scenarios/tools/mcp-servers/go/main.go index d2ae5ab86..72cbdc067 100644 --- a/test/scenarios/tools/mcp-servers/go/main.go +++ b/test/scenarios/tools/mcp-servers/go/main.go @@ -30,10 +30,10 @@ func main() { if argsStr := os.Getenv("MCP_SERVER_ARGS"); argsStr != "" { args = strings.Split(argsStr, " ") } - mcpServers["example"] = copilot.MCPServerConfig{ - "type": "stdio", - "command": cmd, - "args": args, + mcpServers["example"] = copilot.MCPStdioServerConfig{ + Command: cmd, + Args: args, + Tools: []string{"*"}, } }