Skip to content

SDK/server mode: session.create drops mcpServers — programmatically-provided MCP servers never start #3850

@edwardsp

Description

@edwardsp

Summary

When driving the Copilot CLI in server / SDK (programmatic) mode (copilot --server --stdio, via github-copilot-sdk), MCP servers provided on the session config (SessionConfig.with_mcp_servers(...) → the mcpServers field of the session.create request) are never started. The CLI's session.create handler does not forward mcpServers into the internal session it constructs, so initializeMcpHost() has nothing to start, no MCP tools are registered, and the model never sees them. The same MCP server works fine in interactive mode and standalone.

Environment

  • Copilot CLI: reproduced on 1.0.51-2 and 1.0.64-0 (linux-x64)
  • SDK: github-copilot-sdk (Rust) 1.0.1
  • OS: Linux
  • MCP server under test: official Azure MCP — npx -y @azure/mcp@latest server start --namespace kusto (stdio). Verified working standalone (responds to initialize + tools/list, exposes the kusto tool).

Steps to reproduce

  1. Start a client via the SDK and create a session with an explicit stdio MCP server:
    let cfg = SessionConfig::default()
        .with_model("claude-...")
        .with_enable_config_discovery(false)
        .with_mcp_servers(HashMap::from([(
            "azure".to_string(),
            McpServerConfig::Stdio(McpStdioServerConfig {
                command: "npx".into(),
                args: vec!["-y","@azure/mcp@latest","server","start","--namespace","kusto"]
                    .into_iter().map(Into::into).collect(),
                ..Default::default()
            }),
        )]));
    let session = client.create_session(cfg).await?;
    session.send(/* a prompt that needs the MCP tool */).await?;
  2. Send a prompt that requires the MCP tool.

Expected

The azure MCP server is started and its tools (e.g. azure-kusto) are registered and offered to the model.

Actual

  • The server is never spawned (no @azure/mcp / npx child process), no MCP tools are registered, and the model reports the tool is not available — e.g. its own reasoning log: "I'm looking for the kusto tool in my available functions, but I don't see it listed directly … it's not showing up in my tools." The model falls back to other tools.

Evidence / root cause

  1. The SDK does send the server. The session.create request received by the CLI contains it:
    {"enableConfigDiscovery":false,"enableSkills":true,
     "mcpServers":{"azure":{"command":"npx","args":["-y","@azure/mcp@latest","server","start","--namespace","kusto"],"type":"stdio","timeout":120000,...}},
     "model":"...","sessionId":"...","streaming":true,"tools":[]}
  2. The CLI's session.create handler constructs the internal session by forwarding model, sessionId, systemMessage, largeOutput, availableTools, excludedTools, provider, enableStreamingbut not mcpServers (observed in the bundled app.js, both 1.0.51-2 and 1.0.64-0).
  3. As a result initializeMcpHost() (which only acts when this.mcpServers / selectedCustomAgent.mcpServers is non-empty) never runs for these servers.

Workarounds tried (all fail in server mode)

  • Upgrading the CLI 1.0.51-2 → 1.0.64-0: no change.
  • GITHUB_COPILOT_MCP_JSON + GITHUB_COPILOT_3P_MCP_ENABLED=true: not read in server mode (readMcpConfigFromEnv() is not invoked; no "User-provided MCPs" log line appears).
  • Config/plugin discovery (enable_config_discovery=true): does load plugin MCPs in server mode, but it pulls in all ambient servers — there is no supported way to inject a single explicit server in server mode.

The only thing that works is patching the bundled app.js to add mcpServers to the object passed to createSession(...), after which the server starts and azure-kusto is registered as expected — confirming the dropped field is the cause.

Related

These touch the programmatic surface but don't call out the specific session.createmcpServers drop.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions