diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs index d5cb6707b..aad44e4eb 100644 --- a/dotnet/src/Client.cs +++ b/dotnet/src/Client.cs @@ -502,6 +502,7 @@ public async Task CreateSessionAsync(SessionConfig config, Cance config.CustomAgents, config.Agent, config.ConfigDir, + config.EnableConfigDiscovery, config.SkillDirectories, config.DisabledSkills, config.InfiniteSessions, @@ -618,6 +619,7 @@ public async Task ResumeSessionAsync(string sessionId, ResumeSes hasHooks ? true : null, config.WorkingDirectory, config.ConfigDir, + config.EnableConfigDiscovery, config.DisableResume is true ? true : null, config.Streaming is true ? true : null, config.McpServers, @@ -1640,6 +1642,7 @@ internal record CreateSessionRequest( List? CustomAgents, string? Agent, string? ConfigDir, + bool? EnableConfigDiscovery, List? SkillDirectories, List? DisabledSkills, InfiniteSessionConfig? InfiniteSessions, @@ -1686,6 +1689,7 @@ internal record ResumeSessionRequest( bool? Hooks, string? WorkingDirectory, string? ConfigDir, + bool? EnableConfigDiscovery, bool? DisableResume, bool? Streaming, Dictionary? McpServers, diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index 2f81f3b4c..d8262e140 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -1603,6 +1603,7 @@ protected SessionConfig(SessionConfig? other) CustomAgents = other.CustomAgents is not null ? [.. other.CustomAgents] : null; Agent = other.Agent; DisabledSkills = other.DisabledSkills is not null ? [.. other.DisabledSkills] : null; + EnableConfigDiscovery = other.EnableConfigDiscovery; ExcludedTools = other.ExcludedTools is not null ? [.. other.ExcludedTools] : null; Hooks = other.Hooks; InfiniteSessions = other.InfiniteSessions; @@ -1660,6 +1661,19 @@ protected SessionConfig(SessionConfig? other) /// public string? ConfigDir { get; set; } + /// + /// When , automatically discovers MCP server configurations + /// (e.g. .mcp.json, .vscode/mcp.json) and skill directories from + /// the working directory and merges them with any explicitly provided + /// and , with explicit + /// values taking precedence on name collision. + /// + /// Custom instruction files (.github/copilot-instructions.md, AGENTS.md, etc.) + /// are always loaded from the working directory regardless of this setting. + /// + /// + public bool? EnableConfigDiscovery { get; set; } + /// /// Custom tool functions available to the language model during the session. /// @@ -1817,6 +1831,7 @@ protected ResumeSessionConfig(ResumeSessionConfig? other) Agent = other.Agent; DisabledSkills = other.DisabledSkills is not null ? [.. other.DisabledSkills] : null; DisableResume = other.DisableResume; + EnableConfigDiscovery = other.EnableConfigDiscovery; ExcludedTools = other.ExcludedTools is not null ? [.. other.ExcludedTools] : null; Hooks = other.Hooks; InfiniteSessions = other.InfiniteSessions; @@ -1929,6 +1944,19 @@ protected ResumeSessionConfig(ResumeSessionConfig? other) /// public string? ConfigDir { get; set; } + /// + /// When , automatically discovers MCP server configurations + /// (e.g. .mcp.json, .vscode/mcp.json) and skill directories from + /// the working directory and merges them with any explicitly provided + /// and , with explicit + /// values taking precedence on name collision. + /// + /// Custom instruction files (.github/copilot-instructions.md, AGENTS.md, etc.) + /// are always loaded from the working directory regardless of this setting. + /// + /// + public bool? EnableConfigDiscovery { get; set; } + /// /// When true, the session.resume event is not emitted. /// Default: false (resume event is emitted). diff --git a/go/client.go b/go/client.go index f8d29cc98..ebea33209 100644 --- a/go/client.go +++ b/go/client.go @@ -578,6 +578,9 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses req.ClientName = config.ClientName req.ReasoningEffort = config.ReasoningEffort req.ConfigDir = config.ConfigDir + if config.EnableConfigDiscovery { + req.EnableConfigDiscovery = Bool(true) + } req.Tools = config.Tools wireSystemMessage, transformCallbacks := extractTransformCallbacks(config.SystemMessage) req.SystemMessage = wireSystemMessage @@ -754,6 +757,9 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string, } req.WorkingDirectory = config.WorkingDirectory req.ConfigDir = config.ConfigDir + if config.EnableConfigDiscovery { + req.EnableConfigDiscovery = Bool(true) + } if config.DisableResume { req.DisableResume = Bool(true) } diff --git a/go/types.go b/go/types.go index d80a80f54..c26f075e3 100644 --- a/go/types.go +++ b/go/types.go @@ -465,6 +465,13 @@ type SessionConfig struct { // ConfigDir overrides the default configuration directory location. // When specified, the session will use this directory for storing config and state. ConfigDir string + // EnableConfigDiscovery, when true, automatically discovers MCP server configurations + // (e.g. .mcp.json, .vscode/mcp.json) and skill directories from the working directory + // and merges them with any explicitly provided MCPServers and SkillDirectories, with + // explicit values taking precedence on name collision. + // Custom instruction files (.github/copilot-instructions.md, AGENTS.md, etc.) are + // always loaded from the working directory regardless of this setting. + EnableConfigDiscovery bool // Tools exposes caller-implemented tools to the CLI Tools []Tool // SystemMessage configures system message customization @@ -692,6 +699,13 @@ type ResumeSessionConfig struct { WorkingDirectory string // ConfigDir overrides the default configuration directory location. ConfigDir string + // EnableConfigDiscovery, when true, automatically discovers MCP server configurations + // (e.g. .mcp.json, .vscode/mcp.json) and skill directories from the working directory + // and merges them with any explicitly provided MCPServers and SkillDirectories, with + // explicit values taking precedence on name collision. + // Custom instruction files (.github/copilot-instructions.md, AGENTS.md, etc.) are + // always loaded from the working directory regardless of this setting. + EnableConfigDiscovery bool // Streaming enables streaming of assistant message and reasoning chunks. // When true, assistant.message_delta and assistant.reasoning_delta events // with deltaContent are sent as the response is generated. @@ -889,33 +903,34 @@ type SessionLifecycleHandler func(event SessionLifecycleEvent) // createSessionRequest is the request for session.create type createSessionRequest struct { - Model string `json:"model,omitempty"` - SessionID string `json:"sessionId,omitempty"` - ClientName string `json:"clientName,omitempty"` - ReasoningEffort string `json:"reasoningEffort,omitempty"` - Tools []Tool `json:"tools,omitempty"` - SystemMessage *SystemMessageConfig `json:"systemMessage,omitempty"` - AvailableTools []string `json:"availableTools"` - ExcludedTools []string `json:"excludedTools,omitempty"` - Provider *ProviderConfig `json:"provider,omitempty"` - ModelCapabilities *rpc.ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"` - RequestPermission *bool `json:"requestPermission,omitempty"` - RequestUserInput *bool `json:"requestUserInput,omitempty"` - Hooks *bool `json:"hooks,omitempty"` - WorkingDirectory string `json:"workingDirectory,omitempty"` - Streaming *bool `json:"streaming,omitempty"` - MCPServers map[string]MCPServerConfig `json:"mcpServers,omitempty"` - EnvValueMode string `json:"envValueMode,omitempty"` - CustomAgents []CustomAgentConfig `json:"customAgents,omitempty"` - Agent string `json:"agent,omitempty"` - ConfigDir string `json:"configDir,omitempty"` - SkillDirectories []string `json:"skillDirectories,omitempty"` - DisabledSkills []string `json:"disabledSkills,omitempty"` - InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` - Commands []wireCommand `json:"commands,omitempty"` - RequestElicitation *bool `json:"requestElicitation,omitempty"` - Traceparent string `json:"traceparent,omitempty"` - Tracestate string `json:"tracestate,omitempty"` + Model string `json:"model,omitempty"` + SessionID string `json:"sessionId,omitempty"` + ClientName string `json:"clientName,omitempty"` + ReasoningEffort string `json:"reasoningEffort,omitempty"` + Tools []Tool `json:"tools,omitempty"` + SystemMessage *SystemMessageConfig `json:"systemMessage,omitempty"` + AvailableTools []string `json:"availableTools"` + ExcludedTools []string `json:"excludedTools,omitempty"` + Provider *ProviderConfig `json:"provider,omitempty"` + ModelCapabilities *rpc.ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"` + RequestPermission *bool `json:"requestPermission,omitempty"` + RequestUserInput *bool `json:"requestUserInput,omitempty"` + Hooks *bool `json:"hooks,omitempty"` + WorkingDirectory string `json:"workingDirectory,omitempty"` + Streaming *bool `json:"streaming,omitempty"` + MCPServers map[string]MCPServerConfig `json:"mcpServers,omitempty"` + EnvValueMode string `json:"envValueMode,omitempty"` + CustomAgents []CustomAgentConfig `json:"customAgents,omitempty"` + Agent string `json:"agent,omitempty"` + ConfigDir string `json:"configDir,omitempty"` + EnableConfigDiscovery *bool `json:"enableConfigDiscovery,omitempty"` + SkillDirectories []string `json:"skillDirectories,omitempty"` + DisabledSkills []string `json:"disabledSkills,omitempty"` + InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` + Commands []wireCommand `json:"commands,omitempty"` + RequestElicitation *bool `json:"requestElicitation,omitempty"` + Traceparent string `json:"traceparent,omitempty"` + Tracestate string `json:"tracestate,omitempty"` } // wireCommand is the wire representation of a command (name + description only, no handler). @@ -933,34 +948,35 @@ type createSessionResponse struct { // resumeSessionRequest is the request for session.resume type resumeSessionRequest struct { - SessionID string `json:"sessionId"` - ClientName string `json:"clientName,omitempty"` - Model string `json:"model,omitempty"` - ReasoningEffort string `json:"reasoningEffort,omitempty"` - Tools []Tool `json:"tools,omitempty"` - SystemMessage *SystemMessageConfig `json:"systemMessage,omitempty"` - AvailableTools []string `json:"availableTools"` - ExcludedTools []string `json:"excludedTools,omitempty"` - Provider *ProviderConfig `json:"provider,omitempty"` - ModelCapabilities *rpc.ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"` - RequestPermission *bool `json:"requestPermission,omitempty"` - RequestUserInput *bool `json:"requestUserInput,omitempty"` - Hooks *bool `json:"hooks,omitempty"` - WorkingDirectory string `json:"workingDirectory,omitempty"` - ConfigDir string `json:"configDir,omitempty"` - DisableResume *bool `json:"disableResume,omitempty"` - Streaming *bool `json:"streaming,omitempty"` - MCPServers map[string]MCPServerConfig `json:"mcpServers,omitempty"` - EnvValueMode string `json:"envValueMode,omitempty"` - CustomAgents []CustomAgentConfig `json:"customAgents,omitempty"` - Agent string `json:"agent,omitempty"` - SkillDirectories []string `json:"skillDirectories,omitempty"` - DisabledSkills []string `json:"disabledSkills,omitempty"` - InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` - Commands []wireCommand `json:"commands,omitempty"` - RequestElicitation *bool `json:"requestElicitation,omitempty"` - Traceparent string `json:"traceparent,omitempty"` - Tracestate string `json:"tracestate,omitempty"` + SessionID string `json:"sessionId"` + ClientName string `json:"clientName,omitempty"` + Model string `json:"model,omitempty"` + ReasoningEffort string `json:"reasoningEffort,omitempty"` + Tools []Tool `json:"tools,omitempty"` + SystemMessage *SystemMessageConfig `json:"systemMessage,omitempty"` + AvailableTools []string `json:"availableTools"` + ExcludedTools []string `json:"excludedTools,omitempty"` + Provider *ProviderConfig `json:"provider,omitempty"` + ModelCapabilities *rpc.ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"` + RequestPermission *bool `json:"requestPermission,omitempty"` + RequestUserInput *bool `json:"requestUserInput,omitempty"` + Hooks *bool `json:"hooks,omitempty"` + WorkingDirectory string `json:"workingDirectory,omitempty"` + ConfigDir string `json:"configDir,omitempty"` + EnableConfigDiscovery *bool `json:"enableConfigDiscovery,omitempty"` + DisableResume *bool `json:"disableResume,omitempty"` + Streaming *bool `json:"streaming,omitempty"` + MCPServers map[string]MCPServerConfig `json:"mcpServers,omitempty"` + EnvValueMode string `json:"envValueMode,omitempty"` + CustomAgents []CustomAgentConfig `json:"customAgents,omitempty"` + Agent string `json:"agent,omitempty"` + SkillDirectories []string `json:"skillDirectories,omitempty"` + DisabledSkills []string `json:"disabledSkills,omitempty"` + InfiniteSessions *InfiniteSessionConfig `json:"infiniteSessions,omitempty"` + Commands []wireCommand `json:"commands,omitempty"` + RequestElicitation *bool `json:"requestElicitation,omitempty"` + Traceparent string `json:"traceparent,omitempty"` + Tracestate string `json:"tracestate,omitempty"` } // resumeSessionResponse is the response from session.resume diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index 5fdbf0358..6941598b8 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -742,6 +742,7 @@ export class CopilotClient { customAgents: config.customAgents, agent: config.agent, configDir: config.configDir, + enableConfigDiscovery: config.enableConfigDiscovery, skillDirectories: config.skillDirectories, disabledSkills: config.disabledSkills, infiniteSessions: config.infiniteSessions, @@ -873,6 +874,7 @@ export class CopilotClient { hooks: !!(config.hooks && Object.values(config.hooks).some(Boolean)), workingDirectory: config.workingDirectory, configDir: config.configDir, + enableConfigDiscovery: config.enableConfigDiscovery, streaming: config.streaming, mcpServers: config.mcpServers, envValueMode: "direct", diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 13367631f..c2d095234 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -1074,6 +1074,19 @@ export interface SessionConfig { */ configDir?: string; + /** + * When true, automatically discovers MCP server configurations (e.g. `.mcp.json`, + * `.vscode/mcp.json`) and skill directories from the working directory and merges + * them with any explicitly provided `mcpServers` and `skillDirectories`, with + * explicit values taking precedence on name collision. + * + * Note: custom instruction files (`.github/copilot-instructions.md`, `AGENTS.md`, etc.) + * are always loaded from the working directory regardless of this setting. + * + * @default false + */ + enableConfigDiscovery?: boolean; + /** * Tools exposed to the CLI server */ @@ -1226,6 +1239,7 @@ export type ResumeSessionConfig = Pick< | "hooks" | "workingDirectory" | "configDir" + | "enableConfigDiscovery" | "mcpServers" | "customAgents" | "agent" diff --git a/python/copilot/client.py b/python/copilot/client.py index 8be8b8220..d260dcc91 100644 --- a/python/copilot/client.py +++ b/python/copilot/client.py @@ -1202,6 +1202,7 @@ async def create_session( custom_agents: list[CustomAgentConfig] | None = None, agent: str | None = None, config_dir: str | None = None, + enable_config_discovery: bool | None = None, skill_directories: list[str] | None = None, disabled_skills: list[str] | None = None, infinite_sessions: InfiniteSessionConfig | None = None, @@ -1238,6 +1239,13 @@ async def create_session( custom_agents: Custom agent configurations. agent: Agent to use for the session. config_dir: Override for the configuration directory. + enable_config_discovery: When True, automatically discovers MCP server + configurations (e.g. ``.mcp.json``, ``.vscode/mcp.json``) and skill + directories from the working directory and merges them with any + explicitly provided ``mcp_servers`` and ``skill_directories``, with + explicit values taking precedence on name collision. Custom instruction + files (``.github/copilot-instructions.md``, ``AGENTS.md``, etc.) are + always loaded regardless of this setting. skill_directories: Directories to search for skills. disabled_skills: Skills to disable. infinite_sessions: Infinite session configuration. @@ -1362,6 +1370,10 @@ async def create_session( if config_dir: payload["configDir"] = config_dir + # Add config discovery flag if provided + if enable_config_discovery is not None: + payload["enableConfigDiscovery"] = enable_config_discovery + # Add skill directories configuration if provided if skill_directories: payload["skillDirectories"] = skill_directories @@ -1455,6 +1467,7 @@ async def resume_session( custom_agents: list[CustomAgentConfig] | None = None, agent: str | None = None, config_dir: str | None = None, + enable_config_discovery: bool | None = None, skill_directories: list[str] | None = None, disabled_skills: list[str] | None = None, infinite_sessions: InfiniteSessionConfig | None = None, @@ -1491,6 +1504,13 @@ async def resume_session( custom_agents: Custom agent configurations. agent: Agent to use for the session. config_dir: Override for the configuration directory. + enable_config_discovery: When True, automatically discovers MCP server + configurations (e.g. ``.mcp.json``, ``.vscode/mcp.json``) and skill + directories from the working directory and merges them with any + explicitly provided ``mcp_servers`` and ``skill_directories``, with + explicit values taking precedence on name collision. Custom instruction + files (``.github/copilot-instructions.md``, ``AGENTS.md``, etc.) are + always loaded regardless of this setting. skill_directories: Directories to search for skills. disabled_skills: Skills to disable. infinite_sessions: Infinite session configuration. @@ -1588,6 +1608,8 @@ async def resume_session( payload["workingDirectory"] = working_directory if config_dir: payload["configDir"] = config_dir + if enable_config_discovery is not None: + payload["enableConfigDiscovery"] = enable_config_discovery # TODO: disable_resume is not a keyword arg yet; keeping for future use if mcp_servers: