CopilotKitDocs
  • Docs
  • Reference
  • Cookbook
Get Intelligence free
CopilotKitDocs
DocsReferenceCookbook
DocsReferenceCookbook

Getting Started

IntroductionQuickstartBuild with agents

Basics

Prebuilt Components
Programmatic ControlInspector

Generative UI

Tool RenderingState RenderingMCP AppsA2UI

App Control

Frontend Tools
Threads

CrewAI Flows

Multi-Agent Flows

Backend

Copilot RuntimeAG-UI

Premium Features

Troubleshooting

Migrate to V2Error Debugging & ObservabilityCommon Copilot IssuesMigrate to 1.10.XMigrate to 1.8.2

Other

Anonymous Telemetry

Platforms

SlackMicrosoft TeamsReact Native
CrewAI (Crews)Microsoft Teams

Microsoft Teams

Build a Microsoft Teams bot with CopilotKit from an empty Node project.


What you will build#

By the end of this guide, you will have a small Node app that can answer Microsoft Teams messages with a CopilotKit agent. You will test it locally first with Teams DevTools, then optionally expose the same bot through Azure Bot Service and sideload it into Microsoft Teams.

@copilotkit/bot-teams handles the Teams-specific work: receiving Teams activities, rendering Adaptive Cards, streaming updates, and running the local DevTools bridge. Your app provides the CopilotKit runtime, agent configuration, Microsoft credentials, tunnel, and Teams manifest.

ProcessPortPurpose
CopilotKit runtime8200Runs a BuiltInAgent and exposes /api/copilotkit
Teams bot3978Receives Teams activities at POST /api/messages
Teams DevTools3979Local browser UI for testing Teams messages without a Teams account

Prerequisites#

For local development:

  • Node.js 22 or newer
  • npm 10 or newer
  • an OpenAI API key

For sideloading into Microsoft Teams:

  • the devtunnel CLI
  • a Microsoft 365 tenant that allows uploading custom apps
  • access to create a Microsoft Entra app registration
  • access to create an Azure Bot resource

Build and verify locally#

Create the Node project#

Start with a new Node project and install the CopilotKit runtime, core package, and Teams bridge:

mkdir copilotkit-teams-bot
cd copilotkit-teams-bot
npm init -y
npm pkg set type=module
npm install @copilotkit/bot-teams @copilotkit/core @copilotkit/runtime
npm install -D tsx typescript @types/node
mkdir copilotkit-teams-bot
cd copilotkit-teams-bot
pnpm init
pnpm pkg set type=module
pnpm add @copilotkit/bot-teams @copilotkit/core @copilotkit/runtime
pnpm add -D tsx typescript @types/node
mkdir copilotkit-teams-bot
cd copilotkit-teams-bot
yarn init -y
yarn config set nodeLinker node-modules
npm pkg set type=module
yarn add @copilotkit/bot-teams @copilotkit/core @copilotkit/runtime
yarn add -D tsx typescript @types/node

Add TypeScript#

Create tsconfig.json:

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

Add the CopilotKit runtime and Teams bot#

Create bot.ts. This single file starts both the CopilotKit runtime and the Teams-facing bot:

bot.ts
import { createServer } from "node:http";
import { CopilotKitCore, ProxiedCopilotRuntimeAgent } from "@copilotkit/core";
import { createTeamsAgentBot } from "@copilotkit/bot-teams/bot";
import { BuiltInAgent, CopilotSseRuntime } from "@copilotkit/runtime/v2";
import { createCopilotNodeListener } from "@copilotkit/runtime/v2/node";

const agentId = "assistant";
const runtimePort = Number(process.env.RUNTIME_PORT ?? 8200);
const botPort = Number(process.env.PORT ?? 3978);
const runtimeUrl = `http://localhost:${runtimePort}/api/copilotkit`;

const runtime = new CopilotSseRuntime({
  agents: {
    [agentId]: new BuiltInAgent({
      model: process.env.OPENAI_MODEL ?? "openai/gpt-4o-mini",
      prompt:
        "You are a helpful Microsoft Teams assistant. Keep replies concise and useful.",
    }),
  },
});

createServer(
  createCopilotNodeListener({
    runtime,
    basePath: "/api/copilotkit",
  }),
).listen(runtimePort, () => {
  console.log(`CopilotKit runtime listening at ${runtimeUrl}`);
});

const core = new CopilotKitCore({ runtimeUrl });
core.setDefaultThrottleMs(1000);
core.addAgent__unsafe_dev_only({
  id: agentId,
  agent: new ProxiedCopilotRuntimeAgent({
    agentId,
    runtimeAgentId: agentId,
    runtimeUrl,
  }),
});

const bot = createTeamsAgentBot({
  core,
  agentId,
  approvalTimeoutMs: 5 * 60 * 1000,
  reviewerName: "Reviewer",
});

