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

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. 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 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), 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.

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, 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.

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 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.

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, 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:

  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).

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.

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 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 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.

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). 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). 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →