Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions dotnet/src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,7 @@ public async Task<CopilotSession> CreateSessionAsync(SessionConfig config, Cance
ToolFilterPrecedence: toolFilter.ToolFilterPrecedence,
ExpAssignments: config.ExpAssignments,
EnableManagedSettings: config.EnableManagedSettings,
GitHubMcpToolConfig: config.GitHubMcpToolConfig,
EnableGitHubTelemetryForwarding: _options.OnGitHubTelemetry != null ? true : null);

var rpcTimestamp = Stopwatch.GetTimestamp();
Expand Down Expand Up @@ -1410,6 +1411,7 @@ public async Task<CopilotSession> ResumeSessionAsync(string sessionId, ResumeSes
ToolFilterPrecedence: toolFilter.ToolFilterPrecedence,
ExpAssignments: config.ExpAssignments,
EnableManagedSettings: config.EnableManagedSettings,
GitHubMcpToolConfig: config.GitHubMcpToolConfig,
EnableGitHubTelemetryForwarding: _options.OnGitHubTelemetry != null ? true : null);

var rpcTimestamp = Stopwatch.GetTimestamp();
Expand Down Expand Up @@ -2762,7 +2764,8 @@ internal record CreateSessionRequest(
OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence = null,
[property: JsonPropertyName("expAssignments")] CopilotExpAssignmentResponse? ExpAssignments = null,
[property: JsonPropertyName("enableManagedSettings")] bool? EnableManagedSettings = null,
bool? EnableGitHubTelemetryForwarding = null);
bool? EnableGitHubTelemetryForwarding = null,
[property: JsonPropertyName("githubMcpToolConfig")] GitHubMcpToolConfig? GitHubMcpToolConfig = null);
#pragma warning restore GHCP001

internal record ToolDefinition(
Expand Down Expand Up @@ -2868,7 +2871,8 @@ internal record ResumeSessionRequest(
OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence = null,
[property: JsonPropertyName("expAssignments")] CopilotExpAssignmentResponse? ExpAssignments = null,
[property: JsonPropertyName("enableManagedSettings")] bool? EnableManagedSettings = null,
bool? EnableGitHubTelemetryForwarding = null);
bool? EnableGitHubTelemetryForwarding = null,
[property: JsonPropertyName("githubMcpToolConfig")] GitHubMcpToolConfig? GitHubMcpToolConfig = null);
#pragma warning restore GHCP001

internal record ResumeSessionResponse(
Expand Down
51 changes: 51 additions & 0 deletions dotnet/src/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2957,6 +2957,36 @@ public sealed class CopilotExpAssignmentResponse
public string AssignmentContext { get; set; } = string.Empty;
}

/// <summary>
/// Configuration for the built-in GitHub MCP server.
/// </summary>
public sealed class GitHubMcpToolConfig
{
/// <summary>Enables all GitHub MCP tools.</summary>
[JsonPropertyName("enableAllTools")]
public bool? EnableAllTools { get; set; }

/// <summary>Additional GitHub MCP toolsets to enable.</summary>
[JsonPropertyName("additionalToolsets")]
public IList<string>? AdditionalToolsets { get; set; }

/// <summary>Additional GitHub MCP tools to enable.</summary>
[JsonPropertyName("additionalTools")]
public IList<string>? AdditionalTools { get; set; }

/// <summary>Enables GitHub MCP insiders-mode tools.</summary>
[JsonPropertyName("enableInsidersMode")]
public bool? EnableInsidersMode { get; set; }

/// <summary>
/// Disables form deferral for GitHub MCP tools. This only applies to the
/// built-in GitHub MCP server and only has an effect when MCP Apps and
/// form-backed GitHub tools are enabled.
/// </summary>
[JsonPropertyName("disableFormDeferral")]
public bool? DisableFormDeferral { get; set; }
}

