From 0b4cc4ad97e20cf5f061ebd1616d46a8face394d Mon Sep 17 00:00:00 2001 From: Jailior Date: Sat, 24 Jan 2026 13:54:58 -0800 Subject: [PATCH 1/2] docs: add MCP usage documentation and language specific examples --- docs/getting-started.md | 3 + docs/mcp-usage.md | 289 ++++++++++++++++++++++++++++++++++++++++ dotnet/README.md | 35 +++++ go/README.md | 30 +++++ nodejs/README.md | 25 ++++ python/README.md | 25 ++++ 6 files changed, 407 insertions(+) create mode 100644 docs/mcp-usage.md diff --git a/docs/getting-started.md b/docs/getting-started.md index 61743e78..116aa535 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -839,10 +839,13 @@ const session = await client.createSession({ github: { type: "http", url: "https://api.githubcopilot.com/mcp/", + tools: ["*"] }, }, }); ``` +Learn more about MCP server usage: [Using MCP servers with the Copilot SDK](./mcp-usage.md) + ### Create Custom Agents diff --git a/docs/mcp-usage.md b/docs/mcp-usage.md new file mode 100644 index 00000000..ad9294f9 --- /dev/null +++ b/docs/mcp-usage.md @@ -0,0 +1,289 @@ +# Using MCP servers with the Copilot SDK + +This document shows how to configure MCP (Model Context Protocol) servers for sessions in each client SDK supported by this repository. + +### What is MCP? +- MCP servers expose pre-built tools and resources (for example, GitHub MCP Server provides tools for issues, PRs, and repositories). +- You can configure local (stdio/local) or remote (HTTP/SSE) MCP servers and make them available to sessions. + +### Common concepts +- `mcpServers` is the session-level configuration that maps server name to server configuration. +- Server config has two broad shapes: + - **Local/stdio servers**: `type: "local" | "stdio"`, `command`, `args`, `env`, `cwd` + - `type`: Defaults to `"local"` if not specified + - `command`: The executable to run (e.g., `"node"`, `"python"`) + - `args`: Arguments to pass to the command + - `env`: Optional environment variables for the process + - `cwd`: Optional working directory for the process + - **Remote servers**: `type: "http" | "sse"`, `url`, `headers` + - `type`: Either `"http"` or `"sse"` (Server-Sent Events) + - `url`: The endpoint URL of the MCP server + - `headers`: Optional HTTP headers for authentication +- `tools`: Array of tool names to expose from the server (use `["*"]` for all tools, `[]` for none) + +### Examples + +Below are examples for configuring both local and remote MCP servers: + +
+Node.js / TypeScript + +```ts +import { CopilotClient, type MCPLocalServerConfig, type MCPRemoteServerConfig } from "@github/copilot-sdk"; + +const client = new CopilotClient(); +await client.start(); + +const session = await client.createSession({ + mcpServers: { + "github": { + type: "http", + url: "https://api.githubcopilot.com/mcp/", + tools: ["github-repos", "github-pull-requests"], + headers: { Authorization: "Bearer " }, + } as MCPRemoteServerConfig, + "local-tools": { + type: "local", + command: "node", + args: ["./local-mcp-server.js"], + tools: ["my-tool"], + env: { "DEBUG": "1" }, + } as MCPLocalServerConfig, + }, +}); + +// Wait for response using session.idle event +const done = new Promise((resolve) => { + session.on((event) => { + if (event.type === "assistant.message") { + console.log(event.data.content); + } else if (event.type === "session.idle") { + resolve(); + } + }); +}); + +// Send a message and wait for completion +await session.send({ prompt: "Use the GitHub MCP Server tools to fetch PR data" }); +await done; + +await session.destroy(); +await client.stop(); +``` + +
+ +
+Python + +```python +import asyncio +from copilot import CopilotClient + +async def main(): + client = CopilotClient() + await client.start() + + session = await client.create_session({ + "mcp_servers": { + "github": { + "type": "http", + "url": "https://api.githubcopilot.com/mcp/", + "tools": ["github-repos", "github-pull-requests"], + "headers": {"Authorization": "Bearer "}, + }, + "local-tools": { + "type": "local", + "command": "echo", + "args": ["hello"], + "tools": ["*"], + "env": {"DEBUG": "1"}, + } + } + }) + + done = asyncio.Event() + + await session.send({"prompt": "Use the GitHub MCP Server tools to fetch PR data"}) + await done.wait() + + await session.destroy() + await client.stop() + +asyncio.run(main()) +``` + +
+ + +
+Go + +```go +package main + +import ( + "fmt" + "log" + + copilot "github.com/github/copilot-sdk/go" +) + +func main() { + client := copilot.NewClient(nil) + + if err := client.Start(); err != nil { + log.Fatal(err) + } + defer client.Stop() + + mcpServers := map[string]copilot.MCPServerConfig{ + "github": { + "type": "http", + "url": "https://api.githubcopilot.com/mcp/", + "tools": []string{"github-repos", "github-pull-requests"}, + "headers": map[string]string{ + "Authorization": "Bearer ", + }, + }, + "local-tools": { + "type": "local", + "command": "echo", + "args": []string{"hello"}, + "tools": []string{"*"}, + "env": map[string]string{"DEBUG": "1"}, + }, + } + + session, err := client.CreateSession(&copilot.SessionConfig{ + MCPServers: mcpServers, + }) + if err != nil { + log.Fatalf("Failed to create session: %v", err) + } + defer session.Destroy() + + _, err = session.Send(copilot.MessageOptions{ + Prompt: "Use the GitHub MCP Server tools to fetch PR data", + }) + if err != nil { + log.Fatal(err) + } +} +``` + +
+ +
+.NET + +```csharp +using GitHub.Copilot.SDK; + +await using var client = new CopilotClient(); +await client.StartAsync(); + +var mcpServers = new Dictionary +{ + ["github"] = new McpRemoteServerConfig + { + Type = "http", + Url = "https://api.githubcopilot.com/mcp/", + Tools = new[] { "github-repos", "github-pull-requests" }, + Headers = new Dictionary + { + ["Authorization"] = "Bearer " + } + }, + ["local-tools"] = new McpLocalServerConfig + { + Type = "local", + Command = "echo", + Args = new[] { "hello" }, + Tools = new[] { "*" }, + Env = new Dictionary { ["DEBUG"] = "1" } + } +}; + +await using var session = await client.CreateSessionAsync(new SessionConfig +{ + McpServers = mcpServers +}); + +var done = new TaskCompletionSource(); + +await session.SendAsync(new MessageOptions { Prompt = "What is 2+2?" }); +await done.Task; + +await session.DisposeAsync(); +``` + +
+ +
+ +> Note that the **GitHub MCP server** is **already configured** as part of Copilot CLI and the SDK, +so configuring it explicitly is not necessary. + + +### Notes and tips + +#### Configuration best practices: +- When adding remote MCP servers, prefer using service tokens or environment-based secrets rather than hard-coding tokens in samples. +- For local servers, document any required dependencies and how to run them (e.g., `npm install` then `node server.js`). +- Always call `session.destroy()` or `await session.DisposeAsync()` when finished with a session to clean up resources. + + +#### Session resumption with MCP servers: +- You can also configure or add MCP servers when resuming a session: + + +
+Node.js / TypeScript + +```ts +const session = await client.resumeSession(sessionId, { + mcpServers: { /* server configs */ } +}); +``` +
+ +
+Python + +```py +session = await client.resume_session(session_id, {"mcp_servers": { """ """ }}) +``` +
+ +
+Go + +```go +session, err := client.ResumeSessionWithOptions(sessionID, &copilot.ResumeSessionConfig{ + MCPServers: mcpServers, +}) +``` +
+ +
+.NET + +```csharp +var session = await client.ResumeSessionAsync(sessionId, new ResumeSessionConfig +{ + McpServers = mcpServers +}); +``` +
+ + +#### Additional resources: +- For more information on available MCP servers: + - [GitHub MCP Server Documentation](https://github.com/github/github-mcp-server) + - [MCP Servers Directory](https://github.com/modelcontextprotocol/servers) - Explore more MCP servers +- For troubleshooting local MCP servers, check that: + - The command exists and is in the PATH + - The process has appropriate permissions and environment variables + - Arguments are correctly formatted for the command line + diff --git a/dotnet/README.md b/dotnet/README.md index e176da40..bcdff017 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -323,6 +323,41 @@ When enabled, sessions emit compaction events: - `SessionCompactionStartEvent` - Background compaction started - `SessionCompactionCompleteEvent` - Compaction finished (includes token counts) +## MCP Servers + +Configure local and remote MCP server usage: + +```csharp +var mcpServers = new Dictionary +{ + ["github"] = new McpRemoteServerConfig + { + Type = "http", + Url = "https://api.githubcopilot.com/mcp/", + Tools = new[] { "github-repos", "github-pull-requests" }, + Headers = new Dictionary + { + ["Authorization"] = "Bearer " + } + }, + ["local-tools"] = new McpLocalServerConfig + { + Type = "local", + Command = "echo", + Args = new[] { "hello" }, + Tools = new[] { "*" }, + Env = new Dictionary { ["DEBUG"] = "1" } + } +}; + +var session = await client.CreateSessionAsync(new SessionConfig +{ + McpServers = mcpServers +}); +``` + +Futher MCP server usage details: [Using MCP servers with the Copilot SDK](../docs/mcp-usage.md) + ## Advanced Usage ### Manual Server Control diff --git a/go/README.md b/go/README.md index 1352d9a3..2e458ef0 100644 --- a/go/README.md +++ b/go/README.md @@ -325,6 +325,36 @@ When enabled, sessions emit compaction events: - `session.compaction_start` - Background compaction started - `session.compaction_complete` - Compaction finished (includes token counts) +## MCP Servers + +Configure local and remote MCP server usage: + +```go +mcpServers := map[string]copilot.MCPServerConfig{ + "github": { + "type": "http", + "url": "https://api.githubcopilot.com/mcp/", + "tools": []string{"github-repos", "github-pull-requests"}, + "headers": map[string]string{ + "Authorization": "Bearer ", + }, + }, + "local-tools": { + "type": "local", + "command": "echo", + "args": []string{"hello"}, + "tools": []string{"*"}, + "env": map[string]string{"DEBUG": "1"}, + }, +} + +session, err := client.CreateSession(&copilot.SessionConfig{ + MCPServers: mcpServers, +}) +``` + +Futher MCP server usage details: [Using MCP servers with the Copilot SDK](../docs/mcp-usage.md) + ## Transport Modes ### stdio (Default) diff --git a/nodejs/README.md b/nodejs/README.md index bd4ef15b..cae83031 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -263,6 +263,31 @@ When `streaming: true`: Note: `assistant.message` and `assistant.reasoning` (final events) are always sent regardless of streaming setting. +## MCP Servers + +Configure local and remote MCP server usage: + +```ts +const session = await client.createSession({ + mcpServers: { + "github": { + type: "http", + url: "https://api.githubcopilot.com/mcp/", + tools: ["github-repos", "github-pull-requests"], + headers: { Authorization: "Bearer " }, + } as MCPRemoteServerConfig, + "local-tools": { + type: "local", + command: "node", + args: ["./local-mcp-server.js"], + tools: ["my-tool"], + env: { "DEBUG": "1" }, + } as MCPLocalServerConfig, + }, +}); +``` +Futher MCP server usage details: [Using MCP servers with the Copilot SDK](../docs/mcp-usage.md) + ## Advanced Usage ### Manual Server Control diff --git a/python/README.md b/python/README.md index fefc1e0f..56720b84 100644 --- a/python/README.md +++ b/python/README.md @@ -273,6 +273,31 @@ When enabled, sessions emit compaction events: - `session.compaction_start` - Background compaction started - `session.compaction_complete` - Compaction finished (includes token counts) +## MCP Servers + +Configure local and remote MCP server usage: + +```python +session = await client.create_session({ + "mcp_servers": { + "github": { + "type": "http", + "url": "https://api.githubcopilot.com/mcp/", + "tools": ["github-repos", "github-pull-requests"], + "headers": {"Authorization": "Bearer "}, + }, + "local-tools": { + "type": "local", + "command": "echo", + "args": ["hello"], + "tools": ["*"], + "env": {"DEBUG": "1"}, + } + } +}) +``` +Futher MCP server usage details: [Using MCP servers with the Copilot SDK](../docs/mcp-usage.md) + ## Requirements - Python 3.9+ From eb94b53c84fb01fcf389cb83fae355d06f27aa9d Mon Sep 17 00:00:00 2001 From: Jailior Date: Sat, 24 Jan 2026 13:56:57 -0800 Subject: [PATCH 2/2] use send and wait and remove manual server control --- docs/mcp-usage.md | 135 +++++++++++++++++++++------------------------- dotnet/README.md | 10 ++-- go/README.md | 14 ++--- nodejs/README.md | 4 +- python/README.md | 4 +- 5 files changed, 76 insertions(+), 91 deletions(-) diff --git a/docs/mcp-usage.md b/docs/mcp-usage.md index ad9294f9..53fa24c3 100644 --- a/docs/mcp-usage.md +++ b/docs/mcp-usage.md @@ -32,7 +32,6 @@ Below are examples for configuring both local and remote MCP servers: import { CopilotClient, type MCPLocalServerConfig, type MCPRemoteServerConfig } from "@github/copilot-sdk"; const client = new CopilotClient(); -await client.start(); const session = await client.createSession({ mcpServers: { @@ -45,30 +44,20 @@ const session = await client.createSession({ "local-tools": { type: "local", command: "node", - args: ["./local-mcp-server.js"], - tools: ["my-tool"], + args: ["./mcp_server.js"], + tools: ["*"], env: { "DEBUG": "1" }, } as MCPLocalServerConfig, }, }); -// Wait for response using session.idle event -const done = new Promise((resolve) => { - session.on((event) => { - if (event.type === "assistant.message") { - console.log(event.data.content); - } else if (event.type === "session.idle") { - resolve(); - } - }); -}); - // Send a message and wait for completion -await session.send({ prompt: "Use the GitHub MCP Server tools to fetch PR data" }); -await done; +const response = await session.sendAndWait({ prompt: "Use the local-tools MCP Server to echo 'Hello from Copilot SDK!'." }); + +console.log(response?.data.content); -await session.destroy(); await client.stop(); +process.exit(0); ``` @@ -94,18 +83,17 @@ async def main(): }, "local-tools": { "type": "local", - "command": "echo", - "args": ["hello"], + "command": "python3", + "args": ["./mcp_server.py"], "tools": ["*"], "env": {"DEBUG": "1"}, } } }) - done = asyncio.Event() + response = await session.send_and_wait({"prompt": "Use the local-tools MCP Server to echo 'Hello from Copilot SDK!'."}) - await session.send({"prompt": "Use the GitHub MCP Server tools to fetch PR data"}) - await done.wait() + print(response.data.content) await session.destroy() await client.stop() @@ -123,52 +111,54 @@ asyncio.run(main()) package main import ( - "fmt" - "log" + "fmt" + "log" - copilot "github.com/github/copilot-sdk/go" + copilot "github.com/github/copilot-sdk/go" ) func main() { - client := copilot.NewClient(nil) - - if err := client.Start(); err != nil { - log.Fatal(err) - } - defer client.Stop() - - mcpServers := map[string]copilot.MCPServerConfig{ - "github": { - "type": "http", - "url": "https://api.githubcopilot.com/mcp/", - "tools": []string{"github-repos", "github-pull-requests"}, - "headers": map[string]string{ - "Authorization": "Bearer ", - }, - }, - "local-tools": { - "type": "local", - "command": "echo", - "args": []string{"hello"}, - "tools": []string{"*"}, - "env": map[string]string{"DEBUG": "1"}, - }, - } - - session, err := client.CreateSession(&copilot.SessionConfig{ - MCPServers: mcpServers, - }) - if err != nil { - log.Fatalf("Failed to create session: %v", err) - } - defer session.Destroy() - - _, err = session.Send(copilot.MessageOptions{ - Prompt: "Use the GitHub MCP Server tools to fetch PR data", - }) - if err != nil { - log.Fatal(err) - } + client := copilot.NewClient(nil) + + if err := client.Start(); err != nil { + log.Fatal(err) + } + defer client.Stop() + + mcpServers := map[string]copilot.MCPServerConfig{ + "github": { + "type": "http", + "url": "https://api.githubcopilot.com/mcp/", + "tools": []string{"github-repos", "github-pull-requests"}, + "headers": map[string]string{ + "Authorization": "Bearer ", + }, + }, + "local-tools": { + "type": "local", + "command": "go run", + "args": []string{"./mcp_server.go"}, + "tools": []string{"*"}, + "env": map[string]string{"DEBUG": "1"}, + }, + } + + session, err := client.CreateSession(&copilot.SessionConfig{ + MCPServers: mcpServers, + }) + if err != nil { + log.Fatalf("Failed to create session: %v", err) + } + defer session.Destroy() + + response, err := session.SendAndWait(copilot.MessageOptions{ + Prompt: "Use the local-tools MCP Server to echo 'Hello from Copilot SDK!'.", + }, 0) + if err != nil { + log.Fatal(err) + } + + fmt.Println(*response.Data.Content) } ``` @@ -181,7 +171,6 @@ func main() { using GitHub.Copilot.SDK; await using var client = new CopilotClient(); -await client.StartAsync(); var mcpServers = new Dictionary { @@ -189,7 +178,7 @@ var mcpServers = new Dictionary { Type = "http", Url = "https://api.githubcopilot.com/mcp/", - Tools = new[] { "github-repos", "github-pull-requests" }, + Tools = ["github-repos", "github-pull-requests"], Headers = new Dictionary { ["Authorization"] = "Bearer " @@ -198,9 +187,9 @@ var mcpServers = new Dictionary ["local-tools"] = new McpLocalServerConfig { Type = "local", - Command = "echo", - Args = new[] { "hello" }, - Tools = new[] { "*" }, + Command = "dotnet", + Args = ["./mcp_server.dll"], + Tools = ["*"], Env = new Dictionary { ["DEBUG"] = "1" } } }; @@ -210,12 +199,8 @@ await using var session = await client.CreateSessionAsync(new SessionConfig McpServers = mcpServers }); -var done = new TaskCompletionSource(); - -await session.SendAsync(new MessageOptions { Prompt = "What is 2+2?" }); -await done.Task; - -await session.DisposeAsync(); +var response = await session.SendAndWaitAsync(new MessageOptions { Prompt = "Use the local-tools MCP Server to echo 'Hello from Copilot SDK!'." }); +Console.WriteLine(response?.Data.Content); ``` diff --git a/dotnet/README.md b/dotnet/README.md index bcdff017..cc93c18d 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -334,7 +334,7 @@ var mcpServers = new Dictionary { Type = "http", Url = "https://api.githubcopilot.com/mcp/", - Tools = new[] { "github-repos", "github-pull-requests" }, + Tools = ["github-repos", "github-pull-requests"], Headers = new Dictionary { ["Authorization"] = "Bearer " @@ -343,14 +343,14 @@ var mcpServers = new Dictionary ["local-tools"] = new McpLocalServerConfig { Type = "local", - Command = "echo", - Args = new[] { "hello" }, - Tools = new[] { "*" }, + Command = "dotnet", + Args = ["./mcp_server.dll"], + Tools = ["*"], Env = new Dictionary { ["DEBUG"] = "1" } } }; -var session = await client.CreateSessionAsync(new SessionConfig +await using var session = await client.CreateSessionAsync(new SessionConfig { McpServers = mcpServers }); diff --git a/go/README.md b/go/README.md index 2e458ef0..a61b0a85 100644 --- a/go/README.md +++ b/go/README.md @@ -332,19 +332,19 @@ Configure local and remote MCP server usage: ```go mcpServers := map[string]copilot.MCPServerConfig{ "github": { - "type": "http", - "url": "https://api.githubcopilot.com/mcp/", + "type": "http", + "url": "https://api.githubcopilot.com/mcp/", "tools": []string{"github-repos", "github-pull-requests"}, "headers": map[string]string{ "Authorization": "Bearer ", }, }, "local-tools": { - "type": "local", - "command": "echo", - "args": []string{"hello"}, - "tools": []string{"*"}, - "env": map[string]string{"DEBUG": "1"}, + "type": "local", + "command": "go run", + "args": []string{"./mcp_server.go"}, + "tools": []string{"*"}, + "env": map[string]string{"DEBUG": "1"}, }, } diff --git a/nodejs/README.md b/nodejs/README.md index cae83031..cbccdcc2 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -279,8 +279,8 @@ const session = await client.createSession({ "local-tools": { type: "local", command: "node", - args: ["./local-mcp-server.js"], - tools: ["my-tool"], + args: ["./mcp_server.js"], + tools: ["*"], env: { "DEBUG": "1" }, } as MCPLocalServerConfig, }, diff --git a/python/README.md b/python/README.md index 56720b84..2109a1ad 100644 --- a/python/README.md +++ b/python/README.md @@ -288,8 +288,8 @@ session = await client.create_session({ }, "local-tools": { "type": "local", - "command": "echo", - "args": ["hello"], + "command": "python3", + "args": ["./mcp_server.py"], "tools": ["*"], "env": {"DEBUG": "1"}, }