Teams Toolkit & App SDK¶
Last Updated: 2025-07
Status: Research Reference
Relevance to Entraclaw: High — Teams is the primary human-to-agent communication channel
Overview¶
Microsoft Teams Toolkit (rebranded as Microsoft 365 Agents Toolkit / ATK in May 2025) is a VS Code / Visual Studio extension that scaffolds, packages, provisions, and deploys apps and agents for Microsoft Teams, Outlook, and Microsoft 365 Copilot.
Why This Matters for Entraclaw¶
Entraclaw autonomous agents on devices need a channel to communicate with humans. Teams is the primary target. The question is whether we should:
- Use Teams Toolkit to scaffold and manage our agent as a Teams app
- Use the SDKs directly (Teams SDK or M365 Agents SDK) and handle packaging ourselves
- Use Azure Bot Service as a channel-agnostic transport and register Teams as a channel
TL;DR Assessment: Teams Toolkit is useful for rapid prototyping and handles tedious manifest/packaging/auth plumbing. But for Entraclaw's scenario — autonomous agents with their own identity (Agent IDs) communicating proactively — we'll likely use the Teams SDK (Python) directly for bot logic and proactive messaging, with the Toolkit mainly for manifest management and sideloading during development.
The SDK Landscape (as of mid-2025)¶
The Microsoft SDK landscape for Teams is in significant flux. Here's the current state:
| SDK | Status | Use When | Languages |
|---|---|---|---|
| TeamsFx | Deprecated (community support until Sep 2026) | Legacy — do not use for new projects | JS/TS, .NET |
| Teams SDK (formerly Teams AI Library v2) | Active / Recommended | Teams-only apps: bots, tabs, message extensions, AI agents | JS/TS, C#, Python (preview) |
| M365 Agents SDK | Active | Multi-channel agents (Teams + Outlook + Copilot + Slack/Twilio) | JS/TS, C#, Python |
| Bot Framework v4 | Deprecated (no new features after Dec 2025) | Legacy multi-channel bots — migrate away | JS/TS, C#, Python, Java |
| Azure AI Foundry Agent SDK | Active | Cross-cloud agent orchestrations with Azure AI | Python, C# |
Key Naming History¶
Bot Framework v4 → deprecated Dec 2025
TeamsFx → deprecated Sep 2026
Teams AI Library v1 → released Nov 2023, built on Bot Framework
Teams AI Library v2 → released Sep 2025, renamed "Teams SDK" Nov 2025
Teams Toolkit → rebranded "M365 Agents Toolkit" May 2025
Which SDK for Entraclaw?¶
Teams SDK (Python) is the right choice for Entraclaw because: - Teams-only for now (no Slack/Twilio needed yet) - Python is our primary language - Built-in AI/LLM integration patterns - Proactive messaging support - SSO + OBO flow support for accessing Graph on behalf of users
Key APIs & Interfaces¶
Teams SDK (Python) — teams-ai on PyPI¶
The Python SDK requires Python 3.9+ and builds on the Bot Framework adapter. Key abstractions:
from teams import App
app = App()
@app.on("message")
async def on_message(context, state):
"""Handle incoming messages from Teams users."""
user_text = context.activity.text
await context.send_activity(f"You said: {user_text}")
# AI-powered agent with function calling
@app.ai.action("get_device_status")
async def get_device_status(context, state, parameters):
"""LLM can call this function when user asks about device status."""
device_id = parameters.get("device_id")
# ... look up device via Entraclaw backend
return {"status": "online", "last_seen": "2025-07-01T12:00:00Z"}
Teams SDK (TypeScript) — Streamlined API¶
import { App } from '@microsoft/teams.apps';
const app = new App();
app.on('message', async ({ api, isSignedIn, send, signin }) => {
if (!isSignedIn) await signin();
const me = await api.user.me.get();
await send(`Hello, ${me.displayName}!`);
});
app.listen(3000);
Teams CLI — Bootstrap Projects¶
# Create a new Python bot project
npx @microsoft/teams.cli@latest new python entraclaw-agent --template echo
# Create a TypeScript project
npx @microsoft/teams.cli@latest new typescript entraclaw-agent --template echo
Key SDK Classes & Concepts¶
| Class/Concept | Purpose |
|---|---|
App |
Main application entry point, handles routing |
@app.on("message") |
Decorator-based activity routing |
@app.ai.action(name) |
Register functions the LLM can call |
Prompt |
Defines the system prompt + conversation context for the LLM |
TurnState |
Manages per-turn and per-conversation state |
ConversationReference |
Serializable reference to a conversation (needed for proactive messaging) |
CloudAdapter |
Bot Framework adapter that handles Teams channel communication |
| MCP Plugin | Model Context Protocol client/server support for multi-agent interop |
Auth & Identity Model¶
How Teams App Auth Works¶
Teams apps authenticate via Microsoft Entra ID (Azure AD) using a registered App Registration:
┌──────────────┐ SSO Token ┌─────────────────┐
│ Teams Client │──────────────────→ │ Your Bot Backend │
│ (user signed │ │ (validates token)│
│ into Teams) │ └────────┬────────┘
└──────────────┘ │
OBO Flow │ (exchange token)
▼
┌─────────────────────┐
│ Microsoft Entra ID │
│ (issues new token │
│ with Graph scopes) │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Microsoft Graph API │
│ (User.Read, Mail, │
│ Calendar, etc.) │
└─────────────────────┘
SSO (Single Sign-On)¶
- Users already authenticated in Teams get seamless access to the bot
- The bot receives a token scoped to
access_as_user - No login prompt for the user in most cases
OBO (On-Behalf-Of) Flow¶
- Backend exchanges the SSO token for a token with downstream API permissions
- Always acts with delegated permissions (user's context)
- Cannot do app-only operations via OBO
Key Entra ID App Registration Fields¶
{
"appId": "YOUR-APP-GUID",
"api": {
"requestedAccessTokenVersion": 2,
"oauth2PermissionScopes": [
{
"value": "access_as_user",
"type": "User",
"userConsentDisplayName": "Access as you"
}
]
},
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{ "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", "type": "Scope" }
]
}
]
}
How This Relates to Agent IDs¶
This is a critical design question for Entraclaw:
| Aspect | Teams App Identity | Entraclaw Agent ID |
|---|---|---|
| Identity Provider | Microsoft Entra ID | Our own (backed by Entra ID?) |
| Principal Type | App Registration (service principal) | Per-agent identity |
| Token Type | Entra ID JWT (delegated via OBO) | TBD — could be Entra workload identity |
| Scope | User-delegated or app-only | Per-agent permissions |
Options for mapping Agent IDs to Teams: 1. One Entra App Registration per agent type — each agent class gets its own app ID 2. One App Registration, multiple bot instances — single Teams app, agent ID in metadata 3. Managed Identity per agent — use Azure Managed Identities mapped to agent IDs
The most practical for now: one Teams app registration for all Entraclaw agents, with agent identity tracked in our own system. The Teams bot acts as a gateway/router to the appropriate agent.
Teams AI Library / Teams SDK AI Features¶
The Teams SDK (formerly Teams AI Library) provides first-class AI integration:
Core AI Abstractions¶
from teams.ai import AIOptions, OpenAIModel, PromptManager
# Configure the AI model
model = OpenAIModel(
api_key=os.environ["OPENAI_API_KEY"],
default_model="gpt-4o"
)
# Define prompts with system instructions
prompt_manager = PromptManager(prompts_folder="./prompts")
# Wire up to the app
app = App(options=AppOptions(
ai=AIOptions(
model=model,
prompt="default",
prompt_manager=prompt_manager
)
))
Function Calling (Tools)¶
The SDK auto-generates JSON schemas for registered functions:
@app.ai.action("lookup_agent")
async def lookup_agent(context, state, parameters):
"""Look up an Entraclaw agent by its Agent ID.
Args:
agent_id: The unique identifier of the agent
"""
agent = await entraclaw_service.get_agent(parameters["agent_id"])
return agent.to_dict()
Model Context Protocol (MCP) Support¶
As of late 2025, the Teams SDK supports MCP natively:
- MCP Client plugin: Your Teams bot can consume external MCP servers (tools, prompts, resources)
- MCP Server plugin: Your Teams bot can expose its capabilities as an MCP server
- Agent-to-Agent (A2A): Teams agents can communicate with each other
This is directly relevant to Entraclaw — an Entraclaw agent running on a device could expose an MCP server, and the Teams bot could act as an MCP client to it.
Prompt Files¶
Prompts are defined in a folder structure:
prompts/
default/
skprompt.txt # System prompt text
config.json # Model parameters (temperature, max_tokens)
actions.json # Available function definitions
App Manifest & Sideloading¶
Manifest Structure¶
The Teams app manifest (manifest.json) declares what the app can do:
{
"$schema": "https://developer.microsoft.com/json-schemas/teams/v1.19/MicrosoftTeams.schema.json",
"manifestVersion": "1.19",
"version": "1.0.0",
"id": "YOUR-APP-ID-GUID",
"packageName": "com.entraclaw.agent",
"developer": {
"name": "Entraclaw",
"websiteUrl": "https://entraclaw.dev",
"privacyUrl": "https://entraclaw.dev/privacy",
"termsOfUseUrl": "https://entraclaw.dev/terms"
},
"name": {
"short": "Entraclaw Agent",
"full": "Entraclaw Autonomous Agent Interface"
},
"description": {
"short": "Communicate with your Entraclaw agents",
"full": "Interface for humans to interact with Entraclaw autonomous agents on devices"
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"accentColor": "#6264A7",
"bots": [
{
"botId": "YOUR-BOT-APP-ID",
"scopes": ["personal", "team", "groupChat"],
"supportsFiles": false,
"isNotificationOnly": false,
"commandLists": [
{
"scopes": ["personal"],
"commands": [
{ "title": "status", "description": "Check agent status" },
{ "title": "agents", "description": "List your agents" }
]
}
]
}
],
"permissions": ["identity", "messageTeamMembers"],
"validDomains": ["entraclaw.dev", "*.azurewebsites.net"]
}
Key Manifest Fields for Entraclaw¶
| Field | Purpose | Entraclaw Relevance |
|---|---|---|
bots[].botId |
Entra App Registration ID | Our bot's app registration |
bots[].scopes |
Where bot works (personal/team/groupChat) | Likely personal for 1:1 agent chat |
bots[].isNotificationOnly |
If true, can't receive messages | false — we need bidirectional |
permissions |
App permissions | identity for SSO, messageTeamMembers for proactive messaging |
webApplicationInfo |
SSO configuration | Links to our Entra app registration |
Packaging¶
The app package is a ZIP file at the root level:
Sideloading for Development¶
- Enable in tenant: Teams Admin Center → Teams apps → Setup policies → Allow uploading custom apps
- In Teams: Apps → Manage your apps → Upload a custom app → Upload for me/my org
- Or use the Agents Toolkit in VS Code which automates this
Common Sideloading Gotchas¶
- All URLs must be HTTPS (no HTTP)
- Icons must be exact sizes (192×192 color, 32×32 outline)
validDomainsmust include all domains your app accesses- ZIP must have files at root (no nested folders)
- Manifest can pass validation but still fail on sideload due to subtle issues
- Teams web client has intermittent sideloading bugs — try desktop client as fallback
- Clear Teams cache if you see stale app versions
Integration Patterns for Entraclaw¶
Architecture: Entraclaw Agent as a Teams Bot¶
┌──────────────────────────────────────────────────────────────┐
│ Microsoft Teams │
│ ┌──────────┐ │
│ │ User │ ← chat messages → ┌──────────────────────┐ │
│ │ (human) │ │ Entraclaw Teams Bot │ │
│ └──────────┘ │ (Teams SDK / Python) │ │
│ └──────────┬───────────┘ │
└──────────────────────────────────────────────────┼────────────┘
│
Azure Bot Service │
(channel registration) │
│
┌──────────────────────────────┤
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ Entraclaw Backend│ │ Proactive Messaging │
│ (Agent Router) │ │ Service │
│ │ │ (stores ConvRefs, │
│ - Agent Registry│ │ sends notifications)│
│ - OBO token mgmt│ └─────────────────────┘
│ - Agent dispatch│ │
└────────┬────────┘ │
│ │
┌────────▼────────┐ │
│ Entraclaw Agents │ ← notifications ──┘
│ (on devices) │
│ - Agent ID auth │
│ - Task execution │
│ - MCP servers │
└─────────────────┘
Pattern 1: Reactive Messaging (User → Agent)¶
- User sends message in Teams
- Teams SDK bot receives the activity
- Bot identifies target agent (from conversation context or user selection)
- Bot forwards request to Entraclaw backend
- Agent processes and responds
- Bot sends response back to Teams
Pattern 2: Proactive Messaging (Agent → User)¶
This is the more important pattern for Entraclaw — agents need to notify humans.
from botbuilder.core import CloudAdapter, ConversationReference
# Store conversation reference when user first interacts
conversation_references: dict[str, ConversationReference] = {}
@app.on("conversationUpdate")
async def on_install(context, state):
"""Capture conversation reference when bot is installed."""
ref = context.activity.get_conversation_reference()
user_id = context.activity.from_property.aad_object_id
conversation_references[user_id] = ref
# Persist to database for durability
# Later, when an agent needs to notify a user:
async def notify_user(adapter: CloudAdapter, user_aad_id: str, message: str):
"""Send a proactive message from an agent to a user."""
ref = conversation_references.get(user_aad_id)
if not ref:
raise ValueError("User hasn't installed the bot yet")
async def callback(turn_context):
await turn_context.send_activity(message)
await adapter.continue_conversation(
ref,
callback,
bot_app_id="YOUR-BOT-APP-ID"
)
Key constraint: Proactive messaging only works if the user has installed the bot app (or an admin has installed it for them). You can use Graph API to programmatically install the app for users.
Pattern 3: MCP Bridge (Agent ↔ Teams via MCP)¶
With Teams SDK's MCP support: 1. Entraclaw agent on device exposes an MCP server 2. Teams bot connects as an MCP client 3. User asks a question in Teams 4. Bot invokes MCP tools on the agent 5. Results flow back through Teams
Declarative Agents vs Coded Agents¶
Two paradigms exist in the Microsoft 365 ecosystem:
Declarative Agents¶
- No/low code — define behavior via configuration, instructions, and connectors
- Built in Copilot Studio or with the Agents Toolkit
- Leverage Microsoft's orchestrator and LLM
- Inherit M365 compliance and security automatically
- Not suitable for Entraclaw — we need full control over orchestration, model choice, and external system integration
Custom Engine (Coded) Agents¶
- Full code — you implement orchestration, model integration, and business logic
- Built with Teams SDK or M365 Agents SDK
- Choose your own LLM (OpenAI, Azure OpenAI, local models, etc.)
- Full control over data flow and external integrations
- This is Entraclaw's path — custom engine agent with our own backend
Decision Matrix¶
| Requirement | Declarative | Custom Engine |
|---|---|---|
| Choose own LLM | ❌ | ✅ |
| Custom orchestration | ❌ | ✅ |
| External system integration | Limited | ✅ |
| Proactive messaging | Limited | ✅ |
| Agent-to-agent comms | ❌ | ✅ (via MCP/A2A) |
| Rapid prototyping | ✅ | ❌ |
| M365 compliance built-in | ✅ | Manual |
Community Learnings & Gotchas¶
Developer Pain Points (from Reddit, SO, GitHub Issues)¶
-
SDK Confusion: The biggest complaint is which SDK to use. Microsoft has 3+ overlapping SDKs (Teams SDK, M365 Agents SDK, Azure AI Foundry Agent SDK) with unclear boundaries. The Voitanos blog post captures this frustration well — even MVPs struggle to advise developers.
-
Steep Learning Curve: Non-Microsoft-ecosystem developers find the manifest schema, Entra ID app registration, Azure Bot Service setup, and token flows overwhelming. Each layer adds complexity.
-
Sideloading Fragility: The sideloading experience is buggy, especially in the Teams web client. Nondescript "Something Went Wrong" errors are common. Fixes include:
- Try desktop client instead of web
- Clear Teams cache
- Re-upload the ZIP
-
Check that admin policies allow custom apps
-
Documentation Churn: Docs frequently change as SDKs are renamed/deprecated. TeamsFx docs still appear in search results but point to deprecated patterns. The rename from "Teams AI Library" to "Teams SDK" happened Nov 2025.
-
Python Support is Preview: The Python SDK is functional but still in developer preview. APIs may change. TypeScript and C# have more mature support and more samples.
-
Proactive Messaging Complexity: Storing and managing
ConversationReferenceobjects requires infrastructure (database). References can go stale if the Teams app is uninstalled/reinstalled. TheserviceUrlin the reference can change. -
Dev Tunnel Flakiness: The Toolkit uses dev tunnels for local debugging, which can be unreliable. Some developers prefer ngrok.
What Works Well¶
- Scaffolding: The Toolkit/CLI gets you from zero to a running bot in under 5 minutes
- Manifest management: Toolkit handles environment variable substitution in manifests
- SSO integration: Once configured, SSO + OBO flow works smoothly
- Adaptive Cards: Rich UI rendering in Teams is well-supported
- Hot reload: Dev experience with the Toolkit's F5 debugging is good
Open Questions for Entraclaw¶
- Agent Identity Mapping: How do we map Entraclaw Agent IDs to the Teams bot's single app registration? Options:
- Agent ID as metadata in the conversation state
- Multiple bot registrations (one per agent — probably overkill)
-
Agent ID as a "sub-account" within our bot
-
Proactive Messaging Scale: If 1000 agents need to notify users simultaneously, what's the throttling behavior of Azure Bot Service / Teams?
-
Python SDK Stability: Is the
teams-aiPython package stable enough for production? Or should we use TypeScript for the Teams layer and call our Python backend via API? -
MCP Integration Path: Can Entraclaw device agents expose MCP servers that the Teams bot connects to? What about NAT traversal for on-premise devices?
-
Multi-Tenant Deployment: If Entraclaw serves multiple M365 tenants, do we need separate bot registrations per tenant or can a single multi-tenant app registration work?
-
Admin Consent: For enterprise deployment, how do we handle admin consent for our bot app? Can we avoid per-user consent via organization-wide app installation?
-
Message Format: Should agent→human notifications use plain text, Adaptive Cards, or both? Adaptive Cards allow structured data + action buttons but add complexity.
-
Conversation Continuity: When an agent sends a proactive message and the user replies, how do we maintain context across the reactive/proactive boundary?
Sources¶
| Source | Notes |
|---|---|
| M365 Agents Toolkit Overview — Microsoft Learn | Official overview, rebranding from Teams Toolkit |
| Teams SDK Welcome Page | New unified SDK docs, CLI commands, language support |
| Teams SDK Python Guides | Python-specific in-depth guides (preview) |
| Teams SDK GitHub Repo | Source code, samples, issues |
| TeamsFx SDK Docs — Microsoft Learn | Deprecated SDK reference (still useful for understanding auth patterns) |
| Voitanos: Teams SDK Evolution 2025 | Best independent analysis of the SDK confusion landscape |
| Announcing Teams SDK (formerly Teams AI Library) | Official announcement with MCP support details |
| Teams Manifest Schema | Manifest structure reference |
| SSO Setup — Teams SDK | SSO configuration guide |
| OBO Flow — Microsoft Identity Platform | Official OBO flow documentation |
| Proactive Messages — Microsoft Learn | Proactive messaging patterns and requirements |
| Proactive Messaging — Teams SDK | New SDK proactive messaging guide |
| Declarative Agent Tool Comparison — Microsoft Learn | When to use declarative vs coded agents |
| Custom Engine Agent Architecture | Deep dive on custom engine agent patterns |
| teams-ai on PyPI | Python SDK package |
| Upload Custom Apps — Microsoft Learn | Sideloading documentation |
| Microsoft AI SDKs Decoded | From Bot Framework to MAF — full history |
| MCP Server — Teams SDK | MCP server integration guide |
| GitHub: microsoft/mcp | Microsoft's official MCP implementations |
| SO: teams-toolkit tag | Community Q&A on common issues |
| GitHub Issue: Sideloading Bugs | Known sideloading issues tracker |