/// <summary>
/// Shared configuration properties for creating or resuming a Copilot session.
/// Use <see cref="SessionConfig"/> when creating a new session, or
Expand Down Expand Up @@ -2994,6 +3024,20 @@ protected SessionConfigBase(SessionConfigBase? other)
EnableSessionStore = other.EnableSessionStore;
EnableSkills = other.EnableSkills;
EnableMcpApps = other.EnableMcpApps;
GitHubMcpToolConfig = other.GitHubMcpToolConfig is null
? null
: new GitHubMcpToolConfig
{
EnableAllTools = other.GitHubMcpToolConfig.EnableAllTools,
AdditionalToolsets = other.GitHubMcpToolConfig.AdditionalToolsets is not null
? [.. other.GitHubMcpToolConfig.AdditionalToolsets]
: null,
AdditionalTools = other.GitHubMcpToolConfig.AdditionalTools is not null
? [.. other.GitHubMcpToolConfig.AdditionalTools]
: null,
Comment thread
connor4312 marked this conversation as resolved.
EnableInsidersMode = other.GitHubMcpToolConfig.EnableInsidersMode,
DisableFormDeferral = other.GitHubMcpToolConfig.DisableFormDeferral,
};
ExcludedBuiltInAgents = other.ExcludedBuiltInAgents is not null ? [.. other.ExcludedBuiltInAgents] : null;
ExcludedTools = other.ExcludedTools is not null ? [.. other.ExcludedTools] : null;
Hooks = other.Hooks;
Expand Down Expand Up @@ -3309,6 +3353,13 @@ protected SessionConfigBase(SessionConfigBase? other)
[Experimental(Diagnostics.Experimental)]
public bool EnableMcpApps { get; set; }

/// <summary>
/// Configuration for the built-in GitHub MCP server.
/// <c>DisableFormDeferral</c> only applies to that server and only has an
/// effect when MCP Apps and form-backed GitHub tools are enabled.
/// </summary>
public GitHubMcpToolConfig? GitHubMcpToolConfig { get; set; }

/// <summary>Hook handlers for session lifecycle events.</summary>
public SessionHooks? Hooks { get; set; }

Expand Down
45 changes: 45 additions & 0 deletions dotnet/test/Unit/SerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,51 @@ public void SessionRequests_OmitCapiOptions_WhenUnset()
Assert.False(resumeDocument.RootElement.TryGetProperty("capi", out _));
}

[Fact]
public void SessionRequests_CanSerializeGitHubMcpToolConfig_WithSdkOptions()
{
var options = GetSerializerOptions();
var githubConfig = new GitHubMcpToolConfig
{
EnableAllTools = true,
AdditionalToolsets = ["repos"],
AdditionalTools = ["get_issue"],
EnableInsidersMode = true,
DisableFormDeferral = true,
};

var createRequestType = GetNestedType(typeof(CopilotClient), "CreateSessionRequest");
var createRequest = CreateInternalRequest(
createRequestType,
("GitHubMcpToolConfig", githubConfig));
using var createDocument = JsonDocument.Parse(JsonSerializer.Serialize(createRequest, createRequestType, options));
var createConfig = createDocument.RootElement.GetProperty("githubMcpToolConfig");
Assert.True(createConfig.GetProperty("enableAllTools").GetBoolean());
Assert.Equal("repos", createConfig.GetProperty("additionalToolsets")[0].GetString());
Assert.True(createConfig.GetProperty("disableFormDeferral").GetBoolean());

var resumeRequestType = GetNestedType(typeof(CopilotClient), "ResumeSessionRequest");
var resumeRequest = CreateInternalRequest(
resumeRequestType,
("SessionId", "session-id"),
("GitHubMcpToolConfig", githubConfig));
using var resumeDocument = JsonDocument.Parse(JsonSerializer.Serialize(resumeRequest, resumeRequestType, options));
Assert.True(resumeDocument.RootElement.TryGetProperty("githubMcpToolConfig", out _));
}

[Fact]
public void SessionRequests_OmitGitHubMcpToolConfig_WhenUnset()
{
var options = GetSerializerOptions();
foreach (var requestName in new[] { "CreateSessionRequest", "ResumeSessionRequest" })
{
var requestType = GetNestedType(typeof(CopilotClient), requestName);
var request = CreateInternalRequest(requestType, ("SessionId", "session-id"));
using var document = JsonDocument.Parse(JsonSerializer.Serialize(request, requestType, options));
Assert.False(document.RootElement.TryGetProperty("githubMcpToolConfig", out _));
}
}

