# How to Integrate Local STDIO and HTTP/SSE MCP Servers with the Copilot SDK

> Integrate local STDIO and HTTP/SSE MCP servers with the Copilot SDK. Learn how to expose external tools to the model-context-protocol runtime for seamless integration.

- Repository: [GitHub/copilot-sdk](https://github.com/github/copilot-sdk)
- Tags: how-to-guide
- Published: 2026-08-02

---

**The Copilot SDK exposes external tools to the model-context-protocol runtime by configuring `McpServerConfig` structs in `SessionConfig.McpServers`, supporting local subprocesses via STDIO or remote endpoints via HTTP/SSE.**

The GitHub Copilot SDK enables developers to extend AI capabilities by connecting custom tools through the Model Context Protocol (MCP). Whether you need to integrate a local script running as a subprocess or a remote microservice streaming events over HTTP, the SDK provides a unified configuration interface defined in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go). This guide walks through the concrete implementation details found in the `github/copilot-sdk` repository.

## Core Architecture and Configuration Types

The SDK defines a hierarchy of configuration structs in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go) that handle different transport mechanisms. Each struct embeds the base `McpServerConfig` fields while adding protocol-specific parameters.

**McpServerConfig** serves as the abstract base type (lines 1096-1130 in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go)), containing common fields including `name`, `enabled`, and `type`. The runtime differentiates concrete implementations through the presence of protocol-specific fields.

**McpStdioServerConfig** (lines 1134-1159) handles local subprocesses, storing the `Command`, `Args`, environment variables, and optional `WorkingDir`. You can also specify `StartupTimeoutSeconds` to control how long the SDK waits for the process to initialize.

**McpHttpServerConfig** (lines 1163-1180) manages remote HTTP-based servers with `Url` and optional `Token` fields for bearer token authentication.

**McpSseServerConfig** (lines 1184-1201) extends the HTTP configuration for Server-Sent Events, adding an `SseUrl` field for the streaming endpoint while inheriting the base URL and authentication from `McpHttpServerConfig`.

The top-level **SessionConfig** struct (lines 1850-1865) aggregates these through the `McpServers []McpServerConfig` slice, which the runtime iterates during initialization.

## Implementing Local STDIO MCP Servers

To integrate a local tool that communicates over standard input/output, populate the STDIO-specific fields in your session configuration. The SDK spawns the process using `exec.Command` and wraps the stdin/stdout pipes in a JSON-RPC connection.

```go
package main

import (
    "log"
    "github.com/github/copilot-sdk/go"
)

func main() {
    sess, err := copilot.NewSession(&copilot.SessionConfig{
        McpServers: []copilot.McpServerConfig{
            {
                Name:        "local-echo",
                Enabled:     true,
                Command:     "node",
                Args:        []string{"./echo-server.js"},
                Env:         []string{"ECHO_DEBUG=1"},
                WorkingDir:  "./tools",
                StartupTimeoutSeconds: 5,
            },
        },
    })
    if err != nil {
        log.Fatalf("session init failed: %v", err)
    }
    
    // Use session for tool invocation
    _ = sess
}

```

The `Command` and `Args` fields map directly to the subprocess execution. According to the source code in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go), the SDK validates these fields before launching the process and reports startup failures through `session.Events` as `McpServerError` diagnostics.

## Configuring Remote HTTP MCP Servers

For remote microservices exposing MCP endpoints over HTTP, use `McpHttpServerConfig`. The SDK constructs an `http.Client` that attaches the optional bearer token to every request.

```go
sess, err := copilot.NewSession(&copilot.SessionConfig{
    McpServers: []copilot.McpServerConfig{
        {
            Name:    "remote-math",
            Enabled: true,
            Url:     "https://api.math.example.com/mcp",
            Token:   "Bearer static-token-12345",
        },
    },
})

```

The `Url` field specifies the base endpoint, while `Token` populates the Authorization header. This configuration is defined in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go) lines 1163-1180.

## Setting Up SSE MCP Servers

Server-Sent Events enable streaming tool calls for long-running operations. The `McpSseServerConfig` requires both the base `Url` and the `SseUrl` for the event stream.

```go
sess, err := copilot.NewSession(&copilot.SessionConfig{
    McpServers: []copilot.McpServerConfig{
        {
            Name:    "streaming-search",
            Enabled: true,
            Url:     "https://search.example.com/mcp",
            SseUrl:  "https://search.example.com/mcp/events",
        },
    },
})

```

