All skills
microsoft avatar

/teams-app-developer

@0bef15b
by microsoftmicrosoft/skills3.1k stars
351

Builds, tests, and deploys Microsoft 365 apps and agents for Teams and Copilot. Includes sub-skills for project creation, local testing, cloud deployment, troubleshooting, and Slack-to-Teams migration. USE FOR: Teams agent, bot, tab, message extension, Declarative Agents, Custom Engine Agents, local testing, Agents Playground, Azure resource provision, remote deployment, Slack to Teams migration, cross-platform bot development, Block Kit to Adaptive Cards conversion. DO NOT USE FOR: general web development, non-bot/non-Teams projects.

Use this Skill: https://skilld.dev/gh/microsoft/skills/teams-app-developer

This session only. Nothing lands on disk.

expertsteamsdev.debug-test-ts.md

≈3.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

dev.debug-test-ts

purpose

Developer tools, local debugging, DevTools plugin, sideloading, tunneling, ConsoleLogger configuration, and build verification for Teams SDK v2.

rules

  1. Always include DevtoolsPlugin from @microsoft/teams.dev in the plugins array during local development. It provides a web-based DevTools UI, WebSocket-based real-time activity inspection, and message replay capabilities. github.com/microsoft/teams.ts -- dev
  2. The DevTools UI runs at http://localhost:{PORT+1}/devtools (default http://localhost:3979/devtools). It starts automatically when the app starts with DevtoolsPlugin registered. Open it in a browser to inspect inbound and outbound activities. github.com/microsoft/teams.ts -- dev
  3. The bot endpoint is http://localhost:{PORT}/api/messages (default http://localhost:3978/api/messages). This is the URL that Teams (or the Bot Framework Emulator) sends activities to. For Azure deployment, update the messaging endpoint to https://your-domain/api/messages. github.com/microsoft/teams.ts
  4. Run locally with npm run dev which executes tsx watch -r dotenv/config src/index.ts. This provides TypeScript execution with automatic file watching -- changes to source files trigger an instant restart without a build step. github.com/microsoft/teams.ts
  5. Configure logging with ConsoleLogger at the appropriate level: 'trace' for deep SDK internals, 'debug' for development, 'info' for staging, 'warn' or 'error' for production. Use pattern: '-azure/msal-node' to suppress noisy MSAL authentication logs. Child loggers are created with logger.child('name'). github.com/microsoft/teams.ts -- common
  6. Run npx tsc --noEmit as a build verification gate before testing or deploying. This type-checks all TypeScript source without producing output files. The project must compile cleanly -- type errors caught here prevent runtime failures. github.com/microsoft/teams.ts
  7. For testing with real Teams clients locally, use a tunneling solution (ngrok, dev tunnels, Cloudflare Tunnel) to expose your local localhost:3978 endpoint over HTTPS. Update the Azure Bot messaging endpoint to the tunnel URL (e.g., https://abc123.ngrok.io/api/messages). learn.microsoft.com -- Dev tunnels
  8. Sideload the app by opening the Teams sideloading URL after provisioning: https://teams.microsoft.com/l/app/${{TEAMS_APP_ID}}?installAppPackage=true&webjoin=true&appTenantId=${{TENANT_ID}}&login_hint=${{USER_EMAIL}} Use TEAMS_APP_ID and USER_EMAIL from env/.env.local; use TENANT_ID from .localConfigs (generated by atk deploy --env local, mapped from TEAMS_APP_TENANT_ID in env/.env.local). Alternatively, zip the appPackage/ directory (manifest.json + icons) and upload in Teams via Apps > Manage your apps > Upload a custom app. Both paths require admin-enabled custom app upload or a developer tenant. learn.microsoft.com -- Sideload apps
  9. Use skipAuth: true in AppOptions for purely local development against DevTools without Azure Bot credentials. This disables JWT validation. Never use it in production or when testing against real Teams clients. github.com/microsoft/teams.ts -- apps
  10. Use Agents Toolkit (ATK) as the recommended provisioning path for local development. First start a devtunnel (devtunnel host -p 3978 --allow-anonymous) and set BOT_ENDPOINT in env/.env.local to the tunnel URL. Then run atk provision --env local -i false to create the Entra ID app registration, Bot Framework registration, and Teams app. Then run atk deploy --env local -i false to generate .localConfigs with CLIENT_ID, CLIENT_SECRET, TENANT_ID, and PORT. Verify .localConfigs has TENANT_ID — if missing, copy the value of TEAMS_APP_TENANT_ID from env/.env.local into TENANT_ID in .localConfigs. See → toolkit.lifecycle-cli.md for the full m365agents.yml reference. learn.microsoft.com -- Agents Toolkit
  11. For manual bot registration without ATK, create the Entra ID app registration and Azure Bot resource through the Azure Portal or Azure CLI, then copy the credentials into .env. This path is useful for understanding what ATK automates or when ATK is not available. See → azure-bot-deploy-ts.md for the full manual workflow.

patterns

Local development setup with DevTools

import { App } from '@microsoft/teams.apps';
import { ConsoleLogger } from '@microsoft/teams.common';
import { DevtoolsPlugin } from '@microsoft/teams.dev';

const app = new App({
  // Use skipAuth for local DevTools-only testing (no Azure credentials needed)
  // Remove skipAuth when testing against real Teams clients
  skipAuth: true,

  logger: new ConsoleLogger('dev-bot', { level: 'debug' }),
  plugins: [new DevtoolsPlugin()],
});

app.on('message', async ({ reply, activity }) => {
  await reply(`Echo: ${activity.text}`);
});

// Bot endpoint: http://localhost:3978/api/messages
// DevTools UI:  http://localhost:3979/devtools
app.start(3978);

Production-ready logging configuration

import { App } from '@microsoft/teams.apps';
import { ConsoleLogger } from '@microsoft/teams.common';
import { DevtoolsPlugin } from '@microsoft/teams.dev';

// Development logger: verbose, noisy auth logs suppressed
const devLogger = new ConsoleLogger('my-bot', {
  level: 'debug',
  pattern: '-azure/msal-node',
});

// Production logger: only warnings and errors
const prodLogger = new ConsoleLogger('my-bot', {
  level: 'warn',
});

// Choose based on environment
const isProduction = process.env.NODE_ENV === 'production';
const logger = isProduction ? prodLogger : devLogger;

const app = new App({
  clientId: process.env.CLIENT_ID,
  clientSecret: process.env.CLIENT_SECRET,
  tenantId: process.env.TENANT_ID,
  logger,
  // Only include DevtoolsPlugin in non-production
  plugins: isProduction ? [] : [new DevtoolsPlugin()],
});

// Child loggers for scoped output
app.on('message', async (ctx) => {
  const handlerLog = ctx.log; // Scoped to this activity
  handlerLog.info(`Message from ${ctx.activity.from.name}`);
  // Output: [my-bot] Message from John Doe

  await ctx.send('Hello!');
});

app.start(process.env.PORT || 3978).catch(console.error);

Build verification and debugging workflow

// === Option A: ATK-provisioned workflow (recommended) ===

// 1. Install dependencies
//    npm install

// 2. Start a dev tunnel (must be running BEFORE provisioning)
//    devtunnel host -p 3978 --allow-anonymous
//    Copy the tunnel URL and set BOT_ENDPOINT in env/.env.local

// 3. Provision bot resources via ATK (creates Entra ID app + Bot Framework + Teams app)
//    atk provision --env local -i false

// 4. Generate .localConfigs with credentials
//    atk deploy --env local -i false
//    Verify .localConfigs contains CLIENT_ID, CLIENT_SECRET, TENANT_ID, PORT.
//    If TENANT_ID is missing, copy the value of TEAMS_APP_TENANT_ID from env/.env.local into TENANT_ID in .localConfigs.

// 5. Type-check the project (build gate)
//    npx tsc --noEmit

// 6. Start dev server with file watching
//    npm run dev

// 7. Open DevTools in browser
//    http://localhost:3979/devtools

// 7. For real Teams testing, start a dev tunnel and provision:
//    devtunnel host -p 3978 --allow-anonymous
//    Set BOT_ENDPOINT in env/.env.local to the tunnel URL
//    atk provision --env local -i false
//    atk deploy --env local -i false
//    Open Teams sideload URL (TEAMS_APP_ID from env/.env.local):
//    https://teams.microsoft.com/l/app/$TEAMS_APP_ID?installAppPackage=true&webjoin=true&appTenantId=$TENANT_ID
//    (TEAMS_APP_ID from env/.env.local; TENANT_ID from .localConfigs, mapped from TEAMS_APP_TENANT_ID in env/.env.local)

// === Option B: Manual workflow (no ATK) ===

// 1. npm install
// 2. Create .env: CLIENT_ID, CLIENT_SECRET, TENANT_ID, PORT=3978
//    (Register bot manually -- see azure-bot-deploy-ts.md)
// 3. npx tsc --noEmit
// 4. npm run dev
// 5. devtunnel host -p 3978 --allow-anonymous → update Azure Bot messaging endpoint
// 6. Sideload: zip appPackage/ → upload in Teams

// === Build for production (both options) ===

// npm run build     # Compiles to dist/ via tsup
// npm run start     # Runs compiled JS: node -r dotenv/config .

// Common troubleshooting:
// - Bot not responding in Teams?
//     Check: tunnel running, messaging endpoint updated, manifest scopes correct
// - DevTools blank?
//     Check: DevtoolsPlugin in plugins array, port+1 not blocked
// - Type errors on import?
//     Check: tsconfig module is "NodeNext", not "commonjs"
// - .env not loaded?
//     Check: dotenv in devDependencies, -r dotenv/config in scripts
// - 401 Unauthorized after atk deploy?
//     Check: .localConfigs has TENANT_ID; if missing, copy the value of TEAMS_APP_TENANT_ID from env/.env.local into TENANT_ID in .localConfigs

pitfalls

  • Forgetting to start the tunnel: Without ngrok or dev tunnels, the Azure Bot Framework cannot reach your local endpoint. Teams messages never arrive. Always verify the tunnel is running and the messaging endpoint is updated.
  • DevTools port conflict: DevTools runs on PORT + 1. If port 3979 is already in use, DevTools fails silently. Check for port conflicts or change the bot's PORT.
  • Using skipAuth with real Teams clients: skipAuth: true disables JWT validation. Real Teams activities require proper authentication. Use skipAuth only with DevTools for rapid iteration.
  • Not running npx tsc --noEmit: Skipping the type-check means errors surface only at runtime. Always run this gate after changes, especially before committing or deploying.
  • Stale tunnel URL in Azure Bot config: Ngrok generates a new URL each time it restarts (unless on a paid plan). Forgetting to update the Azure Bot messaging endpoint after restarting ngrok means the bot stops receiving messages.
  • Missing sideload permissions: Sideloading requires either admin-enabled custom app upload or a Microsoft 365 developer tenant. Without it, the "Upload a custom app" option does not appear in Teams.
  • Wrong log level in production: Running with 'debug' or 'trace' in production floods logs and can impact performance. Switch to 'info' or 'warn' for deployed environments.
  • Testing only in DevTools: DevTools simulates a Teams client but does not replicate all Teams behaviors (e.g., @mention stripping, SSO token exchange, card rendering differences). Always test in a real Teams client before shipping.
  • .localConfigs missing TENANT_ID: After atk deploy --env local, the generated .localConfigs may omit TENANT_ID. Without it, MSAL defaults to the wrong token authority, causing 401 errors. Copy the value of TEAMS_APP_TENANT_ID from env/.env.local into TENANT_ID in .localConfigs.
  • Dev tunnel URL blacklisted or expired: Dev tunnel URLs can be flagged by corporate proxies or expire after inactivity. If the bot suddenly stops receiving messages with a working tunnel, create a fresh tunnel and update the messaging endpoint.

references

instructions

This expert covers local development, debugging, and testing workflows for Teams SDK v2 bots. Use it when you need to:

  • Set up DevtoolsPlugin and access the DevTools UI at localhost:3979/devtools
  • Run the bot locally with npm run dev (tsx watch with hot reload)
  • Configure ConsoleLogger levels and noise filtering for different environments
  • Use skipAuth: true for credential-free local testing
  • Provision bot credentials locally with atk provision --env local and atk deploy --env local
  • Set up dev tunnels or ngrok for testing with real Teams clients
  • Sideload the bot via the Teams sideloading URL or by packaging and uploading appPackage/ as a zip
  • Run npx tsc --noEmit as a build verification gate
  • Troubleshoot common issues (bot not responding, DevTools blank, import errors)
  • Understand the difference between DevTools testing and real Teams testing

Pair with runtime.app-init-ts.md for App constructor setup and project.scaffold-files-ts.md for npm scripts and project file structure. Pair with project.scaffold-files-ts.md for npm scripts and build verification, and runtime.app-init-ts.md for DevtoolsPlugin configuration.

research

Deep Research prompt:

"Write a micro expert on developing, debugging, and testing Teams SDK v2 bots in TypeScript. Cover DevtoolsPlugin setup from @microsoft/teams.dev, DevTools UI at localhost:3979/devtools with WebSocket activity inspection and message replay, local development with npm run dev (tsx watch), bot endpoint at localhost:3978/api/messages, ConsoleLogger configuration (levels: error/warn/info/debug/trace, pattern filtering, child loggers), skipAuth for local testing, ngrok and dev tunnels for HTTPS exposure, sideloading via zip upload, npx tsc --noEmit build gate, M365 Agents Toolkit VS Code extension, and a troubleshooting flowchart for common issues (bot not responding, port conflicts, stale tunnel URLs, missing sideload permissions). Include a step-by-step local workflow and production logging patterns."

Source: SKILL.md on GitHub

1 alert3mo3 checks · Risk SAFE
  • Gen Agent Trust Hub3mo

    This skill provides a comprehensive developer guide for building Microsoft 365 agents and Teams applications. It includes several security considerations such as handling untrusted user input, using dynamic execution in examples, and reading sensitive local files for protocol requirements. These patterns are presented with appropriate security warnings and architectural mitigations. See detailed analysis for more context.

  • Socket3mo

    No alerts

  • Snyk3mo

    Risk: HIGH · 1 issue

Signed by skilld at 0bef15b. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 20 hours ago.

Activeupdated 3 months ago

README badge

README badge for microsoft/skills/teams-app-developer