How It Works
The Teams server runs as a local STDIO process alongside Octo. It uses Microsoft Graph API with user-consent-only scopes and ships a pre-registered public client ID, so authentication is a one-time device code flow — open a URL, enter a code, done.The server uses the same pre-registered Azure AD application as Softeria ms-365-mcp-server. No tenant admin involvement needed.
Setup
The Teams server is included with Octo. Just add the entry to.mcp.json:
Authentication
Complete device code flow
The server prints a URL and code to the console:Open the URL, enter the code, and sign in with your Microsoft account.
Approve permissions
Microsoft shows a consent screen for these permissions:
Click Accept. All permissions are user-consent — no admin approval needed.
| Permission | Description |
|---|---|
| Read your chat messages | Chat.Read |
| Send chat messages | ChatMessage.Send |
| Read names and descriptions of teams | Team.ReadBasic.All |
| Read names and descriptions of channels | Channel.ReadBasic.All |
| Sign you in and read your profile | User.Read |
Available Tools
The server exposes 10 tools:| Tool | Description |
|---|---|
login | Authenticate via device code flow |
logout | Clear cached tokens |
list-chats | List recent chats with message previews and members |
list-chat-messages | Read messages from a specific chat |
list-chat-members | List members of a chat |
find-chat | Search for chats by person name or topic |
send-chat-message | Send a message to a chat |
reply-to-chat-message | Reply to a specific message |
list-joined-teams | List Teams you belong to |
list-team-channels | List channels in a Team |
Parameter Names
All parameters use camelCase to match what LLMs naturally generate:Contacts Cache
The server maintains a local contacts cache at~/.octo/teams_contacts.json. This lets the find-chat tool resolve names instantly without calling the API.
How It Builds
The cache auto-populates when you uselist-chats — member names and chat metadata are indexed. After one list-chats call with 50 chats, the cache typically contains 1000+ users from your organization.
How find-chat Uses It
- You ask: “check messages from Valentina”
- Agent calls
find-chatwithquery: "Valentina" - Server searches the cache by name — instant match
- Agent gets the chat ID and calls
list-chat-messages
find-chat automatically fetches the 50 most recent chats, updates the cache, and retries.
Token & Cache Storage
All state is stored under~/.octo/ by default:
| File | Purpose |
|---|---|
~/.octo/teams_token_cache.json | MSAL token cache (access + refresh tokens) |
~/.octo/teams_contacts.json | Contacts and chat index for fast lookups |
0600 (owner-only read/write).
Overriding Locations
| Environment Variable | Default | Description |
|---|---|---|
TEAMS_TOKEN_CACHE | ~/.octo/teams_token_cache.json | Path to the MSAL token cache file |
TEAMS_CACHE_DIR | ~/.octo | Directory for the contacts cache |
TEAMS_CLIENT_ID | Pre-registered public client | Override with your own Azure AD app |
TEAMS_TENANT_ID | common | Azure AD tenant ID |
.mcp.json under env if needed:
Permissions & Limitations
What Works (user-consent only)
- Reading 1:1 and group chat messages
- Sending messages to any chat you’re a member of
- Replying to specific messages
- Listing teams and channels you belong to
- Browsing chat members
What Doesn’t Work (requires admin consent)
| Feature | Required Scope | Why |
|---|---|---|
| Reading channel messages | ChannelMessage.Read.All | Admin consent required |
| Posting to channels | ChannelMessage.Send | Admin consent required |
| Reading all user chats (app-level) | Chat.Read.All | Application permission |
If your organization’s Azure AD admin has pre-approved these scopes for the Softeria app, channel features may work. But Octo does not request them by default.
Using Your Own Azure AD App
If you prefer to use your own app registration (e.g., to request additional scopes or for compliance):Register an app
Go to Azure Portal > App registrations > New registration.
- Name: anything (e.g., “Octo Teams”)
- Supported account types: Accounts in any organizational directory (multi-tenant)
Enable public client
Under Authentication > Advanced settings, set Allow public client flows to Yes.
Add API permissions
Under API permissions > Add a permission > Microsoft Graph > Delegated:
User.ReadChat.ReadChatMessage.SendTeam.ReadBasic.AllChannel.ReadBasic.All
ChannelMessage.Read.All — requires admin consent).Troubleshooting
Token expired or invalid
Token expired or invalid
The refresh token may have expired. Run Or delete the cache file:
logout then login again:rm ~/.octo/teams_token_cache.jsonPermission denied for /me/chats
Permission denied for /me/chats
Your organization may block the
Chat.Read scope. Check with your Azure AD admin, or try using your own app registration with admin-approved scopes.find-chat returns no results
find-chat returns no results
The contacts cache may not be populated yet. Run Then retry your search.
list-chats with a high limit first:MCP server fails to start
MCP server fails to start
Verify the Python path is correct and
msal is installed:Device code not visible
Device code not visible
The device code is printed to stderr. If your MCP client doesn’t show stderr, check the process output manually or look for the
login tool’s return value.