As implemented in [`go/session.go`](https://github.com/github/copilot-sdk/blob/main/go/session.go), the SDK upgrades the HTTP client to an `EventSource` connection against the `SseUrl` endpoint, translating each SSE message into JSON-RPC request/response pairs.

## Runtime Initialization Flow

When you invoke `copilot.NewSession(...)`, the runtime executes a four-stage initialization process defined in [`go/session.go`](https://github.com/github/copilot-sdk/blob/main/go/session.go):

1. **Configuration parsing** – The SDK iterates `SessionConfig.McpServers` and matches each entry to its concrete type (`McpStdioServerConfig`, `McpHttpServerConfig`, or `McpSseServerConfig`).

2. **Transport initialization** – 
   - STDIO servers trigger `exec.Command` with piped stdin/stdout
   - HTTP servers instantiate `http.Client` with the base URL
   - SSE servers create an `EventSource` against the streaming endpoint

3. **Tool registration** – The SDK queries each server for available tools and registers them with the session's tool registry.

4. **OAuth handling** – If the server requires per-user tokens, the SDK invokes the optional `McpOAuthHandler` configured in `SessionConfig` (lines 2043-2050 in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go)).

## Advanced Implementation Details

### OAuth Authentication for MCP Apps

When your MCP server requires per-user OAuth tokens rather than static bearer tokens, configure the `McpOAuthHandler` field in your session configuration. This handler manages token acquisition and refresh flows. The test harness at `test/harness/test-mcp-oauth-server.mjs` provides a reference implementation for OAuth-enabled HTTP servers.

### Error Handling and Debugging

The SDK reports transport failures distinctly by type. STDIO launch failures appear when the subprocess exits or fails to start within `StartupTimeoutSeconds`. HTTP/SSE connectivity issues surface as connection errors in the session event stream. Monitor `session.Events` for `McpServerError` payloads to diagnose initialization problems. Additional debugging guidance is available in [`docs/troubleshooting/mcp-debugging.md`](https://github.com/github/copilot-sdk/blob/main/docs/troubleshooting/mcp-debugging.md).

### Tool Deferral Behavior

When the total tool count exceeds the session's `tool_limit`, the SDK automatically defers MCP tools behind a form-based UI. You can toggle this behavior using the `disable_form_deferral` flag in `GitHubMcpConfig` for built-in GitHub MCP integrations.

## Summary

- **Configuration hierarchy**: Base `McpServerConfig` in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go) branches into `McpStdioServerConfig`, `McpHttpServerConfig`, and `McpSseServerConfig` for different transport mechanisms.
- **STDIO integration**: Launch local subprocesses by specifying `Command`, `Args`, `Env`, and `WorkingDir` with optional `StartupTimeoutSeconds`.
- **HTTP endpoints**: Connect to remote servers using `Url` and optional `Token` fields for bearer authentication.
- **SSE streaming**: Configure both `Url` and `SseUrl` to enable Server-Sent Events for real-time tool interactions.
- **Runtime flow**: [`go/session.go`](https://github.com/github/copilot-sdk/blob/main/go/session.go) handles type detection, transport initialization, tool registration, and optional OAuth flows when creating sessions via `copilot.NewSession`.

## Frequently Asked Questions

### How does the Copilot SDK determine which transport protocol to use for an MCP server?

The SDK inspects the concrete fields present in each `McpServerConfig` entry. If the configuration includes `Command` and `Args` fields, it instantiates a STDIO transport. If it contains a `Url` field without `SseUrl`, it creates an HTTP client. When `SseUrl` is present, the SDK upgrades to an SSE EventSource connection. This type inference happens during the initialization phase in [`go/session.go`](https://github.com/github/copilot-sdk/blob/main/go/session.go).

### Can I mix STDIO and HTTP/SSE servers in the same session?

Yes. The `SessionConfig.McpServers` field accepts a slice of mixed configuration types. You can register local STDIO tools alongside remote HTTP endpoints in a single `copilot.NewSession` call. The runtime initializes each transport independently and aggregates all exposed tools into the session's unified tool registry.

### What happens if my STDIO server fails to start within the timeout period?

The SDK respects the `StartupTimeoutSeconds` field defined in `McpStdioServerConfig` (lines 1134-1159 in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go)). If the subprocess does not become ready within this window, the runtime generates an `McpServerError` event and excludes that server's tools from the session. The session continues initialization with other configured servers unless the error is catastrophic.

### How do I authenticate with MCP servers that require dynamic OAuth tokens?

Instead of using the static `Token` field, configure the `McpOAuthHandler` callback in your `SessionConfig` (lines 2043-2050 in [`go/types.go`](https://github.com/github/copilot-sdk/blob/main/go/types.go)). This handler executes during initialization to acquire per-user tokens. The repository provides example implementations in `test/harness/test-mcp-oauth-server.mjs` demonstrating the OAuth flow for HTTP-based MCP servers.