github / github/copilot-sdk

`resumeSession` silently ignores the `mcpServers` config field

Ouverte
#1,113 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
Java
Étoiles
10.5k
Forks
1.5k
Merge moyen
1 j 11 h
PR mergées (30 j)
128

Description

`CopilotClient.resumeSession(id, { mcpServers: ... })` does not apply the `mcpServers` value passed on resume. The servers connected during the
original `createSession` call remain connected; any servers declared on resume are never loaded. Other fields in `ResumeSessionConfig` (`tools`,
`skillDirectories`, `systemMessage`) *are* applied on the same call, so the behaviour is asymmetric.

### Reproduction

```js
import { CopilotClient } from '@github/copilot-sdk'

const baseConfig = {
model: 'gpt-4.1',
streaming: true,
onPermissionRequest: async () => ({ decision: 'allow', persist: false })
}

// Two different public MCP reference servers — distinct tool sets.
const mcpEverything = {
type: 'local',
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-everything'],
tools: '*'
}
const mcpMemory = {
type: 'local',
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-memory'],
tools: '*'
}

const LIST_PROMPT =
'Pick any MCP tool you actually have access to right now and call it ' +
'(any reasonable args). Then in one short sentence, name the tool you ' +
'just called and which MCP server it belongs to.'

async function ask (session, prompt) {
const response = await session.sendAndWait({ prompt }, 60_000)
return response?.data?.content ?? ''
}

const client = new CopilotClient({ autoStart: true })
await client.start()

const logServers = (phase) => (event) => {
if (event.type === 'session.mcp_servers_loaded') {
const names = (event.data?.servers ?? []).map(s => s.name)
console.log(` [SDK event in ${phase}] session.mcp_servers_loaded → ${JSON.stringify(names)}`)
}
}

console.log('\n=== 1. createSession with mcpServers = { everything } ===')
const sessionA = await client.createSession({
...baseConfig,
mcpServers: { everything: mcpEverything }
})
sessionA.on(logServers('createSession'))
console.log(' LLM reply: ' + await ask(sessionA, LIST_PROMPT))

console.log('\n=== 2. resumeSession(sameId, mcpServers = { memory }) ===')
const sessionB = await client.resumeSession(sessionA.id ?? sessionA.sessionId, {
...baseConfig,
mcpServers: { memory: mcpMemory } // ← DIFFERENT server
})
sessionB.on(logServers('resumeSession'))
console.log(' LLM reply: ' + await ask(sessionB, LIST_PROMPT))

await client.disconnect?.()
process.exit(0)
```

#### Run with:
```
npm i @github/copilot-sdk
node repro.mjs
```
(Node 22, `npx` on PATH, and a logged-in Copilot CLI — run
`./node_modules/.bin/copilot login` once.)

### Observed behavior

```
=== 1. createSession with mcpServers = { everything } ===
[SDK event in createSession] session.mcp_servers_loaded → ["everything"]
LLM reply: I called the get-sum tool from the "everything" MCP server.

=== 2. resumeSession(sameId, mcpServers = { memory }) ===
[SDK event in resumeSession] session.mcp_servers_loaded → ["everything"]
LLM reply: I called the get-tiny-image tool from the "everything" MCP server.
```

After step 2 the SDK is still publishing `["everything"]` in `session.mcp_servers_loaded`, and the LLM can only call tools from `everything` — even though the resume config explicitly passed `{ memory: ... }` and did **not** include `everything`.

### Expected behavior

After `resumeSession(id, { mcpServers: { memory: ... } })`:

- `session.mcp_servers_loaded` should emit `["memory"]`.
- The previously-loaded `everything` server should be disconnected (or at least no longer be visible as a tool source).
- The LLM should only be able to call tools from `memory` (e.g. `read_graph`, `create_entities`).

### Impact

Prevents agent-switching mid-conversation (same use case as #567). Only workaround is `deleteSession` + `createSession` — which wipes history, defeating the point of `resumeSession`.

### Environment
- `@github/copilot-sdk` 0.2.1 and 0.2.2 (both affected)
- CLI binary 1.0.34, Node 22.14, Linux

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.