From df6b41289d90322c1f8717c5e59625e38090dba4 Mon Sep 17 00:00:00 2001 From: Oliver Slapinski Date: Sun, 23 Aug 2026 23:51:16 -0400 Subject: [PATCH 1/2] Node: expose MCP server instruction policy Signed-off-by: Oliver Slapinski --- nodejs/src/client.ts | 6 +++++ nodejs/src/types.ts | 11 +++++++++ nodejs/test/client.test.ts | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index 1be2cbb941..5c109d1b3a 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -1604,6 +1604,9 @@ export class CopilotClient { ? { enableGitHubTelemetryForwarding: true } : {}), mcpServers: toWireMcpServers(config.mcpServers), + ...(config.allowAllMcpServerInstructions !== undefined + ? { allowAllMcpServerInstructions: config.allowAllMcpServerInstructions } + : {}), mcpOAuthTokenStorage: config.mcpOAuthTokenStorage, envValueMode: "direct", customAgents: toWireCustomAgents(config.customAgents), @@ -1864,6 +1867,9 @@ export class CopilotClient { ? { enableGitHubTelemetryForwarding: true } : {}), mcpServers: toWireMcpServers(config.mcpServers), + ...(config.allowAllMcpServerInstructions !== undefined + ? { allowAllMcpServerInstructions: config.allowAllMcpServerInstructions } + : {}), mcpOAuthTokenStorage: config.mcpOAuthTokenStorage, envValueMode: "direct", customAgents: toWireCustomAgents(config.customAgents), diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 678cd58633..e943e3acf0 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -2623,6 +2623,17 @@ export interface SessionConfigBase { */ mcpServers?: Record; + /** + * Include instructions from every MCP server in the system prompt instead + * of only allowlisted servers. + * + * Enabling this broadens the session's instruction trust boundary. Only + * enable it when every configured MCP server is trusted. + * + * @default false + */ + allowAllMcpServerInstructions?: boolean; + /** * Custom agent configurations for the session. */ diff --git a/nodejs/test/client.test.ts b/nodejs/test/client.test.ts index e2d630ba0e..97ec08905f 100644 --- a/nodejs/test/client.test.ts +++ b/nodejs/test/client.test.ts @@ -3888,6 +3888,56 @@ describe("CopilotClient", () => { }); }); +describe("allowAllMcpServerInstructions serialization", () => { + async function startCaptureClient() { + const client = new CopilotClient({ + connection: RuntimeConnection.forUri("localhost:1234"), + }); + const sendRequest = vi.fn(async (method: string, params: any) => { + if (method === "session.create") return { sessionId: params.sessionId }; + if (method === "session.resume") return { sessionId: params.sessionId }; + throw new Error(`Unexpected method: ${method}`); + }); + vi.spyOn(client as any, "connectToServer").mockImplementation(async () => { + (client as any).connection = { sendRequest, dispose: vi.fn() }; + }); + vi.spyOn(client as any, "verifyProtocolVersion").mockResolvedValue(undefined); + await client.start(); + onTestFinished(() => client.forceStop()); + return { client, sendRequest }; + } + + it.each([true, false])("forwards %s on create and resume", async (value) => { + const { client, sendRequest } = await startCaptureClient(); + + const session = await client.createSession({ + onPermissionRequest: approveAll, + allowAllMcpServerInstructions: value, + }); + await client.resumeSession(session.sessionId, { + onPermissionRequest: approveAll, + allowAllMcpServerInstructions: value, + }); + + const createCall = sendRequest.mock.calls.find(([method]) => method === "session.create"); + const resumeCall = sendRequest.mock.calls.find(([method]) => method === "session.resume"); + expect(createCall![1].allowAllMcpServerInstructions).toBe(value); + expect(resumeCall![1].allowAllMcpServerInstructions).toBe(value); + }); + + it("omits the option on create and resume by default", async () => { + const { client, sendRequest } = await startCaptureClient(); + + const session = await client.createSession({ onPermissionRequest: approveAll }); + await client.resumeSession(session.sessionId, { onPermissionRequest: approveAll }); + + const createCall = sendRequest.mock.calls.find(([method]) => method === "session.create"); + const resumeCall = sendRequest.mock.calls.find(([method]) => method === "session.resume"); + expect(createCall![1]).not.toHaveProperty("allowAllMcpServerInstructions"); + expect(resumeCall![1]).not.toHaveProperty("allowAllMcpServerInstructions"); + }); +}); + describe("managedSettings serialization", () => { async function captureCreateParams(config: Record): Promise { const client = new CopilotClient(); From ed361202fe1904bd479a94639af42fe0847de273 Mon Sep 17 00:00:00 2001 From: Oliver Slapinski Date: Fri, 11 Sep 2026 16:09:06 -0400 Subject: [PATCH 2/2] test(dotnet): exercise MCP policy through public API --- .../test/Unit/ClientSessionLifetimeTests.cs | 48 +++++++++++++++++++ dotnet/test/Unit/SerializationTests.cs | 33 ------------- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/dotnet/test/Unit/ClientSessionLifetimeTests.cs b/dotnet/test/Unit/ClientSessionLifetimeTests.cs index 173569788c..cbe0e301a9 100644 --- a/dotnet/test/Unit/ClientSessionLifetimeTests.cs +++ b/dotnet/test/Unit/ClientSessionLifetimeTests.cs @@ -512,6 +512,54 @@ public async Task SessionRequests_Serialize_CapiAutoTier(AutoTier tier, string e } } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task SessionRequests_Forward_McpServerInstructionPolicy(bool value) + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + + await using var created = await client.CreateSessionAsync(new SessionConfig + { + AllowAllMcpServerInstructions = value, + OnPermissionRequest = PermissionHandler.ApproveAll + }); + await using var resumed = await client.ResumeSessionAsync("resume-with-mcp-instruction-policy", new ResumeSessionConfig + { + AllowAllMcpServerInstructions = value, + OnPermissionRequest = PermissionHandler.ApproveAll + }); + + foreach (var method in new[] { "session.create", "session.resume" }) + { + var request = Assert.Single(server.Requests, request => request.Method == method); + Assert.Equal(value, request.Params.GetProperty("allowAllMcpServerInstructions").GetBoolean()); + } + } + + [Fact] + public async Task SessionRequests_Omit_McpServerInstructionPolicy_WhenUnset() + { + await using var server = await FakeCopilotServer.StartAsync(); + await using var client = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri(server.Url) }); + + await using var created = await client.CreateSessionAsync(new SessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll + }); + await using var resumed = await client.ResumeSessionAsync("resume-without-mcp-instruction-policy", new ResumeSessionConfig + { + OnPermissionRequest = PermissionHandler.ApproveAll + }); + + foreach (var method in new[] { "session.create", "session.resume" }) + { + var request = Assert.Single(server.Requests, request => request.Method == method); + Assert.False(request.Params.TryGetProperty("allowAllMcpServerInstructions", out _)); + } + } + [Theory] [InlineData("efficiency")] [InlineData("balance")] diff --git a/dotnet/test/Unit/SerializationTests.cs b/dotnet/test/Unit/SerializationTests.cs index e0869ed4bc..843c3b7e01 100644 --- a/dotnet/test/Unit/SerializationTests.cs +++ b/dotnet/test/Unit/SerializationTests.cs @@ -551,39 +551,6 @@ public void SessionRequests_CanSerializeMemory_WithSdkOptions() Assert.False(resumeRoot.GetProperty("memory").GetProperty("enabled").GetBoolean()); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public void SessionRequests_SerializeExplicitMcpServerInstructionPolicy(bool value) - { - var options = GetSerializerOptions(); - foreach (var typeName in new[] { "CreateSessionRequest", "ResumeSessionRequest" }) - { - var requestType = GetNestedType(typeof(CopilotClient), typeName); - var request = CreateInternalRequest( - requestType, - ("SessionId", "session-id"), - ("AllowAllMcpServerInstructions", value)); - var json = JsonSerializer.Serialize(request, requestType, options); - using var document = JsonDocument.Parse(json); - Assert.Equal(value, document.RootElement.GetProperty("allowAllMcpServerInstructions").GetBoolean()); - } - } - - [Fact] - public void SessionRequests_OmitUnsetMcpServerInstructionPolicy() - { - var options = GetSerializerOptions(); - foreach (var typeName in new[] { "CreateSessionRequest", "ResumeSessionRequest" }) - { - var requestType = GetNestedType(typeof(CopilotClient), typeName); - var request = CreateInternalRequest(requestType, ("SessionId", "session-id")); - var json = JsonSerializer.Serialize(request, requestType, options); - using var document = JsonDocument.Parse(json); - Assert.False(document.RootElement.TryGetProperty("allowAllMcpServerInstructions", out _)); - } - } - [Fact] public void SessionRequests_CanSerializeCitationAgentExclusionAndLimits_WithSdkOptions() {