Microsoft Teams Tool
Read Microsoft Teams teams, channels and channel messages, and post to a channel. Every route addresses the tenant rather than /me, so it works on an app-only credential — which is what a schedule needs.
Tool ID
msgraph-teams
Credential Required
Yes — the shared msgraph credential, owned by the msgraph connector. Configure the tenant
once and all nine tools use it; rotating the client secret is one edit rather than nine.
It is a server-managed OAuth credential: InTouch mints and refreshes the access token itself and
the connector never sees the secret. For unattended work set grant_type to client_credentials
(the app-only grant) — an app-only token belongs to the application, so a 06:00 schedule does not
run as a person, see only what that person can see, and stop working the day they leave.
Credential Properties
| Property | Type | Default | Description |
|---|---|---|---|
client_id |
string | — | Required. The Entra app registration's Application (client) ID. |
client_secret |
string | — | Required for app-only. The secret's Value, not its Secret ID. |
token_url |
string | — | Required. https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token |
grant_type |
string | (blank) | client_credentials for unattended app-only use. Blank means the user-delegated refresh-token flow. |
scope |
string | — | https://graph.microsoft.com/.default — resolves to whatever application permissions an admin has consented to. |
access_token |
string | — | Machine-managed. Leave empty; the server mints and persists it. |
refresh_token |
string | — | Delegated credentials only. Not used by the app-only grant. |
expires_at |
string | 0 |
Machine-managed expiry, epoch seconds. |
Entra setup
- https://entra.microsoft.com → App registrations → your app → API permissions.
- Add a permission → Microsoft Graph → Application permissions — not Delegated. Picking Delegated is the most common failure: it consents cleanly and then 403s at runtime.
- Tick the permissions listed under Permissions below, then Grant admin consent. The Status column must read Granted.
- Permissions live in the token, not the portal. A token minted before the grant carries the old
claims for about an hour — blank
access_tokento force a fresh mint.
Permissions
Team.ReadBasic.All and Channel.ReadBasic.All for enumeration; ChannelMessage.Read.All to read messages; ChannelMessage.Send (delegated) to post.
Operations
1. list_teams — List teams
Every team in the tenant. Works app-only — the enumeration a /me-based connector cannot do. Calls GET /teams.
Properties:
| Property | Type | Default | Description |
|---|---|---|---|
operation |
string | — | Required. list_teams |
query |
string | — | Optional. OData query params as a JSON object string — e.g. {"$top": 20} to cap a message listing. |
Published Outputs:
- result — the JSON response body
- status — HTTP status code
2. get_team — Get one team
One team by id. Calls GET /teams/{id}.
Properties:
| Property | Type | Default | Description |
|---|---|---|---|
operation |
string | — | Required. get_team |
id |
string | — | Required. Team id. Required by get_team, list_channels, get_channel, list_channel_messages and send_channel_message. |
query |
string | — | Optional. OData query params as a JSON object string — e.g. {"$top": 20} to cap a message listing. |
Published Outputs:
- result — the JSON response body
- status — HTTP status code
3. list_user_joined_teams — List a user's teams
One person's teams, addressed by user rather than by "me", so a schedule can ask it. Calls GET /users/{userId}/joinedTeams.
Properties:
| Property | Type | Default | Description |
|---|---|---|---|
operation |
string | — | Required. list_user_joined_teams |
userId |
string | — | Required. User id or userPrincipalName (e.g. [email protected]). Required by list_user_joined_teams. |
query |
string | — | Optional. OData query params as a JSON object string — e.g. {"$top": 20} to cap a message listing. |
Published Outputs:
- result — the JSON response body
- status — HTTP status code
4. list_channels — List channels
The channels in a team. Calls GET /teams/{id}/channels.
Properties:
| Property | Type | Default | Description |
|---|---|---|---|
operation |
string | — | Required. list_channels |
id |
string | — | Required. Team id. Required by get_team, list_channels, get_channel, list_channel_messages and send_channel_message. |
query |
string | — | Optional. OData query params as a JSON object string — e.g. {"$top": 20} to cap a message listing. |
Published Outputs:
- result — the JSON response body
- status — HTTP status code
5. get_channel — Get one channel
One channel by id. Calls GET /teams/{id}/channels/{channelId}.
Properties:
| Property | Type | Default | Description |
|---|---|---|---|
operation |
string | — | Required. get_channel |
id |
string | — | Required. Team id. Required by get_team, list_channels, get_channel, list_channel_messages and send_channel_message. |
channelId |
string | — | Required. Channel id. Required by get_channel, list_channel_messages and send_channel_message. |
query |
string | — | Optional. OData query params as a JSON object string — e.g. {"$top": 20} to cap a message listing. |
Published Outputs:
- result — the JSON response body
- status — HTTP status code
6. list_channel_messages — List channel messages
Channel message history. App-only needs the protected-API approval described below. Calls GET /teams/{id}/channels/{channelId}/messages.
Properties:
| Property | Type | Default | Description |
|---|---|---|---|
operation |
string | — | Required. list_channel_messages |
id |
string | — | Required. Team id. Required by get_team, list_channels, get_channel, list_channel_messages and send_channel_message. |
channelId |
string | — | Required. Channel id. Required by get_channel, list_channel_messages and send_channel_message. |
query |
string | — | Optional. OData query params as a JSON object string — e.g. {"$top": 20} to cap a message listing. |
Published Outputs:
- result — the JSON response body
- status — HTTP status code
7. send_channel_message — Post to a channel
Post a message. Delegated credentials only — see the notes. Calls POST /teams/{id}/channels/{channelId}/messages.
Properties:
| Property | Type | Default | Description |
|---|---|---|---|
operation |
string | — | Required. send_channel_message |
id |
string | — | Required. Team id. Required by get_team, list_channels, get_channel, list_channel_messages and send_channel_message. |
channelId |
string | — | Required. Channel id. Required by get_channel, list_channel_messages and send_channel_message. |
body |
string | — | Required. Message to post, as a JSON object string — {"body": {"content": "Nightly load finished"}}. Use {"body": {"contentType": "html", "content": "done"}} for formatting. Only used by send_channel_message. |
query |
string | — | Optional. OData query params as a JSON object string — e.g. {"$top": 20} to cap a message listing. |
Published Outputs:
- result — the JSON response body
- status — HTTP status code
Paging
Graph answers a collection with 100 rows and an @odata.nextLink, so a naive listing returns a
fraction of a large tenant with HTTP 200 and no sign anything is missing. This connector follows
the continuation link until the collection is exhausted. If it stops at the page cap it says so —
the result carries complete: false with a warning, and the step returns WARNING rather than
SUCCESS. A page cap must never look like the end of the data.
Notes — two limits that are not bugs
Reading channel messages app-only is a protected API. ChannelMessage.Read.All on an
application token is not granted by consenting in the portal alone: Microsoft gates it behind an
application form, and approved usage is metered and billed per message under the Teams API payment
model. Expect 403 until that is approved. The same call on a delegated credential — a person's
own token, their own channels — needs no approval. Enumerating teams and channels is not
protected; only message content is.
Posting is delegated-only, at any price. ChannelMessage.Send exists in Entra as a Delegated
permission and not as an Application one. No consent makes an app-only credential post a normal
channel message; the app-only routes are the Teams migration APIs or a registered bot, neither of
which is a REST call a job can make. For a scheduled job that must announce something to a channel,
use an incoming webhook or InTouch's own messaging.
Self-Contained JAR
The jar bundles all runtime dependencies; only intouch-tool-api is provided by the server.
Publishes
The keys a later task may reference as {{taskName.key}}. Referencing anything not listed here resolves to nothing at run time.
completeoperationresultstatuswarning