Teams Agent Preflight FAQ
preflight.sh (Linux/macOS) and preflight.ps1 (Windows) check your machine and accounts before you run setup. Find your failed check below, apply the fix, run again.
How preflight works
Preflight only reads. It installs nothing and creates nothing in Azure or Microsoft 365. Run it, fix every FAIL, run again, then run setup.sh / setup.ps1. Setup does not run preflight for you.
Checks run in stages. A failed stage stops the run, so later checks stay hidden until you fix it. WARN never blocks.
| Stage | Check | Passes when | If not |
|---|---|---|---|
| 1 Prerequisites | python3, node, npm, az, atk |
Command found. Version printed, no minimum enforced | FAIL, stop. Tools not installed |
| 1 Prerequisites | PowerShell policy (Windows) | Not Restricted |
FAIL. PowerShell policy |
| 2 Auth | Azure login | az account show works |
FAIL, stop. Azure login |
| 2 Auth | Teams/M365 login | atk auth list shows an account |
FAIL, stop. M365 login |
| 2 Auth | Azure tenant | Active subscription tenant = tenant of the first subscription in az account list |
FAIL, stop. Azure tenant mismatch |
| 3 Permissions | Azure RBAC | Owner or Contributor on the subscription (direct assignment) | FAIL, or WARN. Azure RBAC |
| 3 Permissions | Entra ID app registration | Application Administrator or Global Administrator | FAIL. Entra ID app registration |
| 3 Permissions | Teams publish | Teams Administrator or Global Administrator | FAIL. Teams publish role |
| 4 Environment | npm global bin | Folder is on PATH |
WARN. Warnings |
| 4 Environment | Proxy env vars | HTTP_PROXY / HTTPS_PROXY / NO_PROXY not set |
WARN. Warnings |
On Windows the last stage is called Windows QA, and there is no separate npm row. Same checks otherwise.
The run ends with PASS (no FAIL, WARN allowed) or FAIL, plus OK / FAIL / WARN counts. The exit code is 0 either way, so read the summary line.
Not checked: MCP URL reachable, Tursio API key valid, OpenAI key or model valid, Azure name or quota limits.
Reading the output
| All pass (Windows) | Missing tools stop the run (Linux) |
|---|---|
![]() |
![]() |
Every row OK. Summary: PASS, ready to run setup.ps1. |
npm and atk missing. Preflight prints STOP and skips Auth and Permissions. Install, run again. |
Fixes
Tools not installed
| Tool | Install |
|---|---|
python3 / python |
Python 3.11+. Linux/macOS: python.org/downloads. Windows: python-3.12.10-amd64.exe, tick Add Python to PATH and Install for all users |
node, npm |
Node.js 18+ from nodejs.org/en/download. npm comes with it |
az |
Azure CLI: aka.ms/installazurecli. Check with az --version |
atk |
npm install -g @microsoft/m365agentstoolkit-cli@1.1.17 |
Windows, python still not found: Settings → Apps → Advanced app settings → App execution aliases, turn off the python.exe store alias.
Old teamsapp CLI installed? Remove it before installing atk. Both packages install a command named teamsapp:
setup.sh removes it for you if found.
PowerShell policy (Windows)
Policy is Restricted and blocks scripts. Run:
Azure login
Follow the device-code prompt.M365 login
Browser opens. Sign in with your Microsoft 365 account.Azure tenant mismatch
Tenant of your active subscription differs from the tenant of the first subscription in az account list. Preflight treats the first one as expected.
az account list --output tableaz account set --subscription <subscription-id>- Run preflight again.
Azure RBAC
Account lacks Contributor or Owner on the subscription. Subscription comes from AZURE_SUBSCRIPTION_ID in env/.env.dev, else your active one. Preflight sees roles assigned directly to you. A role granted only through a group may not show.
- Contributor: enough for most installs.
- Owner: needed only if you also manage role assignments.
Ask your Azure admin: Azure Portal → Subscriptions → [subscription] → Access control (IAM) → Add role assignment.
WARN, not FAIL: could not query role assignments (run az login --use-device-code, run again) or no subscription found (az account set --subscription <id>, run again).
Entra ID app registration
Account lacks Application Administrator (or Global Administrator) in Entra ID. Ask your Entra admin: Azure Portal → Microsoft Entra ID → Roles and administrators → Application Administrator → Add assignments.
Teams publish role
Publishing to the org catalog needs Teams Administrator (or Global Administrator). Ask your Microsoft 365 admin: Microsoft 365 admin center → Roles → Role assignments → Teams Administrator.
Only one person may upload apps? Run setup with --skip-publish (-SkipPublish on Windows) and give the package zip to that person.
Role check fails but you hold the role
Preflight reads your directory roles from Microsoft Graph. If that call fails, the role list is empty and both role checks report FAIL. Causes:
- Not signed in to Azure CLI:
az login --use-device-code - Conditional-access policy blocks the Graph call
- Transient network or token problem
Test the call yourself:
az rest --method GET --url "https://graph.microsoft.com/v1.0/me/transitiveMemberOf/microsoft.graph.directoryRole?\$select=displayName" --query "value[].displayName" -o tsv
Warnings
Do not stop install.
- npm global bin: npm's global folder may not be on
PATH. Add it, open a new terminal.atknot found after install means this. - Proxy env vars:
HTTP_PROXY,HTTPS_PROXYorNO_PROXYis set. It may breakaz,npm,atk. If installs time out, unset them for the run or allow the Microsoft endpoints.
After preflight: what setup builds
Not checked by preflight. Preflight creates nothing. Later, setup.sh / setup.ps1 builds four things in one Azure resource group. All names start bot + your resource suffix (example acme gives botacme). Suffix: lowercase letters and digits, whole name 4 to 20 chars. Pick once: changing it later makes a second deployment, not a rename. Region: westus2.
| # | Azure resource | Name | What it is for |
|---|---|---|---|
| 1 | Managed identity (user-assigned) | bot<suffix> |
Bot identity. Its client ID is the bot app ID. No password to store or rotate |
| 2 | App Service plan (Linux) | bot<suffix> |
Compute. Size B2. Run one instance only: the agent keeps schedules and chat history itself |
| 3 | Web App | bot<suffix> |
Runs the agent (python app.py, Python 3.12, always on). Listens on /api/messages. Holds all settings |
| 4 | Azure Bot | bot<suffix> |
Front door for Teams. Plan F0, user-assigned identity, Teams channel on. Points to the Web App |
In Microsoft 365: one Teams app. Setup creates it, packages it, publishes it to the org catalog.
You bring these (preflight does not check them):
- Tursio MCP server: public https URL ending
/mcp, reachable from Azure. - Tursio API key: Tursio portal, Settings, API Agent.
- OpenAI model: Azure OpenAI (endpoint, key, deployment name) or standard OpenAI (key, model id). Use gpt-5 or later. Not
-chatmodels: they fail whileSHOW_REASONINGis on (setup default).
No database, storage account, Key Vault or App Insights is created.
How the parts connect
Teams user
| message
Teams (Microsoft 365) <-- Teams app (manifest, bot ID = identity client ID)
|
Azure Bot (Teams channel)
| HTTPS POST https://bot<suffix>.azurewebsites.net/api/messages
Web App bot<suffix> <-- runs under managed identity bot<suffix>
|-- OpenAI / Azure OpenAI (OPENAI_API_KEY or AZURE_OPENAI_API_KEY + ENDPOINT, OPENAI_MODEL_NAME)
|-- Tursio MCP server (MCP_SERVER_URL, Authorization: Bearer TURSIO_API_KEY, X-Tursio-User)
|
Tursio data
- Azure Bot and Web App share one identity. Bot app ID = identity client ID. The Web App gets the same client ID and tenant ID in
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__*, auth typeUserManagedIdentity, empty secret. That is how the Web App proves it is the bot. - Azure Bot endpoint = Web App host +
/api/messages. Setup checks it after deploy and fixes it withaz bot updateif wrong. - Web App settings carry the rest: model, MCP URL, Tursio API key, agent name (
BRAND_NAME),SCHEDULE_TIMEZONE,SHOW_REASONING,REASONING_EFFORT. - Every MCP call uses one shared API key as bearer. User name goes in
X-Tursio-User. - Keys are plain App Service settings. Limit who can access the resource group.
Setup steps
Setup only checks python3, node, az are on PATH, then asks you to run preflight if not.
- Questions: agent name, Teams app suffix, resource suffix, MCP URL, Tursio API key, OpenAI provider, key, model, schedule timezone.
azlogin, pick subscription.atk auth login m365.atk provision: Teams app, resource group, the four resources. Skipped on Redeploy to existing resource group.atk deploy: zip push. Bot endpoint check.atk package,atk publish.--skip-publish(-SkipPublishon Windows) stops after package.

Above: start of setup.ps1. The banner says to run preflight first. Saved answers show in brackets, Enter keeps them. Setup prints a summary and waits for y before it changes anything.