[Fact]
public void SessionRequests_CanSerializeReasoningSummary_WithSdkOptions()
{
Expand Down
2 changes: 2 additions & 0 deletions go/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
if config.EnableMCPApps {
req.RequestMCPApps = Bool(true)
}
req.GitHubMCPToolConfig = config.GitHubMCPToolConfig

if config.Streaming != nil {
req.Streaming = config.Streaming
Expand Down Expand Up @@ -1220,6 +1221,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
if config.EnableMCPApps {
req.RequestMCPApps = Bool(true)
}
req.GitHubMCPToolConfig = config.GitHubMCPToolConfig

traceparent, tracestate := getTraceContext(ctx)
req.Traceparent = traceparent
Expand Down
62 changes: 62 additions & 0 deletions go/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2363,6 +2363,68 @@ func TestResumeSessionRequest_RequestMCPApps(t *testing.T) {
})
}

func TestSessionRequests_GitHubMCPToolConfig(t *testing.T) {
config := &GitHubMCPToolConfig{
EnableAllTools: Bool(true),
AdditionalToolsets: []string{"repos"},
AdditionalTools: []string{"get_issue"},
EnableInsidersMode: Bool(true),
DisableFormDeferral: Bool(true),
}
expected := map[string]any{
"enableAllTools": true,
"additionalToolsets": []any{"repos"},
"additionalTools": []any{"get_issue"},
"enableInsidersMode": true,
"disableFormDeferral": true,
}

t.Run("create", func(t *testing.T) {
data, err := json.Marshal(createSessionRequest{GitHubMCPToolConfig: config})
if err != nil {
t.Fatalf("Failed to marshal: %v", err)
}
var payload map[string]any
if err := json.Unmarshal(data, &payload); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if !reflect.DeepEqual(payload["githubMcpToolConfig"], expected) {
t.Fatalf("Unexpected githubMcpToolConfig: %#v", payload["githubMcpToolConfig"])
}
})

t.Run("resume", func(t *testing.T) {
data, err := json.Marshal(resumeSessionRequest{
SessionID: "s1",
GitHubMCPToolConfig: config,
})
if err != nil {
t.Fatalf("Failed to marshal: %v", err)
}
var payload map[string]any
if err := json.Unmarshal(data, &payload); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if !reflect.DeepEqual(payload["githubMcpToolConfig"], expected) {
t.Fatalf("Unexpected githubMcpToolConfig: %#v", payload["githubMcpToolConfig"])
}
})

t.Run("unset is omitted", func(t *testing.T) {
data, err := json.Marshal(createSessionRequest{})
if err != nil {
t.Fatalf("Failed to marshal: %v", err)
}
var payload map[string]any
if err := json.Unmarshal(data, &payload); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
if _, ok := payload["githubMcpToolConfig"]; ok {
t.Fatal("Expected githubMcpToolConfig to be omitted")
}
Comment thread
connor4312 marked this conversation as resolved.
})
}

