Skip to content

Commit 28afd5e

Browse files
committed
Reload MCP servers after session resume
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 812b44f2-ef93-4b32-b051-c7092f612279
1 parent 3a5e416 commit 28afd5e

9 files changed

Lines changed: 62 additions & 9 deletions

File tree

dotnet/src/Client.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,15 @@ public async Task<CopilotSession> ResumeSessionAsync(string sessionId, ResumeSes
14801480
session.SetCapabilities(response.Capabilities);
14811481
session.SetOpenCanvases(response.OpenCanvases);
14821482

1483+
if (config.McpServers is not null)
1484+
{
1485+
await InvokeRpcAsync<JsonElement>(
1486+
connection.Rpc,
1487+
"session.mcp.reloadWithConfig",
1488+
[new ReloadMcpServersRequest(sessionId, new ReloadMcpServersConfig(config.McpServers))],
1489+
cancellationToken);
1490+
}
1491+
14831492
if (config.OnMcpAuthRequest is not null)
14841493
{
14851494
await session.Rpc.EventLog.RegisterInterestAsync("mcp.oauth_required", cancellationToken);
@@ -2952,6 +2961,13 @@ internal record ResumeSessionResponse(
29522961
IList<OpenCanvasInstance>? OpenCanvases = null);
29532962
#pragma warning restore GHCP001
29542963

2964+
internal record ReloadMcpServersRequest(
2965+
string SessionId,
2966+
ReloadMcpServersConfig Config);
2967+
2968+
internal record ReloadMcpServersConfig(
2969+
IDictionary<string, McpServerConfig> McpServers);
2970+
29552971
internal record CommandWireDefinition(
29562972
string Name,
29572973
string Description);
@@ -3028,6 +3044,8 @@ internal record HooksInvokeResponse(
30283044
[JsonSerializable(typeof(CapiSessionOptions))]
30293045
[JsonSerializable(typeof(NamedProviderConfig))]
30303046
[JsonSerializable(typeof(ProviderModelConfig))]
3047+
[JsonSerializable(typeof(ReloadMcpServersConfig))]
3048+
[JsonSerializable(typeof(ReloadMcpServersRequest))]
30313049
[JsonSerializable(typeof(SessionLimitsConfig))]
30323050
[JsonSerializable(typeof(ResumeSessionRequest))]
30333051
[JsonSerializable(typeof(ResumeSessionResponse))]

dotnet/test/E2E/SessionMcpAndAgentConfigE2ETests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ public async Task Should_Accept_MCP_Server_Configuration_On_Session_Resume()
5858
// Create a session first
5959
var session1 = await CreateSessionAsync();
6060
var sessionId = session1.SessionId;
61-
await session1.SendAndWaitAsync(new MessageOptions { Prompt = "What is 1+1?" });
6261
await session1.DisposeAsync();
6362

6463
// Resume with MCP servers

go/client.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,6 +1356,19 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
13561356
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
13571357
}
13581358

1359+
if config.MCPServers != nil {
1360+
internalSessionRPC := rpc.NewInternalSessionRPC(c.client, sessionID)
1361+
_, err := internalSessionRPC.MCP.ReloadWithConfig(ctx, &rpc.MCPReloadWithConfigRequest{
1362+
Config: map[string]any{"mcpServers": config.MCPServers},
1363+
})
1364+
if err != nil {
1365+
c.sessionsMux.Lock()
1366+
delete(c.sessions, sessionID)
1367+
c.sessionsMux.Unlock()
1368+
return nil, fmt.Errorf("failed to reload MCP servers after resume: %w", err)
1369+
}
1370+
}
1371+
13591372
if config.OnMCPAuthRequest != nil {
13601373
if _, err := c.client.Request(ctx, "session.eventLog.registerInterest", map[string]any{
13611374
"sessionId": sessionID,

go/internal/e2e/mcp_and_agents_e2e_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,6 @@ func TestMCPServersE2E(t *testing.T) {
8888
}
8989
sessionID := session1.SessionID
9090

91-
_, err = session1.SendAndWait(t.Context(), copilot.MessageOptions{Prompt: "What is 1+1?"})
92-
if err != nil {
93-
t.Fatalf("Failed to send message: %v", err)
94-
}
95-
9691
// Resume with MCP servers
9792
mcpServers := testMCPServers(t, "test-server")
9893

java/sdk/src/main/java/com/github/copilot/CopilotClient.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import com.github.copilot.generated.rpc.GitHubTelemetryNotification;
4141
import com.github.copilot.generated.rpc.ServerRpc;
4242
import com.github.copilot.generated.rpc.SessionEventLogRegisterInterestParams;
43+
import com.github.copilot.generated.rpc.SessionMcpReloadWithConfigParams;
44+
import com.github.copilot.generated.rpc.SessionMcpReloadWithConfigResult;
4345
import com.github.copilot.rpc.DeleteSessionResponse;
4446
import com.github.copilot.rpc.GetAuthStatusResponse;
4547
import com.github.copilot.rpc.GetLastSessionIdResponse;
@@ -1146,11 +1148,17 @@ public CompletableFuture<CopilotSession> resumeSession(String sessionId, ResumeS
11461148
rpcNanos);
11471149
String returnedId = response.sessionId();
11481150
String interestSessionId = returnedId != null ? returnedId : sessionId;
1151+
CompletableFuture<?> reload = config.getMcpServers() != null
1152+
? connection.rpc.invoke("session.mcp.reloadWithConfig",
1153+
new SessionMcpReloadWithConfigParams(interestSessionId,
1154+
Map.of("mcpServers", config.getMcpServers())),
1155+
SessionMcpReloadWithConfigResult.class)
1156+
: CompletableFuture.completedFuture(null);
11491157
CompletableFuture<?> interest = config.getOnMcpAuthRequest() != null
11501158
? session.getRpc().eventLog.registerInterest(new SessionEventLogRegisterInterestParams(
11511159
interestSessionId, "mcp.oauth_required"))
11521160
: CompletableFuture.completedFuture(null);
1153-
return interest.thenApply(interestResult -> {
1161+
return reload.thenCompose(ignored -> interest).thenApply(interestResult -> {
11541162
logMcpAuthInterestRegistration(interestResult);
11551163
return response;
11561164
});

java/sdk/src/test/java/com/github/copilot/McpAndAgentsTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ void testShouldAcceptMcpServerConfigurationOnSessionResume() throws Exception {
131131
CopilotSession session1 = client
132132
.createSession(new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL)).get();
133133
String sessionId = session1.getSessionId();
134-
session1.sendAndWait(new MessageOptions().setPrompt("What is 1+1?")).get(60, TimeUnit.SECONDS);
135134

136135
// Resume with MCP servers
137136
var mcpServers = createTestMcpServers("test-server");

python/copilot/client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3423,6 +3423,14 @@ async def resume_session(
34233423
session._set_open_canvases(
34243424
[OpenCanvasInstance.from_dict(inst) for inst in open_canvases_raw]
34253425
)
3426+
if mcp_servers is not None:
3427+
await self._client.request(
3428+
"session.mcp.reloadWithConfig",
3429+
{
3430+
"sessionId": session_id,
3431+
"config": {"mcpServers": _mcp_servers_to_wire(mcp_servers)},
3432+
},
3433+
)
34263434
if on_mcp_auth_request is not None:
34273435
await self._client.request(
34283436
"session.eventLog.registerInterest",

python/e2e/test_mcp_and_agents_e2e.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ async def test_should_accept_mcp_server_configuration_on_session_resume(
9999
on_permission_request=PermissionHandler.approve_all
100100
)
101101
session_id = session1.session_id
102-
await session1.send_and_wait("What is 1+1?")
103102

104103
# Resume with MCP servers
105104
mcp_servers = _test_mcp_servers("test-server")

rust/src/session.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,20 @@ impl Client {
12931293
})
12941294
.into());
12951295
}
1296+
if let Some(mcp_servers) = wire.mcp_servers.as_ref()
1297+
&& let Err(error) = self
1298+
.call(
1299+
"session.mcp.reloadWithConfig",
1300+
Some(serde_json::json!({
1301+
"sessionId": session_id,
1302+
"config": { "mcpServers": mcp_servers },
1303+
})),
1304+
)
1305+
.await
1306+
{
1307+
registration.cleanup(event_loop).await;
1308+
return Err(error);
1309+
}
12961310
if has_mcp_auth_handler {
12971311
register_mcp_auth_interest(self, &session_id).await?;
12981312
}

0 commit comments

Comments
 (0)