# Build Your First Copilot-Powered App In this tutorial, you'll use the Copilot SDK to build a command-line assistant. You'll start with the basics, add streaming responses, then add custom tools - giving Copilot the ability to call your code. **What you'll build:** ``` You: What's the weather like in Seattle? Copilot: Let me check the weather for Seattle... Currently 62°F and cloudy with a chance of rain. Typical Seattle weather! You: How about Tokyo? Copilot: In Tokyo it's 75°F and sunny. Great day to be outside! ``` ## Prerequisites Before you begin, make sure you have: - **GitHub Copilot CLI** installed and authenticated ([Installation guide](https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli)) - Your preferred language runtime: - **Node.js** 18+ or **Python** 3.8+ or **Go** 1.21+ or **.NET** 8.0+ Verify the CLI is working: ```bash copilot --version ``` ## Step 1: Install the SDK
Node.js / TypeScript First, create a new directory and initialize your project: ```bash mkdir copilot-demo && cd copilot-demo npm init -y ``` Then install the SDK and TypeScript runner: ```bash npm install @github/copilot-sdk tsx ```
Python ```bash pip install github-copilot-sdk ```
Go First, create a new directory and initialize your module: ```bash mkdir copilot-demo && cd copilot-demo go mod init copilot-demo ``` Then install the SDK: ```bash go get github.com/github/copilot-sdk/go ```
.NET First, create a new console project: ```bash dotnet new console -n CopilotDemo && cd CopilotDemo ``` Then add the SDK: ```bash dotnet add package GitHub.Copilot.SDK ```
## Step 2: Send Your First Message Create a new file and add the following code. This is the simplest way to use the SDK—about 5 lines of code.
Node.js / TypeScript Create `index.ts`: ```typescript import { CopilotClient } from "@github/copilot-sdk"; const client = new CopilotClient(); const session = await client.createSession({ model: "gpt-4.1" }); const response = await session.sendAndWait({ prompt: "What is 2 + 2?" }); console.log(response?.data.content); await client.stop(); process.exit(0); ``` Run it: ```bash npx tsx index.ts ```
Python Create `main.py`: ```python import asyncio from copilot import CopilotClient async def main(): client = CopilotClient() await client.start() session = await client.create_session({"model": "gpt-4.1"}) response = await session.send_and_wait({"prompt": "What is 2 + 2?"}) print(response.data.content) await client.stop() asyncio.run(main()) ``` Run it: ```bash python main.py ```
Go Create `main.go`: ```go package main import ( "fmt" "log" "os" 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() session, err := client.CreateSession(&copilot.SessionConfig{Model: "gpt-4.1"}) if err != nil { log.Fatal(err) } response, err := session.SendAndWait(copilot.MessageOptions{Prompt: "What is 2 + 2?"}, 0) if err != nil { log.Fatal(err) } fmt.Println(*response.Data.Content) os.Exit(0) } ``` Run it: ```bash go run main.go ```
.NET Create a new console project and add this to `Program.cs`: ```csharp using GitHub.Copilot.SDK; await using var client = new CopilotClient(); await using var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-4.1" }); var response = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2 + 2?" }); Console.WriteLine(response?.Data.Content); ``` Run it: ```bash dotnet run ```
**You should see:** ``` 4 ``` Congratulations! You just built your first Copilot-powered app. ## Step 3: Add Streaming Responses Right now, you wait for the complete response before seeing anything. Let's make it interactive by streaming the response as it's generated.
Node.js / TypeScript Update `index.ts`: ```typescript import { CopilotClient, SessionEvent } from "@github/copilot-sdk"; const client = new CopilotClient(); const session = await client.createSession({ model: "gpt-4.1", streaming: true, }); // Listen for response chunks session.on((event: SessionEvent) => { if (event.type === "assistant.message_delta") { process.stdout.write(event.data.deltaContent); } if (event.type === "session.idle") { console.log(); // New line when done } }); await session.sendAndWait({ prompt: "Tell me a short joke" }); await client.stop(); process.exit(0); ```
Python Update `main.py`: ```python import asyncio import sys from copilot import CopilotClient from copilot.generated.session_events import SessionEventType async def main(): client = CopilotClient() await client.start() session = await client.create_session({ "model": "gpt-4.1", "streaming": True, }) # Listen for response chunks def handle_event(event): if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA: sys.stdout.write(event.data.delta_content) sys.stdout.flush() if event.type == SessionEventType.SESSION_IDLE: print() # New line when done session.on(handle_event) await session.send_and_wait({"prompt": "Tell me a short joke"}) await client.stop() asyncio.run(main()) ```
Go Update `main.go`: ```go package main import ( "fmt" "log" "os" 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() session, err := client.CreateSession(&copilot.SessionConfig{ Model: "gpt-4.1", Streaming: true, }) if err != nil { log.Fatal(err) } // Listen for response chunks session.On(func(event copilot.SessionEvent) { if event.Type == "assistant.message_delta" { fmt.Print(*event.Data.DeltaContent) } if event.Type == "session.idle" { fmt.Println() } }) _, err = session.SendAndWait(copilot.MessageOptions{Prompt: "Tell me a short joke"}, 0) if err != nil { log.Fatal(err) } os.Exit(0) } ```
.NET Update `Program.cs`: ```csharp using GitHub.Copilot.SDK; await using var client = new CopilotClient(); await using var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-4.1", Streaming = true, }); // Listen for response chunks session.On(ev => { if (ev is AssistantMessageDeltaEvent deltaEvent) { Console.Write(deltaEvent.Data.DeltaContent); } if (ev is SessionIdleEvent) { Console.WriteLine(); } }); await session.SendAndWaitAsync(new MessageOptions { Prompt = "Tell me a short joke" }); ```
Run the code again. You'll see the response appear word by word. ## Step 4: Add a Custom Tool Now for the powerful part. Let's give Copilot the ability to call your code by defining a custom tool. We'll create a simple weather lookup tool.
Node.js / TypeScript Update `index.ts`: ```typescript import { CopilotClient, defineTool, SessionEvent } from "@github/copilot-sdk"; // Define a tool that Copilot can call const getWeather = defineTool("get_weather", { description: "Get the current weather for a city", parameters: { type: "object", properties: { city: { type: "string", description: "The city name" }, }, required: ["city"], }, handler: async (args: { city: string }) => { const { city } = args; // In a real app, you'd call a weather API here const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]; const temp = Math.floor(Math.random() * 30) + 50; const condition = conditions[Math.floor(Math.random() * conditions.length)]; return { city, temperature: `${temp}°F`, condition }; }, }); const client = new CopilotClient(); const session = await client.createSession({ model: "gpt-4.1", streaming: true, tools: [getWeather], }); session.on((event: SessionEvent) => { if (event.type === "assistant.message_delta") { process.stdout.write(event.data.deltaContent); } }); await session.sendAndWait({ prompt: "What's the weather like in Seattle and Tokyo?", }); await client.stop(); process.exit(0); ```
Python Update `main.py`: ```python import asyncio import random import sys from copilot import CopilotClient from copilot.tools import define_tool from copilot.generated.session_events import SessionEventType # Define a tool that Copilot can call @define_tool(description="Get the current weather for a city") async def get_weather(params: dict) -> dict: city = params["city"] # In a real app, you'd call a weather API here conditions = ["sunny", "cloudy", "rainy", "partly cloudy"] temp = random.randint(50, 80) condition = random.choice(conditions) return {"city": city, "temperature": f"{temp}°F", "condition": condition} async def main(): client = CopilotClient() await client.start() session = await client.create_session({ "model": "gpt-4.1", "streaming": True, "tools": [get_weather], }) def handle_event(event): if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA: sys.stdout.write(event.data.delta_content) sys.stdout.flush() if event.type == SessionEventType.SESSION_IDLE: print() session.on(handle_event) await session.send_and_wait({ "prompt": "What's the weather like in Seattle and Tokyo?" }) await client.stop() asyncio.run(main()) ```
Go Update `main.go`: ```go package main import ( "fmt" "log" "math/rand" "os" copilot "github.com/github/copilot-sdk/go" ) // Define the parameter type type WeatherParams struct { City string `json:"city" jsonschema:"The city name"` } // Define the return type type WeatherResult struct { City string `json:"city"` Temperature string `json:"temperature"` Condition string `json:"condition"` } func main() { // Define a tool that Copilot can call getWeather := copilot.DefineTool( "get_weather", "Get the current weather for a city", func(params WeatherParams, inv copilot.ToolInvocation) (WeatherResult, error) { // In a real app, you'd call a weather API here conditions := []string{"sunny", "cloudy", "rainy", "partly cloudy"} temp := rand.Intn(30) + 50 condition := conditions[rand.Intn(len(conditions))] return WeatherResult{ City: params.City, Temperature: fmt.Sprintf("%d°F", temp), Condition: condition, }, nil }, ) client := copilot.NewClient(nil) if err := client.Start(); err != nil { log.Fatal(err) } defer client.Stop() session, err := client.CreateSession(&copilot.SessionConfig{ Model: "gpt-4.1", Streaming: true, Tools: []copilot.Tool{getWeather}, }) if err != nil { log.Fatal(err) } session.On(func(event copilot.SessionEvent) { if event.Type == "assistant.message_delta" { fmt.Print(*event.Data.DeltaContent) } if event.Type == "session.idle" { fmt.Println() } }) _, err = session.SendAndWait(copilot.MessageOptions{ Prompt: "What's the weather like in Seattle and Tokyo?", }, 0) if err != nil { log.Fatal(err) } os.Exit(0) } ```
.NET Update `Program.cs`: ```csharp using GitHub.Copilot.SDK; using Microsoft.Extensions.AI; using System.ComponentModel; await using var client = new CopilotClient(); // Define a tool that Copilot can call var getWeather = AIFunctionFactory.Create( ([Description("The city name")] string city) => { // In a real app, you'd call a weather API here var conditions = new[] { "sunny", "cloudy", "rainy", "partly cloudy" }; var temp = Random.Shared.Next(50, 80); var condition = conditions[Random.Shared.Next(conditions.Length)]; return new { city, temperature = $"{temp}°F", condition }; }, "get_weather", "Get the current weather for a city" ); await using var session = await client.CreateSessionAsync(new SessionConfig { Model = "gpt-4.1", Streaming = true, Tools = [getWeather], }); session.On(ev => { if (ev is AssistantMessageDeltaEvent deltaEvent) { Console.Write(deltaEvent.Data.DeltaContent); } if (ev is SessionIdleEvent) { Console.WriteLine(); } }); await session.SendAndWaitAsync(new MessageOptions { Prompt = "What's the weather like in Seattle and Tokyo?", }); ```
Run it and you'll see Copilot call your tool to get weather data, then respond with the results! ## Step 5: Build an Interactive Assistant Let's put it all together into a useful interactive assistant:
Node.js / TypeScript ```typescript import { CopilotClient, defineTool, SessionEvent } from "@github/copilot-sdk"; import * as readline from "readline"; const getWeather = defineTool("get_weather", { description: "Get the current weather for a city", parameters: { type: "object", properties: { city: { type: "string", description: "The city name" }, }, required: ["city"], }, handler: async ({ city }) => { const conditions = ["sunny", "cloudy", "rainy", "partly cloudy"]; const temp = Math.floor(Math.random() * 30) + 50; const condition = conditions[Math.floor(Math.random() * conditions.length)]; return { city, temperature: `${temp}°F`, condition }; }, }); const client = new CopilotClient(); const session = await client.createSession({ model: "gpt-4.1", streaming: true, tools: [getWeather], }); session.on((event: SessionEvent) => { if (event.type === "assistant.message_delta") { process.stdout.write(event.data.deltaContent); } }); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); console.log("🌤️ Weather Assistant (type 'exit' to quit)"); console.log(" Try: 'What's the weather in Paris?'\n"); const prompt = () => { rl.question("You: ", async (input) => { if (input.toLowerCase() === "exit") { await client.stop(); rl.close(); return; } process.stdout.write("Assistant: "); await session.sendAndWait({ prompt: input }); console.log("\n"); prompt(); }); }; prompt(); ``` Run with: ```bash npx tsx weather-assistant.ts ```
Python Create `weather_assistant.py`: ```python import asyncio import random import sys from copilot import CopilotClient from copilot.tools import define_tool from copilot.generated.session_events import SessionEventType @define_tool(description="Get the current weather for a city") async def get_weather(params: dict) -> dict: city = params["city"] conditions = ["sunny", "cloudy", "rainy", "partly cloudy"] temp = random.randint(50, 80) condition = random.choice(conditions) return {"city": city, "temperature": f"{temp}°F", "condition": condition} async def main(): client = CopilotClient() await client.start() session = await client.create_session({ "model": "gpt-4.1", "streaming": True, "tools": [get_weather], }) def handle_event(event): if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA: sys.stdout.write(event.data.delta_content) sys.stdout.flush() session.on(handle_event) print("🌤️ Weather Assistant (type 'exit' to quit)") print(" Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA'\n") while True: try: user_input = input("You: ") except EOFError: break if user_input.lower() == "exit": break sys.stdout.write("Assistant: ") await session.send_and_wait({"prompt": user_input}) print("\n") await client.stop() asyncio.run(main()) ``` Run with: ```bash python weather_assistant.py ```
**Example session:** ``` 🌤️ Weather Assistant (type 'exit' to quit) Try: 'What's the weather in Paris?' or 'Compare weather in NYC and LA' You: What's the weather in Seattle? Assistant: Let me check the weather for Seattle... It's currently 62°F and cloudy in Seattle. You: How about Tokyo and London? Assistant: I'll check both cities for you: - Tokyo: 75°F and sunny - London: 58°F and rainy You: exit ``` You've built an assistant with a custom tool that Copilot can call! --- ## How Tools Work When you define a tool, you're telling Copilot: 1. **What the tool does** (description) 2. **What parameters it needs** (schema) 3. **What code to run** (handler) Copilot decides when to call your tool based on the user's question. When it does: 1. Copilot sends a tool call request with the parameters 2. The SDK runs your handler function 3. The result is sent back to Copilot 4. Copilot incorporates the result into its response --- ## What's Next? Now that you've got the basics, here are more powerful features to explore: ### Connect to MCP Servers MCP (Model Context Protocol) servers provide pre-built tools. Connect to GitHub's MCP server to give Copilot access to repositories, issues, and pull requests: ```typescript const session = await client.createSession({ mcpServers: { github: { type: "http", url: "https://api.githubcopilot.com/mcp/", }, }, }); ``` ### Create Custom Agents Define specialized AI personas for specific tasks: ```typescript const session = await client.createSession({ customAgents: [{ name: "pr-reviewer", displayName: "PR Reviewer", description: "Reviews pull requests for best practices", prompt: "You are an expert code reviewer. Focus on security, performance, and maintainability.", }], }); ``` ### Customize the System Message Control the AI's behavior and personality: ```typescript const session = await client.createSession({ systemMessage: { content: "You are a helpful assistant for our engineering team. Always be concise.", }, }); ``` --- ## Learn More - [Node.js SDK Reference](../nodejs/README.md) - [Python SDK Reference](../python/README.md) - [Go SDK Reference](../go/README.md) - [.NET SDK Reference](../dotnet/README.md) - [GitHub MCP Server Documentation](https://github.com/github/github-mcp-server) - [MCP Servers Directory](https://github.com/modelcontextprotocol/servers) - Explore more MCP servers --- **You did it!** You've learned the core concepts of the GitHub Copilot SDK: - ✅ Creating a client and session - ✅ Sending messages and receiving responses - ✅ Streaming for real-time output - ✅ Defining custom tools that Copilot can call Now go build something amazing! 🚀