func TestResumeSessionRequest_ModeCallbackFlags(t *testing.T) {
req := resumeSessionRequest{
SessionID: "s1",
Expand Down
22 changes: 22 additions & 0 deletions go/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,18 @@ func (e ExpConfigEntry) MarshalJSON() ([]byte, error) {
return json.Marshal(w)
}

// GitHubMCPToolConfig configures the built-in GitHub MCP server.
//
// DisableFormDeferral only applies to the built-in GitHub MCP server and only
// has an effect when MCP Apps and form-backed GitHub tools are enabled.
type GitHubMCPToolConfig struct {
EnableAllTools *bool `json:"enableAllTools,omitempty"`
AdditionalToolsets []string `json:"additionalToolsets,omitempty"`
AdditionalTools []string `json:"additionalTools,omitempty"`
EnableInsidersMode *bool `json:"enableInsidersMode,omitempty"`
DisableFormDeferral *bool `json:"disableFormDeferral,omitempty"`
}

// SessionConfig configures a new session
type SessionConfig struct {
// SessionID is an optional custom session ID
Expand Down Expand Up @@ -1379,6 +1391,10 @@ type SessionConfig struct {
// cause MCP servers to register UI-enabled tool variants the consumer cannot
// display.
EnableMCPApps bool
// GitHubMCPToolConfig configures the built-in GitHub MCP server.
// DisableFormDeferral only applies to that server and only has an effect
// when MCP Apps and form-backed GitHub tools are enabled.
GitHubMCPToolConfig *GitHubMCPToolConfig
// GitHubToken is an optional per-session GitHub token used for authentication.
// When provided, the session authenticates as the token's owner instead of
// using the global client-level auth.
Expand Down Expand Up @@ -1847,6 +1863,10 @@ type ResumeSessionConfig struct {
// Experimental: EnableMCPApps is part of an experimental wire-protocol
// surface (SEP-1865) and may change or be removed in a future release.
EnableMCPApps bool
// GitHubMCPToolConfig configures the built-in GitHub MCP server.
// DisableFormDeferral only applies to that server and only has an effect
// when MCP Apps and form-backed GitHub tools are enabled.
GitHubMCPToolConfig *GitHubMCPToolConfig
// Canvases declares canvases this session provides. Sent over the wire on
// `session.resume`. See SessionConfig.Canvases.
Canvases []CanvasDeclaration
Expand Down Expand Up @@ -2327,6 +2347,7 @@ type createSessionRequest struct {
Commands []wireCommand `json:"commands,omitempty"`
RequestElicitation *bool `json:"requestElicitation,omitempty"`
RequestMCPApps *bool `json:"requestMcpApps,omitempty"`
GitHubMCPToolConfig *GitHubMCPToolConfig `json:"githubMcpToolConfig,omitempty"`
GitHubToken string `json:"gitHubToken,omitempty"`
RemoteSession rpc.RemoteSessionMode `json:"remoteSession,omitempty"`
Cloud *CloudSessionOptions `json:"cloud,omitempty"`
Expand Down Expand Up @@ -2419,6 +2440,7 @@ type resumeSessionRequest struct {
Commands []wireCommand `json:"commands,omitempty"`
RequestElicitation *bool `json:"requestElicitation,omitempty"`
RequestMCPApps *bool `json:"requestMcpApps,omitempty"`
GitHubMCPToolConfig *GitHubMCPToolConfig `json:"githubMcpToolConfig,omitempty"`
GitHubToken string `json:"gitHubToken,omitempty"`
RemoteSession rpc.RemoteSessionMode `json:"remoteSession,omitempty"`
Canvases []CanvasDeclaration `json:"canvases,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess
if (config.isEnableMcpApps()) {
request.setRequestMcpApps(true);
}
request.setGitHubMcpToolConfig(config.getGitHubMcpToolConfig());
if (config.getOnExitPlanMode() != null) {
request.setRequestExitPlanMode(true);
}
Expand Down Expand Up @@ -300,6 +301,7 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo
if (config.isEnableMcpApps()) {
request.setRequestMcpApps(true);
}
request.setGitHubMcpToolConfig(config.getGitHubMcpToolConfig());
if (config.getOnExitPlanMode() != null) {
request.setRequestExitPlanMode(true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ public final class CreateSessionRequest {
@JsonProperty("requestMcpApps")
private Boolean requestMcpApps;

@JsonProperty("githubMcpToolConfig")
private GitHubMcpToolConfig githubMcpToolConfig;

@JsonProperty("requestExitPlanMode")
private Boolean requestExitPlanMode;

Expand Down Expand Up @@ -902,6 +905,16 @@ public void clearRequestMcpApps() {
this.requestMcpApps = null;
}

/** Gets the GitHub MCP tool configuration. @return the configuration */
public GitHubMcpToolConfig getGitHubMcpToolConfig() {
return githubMcpToolConfig;
}

/** Sets the GitHub MCP tool configuration. @param config the value */
public void setGitHubMcpToolConfig(GitHubMcpToolConfig config) {
this.githubMcpToolConfig = config;
}

/** Gets the requestExitPlanMode flag. @return the flag */
public Boolean getRequestExitPlanMode() {
return requestExitPlanMode;
Expand Down
Loading
Loading