await bot.start(botPort);
console.log(`Teams bot listening at http://localhost:${botPort}/api/messages`);
console.log(`Teams DevTools available at http://localhost:${botPort + 1}/devtools`);

Your project should now look like this:

copilotkit-teams-bot/
  package.json
  tsconfig.json
  bot.ts

Run the bot#

Set your OpenAI key and start the bot:

export OPENAI_API_KEY=sk-...
npx tsx bot.ts
$env:OPENAI_API_KEY="sk-..."
npx tsx bot.ts

Open http://localhost:3979/devtools and send:

Hello from Teams

Local verification

If you receive a response card in DevTools, the CopilotKit runtime and Teams bot are working locally.

Sideload into Microsoft Teams#

The local DevTools path does not require Microsoft credentials. The real Teams client does. Keep the same bot.ts; add a tunnel, a Microsoft app registration, an Azure Bot resource, and a Teams app manifest.

Create a public tunnel#

In a separate terminal, expose the bot port:

devtunnel create copilotkit-teams-local -a
devtunnel port create copilotkit-teams-local -p 3978
devtunnel host copilotkit-teams-local

Copy the HTTPS tunnel URL. Your bot messaging endpoint will be:

https://<your-tunnel-host>/api/messages

Create Microsoft credentials#

In Microsoft Entra ID:

  1. Create an app registration.
  2. Copy the Application (client) ID. This is your Teams bot ID.
  3. Copy the Directory (tenant) ID.
  4. Create a client secret and copy its value.

In Azure Bot Service:

  1. Create a bot resource that uses the app registration from Entra ID.
  2. Set the messaging endpoint to https://<your-tunnel-host>/api/messages.
  3. Enable the Microsoft Teams channel.

Run the bot with those credentials:

export OPENAI_API_KEY=sk-...
export CLIENT_ID=<application-client-id>
export CLIENT_SECRET=<client-secret-value>
export TENANT_ID=<directory-tenant-id>
npx tsx bot.ts
$env:OPENAI_API_KEY="sk-..."
$env:CLIENT_ID="<application-client-id>"
$env:CLIENT_SECRET="<client-secret-value>"
$env:TENANT_ID="<directory-tenant-id>"
npx tsx bot.ts

Create the Teams app package#

Create appPackage/manifest.json:

appPackage/manifest.json
{
  "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.19/MicrosoftTeams.schema.json",
  "manifestVersion": "1.19",
  "version": "1.0.0",
  "id": "<new-teams-app-uuid>",
  "developer": {
    "name": "Your company",
    "websiteUrl": "https://example.com",
    "privacyUrl": "https://example.com/privacy",
    "termsOfUseUrl": "https://example.com/terms"
  },
  "name": {
    "short": "CopilotKit Bot",
    "full": "CopilotKit Teams Bot"
  },
  "description": {
    "short": "A CopilotKit assistant for Microsoft Teams.",
    "full": "A Microsoft Teams bot powered by CopilotKit."
  },
  "icons": {
    "outline": "outline.png",
    "color": "color.png"
  },
  "accentColor": "#5B5FC7",
  "bots": [
    {
      "botId": "<application-client-id>",
      "scopes": ["personal"],
      "supportsFiles": false,
      "isNotificationOnly": false
    }
  ],
  "validDomains": ["<your-tunnel-host>"]
}

Replace:

  • <new-teams-app-uuid> with a new UUID for this Teams app package
  • <application-client-id> with the Entra application client ID
  • <your-tunnel-host> with the tunnel host only, without https://

Add the required Teams icons:

  • appPackage/color.png: 192 x 192
  • appPackage/outline.png: 32 x 32, transparent background
appPackage/
  manifest.json
  color.png
  outline.png

Package the manifest:

cd appPackage
zip -r appPackage.local.zip manifest.json color.png outline.png

Upload and test in Teams#

In Microsoft Teams:

  1. Go to Apps.
  2. Select Manage your apps.
  3. Select Upload a custom app.
  4. Choose appPackage/appPackage.local.zip.
  5. Open a personal chat with the bot and send Hello.

You should receive the same response you saw in DevTools.

Troubleshooting#

DevTools opens but messages do not answer

Confirm OPENAI_API_KEY is set in the terminal running npx tsx bot.ts, and check that http://localhost:8200/api/copilotkit is not blocked by another process.

Teams says the bot cannot be reached

Confirm the Azure Bot messaging endpoint is exactly https://<your-tunnel-host>/api/messages, and that devtunnel host copilotkit-teams-local is still running.

Teams returns auth errors

Confirm CLIENT_ID, CLIENT_SECRET, and TENANT_ID match the Entra app registration used by the Azure Bot resource.

Upload a custom app is missing

Your Microsoft 365 tenant does not allow sideloading for your account. Ask a tenant admin to enable custom app upload for Teams.

Port 3978 or 8200 is already in use

Stop the process using that port, or set PORT and RUNTIME_PORT before running npx tsx bot.ts.

10d3939